Merge branch 'master' into 2phase_thd

pull/14583/head
Vijay Pai 7 years ago
commit b357f2f548
  1. 17
      BUILD
  2. 228
      CMakeLists.txt
  3. 288
      Makefile
  4. 2
      README.md
  5. 8
      bazel/grpc_deps.bzl
  6. 66
      build.yaml
  7. 6
      config.m4
  8. 6
      config.w32
  9. 8
      gRPC-C++.podspec
  10. 33
      gRPC-Core.podspec
  11. 12
      grpc.gemspec
  12. 48
      grpc.gyp
  13. 10
      include/grpc/impl/codegen/grpc_types.h
  14. 12
      package.xml
  15. 15
      src/compiler/csharp_generator.cc
  16. 104
      src/compiler/objective_c_generator.cc
  17. 10
      src/compiler/objective_c_generator.h
  18. 40
      src/compiler/objective_c_generator_helpers.h
  19. 145
      src/compiler/objective_c_plugin.cc
  20. 19
      src/core/ext/filters/client_channel/backup_poller.cc
  21. 2
      src/core/ext/filters/client_channel/backup_poller.h
  22. 2197
      src/core/ext/filters/client_channel/client_channel.cc
  23. 55
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc
  24. 178
      src/core/ext/filters/client_channel/method_params.cc
  25. 74
      src/core/ext/filters/client_channel/method_params.h
  26. 8
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  27. 4
      src/core/ext/filters/client_channel/retry_throttle.cc
  28. 100
      src/core/ext/filters/client_channel/status_util.cc
  29. 58
      src/core/ext/filters/client_channel/status_util.h
  30. 15
      src/core/ext/filters/client_channel/subchannel.cc
  31. 9
      src/core/ext/filters/client_channel/subchannel.h
  32. 3
      src/core/ext/filters/max_age/max_age_filter.cc
  33. 89
      src/core/ext/filters/message_size/message_size_filter.cc
  34. 39
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc
  35. 12
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  36. 3
      src/core/ext/transport/chttp2/transport/incoming_metadata.cc
  37. 45
      src/core/lib/gpr/arena.cc
  38. 1
      src/core/lib/gprpp/orphanable.h
  39. 2
      src/core/lib/gprpp/ref_counted.h
  40. 1
      src/core/lib/gprpp/ref_counted_ptr.h
  41. 3
      src/core/lib/security/credentials/fake/fake_credentials.cc
  42. 3
      src/core/lib/security/credentials/fake/fake_credentials.h
  43. 13
      src/core/lib/security/security_connector/security_connector.cc
  44. 61
      src/core/lib/security/transport/lb_targets_info.cc
  45. 75
      src/core/lib/security/transport/target_authority_table.cc
  46. 40
      src/core/lib/security/transport/target_authority_table.h
  47. 147
      src/core/lib/slice/slice_hash_table.cc
  48. 221
      src/core/lib/slice/slice_hash_table.h
  49. 105
      src/core/lib/slice/slice_weak_hash_table.h
  50. 30
      src/core/lib/surface/call.cc
  51. 24
      src/core/lib/transport/metadata_batch.cc
  52. 9
      src/core/lib/transport/metadata_batch.h
  53. 194
      src/core/lib/transport/service_config.cc
  54. 256
      src/core/lib/transport/service_config.h
  55. 602
      src/core/lib/transport/static_metadata.cc
  56. 176
      src/core/lib/transport/static_metadata.h
  57. 54
      src/core/lib/transport/status_metadata.cc
  58. 16
      src/core/lib/transport/status_metadata.h
  59. 27
      src/core/lib/transport/transport.h
  60. 13
      src/csharp/Grpc.Examples/MathGrpc.cs
  61. 7
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  62. 142
      src/csharp/Grpc.IntegrationTesting/Control.cs
  63. 2
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  64. 9
      src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
  65. 31
      src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
  66. 39
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  67. 5
      src/csharp/Grpc.Reflection/ReflectionGrpc.cs
  68. 2
      src/csharp/global.json
  69. 136
      src/objective-c/GRPCClient/GRPCCall.m
  70. 58
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
  71. 199
      src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
  72. 25
      src/objective-c/GRPCClient/private/GRPCHost.m
  73. 6
      src/python/grpcio/grpc_core_dependencies.py
  74. 4
      summerofcode/ideas.md
  75. 11
      test/core/client_channel/BUILD
  76. 49
      test/core/client_channel/status_util_test.cc
  77. 120
      test/core/end2end/end2end_nosec_tests.cc
  78. 120
      test/core/end2end/end2end_tests.cc
  79. 12
      test/core/end2end/fixtures/h2_proxy.cc
  80. 8
      test/core/end2end/fuzzers/hpack.dictionary
  81. 116
      test/core/end2end/gen_build_yaml.py
  82. 65
      test/core/end2end/generate_tests.bzl
  83. 325
      test/core/end2end/tests/retry.cc
  84. 277
      test/core/end2end/tests/retry_cancellation.cc
  85. 262
      test/core/end2end/tests/retry_disabled.cc
  86. 266
      test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
  87. 276
      test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
  88. 257
      test/core/end2end/tests/retry_non_retriable_status.cc
  89. 268
      test/core/end2end/tests/retry_recv_initial_metadata.cc
  90. 261
      test/core/end2end/tests/retry_recv_message.cc
  91. 318
      test/core/end2end/tests/retry_server_pushback_delay.cc
  92. 306
      test/core/end2end/tests/retry_server_pushback_disabled.cc
  93. 424
      test/core/end2end/tests/retry_streaming.cc
  94. 354
      test/core/end2end/tests/retry_streaming_after_commit.cc
  95. 400
      test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
  96. 264
      test/core/end2end/tests/retry_throttled.cc
  97. 299
      test/core/end2end/tests/retry_too_many_attempts.cc
  98. 43
      test/core/slice/BUILD
  99. 248
      test/core/slice/slice_hash_table_test.cc
  100. 105
      test/core/slice/slice_weak_hash_table_test.cc
  101. Some files were not shown because too many files have changed in this diff Show More

17
BUILD

@ -55,7 +55,7 @@ config_setting(
config_setting(
name = "windows",
values = { "cpu": "x64_windows" },
values = {"cpu": "x64_windows"},
)
config_setting(
@ -778,7 +778,6 @@ grpc_cc_library(
"src/core/lib/slice/percent_encoding.cc",
"src/core/lib/slice/slice.cc",
"src/core/lib/slice/slice_buffer.cc",
"src/core/lib/slice/slice_hash_table.cc",
"src/core/lib/slice/slice_intern.cc",
"src/core/lib/slice/slice_string_helpers.cc",
"src/core/lib/surface/api_trace.cc",
@ -808,6 +807,7 @@ grpc_cc_library(
"src/core/lib/transport/service_config.cc",
"src/core/lib/transport/static_metadata.cc",
"src/core/lib/transport/status_conversion.cc",
"src/core/lib/transport/status_metadata.cc",
"src/core/lib/transport/timeout_encoding.cc",
"src/core/lib/transport/transport.cc",
"src/core/lib/transport/transport_op_string.cc",
@ -906,6 +906,7 @@ grpc_cc_library(
"src/core/lib/slice/slice_hash_table.h",
"src/core/lib/slice/slice_internal.h",
"src/core/lib/slice/slice_string_helpers.h",
"src/core/lib/slice/slice_weak_hash_table.h",
"src/core/lib/surface/api_trace.h",
"src/core/lib/surface/call.h",
"src/core/lib/surface/call_test_only.h",
@ -930,6 +931,7 @@ grpc_cc_library(
"src/core/lib/transport/service_config.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/status_conversion.h",
"src/core/lib/transport/status_metadata.h",
"src/core/lib/transport/timeout_encoding.h",
"src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h",
@ -944,6 +946,9 @@ grpc_cc_library(
"gpr_base",
"grpc_codegen",
"grpc_trace",
"ref_counted",
"ref_counted_ptr",
"inlined_vector",
],
)
@ -998,12 +1003,14 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy.cc",
"src/core/ext/filters/client_channel/lb_policy_factory.cc",
"src/core/ext/filters/client_channel/lb_policy_registry.cc",
"src/core/ext/filters/client_channel/method_params.cc",
"src/core/ext/filters/client_channel/parse_address.cc",
"src/core/ext/filters/client_channel/proxy_mapper.cc",
"src/core/ext/filters/client_channel/proxy_mapper_registry.cc",
"src/core/ext/filters/client_channel/resolver.cc",
"src/core/ext/filters/client_channel/resolver_registry.cc",
"src/core/ext/filters/client_channel/retry_throttle.cc",
"src/core/ext/filters/client_channel/status_util.cc",
"src/core/ext/filters/client_channel/subchannel.cc",
"src/core/ext/filters/client_channel/subchannel_index.cc",
"src/core/ext/filters/client_channel/uri_parser.cc",
@ -1018,6 +1025,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/lb_policy.h",
"src/core/ext/filters/client_channel/lb_policy_factory.h",
"src/core/ext/filters/client_channel/lb_policy_registry.h",
"src/core/ext/filters/client_channel/method_params.h",
"src/core/ext/filters/client_channel/parse_address.h",
"src/core/ext/filters/client_channel/proxy_mapper.h",
"src/core/ext/filters/client_channel/proxy_mapper_registry.h",
@ -1025,6 +1033,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/resolver_factory.h",
"src/core/ext/filters/client_channel/resolver_registry.h",
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/status_util.h",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_index.h",
"src/core/ext/filters/client_channel/uri_parser.h",
@ -1327,10 +1336,10 @@ grpc_cc_library(
"src/core/lib/security/credentials/ssl/ssl_credentials.cc",
"src/core/lib/security/security_connector/security_connector.cc",
"src/core/lib/security/transport/client_auth_filter.cc",
"src/core/lib/security/transport/lb_targets_info.cc",
"src/core/lib/security/transport/secure_endpoint.cc",
"src/core/lib/security/transport/security_handshaker.cc",
"src/core/lib/security/transport/server_auth_filter.cc",
"src/core/lib/security/transport/target_authority_table.cc",
"src/core/lib/security/transport/tsi_error.cc",
"src/core/lib/security/util/json_util.cc",
"src/core/lib/surface/init_secure.cc",
@ -1350,9 +1359,9 @@ grpc_cc_library(
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/security_connector/security_connector.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/lb_targets_info.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_handshaker.h",
"src/core/lib/security/transport/target_authority_table.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/json_util.h",
],

@ -344,7 +344,6 @@ add_dependencies(buildtests_c sequential_connectivity_test)
add_dependencies(buildtests_c server_chttp2_test)
add_dependencies(buildtests_c server_test)
add_dependencies(buildtests_c slice_buffer_test)
add_dependencies(buildtests_c slice_hash_table_test)
add_dependencies(buildtests_c slice_string_helpers_test)
add_dependencies(buildtests_c slice_test)
add_dependencies(buildtests_c sockaddr_resolver_test)
@ -594,8 +593,12 @@ add_dependencies(buildtests_cxx server_crash_test_client)
add_dependencies(buildtests_cxx server_early_return_test)
add_dependencies(buildtests_cxx server_request_call_test)
add_dependencies(buildtests_cxx shutdown_test)
add_dependencies(buildtests_cxx slice_hash_table_test)
add_dependencies(buildtests_cxx slice_weak_hash_table_test)
add_dependencies(buildtests_cxx stats_test)
add_dependencies(buildtests_cxx status_metadata_test)
add_dependencies(buildtests_cxx status_test)
add_dependencies(buildtests_cxx status_util_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx streaming_throughput_test)
endif()
@ -880,7 +883,6 @@ add_library(grpc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -911,6 +913,7 @@ add_library(grpc
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -960,10 +963,10 @@ add_library(grpc
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/security_connector/security_connector.cc
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/lb_targets_info.cc
src/core/lib/security/transport/secure_endpoint.cc
src/core/lib/security/transport/security_handshaker.cc
src/core/lib/security/transport/server_auth_filter.cc
src/core/lib/security/transport/target_authority_table.cc
src/core/lib/security/transport/tsi_error.cc
src/core/lib/security/util/json_util.cc
src/core/lib/surface/init_secure.cc
@ -986,12 +989,14 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -1220,7 +1225,6 @@ add_library(grpc_cronet
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -1251,6 +1255,7 @@ add_library(grpc_cronet
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -1297,12 +1302,14 @@ add_library(grpc_cronet
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -1324,10 +1331,10 @@ add_library(grpc_cronet
src/core/lib/security/credentials/ssl/ssl_credentials.cc
src/core/lib/security/security_connector/security_connector.cc
src/core/lib/security/transport/client_auth_filter.cc
src/core/lib/security/transport/lb_targets_info.cc
src/core/lib/security/transport/secure_endpoint.cc
src/core/lib/security/transport/security_handshaker.cc
src/core/lib/security/transport/server_auth_filter.cc
src/core/lib/security/transport/target_authority_table.cc
src/core/lib/security/transport/tsi_error.cc
src/core/lib/security/util/json_util.cc
src/core/lib/surface/init_secure.cc
@ -1546,7 +1553,6 @@ add_library(grpc_test_util
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -1577,6 +1583,7 @@ add_library(grpc_test_util
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -1592,12 +1599,14 @@ add_library(grpc_test_util
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -1833,7 +1842,6 @@ add_library(grpc_test_util_unsecure
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -1864,6 +1872,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -1879,12 +1888,14 @@ add_library(grpc_test_util_unsecure
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -2100,7 +2111,6 @@ add_library(grpc_unsecure
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -2131,6 +2141,7 @@ add_library(grpc_unsecure
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -2179,12 +2190,14 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -2899,7 +2912,6 @@ add_library(grpc++_cronet
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
src/core/lib/slice/slice_buffer.cc
src/core/lib/slice/slice_hash_table.cc
src/core/lib/slice/slice_intern.cc
src/core/lib/slice/slice_string_helpers.cc
src/core/lib/surface/api_trace.cc
@ -2930,6 +2942,7 @@ add_library(grpc++_cronet
src/core/lib/transport/service_config.cc
src/core/lib/transport/static_metadata.cc
src/core/lib/transport/status_conversion.cc
src/core/lib/transport/status_metadata.cc
src/core/lib/transport/timeout_encoding.cc
src/core/lib/transport/transport.cc
src/core/lib/transport/transport_op_string.cc
@ -2950,12 +2963,14 @@ add_library(grpc++_cronet
src/core/ext/filters/client_channel/lb_policy.cc
src/core/ext/filters/client_channel/lb_policy_factory.cc
src/core/ext/filters/client_channel/lb_policy_registry.cc
src/core/ext/filters/client_channel/method_params.cc
src/core/ext/filters/client_channel/parse_address.cc
src/core/ext/filters/client_channel/proxy_mapper.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
src/core/ext/filters/client_channel/resolver_registry.cc
src/core/ext/filters/client_channel/retry_throttle.cc
src/core/ext/filters/client_channel/status_util.cc
src/core/ext/filters/client_channel/subchannel.cc
src/core/ext/filters/client_channel/subchannel_index.cc
src/core/ext/filters/client_channel/uri_parser.cc
@ -4867,6 +4882,21 @@ add_library(end2end_tests
test/core/end2end/tests/request_with_flags.cc
test/core/end2end/tests/request_with_payload.cc
test/core/end2end/tests/resource_quota_server.cc
test/core/end2end/tests/retry.cc
test/core/end2end/tests/retry_cancellation.cc
test/core/end2end/tests/retry_disabled.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
test/core/end2end/tests/retry_non_retriable_status.cc
test/core/end2end/tests/retry_recv_initial_metadata.cc
test/core/end2end/tests/retry_recv_message.cc
test/core/end2end/tests/retry_server_pushback_delay.cc
test/core/end2end/tests/retry_server_pushback_disabled.cc
test/core/end2end/tests/retry_streaming.cc
test/core/end2end/tests/retry_streaming_after_commit.cc
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
test/core/end2end/tests/retry_throttled.cc
test/core/end2end/tests/retry_too_many_attempts.cc
test/core/end2end/tests/server_finishes_request.cc
test/core/end2end/tests/shutdown_finishes_calls.cc
test/core/end2end/tests/shutdown_finishes_tags.cc
@ -4967,6 +4997,21 @@ add_library(end2end_nosec_tests
test/core/end2end/tests/request_with_flags.cc
test/core/end2end/tests/request_with_payload.cc
test/core/end2end/tests/resource_quota_server.cc
test/core/end2end/tests/retry.cc
test/core/end2end/tests/retry_cancellation.cc
test/core/end2end/tests/retry_disabled.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
test/core/end2end/tests/retry_non_retriable_status.cc
test/core/end2end/tests/retry_recv_initial_metadata.cc
test/core/end2end/tests/retry_recv_message.cc
test/core/end2end/tests/retry_server_pushback_delay.cc
test/core/end2end/tests/retry_server_pushback_disabled.cc
test/core/end2end/tests/retry_streaming.cc
test/core/end2end/tests/retry_streaming_after_commit.cc
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc
test/core/end2end/tests/retry_throttled.cc
test/core/end2end/tests/retry_too_many_attempts.cc
test/core/end2end/tests/server_finishes_request.cc
test/core/end2end/tests/shutdown_finishes_calls.cc
test/core/end2end/tests/shutdown_finishes_tags.cc
@ -7879,33 +7924,6 @@ target_link_libraries(slice_buffer_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(slice_hash_table_test
test/core/slice/slice_hash_table_test.cc
)
target_include_directories(slice_hash_table_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
)
target_link_libraries(slice_hash_table_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(slice_string_helpers_test
test/core/slice/slice_string_helpers_test.cc
)
@ -12103,6 +12121,78 @@ target_link_libraries(shutdown_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(slice_hash_table_test
test/core/slice/slice_hash_table_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(slice_hash_table_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(slice_hash_table_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(slice_weak_hash_table_test
test/core/slice/slice_weak_hash_table_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(slice_weak_hash_table_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(slice_weak_hash_table_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(stats_test
test/core/debug/stats_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -12140,6 +12230,39 @@ target_link_libraries(stats_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(status_metadata_test
test/core/transport/status_metadata_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(status_metadata_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(status_metadata_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(status_test
test/cpp/util/status_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -12174,6 +12297,39 @@ target_link_libraries(status_test
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(status_util_test
test/core/client_channel/status_util_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(status_util_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(status_util_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)

@ -1067,7 +1067,6 @@ server_chttp2_test: $(BINDIR)/$(CONFIG)/server_chttp2_test
server_fuzzer: $(BINDIR)/$(CONFIG)/server_fuzzer
server_test: $(BINDIR)/$(CONFIG)/server_test
slice_buffer_test: $(BINDIR)/$(CONFIG)/slice_buffer_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
slice_string_helpers_test: $(BINDIR)/$(CONFIG)/slice_string_helpers_test
slice_test: $(BINDIR)/$(CONFIG)/slice_test
sockaddr_resolver_test: $(BINDIR)/$(CONFIG)/sockaddr_resolver_test
@ -1181,8 +1180,12 @@ server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client
server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test
server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test
shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test
slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test
slice_weak_hash_table_test: $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test
stats_test: $(BINDIR)/$(CONFIG)/stats_test
status_metadata_test: $(BINDIR)/$(CONFIG)/status_metadata_test
status_test: $(BINDIR)/$(CONFIG)/status_test
status_util_test: $(BINDIR)/$(CONFIG)/status_util_test
streaming_throughput_test: $(BINDIR)/$(CONFIG)/streaming_throughput_test
stress_test: $(BINDIR)/$(CONFIG)/stress_test
thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
@ -1469,7 +1472,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/server_chttp2_test \
$(BINDIR)/$(CONFIG)/server_test \
$(BINDIR)/$(CONFIG)/slice_buffer_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
$(BINDIR)/$(CONFIG)/slice_string_helpers_test \
$(BINDIR)/$(CONFIG)/slice_test \
$(BINDIR)/$(CONFIG)/sockaddr_resolver_test \
@ -1639,8 +1641,12 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
$(BINDIR)/$(CONFIG)/stats_test \
$(BINDIR)/$(CONFIG)/status_metadata_test \
$(BINDIR)/$(CONFIG)/status_test \
$(BINDIR)/$(CONFIG)/status_util_test \
$(BINDIR)/$(CONFIG)/streaming_throughput_test \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
@ -1783,8 +1789,12 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/server_early_return_test \
$(BINDIR)/$(CONFIG)/server_request_call_test \
$(BINDIR)/$(CONFIG)/shutdown_test \
$(BINDIR)/$(CONFIG)/slice_hash_table_test \
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test \
$(BINDIR)/$(CONFIG)/stats_test \
$(BINDIR)/$(CONFIG)/status_metadata_test \
$(BINDIR)/$(CONFIG)/status_test \
$(BINDIR)/$(CONFIG)/status_util_test \
$(BINDIR)/$(CONFIG)/streaming_throughput_test \
$(BINDIR)/$(CONFIG)/stress_test \
$(BINDIR)/$(CONFIG)/thread_manager_test \
@ -1994,8 +2004,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/server_test || ( echo test server_test failed ; exit 1 )
$(E) "[RUN] Testing slice_buffer_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_buffer_test || ( echo test slice_buffer_test failed ; exit 1 )
$(E) "[RUN] Testing slice_hash_table_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_hash_table_test || ( echo test slice_hash_table_test failed ; exit 1 )
$(E) "[RUN] Testing slice_string_helpers_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_string_helpers_test || ( echo test slice_string_helpers_test failed ; exit 1 )
$(E) "[RUN] Testing slice_test"
@ -2208,10 +2216,18 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 )
$(E) "[RUN] Testing shutdown_test"
$(Q) $(BINDIR)/$(CONFIG)/shutdown_test || ( echo test shutdown_test failed ; exit 1 )
$(E) "[RUN] Testing slice_hash_table_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_hash_table_test || ( echo test slice_hash_table_test failed ; exit 1 )
$(E) "[RUN] Testing slice_weak_hash_table_test"
$(Q) $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test || ( echo test slice_weak_hash_table_test failed ; exit 1 )
$(E) "[RUN] Testing stats_test"
$(Q) $(BINDIR)/$(CONFIG)/stats_test || ( echo test stats_test failed ; exit 1 )
$(E) "[RUN] Testing status_metadata_test"
$(Q) $(BINDIR)/$(CONFIG)/status_metadata_test || ( echo test status_metadata_test failed ; exit 1 )
$(E) "[RUN] Testing status_test"
$(Q) $(BINDIR)/$(CONFIG)/status_test || ( echo test status_test failed ; exit 1 )
$(E) "[RUN] Testing status_util_test"
$(Q) $(BINDIR)/$(CONFIG)/status_util_test || ( echo test status_util_test failed ; exit 1 )
$(E) "[RUN] Testing streaming_throughput_test"
$(Q) $(BINDIR)/$(CONFIG)/streaming_throughput_test || ( echo test streaming_throughput_test failed ; exit 1 )
$(E) "[RUN] Testing thread_manager_test"
@ -3114,7 +3130,6 @@ LIBGRPC_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -3145,6 +3160,7 @@ LIBGRPC_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -3194,10 +3210,10 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/lb_targets_info.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
src/core/lib/security/transport/server_auth_filter.cc \
src/core/lib/security/transport/target_authority_table.cc \
src/core/lib/security/transport/tsi_error.cc \
src/core/lib/security/util/json_util.cc \
src/core/lib/surface/init_secure.cc \
@ -3220,12 +3236,14 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -3456,7 +3474,6 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -3487,6 +3504,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -3533,12 +3551,14 @@ LIBGRPC_CRONET_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -3560,10 +3580,10 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/lb_targets_info.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
src/core/lib/security/transport/server_auth_filter.cc \
src/core/lib/security/transport/target_authority_table.cc \
src/core/lib/security/transport/tsi_error.cc \
src/core/lib/security/util/json_util.cc \
src/core/lib/surface/init_secure.cc \
@ -3783,7 +3803,6 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -3814,6 +3833,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -3829,12 +3849,14 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -4063,7 +4085,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -4094,6 +4115,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -4109,12 +4131,14 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -4310,7 +4334,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -4341,6 +4364,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -4389,12 +4413,14 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -5110,7 +5136,6 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -5141,6 +5166,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -5161,12 +5187,14 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \
@ -9402,6 +9430,21 @@ LIBEND2END_TESTS_SRC = \
test/core/end2end/tests/request_with_flags.cc \
test/core/end2end/tests/request_with_payload.cc \
test/core/end2end/tests/resource_quota_server.cc \
test/core/end2end/tests/retry.cc \
test/core/end2end/tests/retry_cancellation.cc \
test/core/end2end/tests/retry_disabled.cc \
test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
test/core/end2end/tests/retry_non_retriable_status.cc \
test/core/end2end/tests/retry_recv_initial_metadata.cc \
test/core/end2end/tests/retry_recv_message.cc \
test/core/end2end/tests/retry_server_pushback_delay.cc \
test/core/end2end/tests/retry_server_pushback_disabled.cc \
test/core/end2end/tests/retry_streaming.cc \
test/core/end2end/tests/retry_streaming_after_commit.cc \
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc \
test/core/end2end/tests/retry_throttled.cc \
test/core/end2end/tests/retry_too_many_attempts.cc \
test/core/end2end/tests/server_finishes_request.cc \
test/core/end2end/tests/shutdown_finishes_calls.cc \
test/core/end2end/tests/shutdown_finishes_tags.cc \
@ -9501,6 +9544,21 @@ LIBEND2END_NOSEC_TESTS_SRC = \
test/core/end2end/tests/request_with_flags.cc \
test/core/end2end/tests/request_with_payload.cc \
test/core/end2end/tests/resource_quota_server.cc \
test/core/end2end/tests/retry.cc \
test/core/end2end/tests/retry_cancellation.cc \
test/core/end2end/tests/retry_disabled.cc \
test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
test/core/end2end/tests/retry_non_retriable_status.cc \
test/core/end2end/tests/retry_recv_initial_metadata.cc \
test/core/end2end/tests/retry_recv_message.cc \
test/core/end2end/tests/retry_server_pushback_delay.cc \
test/core/end2end/tests/retry_server_pushback_disabled.cc \
test/core/end2end/tests/retry_streaming.cc \
test/core/end2end/tests/retry_streaming_after_commit.cc \
test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc \
test/core/end2end/tests/retry_throttled.cc \
test/core/end2end/tests/retry_too_many_attempts.cc \
test/core/end2end/tests/server_finishes_request.cc \
test/core/end2end/tests/shutdown_finishes_calls.cc \
test/core/end2end/tests/shutdown_finishes_tags.cc \
@ -13305,38 +13363,6 @@ endif
endif
SLICE_HASH_TABLE_TEST_SRC = \
test/core/slice/slice_hash_table_test.cc \
SLICE_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_HASH_TABLE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/slice_hash_table_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/slice_hash_table_test
endif
$(OBJDIR)/$(CONFIG)/test/core/slice/slice_hash_table_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
endif
endif
SLICE_STRING_HELPERS_TEST_SRC = \
test/core/slice/slice_string_helpers_test.cc \
@ -17909,6 +17935,92 @@ endif
endif
SLICE_HASH_TABLE_TEST_SRC = \
test/core/slice/slice_hash_table_test.cc \
SLICE_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_HASH_TABLE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/slice_hash_table_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/slice_hash_table_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/slice_hash_table_test: $(PROTOBUF_DEP) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(SLICE_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/slice_hash_table_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/slice/slice_hash_table_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_slice_hash_table_test: $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SLICE_HASH_TABLE_TEST_OBJS:.o=.dep)
endif
endif
SLICE_WEAK_HASH_TABLE_TEST_SRC = \
test/core/slice/slice_weak_hash_table_test.cc \
SLICE_WEAK_HASH_TABLE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SLICE_WEAK_HASH_TABLE_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/slice_weak_hash_table_test: $(PROTOBUF_DEP) $(SLICE_WEAK_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(SLICE_WEAK_HASH_TABLE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/slice_weak_hash_table_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/slice/slice_weak_hash_table_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_slice_weak_hash_table_test: $(SLICE_WEAK_HASH_TABLE_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(SLICE_WEAK_HASH_TABLE_TEST_OBJS:.o=.dep)
endif
endif
STATS_TEST_SRC = \
test/core/debug/stats_test.cc \
@ -17952,6 +18064,49 @@ endif
endif
STATUS_METADATA_TEST_SRC = \
test/core/transport/status_metadata_test.cc \
STATUS_METADATA_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_METADATA_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/status_metadata_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/status_metadata_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/status_metadata_test: $(PROTOBUF_DEP) $(STATUS_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(STATUS_METADATA_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_metadata_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/transport/status_metadata_test.o: $(LIBDIR)/$(CONFIG)/libgrpc.a
deps_status_metadata_test: $(STATUS_METADATA_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(STATUS_METADATA_TEST_OBJS:.o=.dep)
endif
endif
STATUS_TEST_SRC = \
test/cpp/util/status_test.cc \
@ -17995,6 +18150,49 @@ endif
endif
STATUS_UTIL_TEST_SRC = \
test/core/client_channel/status_util_test.cc \
STATUS_UTIL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(STATUS_UTIL_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/status_util_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
$(BINDIR)/$(CONFIG)/status_util_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/status_util_test: $(PROTOBUF_DEP) $(STATUS_UTIL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(STATUS_UTIL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_util_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/client_channel/status_util_test.o: $(LIBDIR)/$(CONFIG)/libgrpc.a
deps_status_util_test: $(STATUS_UTIL_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(STATUS_UTIL_TEST_OBJS:.o=.dep)
endif
endif
STREAMING_THROUGHPUT_TEST_SRC = \
test/cpp/end2end/streaming_throughput_test.cc \
@ -22220,10 +22418,10 @@ src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/security_connector/security_connector.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/client_auth_filter.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/lb_targets_info.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/secure_endpoint.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/security_handshaker.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/server_auth_filter.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/target_authority_table.cc: $(OPENSSL_DEP)
src/core/lib/security/transport/tsi_error.cc: $(OPENSSL_DEP)
src/core/lib/security/util/json_util.cc: $(OPENSSL_DEP)
src/core/lib/surface/init_secure.cc: $(OPENSSL_DEP)

@ -1,5 +1,3 @@
[![Build Status](https://grpc-testing.appspot.com/job/gRPC_master/badge/icon)](https://grpc-testing.appspot.com/job/gRPC_master)
[gRPC - An RPC library and framework](http://github.com/grpc/grpc)
===================================

@ -120,12 +120,12 @@ def grpc_deps():
if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
native.http_archive(
name = "com_github_bazelbuild_bazeltoolchains",
strip_prefix = "bazel-toolchains-f3b09700fae5d7b6e659d7cefe0dcc6e8498504c",
strip_prefix = "bazel-toolchains-44200e0c026d86c53470d107b3697a3e46469c43",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f3b09700fae5d7b6e659d7cefe0dcc6e8498504c.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/f3b09700fae5d7b6e659d7cefe0dcc6e8498504c.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/44200e0c026d86c53470d107b3697a3e46469c43.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/44200e0c026d86c53470d107b3697a3e46469c43.tar.gz",
],
sha256 = "ed829b5eea8af1f405f4cc3d6ecfc3b1365bb7843171036030a31b5127002311",
sha256 = "699b55a6916c687f4b7dc092dbbf5f64672cde0dc965f79717735ec4e5416556",
)
# TODO: move some dependencies from "grpc_deps" here?

@ -249,7 +249,6 @@ filegroups:
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
- src/core/lib/slice/slice_buffer.cc
- src/core/lib/slice/slice_hash_table.cc
- src/core/lib/slice/slice_intern.cc
- src/core/lib/slice/slice_string_helpers.cc
- src/core/lib/surface/api_trace.cc
@ -280,6 +279,7 @@ filegroups:
- src/core/lib/transport/service_config.cc
- src/core/lib/transport/static_metadata.cc
- src/core/lib/transport/status_conversion.cc
- src/core/lib/transport/status_metadata.cc
- src/core/lib/transport/timeout_encoding.cc
- src/core/lib/transport/transport.cc
- src/core/lib/transport/transport_op_string.cc
@ -403,6 +403,7 @@ filegroups:
- src/core/lib/slice/slice_hash_table.h
- src/core/lib/slice/slice_internal.h
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_weak_hash_table.h
- src/core/lib/surface/api_trace.h
- src/core/lib/surface/call.h
- src/core/lib/surface/call_test_only.h
@ -427,6 +428,7 @@ filegroups:
- src/core/lib/transport/service_config.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/status_conversion.h
- src/core/lib/transport/status_metadata.h
- src/core/lib/transport/timeout_encoding.h
- src/core/lib/transport/transport.h
- src/core/lib/transport/transport_impl.h
@ -446,6 +448,7 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy.h
- src/core/ext/filters/client_channel/lb_policy_factory.h
- src/core/ext/filters/client_channel/lb_policy_registry.h
- src/core/ext/filters/client_channel/method_params.h
- src/core/ext/filters/client_channel/parse_address.h
- src/core/ext/filters/client_channel/proxy_mapper.h
- src/core/ext/filters/client_channel/proxy_mapper_registry.h
@ -453,6 +456,7 @@ filegroups:
- src/core/ext/filters/client_channel/resolver_factory.h
- src/core/ext/filters/client_channel/resolver_registry.h
- src/core/ext/filters/client_channel/retry_throttle.h
- src/core/ext/filters/client_channel/status_util.h
- src/core/ext/filters/client_channel/subchannel.h
- src/core/ext/filters/client_channel/subchannel_index.h
- src/core/ext/filters/client_channel/uri_parser.h
@ -468,12 +472,14 @@ filegroups:
- src/core/ext/filters/client_channel/lb_policy.cc
- src/core/ext/filters/client_channel/lb_policy_factory.cc
- src/core/ext/filters/client_channel/lb_policy_registry.cc
- src/core/ext/filters/client_channel/method_params.cc
- src/core/ext/filters/client_channel/parse_address.cc
- src/core/ext/filters/client_channel/proxy_mapper.cc
- src/core/ext/filters/client_channel/proxy_mapper_registry.cc
- src/core/ext/filters/client_channel/resolver.cc
- src/core/ext/filters/client_channel/resolver_registry.cc
- src/core/ext/filters/client_channel/retry_throttle.cc
- src/core/ext/filters/client_channel/status_util.cc
- src/core/ext/filters/client_channel/subchannel.cc
- src/core/ext/filters/client_channel/subchannel_index.cc
- src/core/ext/filters/client_channel/uri_parser.cc
@ -649,9 +655,9 @@ filegroups:
- src/core/lib/security/credentials/ssl/ssl_credentials.h
- src/core/lib/security/security_connector/security_connector.h
- src/core/lib/security/transport/auth_filters.h
- src/core/lib/security/transport/lb_targets_info.h
- src/core/lib/security/transport/secure_endpoint.h
- src/core/lib/security/transport/security_handshaker.h
- src/core/lib/security/transport/target_authority_table.h
- src/core/lib/security/transport/tsi_error.h
- src/core/lib/security/util/json_util.h
src:
@ -672,10 +678,10 @@ filegroups:
- src/core/lib/security/credentials/ssl/ssl_credentials.cc
- src/core/lib/security/security_connector/security_connector.cc
- src/core/lib/security/transport/client_auth_filter.cc
- src/core/lib/security/transport/lb_targets_info.cc
- src/core/lib/security/transport/secure_endpoint.cc
- src/core/lib/security/transport/security_handshaker.cc
- src/core/lib/security/transport/server_auth_filter.cc
- src/core/lib/security/transport/target_authority_table.cc
- src/core/lib/security/transport/tsi_error.cc
- src/core/lib/security/util/json_util.cc
- src/core/lib/surface/init_secure.cc
@ -3146,17 +3152,6 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
- name: slice_hash_table_test
build: test
language: c
src:
- test/core/slice/slice_hash_table_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: slice_string_helpers_test
build: test
language: c
@ -4826,6 +4821,30 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: slice_hash_table_test
gtest: true
build: test
language: c++
src:
- test/core/slice/slice_hash_table_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: slice_weak_hash_table_test
gtest: true
build: test
language: c++
src:
- test/core/slice/slice_weak_hash_table_test.cc
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
uses_polling: false
- name: stats_test
gtest: true
build: test
@ -4842,6 +4861,15 @@ targets:
- tsan
timeout_seconds: 1200
uses_polling: false
- name: status_metadata_test
gtest: true
build: test
language: c++
src:
- test/core/transport/status_metadata_test.cc
deps:
- grpc
uses_polling: false
- name: status_test
build: test
language: c++
@ -4854,6 +4882,16 @@ targets:
- gpr_test_util
- gpr
uses_polling: false
- name: status_util_test
gtest: true
cpu_cost: 0.1
build: test
language: c++
src:
- test/core/client_channel/status_util_test.cc
deps:
- grpc
uses_polling: false
- name: streaming_throughput_test
gtest: true
build: test

@ -179,7 +179,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
src/core/lib/slice/slice_buffer.cc \
src/core/lib/slice/slice_hash_table.cc \
src/core/lib/slice/slice_intern.cc \
src/core/lib/slice/slice_string_helpers.cc \
src/core/lib/surface/api_trace.cc \
@ -210,6 +209,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/service_config.cc \
src/core/lib/transport/static_metadata.cc \
src/core/lib/transport/status_conversion.cc \
src/core/lib/transport/status_metadata.cc \
src/core/lib/transport/timeout_encoding.cc \
src/core/lib/transport/transport.cc \
src/core/lib/transport/transport_op_string.cc \
@ -259,10 +259,10 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/ssl/ssl_credentials.cc \
src/core/lib/security/security_connector/security_connector.cc \
src/core/lib/security/transport/client_auth_filter.cc \
src/core/lib/security/transport/lb_targets_info.cc \
src/core/lib/security/transport/secure_endpoint.cc \
src/core/lib/security/transport/security_handshaker.cc \
src/core/lib/security/transport/server_auth_filter.cc \
src/core/lib/security/transport/target_authority_table.cc \
src/core/lib/security/transport/tsi_error.cc \
src/core/lib/security/util/json_util.cc \
src/core/lib/surface/init_secure.cc \
@ -285,12 +285,14 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy.cc \
src/core/ext/filters/client_channel/lb_policy_factory.cc \
src/core/ext/filters/client_channel/lb_policy_registry.cc \
src/core/ext/filters/client_channel/method_params.cc \
src/core/ext/filters/client_channel/parse_address.cc \
src/core/ext/filters/client_channel/proxy_mapper.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver_registry.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \
src/core/ext/filters/client_channel/status_util.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel_index.cc \
src/core/ext/filters/client_channel/uri_parser.cc \

@ -156,7 +156,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\slice\\percent_encoding.cc " +
"src\\core\\lib\\slice\\slice.cc " +
"src\\core\\lib\\slice\\slice_buffer.cc " +
"src\\core\\lib\\slice\\slice_hash_table.cc " +
"src\\core\\lib\\slice\\slice_intern.cc " +
"src\\core\\lib\\slice\\slice_string_helpers.cc " +
"src\\core\\lib\\surface\\api_trace.cc " +
@ -187,6 +186,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\transport\\service_config.cc " +
"src\\core\\lib\\transport\\static_metadata.cc " +
"src\\core\\lib\\transport\\status_conversion.cc " +
"src\\core\\lib\\transport\\status_metadata.cc " +
"src\\core\\lib\\transport\\timeout_encoding.cc " +
"src\\core\\lib\\transport\\transport.cc " +
"src\\core\\lib\\transport\\transport_op_string.cc " +
@ -236,10 +236,10 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\ssl\\ssl_credentials.cc " +
"src\\core\\lib\\security\\security_connector\\security_connector.cc " +
"src\\core\\lib\\security\\transport\\client_auth_filter.cc " +
"src\\core\\lib\\security\\transport\\lb_targets_info.cc " +
"src\\core\\lib\\security\\transport\\secure_endpoint.cc " +
"src\\core\\lib\\security\\transport\\security_handshaker.cc " +
"src\\core\\lib\\security\\transport\\server_auth_filter.cc " +
"src\\core\\lib\\security\\transport\\target_authority_table.cc " +
"src\\core\\lib\\security\\transport\\tsi_error.cc " +
"src\\core\\lib\\security\\util\\json_util.cc " +
"src\\core\\lib\\surface\\init_secure.cc " +
@ -262,12 +262,14 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy_factory.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\method_params.cc " +
"src\\core\\ext\\filters\\client_channel\\parse_address.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
"src\\core\\ext\\filters\\client_channel\\status_util.cc " +
"src\\core\\ext\\filters\\client_channel\\subchannel.cc " +
"src\\core\\ext\\filters\\client_channel\\subchannel_index.cc " +
"src\\core\\ext\\filters\\client_channel\\uri_parser.cc " +

@ -273,9 +273,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/target_authority_table.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/alts_transport_security.h',
@ -296,6 +296,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@ -303,6 +304,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/status_util.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
@ -407,6 +409,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_weak_hash_table.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',
'src/core/lib/surface/call_test_only.h',
@ -431,6 +434,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',
'src/core/lib/transport/status_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
@ -584,6 +588,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_weak_hash_table.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',
'src/core/lib/surface/call_test_only.h',
@ -608,6 +613,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',
'src/core/lib/transport/status_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',

@ -284,9 +284,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/target_authority_table.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/alts_transport_security.h',
@ -307,6 +307,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@ -314,6 +315,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/status_util.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
@ -418,6 +420,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_weak_hash_table.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',
'src/core/lib/surface/call_test_only.h',
@ -442,6 +445,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',
'src/core/lib/transport/status_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
@ -562,7 +566,6 @@ Pod::Spec.new do |s|
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -593,6 +596,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -642,10 +646,10 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/lb_targets_info.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
'src/core/lib/security/transport/server_auth_filter.cc',
'src/core/lib/security/transport/target_authority_table.cc',
'src/core/lib/security/transport/tsi_error.cc',
'src/core/lib/security/util/json_util.cc',
'src/core/lib/surface/init_secure.cc',
@ -668,12 +672,14 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',
@ -772,9 +778,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/security_connector/security_connector.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/lb_targets_info.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/target_authority_table.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/json_util.h',
'src/core/tsi/alts_transport_security.h',
@ -795,6 +801,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy.h',
'src/core/ext/filters/client_channel/lb_policy_factory.h',
'src/core/ext/filters/client_channel/lb_policy_registry.h',
'src/core/ext/filters/client_channel/method_params.h',
'src/core/ext/filters/client_channel/parse_address.h',
'src/core/ext/filters/client_channel/proxy_mapper.h',
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
@ -802,6 +809,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver_factory.h',
'src/core/ext/filters/client_channel/resolver_registry.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/status_util.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_index.h',
'src/core/ext/filters/client_channel/uri_parser.h',
@ -906,6 +914,7 @@ Pod::Spec.new do |s|
'src/core/lib/slice/slice_hash_table.h',
'src/core/lib/slice/slice_internal.h',
'src/core/lib/slice/slice_string_helpers.h',
'src/core/lib/slice/slice_weak_hash_table.h',
'src/core/lib/surface/api_trace.h',
'src/core/lib/surface/call.h',
'src/core/lib/surface/call_test_only.h',
@ -930,6 +939,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/service_config.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',
'src/core/lib/transport/status_metadata.h',
'src/core/lib/transport/timeout_encoding.h',
'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h',
@ -1069,6 +1079,21 @@ Pod::Spec.new do |s|
'test/core/end2end/tests/request_with_flags.cc',
'test/core/end2end/tests/request_with_payload.cc',
'test/core/end2end/tests/resource_quota_server.cc',
'test/core/end2end/tests/retry.cc',
'test/core/end2end/tests/retry_cancellation.cc',
'test/core/end2end/tests/retry_disabled.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
'test/core/end2end/tests/retry_non_retriable_status.cc',
'test/core/end2end/tests/retry_recv_initial_metadata.cc',
'test/core/end2end/tests/retry_recv_message.cc',
'test/core/end2end/tests/retry_server_pushback_delay.cc',
'test/core/end2end/tests/retry_server_pushback_disabled.cc',
'test/core/end2end/tests/retry_streaming.cc',
'test/core/end2end/tests/retry_streaming_after_commit.cc',
'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
'test/core/end2end/tests/retry_throttled.cc',
'test/core/end2end/tests/retry_too_many_attempts.cc',
'test/core/end2end/tests/server_finishes_request.cc',
'test/core/end2end/tests/shutdown_finishes_calls.cc',
'test/core/end2end/tests/shutdown_finishes_tags.cc',

@ -210,9 +210,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/security_connector/security_connector.h )
s.files += %w( src/core/lib/security/transport/auth_filters.h )
s.files += %w( src/core/lib/security/transport/lb_targets_info.h )
s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.h )
s.files += %w( src/core/lib/security/transport/target_authority_table.h )
s.files += %w( src/core/lib/security/transport/tsi_error.h )
s.files += %w( src/core/lib/security/util/json_util.h )
s.files += %w( src/core/tsi/alts_transport_security.h )
@ -233,6 +233,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.h )
s.files += %w( src/core/ext/filters/client_channel/method_params.h )
s.files += %w( src/core/ext/filters/client_channel/parse_address.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.h )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
@ -240,6 +241,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/resolver_factory.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.h )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.h )
s.files += %w( src/core/ext/filters/client_channel/status_util.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.h )
s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
@ -344,6 +346,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/slice_hash_table.h )
s.files += %w( src/core/lib/slice/slice_internal.h )
s.files += %w( src/core/lib/slice/slice_string_helpers.h )
s.files += %w( src/core/lib/slice/slice_weak_hash_table.h )
s.files += %w( src/core/lib/surface/api_trace.h )
s.files += %w( src/core/lib/surface/call.h )
s.files += %w( src/core/lib/surface/call_test_only.h )
@ -368,6 +371,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/service_config.h )
s.files += %w( src/core/lib/transport/static_metadata.h )
s.files += %w( src/core/lib/transport/status_conversion.h )
s.files += %w( src/core/lib/transport/status_metadata.h )
s.files += %w( src/core/lib/transport/timeout_encoding.h )
s.files += %w( src/core/lib/transport/transport.h )
s.files += %w( src/core/lib/transport/transport_impl.h )
@ -492,7 +496,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/slice/percent_encoding.cc )
s.files += %w( src/core/lib/slice/slice.cc )
s.files += %w( src/core/lib/slice/slice_buffer.cc )
s.files += %w( src/core/lib/slice/slice_hash_table.cc )
s.files += %w( src/core/lib/slice/slice_intern.cc )
s.files += %w( src/core/lib/slice/slice_string_helpers.cc )
s.files += %w( src/core/lib/surface/api_trace.cc )
@ -523,6 +526,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/service_config.cc )
s.files += %w( src/core/lib/transport/static_metadata.cc )
s.files += %w( src/core/lib/transport/status_conversion.cc )
s.files += %w( src/core/lib/transport/status_metadata.cc )
s.files += %w( src/core/lib/transport/timeout_encoding.cc )
s.files += %w( src/core/lib/transport/transport.cc )
s.files += %w( src/core/lib/transport/transport_op_string.cc )
@ -572,10 +576,10 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.cc )
s.files += %w( src/core/lib/security/security_connector/security_connector.cc )
s.files += %w( src/core/lib/security/transport/client_auth_filter.cc )
s.files += %w( src/core/lib/security/transport/lb_targets_info.cc )
s.files += %w( src/core/lib/security/transport/secure_endpoint.cc )
s.files += %w( src/core/lib/security/transport/security_handshaker.cc )
s.files += %w( src/core/lib/security/transport/server_auth_filter.cc )
s.files += %w( src/core/lib/security/transport/target_authority_table.cc )
s.files += %w( src/core/lib/security/transport/tsi_error.cc )
s.files += %w( src/core/lib/security/util/json_util.cc )
s.files += %w( src/core/lib/surface/init_secure.cc )
@ -598,12 +602,14 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_factory.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/method_params.cc )
s.files += %w( src/core/ext/filters/client_channel/parse_address.cc )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper.cc )
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver_registry.cc )
s.files += %w( src/core/ext/filters/client_channel/retry_throttle.cc )
s.files += %w( src/core/ext/filters/client_channel/status_util.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel_index.cc )
s.files += %w( src/core/ext/filters/client_channel/uri_parser.cc )

@ -320,7 +320,6 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -351,6 +350,7 @@
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -400,10 +400,10 @@
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/lb_targets_info.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
'src/core/lib/security/transport/server_auth_filter.cc',
'src/core/lib/security/transport/target_authority_table.cc',
'src/core/lib/security/transport/tsi_error.cc',
'src/core/lib/security/util/json_util.cc',
'src/core/lib/surface/init_secure.cc',
@ -426,12 +426,14 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',
@ -617,7 +619,6 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -648,6 +649,7 @@
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -663,12 +665,14 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',
@ -832,7 +836,6 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -863,6 +866,7 @@
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -878,12 +882,14 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',
@ -1026,7 +1032,6 @@
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -1057,6 +1062,7 @@
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -1105,12 +1111,14 @@
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',
@ -2481,6 +2489,21 @@
'test/core/end2end/tests/request_with_flags.cc',
'test/core/end2end/tests/request_with_payload.cc',
'test/core/end2end/tests/resource_quota_server.cc',
'test/core/end2end/tests/retry.cc',
'test/core/end2end/tests/retry_cancellation.cc',
'test/core/end2end/tests/retry_disabled.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
'test/core/end2end/tests/retry_non_retriable_status.cc',
'test/core/end2end/tests/retry_recv_initial_metadata.cc',
'test/core/end2end/tests/retry_recv_message.cc',
'test/core/end2end/tests/retry_server_pushback_delay.cc',
'test/core/end2end/tests/retry_server_pushback_disabled.cc',
'test/core/end2end/tests/retry_streaming.cc',
'test/core/end2end/tests/retry_streaming_after_commit.cc',
'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
'test/core/end2end/tests/retry_throttled.cc',
'test/core/end2end/tests/retry_too_many_attempts.cc',
'test/core/end2end/tests/server_finishes_request.cc',
'test/core/end2end/tests/shutdown_finishes_calls.cc',
'test/core/end2end/tests/shutdown_finishes_tags.cc',
@ -2554,6 +2577,21 @@
'test/core/end2end/tests/request_with_flags.cc',
'test/core/end2end/tests/request_with_payload.cc',
'test/core/end2end/tests/resource_quota_server.cc',
'test/core/end2end/tests/retry.cc',
'test/core/end2end/tests/retry_cancellation.cc',
'test/core/end2end/tests/retry_disabled.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
'test/core/end2end/tests/retry_non_retriable_status.cc',
'test/core/end2end/tests/retry_recv_initial_metadata.cc',
'test/core/end2end/tests/retry_recv_message.cc',
'test/core/end2end/tests/retry_server_pushback_delay.cc',
'test/core/end2end/tests/retry_server_pushback_disabled.cc',
'test/core/end2end/tests/retry_streaming.cc',
'test/core/end2end/tests/retry_streaming_after_commit.cc',
'test/core/end2end/tests/retry_streaming_succeeds_before_replay_finished.cc',
'test/core/end2end/tests/retry_throttled.cc',
'test/core/end2end/tests/retry_too_many_attempts.cc',
'test/core/end2end/tests/server_finishes_request.cc',
'test/core/end2end/tests/shutdown_finishes_calls.cc',
'test/core/end2end/tests/shutdown_finishes_tags.cc',

@ -314,6 +314,14 @@ typedef struct {
Defaults to "blend". In the current implementation "blend" is equivalent to
"latency". */
#define GRPC_ARG_OPTIMIZATION_TARGET "grpc.optimization_target"
/** If set to zero, disables retry behavior. Otherwise, transparent retries
are enabled for all RPCs, and configurable retries are enabled when they
are configured via the service config. For details, see:
https://github.com/grpc/proposal/blob/master/A6-client-retries.md
*/
#define GRPC_ARG_ENABLE_RETRIES "grpc.enable_retries"
/** Per-RPC retry buffer size, in bytes. Default is 256 KiB. */
#define GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE "grpc.per_rpc_retry_buffer_size"
/** Channel arg that carries the bridged objective c object for custom metrics
* logging filter. */
#define GRPC_ARG_MOBILE_LOG_CONFIG "grpc.mobile_log_config"
@ -554,6 +562,8 @@ typedef struct grpc_op {
} recv_initial_metadata;
/** ownership of the byte buffer is moved to the caller; the caller must
call grpc_byte_buffer_destroy on this value, or reuse it in a future op.
The returned byte buffer will be NULL if trailing metadata was
received instead of a message.
*/
struct grpc_op_recv_message {
struct grpc_byte_buffer** recv_message;

@ -217,9 +217,9 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/target_authority_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/tsi/alts_transport_security.h" role="src" />
@ -240,6 +240,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.h" role="src" />
@ -247,6 +248,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/status_util.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
@ -351,6 +353,7 @@
<file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_weak_hash_table.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/call_test_only.h" role="src" />
@ -375,6 +378,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/service_config.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/status_conversion.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/status_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
@ -499,7 +503,6 @@
<file baseinstalldir="/" name="src/core/lib/slice/percent_encoding.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_buffer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_intern.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/api_trace.cc" role="src" />
@ -530,6 +533,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/service_config.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/status_conversion.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/status_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.cc" role="src" />
@ -579,10 +583,10 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/security_connector/security_connector.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/client_auth_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/lb_targets_info.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/server_auth_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/target_authority_table.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/init_secure.cc" role="src" />
@ -605,12 +609,14 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/method_params.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/parse_address.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/proxy_mapper_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_throttle.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/status_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_index.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.cc" role="src" />

@ -451,8 +451,10 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
out->Print(
"public virtual $response$ $methodname$($request$ request, "
"grpc::Metadata "
"headers = null, DateTime? deadline = null, CancellationToken "
"cancellationToken = default(CancellationToken))\n",
"headers = null, global::System.DateTime? deadline = null, "
"global::System.Threading.CancellationToken "
"cancellationToken = "
"default(global::System.Threading.CancellationToken))\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
@ -492,8 +494,10 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor* service) {
out->Print(
"public virtual $returntype$ "
"$methodname$($request_maybe$grpc::Metadata "
"headers = null, DateTime? deadline = null, CancellationToken "
"cancellationToken = default(CancellationToken))\n",
"headers = null, global::System.DateTime? deadline = null, "
"global::System.Threading.CancellationToken "
"cancellationToken = "
"default(global::System.Threading.CancellationToken))\n",
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
@ -675,9 +679,6 @@ grpc::string GetServices(const FileDescriptor* file, bool generate_client,
out.Print("#pragma warning disable 1591\n");
out.Print("#region Designer generated code\n");
out.Print("\n");
out.Print("using System;\n");
out.Print("using System.Threading;\n");
out.Print("using System.Threading.Tasks;\n");
out.Print("using grpc = global::Grpc.Core;\n");
out.Print("\n");

@ -212,37 +212,49 @@ void PrintMethodImplementations(Printer* printer,
return output;
}
::grpc::string GetHeader(const ServiceDescriptor* service) {
::grpc::string GetProtocol(const ServiceDescriptor* service) {
::grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
for (int i = 0; i < service->method_count(); i++) {
PrintMethodDeclarations(&printer, service->method(i));
}
printer.Print("@end\n\n");
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(
"/**\n"
" * Basic service implementation, over gRPC, that only does\n"
" * marshalling and parsing.\n"
" */\n");
printer.Print(vars,
"@interface $service_class$ :"
" GRPCProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");
printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
for (int i = 0; i < service->method_count(); i++) {
PrintMethodDeclarations(&printer, service->method(i));
}
printer.Print("@end\n\n");
return output;
}
::grpc::string GetInterface(const ServiceDescriptor* service) {
::grpc::string output;
// Scope the output stream so it closes and finalizes output to the string.
grpc::protobuf::io::StringOutputStream output_stream(&output);
Printer printer(&output_stream, '$');
map< ::grpc::string, ::grpc::string> vars = {
{"service_class", ServiceClassName(service)}};
printer.Print(vars,
"/**\n"
" * Basic service implementation, over gRPC, that only does\n"
" * marshalling and parsing.\n"
" */\n");
printer.Print(vars,
"@interface $service_class$ :"
" GRPCProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
printer.Print("@end\n");
return output;
}
@ -258,26 +270,32 @@ void PrintMethodImplementations(Printer* printer,
{"service_class", ServiceClassName(service)},
{"package", service->file()->package()}};
printer.Print(vars, "@implementation $service_class$\n\n");
printer.Print(vars,
"@implementation $service_class$\n\n"
"// Designated initializer\n"
"- (instancetype)initWithHost:(NSString *)host {\n"
" self = [super initWithHost:host\n"
" packageName:@\"$package$\"\n"
" serviceName:@\"$service_name$\"];\n"
" return self;\n"
"}\n\n");
printer.Print("// Designated initializer\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
printer.Print(
vars,
" return (self = [super initWithHost:host"
" packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
printer.Print("}\n\n");
printer.Print(
"// Override superclass initializer to disallow different"
" package and service names.\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
printer.Print(" packageName:(NSString *)packageName\n");
printer.Print(" serviceName:(NSString *)serviceName {\n");
printer.Print(" return [self initWithHost:host];\n");
printer.Print("}\n\n");
printer.Print("+ (instancetype)serviceWithHost:(NSString *)host {\n");
printer.Print(" return [[self alloc] initWithHost:host];\n");
printer.Print("}\n\n\n");
" package and service names.\n"
"- (instancetype)initWithHost:(NSString *)host\n"
" packageName:(NSString *)packageName\n"
" serviceName:(NSString *)serviceName {\n"
" return [self initWithHost:host];\n"
"}\n\n");
printer.Print(
"#pragma mark - Class Methods\n\n"
"+ (instancetype)serviceWithHost:(NSString *)host {\n"
" return [[self alloc] initWithHost:host];\n"
"}\n\n");
printer.Print("#pragma mark - Method Implementations\n\n");
for (int i = 0; i < service->method_count(); i++) {
PrintMethodImplementations(&printer, service->method(i));

@ -31,9 +31,13 @@ using ::grpc::string;
// Returns forward declaration of classes in the generated header file.
string GetAllMessageClasses(const FileDescriptor* file);
// Returns the content to be included in the "global_scope" insertion point of
// the generated header file.
string GetHeader(const ServiceDescriptor* service);
// Returns the content to be included defining the @protocol segment at the
// insertion point of the generated implementation file.
string GetProtocol(const ServiceDescriptor* service);
// Returns the content to be included defining the @interface segment at the
// insertion point of the generated implementation file.
string GetInterface(const ServiceDescriptor* service);
// Returns the content to be included in the "global_scope" insertion point of
// the generated implementation file.

@ -40,5 +40,45 @@ inline string ServiceClassName(const ServiceDescriptor* service) {
string prefix = file->options().objc_class_prefix();
return prefix + service->name();
}
inline ::grpc::string LocalImport(const ::grpc::string& import) {
return ::grpc::string("#import \"" + import + "\"\n");
}
inline ::grpc::string SystemImport(const ::grpc::string& import) {
return ::grpc::string("#import <" + import + ">\n");
}
inline ::grpc::string PreprocConditional(::grpc::string symbol, bool invert) {
return invert ? "!defined(" + symbol + ") || !" + symbol
: "defined(" + symbol + ") && " + symbol;
}
inline ::grpc::string PreprocIf(const ::grpc::string& symbol,
const ::grpc::string& if_true) {
return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
if_true + "#endif\n");
}
inline ::grpc::string PreprocIfNot(const ::grpc::string& symbol,
const ::grpc::string& if_true) {
return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
if_true + "#endif\n");
}
inline ::grpc::string PreprocIfElse(const ::grpc::string& symbol,
const ::grpc::string& if_true,
const ::grpc::string& if_false) {
return ::grpc::string("#if " + PreprocConditional(symbol, false) + "\n" +
if_true + "#else\n" + if_false + "#endif\n");
}
inline ::grpc::string PreprocIfNotElse(const ::grpc::string& symbol,
const ::grpc::string& if_true,
const ::grpc::string& if_false) {
return ::grpc::string("#if " + PreprocConditional(symbol, true) + "\n" +
if_true + "#else\n" + if_false + "#endif\n");
}
} // namespace grpc_objective_c_generator
#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H

@ -29,12 +29,42 @@
using ::google::protobuf::compiler::objectivec::
IsProtobufLibraryBundledProtoFile;
using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
using ::grpc_objective_c_generator::LocalImport;
using ::grpc_objective_c_generator::PreprocIfElse;
using ::grpc_objective_c_generator::PreprocIfNot;
using ::grpc_objective_c_generator::SystemImport;
namespace {
inline ::grpc::string ImportProtoHeaders(
const grpc::protobuf::FileDescriptor* dep, const char* indent) {
::grpc::string header = grpc_objective_c_generator::MessageHeaderName(dep);
if (!IsProtobufLibraryBundledProtoFile(dep)) {
return indent + LocalImport(header);
}
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
::grpc::string framework_header =
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name;
static const ::grpc::string kFrameworkImportsCondition =
"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS";
return PreprocIfElse(kFrameworkImportsCondition,
indent + SystemImport(framework_header),
indent + LocalImport(header));
}
} // namespace
class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
public:
ObjectiveCGrpcGenerator() {}
virtual ~ObjectiveCGrpcGenerator() {}
public:
virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
const ::grpc::string& parameter,
grpc::protobuf::compiler::GeneratorContext* context,
@ -44,97 +74,68 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
return true;
}
static const ::grpc::string kNonNullBegin = "NS_ASSUME_NONNULL_BEGIN\n";
static const ::grpc::string kNonNullEnd = "NS_ASSUME_NONNULL_END\n";
static const ::grpc::string kProtocolOnly = "GPB_GRPC_PROTOCOL_ONLY";
static const ::grpc::string kForwardDeclare =
"GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO";
::grpc::string file_name =
google::protobuf::compiler::objectivec::FilePath(file);
::grpc::string prefix = file->options().objc_class_prefix();
{
// Generate .pbrpc.h
::grpc::string imports =
::grpc::string("#if !GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n") +
"#import \"" + file_name +
".pbobjc.h\"\n"
"#endif\n\n"
"#import <ProtoRPC/ProtoService.h>\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriteable.h>\n"
"#import <RxLibrary/GRXWriter.h>\n";
::grpc::string proto_imports;
proto_imports += "#if GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n" +
grpc_objective_c_generator::GetAllMessageClasses(file) +
"#else\n";
::grpc::string imports = LocalImport(file_name + ".pbobjc.h");
::grpc::string system_imports = SystemImport("ProtoRPC/ProtoService.h") +
SystemImport("ProtoRPC/ProtoRPC.h") +
SystemImport("RxLibrary/GRXWriteable.h") +
SystemImport("RxLibrary/GRXWriter.h");
::grpc::string forward_declarations = "@class GRPCProtoCall;\n\n";
::grpc::string class_declarations =
grpc_objective_c_generator::GetAllMessageClasses(file);
::grpc::string class_imports;
for (int i = 0; i < file->dependency_count(); i++) {
::grpc::string header =
grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
if (IsProtobufLibraryBundledProtoFile(dependency)) {
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
proto_imports +=
" #if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
" #import <" +
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
">\n"
" #else\n"
" #import \"" +
header +
"\"\n"
" #endif\n";
} else {
proto_imports += ::grpc::string(" #import \"") + header + "\"\n";
}
class_imports += ImportProtoHeaders(file->dependency(i), " ");
}
proto_imports += "#endif\n";
::grpc::string declarations;
::grpc::string protocols;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i);
declarations += grpc_objective_c_generator::GetHeader(service);
protocols += grpc_objective_c_generator::GetProtocol(service);
}
static const ::grpc::string kNonNullBegin =
"\nNS_ASSUME_NONNULL_BEGIN\n\n";
static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
::grpc::string interfaces;
for (int i = 0; i < file->service_count(); i++) {
const grpc::protobuf::ServiceDescriptor* service = file->service(i);
interfaces += grpc_objective_c_generator::GetInterface(service);
}
Write(context, file_name + ".pbrpc.h",
imports + '\n' + proto_imports + '\n' + kNonNullBegin +
declarations + kNonNullEnd);
PreprocIfNot(kForwardDeclare, imports) + "\n" +
PreprocIfNot(kProtocolOnly, system_imports) + "\n" +
PreprocIfElse(kForwardDeclare, class_declarations,
class_imports) +
"\n" + forward_declarations + "\n" + kNonNullBegin + "\n" +
protocols + "\n" + PreprocIfNot(kProtocolOnly, interfaces) +
"\n" + kNonNullEnd + "\n");
}
{
// Generate .pbrpc.m
::grpc::string imports = ::grpc::string("#import \"") + file_name +
".pbrpc.h\"\n"
"#import \"" +
file_name +
".pbobjc.h\"\n\n"
"#import <ProtoRPC/ProtoRPC.h>\n"
"#import <RxLibrary/GRXWriter+Immediate.h>\n";
::grpc::string imports = LocalImport(file_name + ".pbrpc.h") +
LocalImport(file_name + ".pbobjc.h") +
SystemImport("ProtoRPC/ProtoRPC.h") +
SystemImport("RxLibrary/GRXWriter+Immediate.h");
::grpc::string class_imports;
for (int i = 0; i < file->dependency_count(); i++) {
::grpc::string header =
grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
const grpc::protobuf::FileDescriptor* dependency = file->dependency(i);
if (IsProtobufLibraryBundledProtoFile(dependency)) {
::grpc::string base_name = header;
grpc_generator::StripPrefix(&base_name, "google/protobuf/");
// create the import code snippet
imports +=
"#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
" #import <" +
::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
">\n"
"#else\n"
" #import \"" +
header +
"\"\n"
"#endif\n";
} else {
imports += ::grpc::string("#import \"") + header + "\"\n";
}
class_imports += ImportProtoHeaders(file->dependency(i), "");
}
::grpc::string definitions;
@ -143,7 +144,9 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
definitions += grpc_objective_c_generator::GetSource(service);
}
Write(context, file_name + ".pbrpc.m", imports + '\n' + definitions);
Write(context, file_name + ".pbrpc.m",
PreprocIfNot(kProtocolOnly,
imports + "\n" + class_imports + "\n" + definitions));
}
return true;

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -127,13 +127,7 @@ static void run_poller(void* arg, grpc_error* error) {
&p->run_poller_closure);
}
void grpc_client_channel_start_backup_polling(
grpc_pollset_set* interested_parties) {
gpr_once_init(&g_once, init_globals);
if (g_poll_interval_ms == 0) {
return;
}
gpr_mu_lock(&g_poller_mu);
static void g_poller_init_locked() {
if (g_poller == nullptr) {
g_poller = static_cast<backup_poller*>(gpr_zalloc(sizeof(backup_poller)));
g_poller->pollset =
@ -149,7 +143,16 @@ void grpc_client_channel_start_backup_polling(
grpc_core::ExecCtx::Get()->Now() + g_poll_interval_ms,
&g_poller->run_poller_closure);
}
}
void grpc_client_channel_start_backup_polling(
grpc_pollset_set* interested_parties) {
gpr_once_init(&g_once, init_globals);
if (g_poll_interval_ms == 0) {
return;
}
gpr_mu_lock(&g_poller_mu);
g_poller_init_locked();
gpr_ref(&g_poller->refs);
/* Get a reference to g_poller->pollset before releasing g_poller_mu to make
* TSAN happy. Otherwise, reading from g_poller (i.e g_poller->pollset) after

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

File diff suppressed because it is too large Load Diff

@ -30,47 +30,41 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/lib/slice/slice_internal.h"
static void destroy_balancer_name(void* balancer_name) {
gpr_free(balancer_name);
}
static grpc_slice_hash_table_entry targets_info_entry_create(
const char* address, const char* balancer_name) {
grpc_slice_hash_table_entry entry;
entry.key = grpc_slice_from_copied_string(address);
entry.value = gpr_strdup(balancer_name);
return entry;
}
namespace grpc_core {
namespace {
static int balancer_name_cmp_fn(void* a, void* b) {
const char* a_str = static_cast<const char*>(a);
const char* b_str = static_cast<const char*>(b);
return strcmp(a_str, b_str);
int BalancerNameCmp(const grpc_core::UniquePtr<char>& a,
const grpc_core::UniquePtr<char>& b) {
return strcmp(a.get(), b.get());
}
static grpc_slice_hash_table* build_targets_info_table(
RefCountedPtr<TargetAuthorityTable> CreateTargetAuthorityTable(
grpc_lb_addresses* addresses) {
grpc_slice_hash_table_entry* targets_info_entries =
static_cast<grpc_slice_hash_table_entry*>(
gpr_zalloc(sizeof(*targets_info_entries) * addresses->num_addresses));
TargetAuthorityTable::Entry* target_authority_entries =
static_cast<TargetAuthorityTable::Entry*>(gpr_zalloc(
sizeof(*target_authority_entries) * addresses->num_addresses));
for (size_t i = 0; i < addresses->num_addresses; ++i) {
char* addr_str;
GPR_ASSERT(grpc_sockaddr_to_string(
&addr_str, &addresses->addresses[i].address, true) > 0);
targets_info_entries[i] = targets_info_entry_create(
addr_str, addresses->addresses[i].balancer_name);
target_authority_entries[i].key = grpc_slice_from_copied_string(addr_str);
target_authority_entries[i].value.reset(
gpr_strdup(addresses->addresses[i].balancer_name));
gpr_free(addr_str);
}
grpc_slice_hash_table* targets_info = grpc_slice_hash_table_create(
addresses->num_addresses, targets_info_entries, destroy_balancer_name,
balancer_name_cmp_fn);
gpr_free(targets_info_entries);
return targets_info;
RefCountedPtr<TargetAuthorityTable> target_authority_table =
TargetAuthorityTable::Create(addresses->num_addresses,
target_authority_entries, BalancerNameCmp);
gpr_free(target_authority_entries);
return target_authority_table;
}
} // namespace
} // namespace grpc_core
grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
grpc_channel_args* args) {
const char* args_to_remove[1];
@ -83,9 +77,11 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
grpc_lb_addresses* addresses =
static_cast<grpc_lb_addresses*>(arg->value.pointer.p);
grpc_slice_hash_table* targets_info = build_targets_info_table(addresses);
grpc_core::RefCountedPtr<grpc_core::TargetAuthorityTable>
target_authority_table = grpc_core::CreateTargetAuthorityTable(addresses);
args_to_add[num_args_to_add++] =
grpc_lb_targets_info_create_channel_arg(targets_info);
grpc_core::CreateTargetAuthorityTableChannelArg(
target_authority_table.get());
// Substitute the channel credentials with a version without call
// credentials: the load balancer is not necessarily trusted to handle
// bearer token credentials.
@ -105,7 +101,6 @@ grpc_channel_args* grpc_lb_policy_grpclb_modify_lb_channel_args(
args, args_to_remove, num_args_to_remove, args_to_add, num_args_to_add);
// Clean up.
grpc_channel_args_destroy(args);
grpc_slice_hash_table_unref(targets_info);
if (creds_sans_call_creds != nullptr) {
grpc_channel_credentials_unref(creds_sans_call_creds);
}

@ -0,0 +1,178 @@
/*
*
* 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.
*
*/
#include <grpc/support/port_platform.h>
#include <stdio.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/method_params.h"
#include "src/core/ext/filters/client_channel/status_util.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
// As per the retry design, we do not allow more than 5 retry attempts.
#define MAX_MAX_RETRY_ATTEMPTS 5
namespace grpc_core {
namespace internal {
namespace {
bool ParseWaitForReady(
grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) {
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
return false;
}
*wait_for_ready = field->type == GRPC_JSON_TRUE
? ClientChannelMethodParams::WAIT_FOR_READY_TRUE
: ClientChannelMethodParams::WAIT_FOR_READY_FALSE;
return true;
}
// Parses a JSON field of the form generated for a google.proto.Duration
// proto message, as per:
// https://developers.google.com/protocol-buffers/docs/proto3#json
bool ParseDuration(grpc_json* field, grpc_millis* duration) {
if (field->type != GRPC_JSON_STRING) return false;
size_t len = strlen(field->value);
if (field->value[len - 1] != 's') return false;
UniquePtr<char> buf(gpr_strdup(field->value));
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
char* decimal_point = strchr(buf.get(), '.');
int nanos = 0;
if (decimal_point != nullptr) {
*decimal_point = '\0';
nanos = gpr_parse_nonnegative_int(decimal_point + 1);
if (nanos == -1) {
return false;
}
int num_digits = static_cast<int>(strlen(decimal_point + 1));
if (num_digits > 9) { // We don't accept greater precision than nanos.
return false;
}
for (int i = 0; i < (9 - num_digits); ++i) {
nanos *= 10;
}
}
int seconds =
decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get());
if (seconds == -1) return false;
*duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
return true;
}
UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
grpc_json* field) {
auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>();
if (field->type != GRPC_JSON_OBJECT) return nullptr;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) return nullptr;
if (strcmp(sub_field->key, "maxAttempts") == 0) {
if (retry_policy->max_attempts != 0) return nullptr; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
if (retry_policy->max_attempts <= 1) return nullptr;
if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
gpr_log(GPR_ERROR,
"service config: clamped retryPolicy.maxAttempts at %d",
MAX_MAX_RETRY_ATTEMPTS);
retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
}
} else if (strcmp(sub_field->key, "initialBackoff") == 0) {
if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate.
if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
return nullptr;
}
if (retry_policy->initial_backoff == 0) return nullptr;
} else if (strcmp(sub_field->key, "maxBackoff") == 0) {
if (retry_policy->max_backoff > 0) return nullptr; // Duplicate.
if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
return nullptr;
}
if (retry_policy->max_backoff == 0) return nullptr;
} else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return nullptr;
if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
1) {
return nullptr;
}
if (retry_policy->backoff_multiplier <= 0) return nullptr;
} else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
if (!retry_policy->retryable_status_codes.Empty()) {
return nullptr; // Duplicate.
}
if (sub_field->type != GRPC_JSON_ARRAY) return nullptr;
for (grpc_json* element = sub_field->child; element != nullptr;
element = element->next) {
if (element->type != GRPC_JSON_STRING) return nullptr;
grpc_status_code status;
if (!grpc_status_code_from_string(element->value, &status)) {
return nullptr;
}
retry_policy->retryable_status_codes.Add(status);
}
if (retry_policy->retryable_status_codes.Empty()) return nullptr;
}
}
// Make sure required fields are set.
if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 ||
retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 ||
retry_policy->retryable_status_codes.Empty()) {
return nullptr;
}
return retry_policy;
}
} // namespace
RefCountedPtr<ClientChannelMethodParams>
ClientChannelMethodParams::CreateFromJson(const grpc_json* json) {
RefCountedPtr<ClientChannelMethodParams> method_params =
MakeRefCounted<ClientChannelMethodParams>();
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "waitForReady") == 0) {
if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) {
return nullptr; // Duplicate.
}
if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) {
return nullptr;
}
} else if (strcmp(field->key, "timeout") == 0) {
if (method_params->timeout_ > 0) return nullptr; // Duplicate.
if (!ParseDuration(field, &method_params->timeout_)) return nullptr;
} else if (strcmp(field->key, "retryPolicy") == 0) {
if (method_params->retry_policy_ != nullptr) {
return nullptr; // Duplicate.
}
method_params->retry_policy_ = ParseRetryPolicy(field);
if (method_params->retry_policy_ == nullptr) return nullptr;
}
}
return method_params;
}
} // namespace internal
} // namespace grpc_core

@ -0,0 +1,74 @@
/*
*
* 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/status_util.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis
#include "src/core/lib/json/json.h"
namespace grpc_core {
namespace internal {
class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> {
public:
enum WaitForReady {
WAIT_FOR_READY_UNSET = 0,
WAIT_FOR_READY_FALSE,
WAIT_FOR_READY_TRUE
};
struct RetryPolicy {
int max_attempts = 0;
grpc_millis initial_backoff = 0;
grpc_millis max_backoff = 0;
float backoff_multiplier = 0;
StatusCodeSet retryable_status_codes;
};
/// Creates a method_parameters object from \a json.
/// Intended for use with ServiceConfig::CreateMethodConfigTable().
static RefCountedPtr<ClientChannelMethodParams> CreateFromJson(
const grpc_json* json);
grpc_millis timeout() const { return timeout_; }
WaitForReady wait_for_ready() const { return wait_for_ready_; }
const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
private:
// So New() can call our private ctor.
template <typename T, typename... Args>
friend T* grpc_core::New(Args&&... args);
ClientChannelMethodParams() {}
virtual ~ClientChannelMethodParams() {}
grpc_millis timeout_ = 0;
WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET;
UniquePtr<RetryPolicy> retry_policy_;
};
} // namespace internal
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H */

@ -295,7 +295,7 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
size_t num_args_to_add = 0;
new_args[num_args_to_add++] =
grpc_lb_addresses_create_channel_arg(r->lb_addresses_);
grpc_service_config* service_config = nullptr;
grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config;
char* service_config_string = nullptr;
if (r->service_config_json_ != nullptr) {
service_config_string = ChooseServiceConfig(r->service_config_json_);
@ -306,10 +306,11 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
args_to_remove[num_args_to_remove++] = GRPC_ARG_SERVICE_CONFIG;
new_args[num_args_to_add++] = grpc_channel_arg_string_create(
(char*)GRPC_ARG_SERVICE_CONFIG, service_config_string);
service_config = grpc_service_config_create(service_config_string);
service_config =
grpc_core::ServiceConfig::Create(service_config_string);
if (service_config != nullptr) {
const char* lb_policy_name =
grpc_service_config_get_lb_policy_name(service_config);
service_config->GetLoadBalancingPolicyName();
if (lb_policy_name != nullptr) {
args_to_remove[num_args_to_remove++] = GRPC_ARG_LB_POLICY_NAME;
new_args[num_args_to_add++] = grpc_channel_arg_string_create(
@ -322,7 +323,6 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
result = grpc_channel_args_copy_and_add_and_remove(
r->channel_args_, args_to_remove, num_args_to_remove, new_args,
num_args_to_add);
if (service_config != nullptr) grpc_service_config_destroy(service_config);
gpr_free(service_config_string);
grpc_lb_addresses_destroy(r->lb_addresses_);
// Reset backoff state so that we start from the beginning when the

@ -40,7 +40,7 @@ struct grpc_server_retry_throttle_data {
int milli_token_ratio;
gpr_atm milli_tokens;
// A pointer to the replacement for this grpc_server_retry_throttle_data
// entry. If non-NULL, then this entry is stale and must not be used.
// entry. If non-nullptr, then this entry is stale and must not be used.
// We hold a reference to the replacement.
gpr_atm replacement;
};
@ -58,6 +58,7 @@ static void get_replacement_throttle_data_if_needed(
bool grpc_server_retry_throttle_data_record_failure(
grpc_server_retry_throttle_data* throttle_data) {
if (throttle_data == nullptr) return true;
// First, check if we are stale and need to be replaced.
get_replacement_throttle_data_if_needed(&throttle_data);
// We decrement milli_tokens by 1000 (1 token) for each failure.
@ -72,6 +73,7 @@ bool grpc_server_retry_throttle_data_record_failure(
void grpc_server_retry_throttle_data_record_success(
grpc_server_retry_throttle_data* throttle_data) {
if (throttle_data == nullptr) return;
// First, check if we are stale and need to be replaced.
get_replacement_throttle_data_if_needed(&throttle_data);
// We increment milli_tokens by milli_token_ratio for each success.

@ -0,0 +1,100 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/status_util.h"
#include "src/core/lib/gpr/useful.h"
typedef struct {
const char* str;
grpc_status_code status;
} status_string_entry;
static const status_string_entry g_status_string_entries[] = {
{"OK", GRPC_STATUS_OK},
{"CANCELLED", GRPC_STATUS_CANCELLED},
{"UNKNOWN", GRPC_STATUS_UNKNOWN},
{"INVALID_ARGUMENT", GRPC_STATUS_INVALID_ARGUMENT},
{"DEADLINE_EXCEEDED", GRPC_STATUS_DEADLINE_EXCEEDED},
{"NOT_FOUND", GRPC_STATUS_NOT_FOUND},
{"ALREADY_EXISTS", GRPC_STATUS_ALREADY_EXISTS},
{"PERMISSION_DENIED", GRPC_STATUS_PERMISSION_DENIED},
{"UNAUTHENTICATED", GRPC_STATUS_UNAUTHENTICATED},
{"RESOURCE_EXHAUSTED", GRPC_STATUS_RESOURCE_EXHAUSTED},
{"FAILED_PRECONDITION", GRPC_STATUS_FAILED_PRECONDITION},
{"ABORTED", GRPC_STATUS_ABORTED},
{"OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE},
{"UNIMPLEMENTED", GRPC_STATUS_UNIMPLEMENTED},
{"INTERNAL", GRPC_STATUS_INTERNAL},
{"UNAVAILABLE", GRPC_STATUS_UNAVAILABLE},
{"DATA_LOSS", GRPC_STATUS_DATA_LOSS},
};
bool grpc_status_code_from_string(const char* status_str,
grpc_status_code* status) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(g_status_string_entries); ++i) {
if (strcmp(status_str, g_status_string_entries[i].str) == 0) {
*status = g_status_string_entries[i].status;
return true;
}
}
return false;
}
const char* grpc_status_code_to_string(grpc_status_code status) {
switch (status) {
case GRPC_STATUS_OK:
return "OK";
case GRPC_STATUS_CANCELLED:
return "CANCELLED";
case GRPC_STATUS_UNKNOWN:
return "UNKNOWN";
case GRPC_STATUS_INVALID_ARGUMENT:
return "INVALID_ARGUMENT";
case GRPC_STATUS_DEADLINE_EXCEEDED:
return "DEADLINE_EXCEEDED";
case GRPC_STATUS_NOT_FOUND:
return "NOT_FOUND";
case GRPC_STATUS_ALREADY_EXISTS:
return "ALREADY_EXISTS";
case GRPC_STATUS_PERMISSION_DENIED:
return "PERMISSION_DENIED";
case GRPC_STATUS_UNAUTHENTICATED:
return "UNAUTHENTICATED";
case GRPC_STATUS_RESOURCE_EXHAUSTED:
return "RESOURCE_EXHAUSTED";
case GRPC_STATUS_FAILED_PRECONDITION:
return "FAILED_PRECONDITION";
case GRPC_STATUS_ABORTED:
return "ABORTED";
case GRPC_STATUS_OUT_OF_RANGE:
return "OUT_OF_RANGE";
case GRPC_STATUS_UNIMPLEMENTED:
return "UNIMPLEMENTED";
case GRPC_STATUS_INTERNAL:
return "INTERNAL";
case GRPC_STATUS_UNAVAILABLE:
return "UNAVAILABLE";
case GRPC_STATUS_DATA_LOSS:
return "DATA_LOSS";
default:
return "UNKNOWN";
}
}

@ -0,0 +1,58 @@
/*
*
* Copyright 2017 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 GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H
#include <grpc/support/port_platform.h>
#include <grpc/status.h>
#include <stdbool.h>
#include <string.h>
/// If \a status_str is a valid status string, sets \a status to the
/// corresponding status value and returns true.
bool grpc_status_code_from_string(const char* status_str,
grpc_status_code* status);
/// Returns the string form of \a status, or "UNKNOWN" if invalid.
const char* grpc_status_code_to_string(grpc_status_code status);
namespace grpc_core {
namespace internal {
/// A set of grpc_status_code values.
class StatusCodeSet {
public:
bool Empty() const { return status_code_mask_ == 0; }
void Add(grpc_status_code status) { status_code_mask_ |= (1 << status); }
bool Contains(grpc_status_code status) const {
return status_code_mask_ & (1 << status);
}
private:
int status_code_mask_ = 0; // A bitfield of status codes in the set.
};
} // namespace internal
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_STATUS_UTIL_H */

@ -659,7 +659,6 @@ static void on_subchannel_connected(void* arg, grpc_error* error) {
static void subchannel_call_destroy(void* call, grpc_error* error) {
GPR_TIMER_SCOPE("grpc_subchannel_call_unref.destroy", 0);
grpc_subchannel_call* c = static_cast<grpc_subchannel_call*>(call);
GPR_ASSERT(c->schedule_closure_after_destroy != nullptr);
grpc_core::ConnectedSubchannel* connection = c->connection;
grpc_call_stack_destroy(SUBCHANNEL_CALL_TO_CALL_STACK(c), nullptr,
c->schedule_closure_after_destroy);
@ -673,9 +672,10 @@ void grpc_subchannel_call_set_cleanup_closure(grpc_subchannel_call* call,
call->schedule_closure_after_destroy = closure;
}
void grpc_subchannel_call_ref(
grpc_subchannel_call* grpc_subchannel_call_ref(
grpc_subchannel_call* c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
return c;
}
void grpc_subchannel_call_unref(
@ -705,6 +705,13 @@ const grpc_subchannel_key* grpc_subchannel_get_key(
return subchannel->key;
}
void* grpc_connected_subchannel_call_get_parent_data(
grpc_subchannel_call* subchannel_call) {
grpc_channel_stack* chanstk = subchannel_call->connection->channel_stack();
return (char*)subchannel_call + sizeof(grpc_subchannel_call) +
chanstk->call_stack_size;
}
grpc_call_stack* grpc_subchannel_call_get_call_stack(
grpc_subchannel_call* subchannel_call) {
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
@ -776,8 +783,8 @@ void ConnectedSubchannel::Ping(grpc_closure* on_initiate,
grpc_error* ConnectedSubchannel::CreateCall(const CallArgs& args,
grpc_subchannel_call** call) {
*call = static_cast<grpc_subchannel_call*>(gpr_arena_alloc(
args.arena,
sizeof(grpc_subchannel_call) + channel_stack_->call_stack_size));
args.arena, sizeof(grpc_subchannel_call) +
channel_stack_->call_stack_size + args.parent_data_size));
grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
RefCountedPtr<ConnectedSubchannel> connection =
Ref(DEBUG_LOCATION, "subchannel_call");

@ -81,6 +81,7 @@ class ConnectedSubchannel : public RefCountedWithTracing<ConnectedSubchannel> {
gpr_arena* arena;
grpc_call_context_element* context;
grpc_call_combiner* call_combiner;
size_t parent_data_size;
};
explicit ConnectedSubchannel(grpc_channel_stack* channel_stack);
@ -109,11 +110,17 @@ grpc_subchannel* grpc_subchannel_weak_ref(
grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_weak_unref(
grpc_subchannel* channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_ref(
grpc_subchannel_call* grpc_subchannel_call_ref(
grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_unref(
grpc_subchannel_call* call GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
/** Returns a pointer to the parent data associated with \a subchannel_call.
The data will be of the size specified in \a parent_data_size
field of the args passed to \a grpc_connected_subchannel_create_call(). */
void* grpc_connected_subchannel_call_get_parent_data(
grpc_subchannel_call* subchannel_call);
/** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity(
grpc_subchannel* channel, grpc_error** error);

@ -370,6 +370,9 @@ static void channel_connectivity_changed(void* arg, grpc_error* error) {
max_idle_timer, and prevent max_idle_timer from being started in the
future. */
increase_call_count(chand);
if (gpr_atm_acq_load(&chand->idle_state) == MAX_IDLE_STATE_SEEN_EXIT_IDLE) {
grpc_timer_cancel(&chand->max_idle_timer);
}
}
}

@ -29,6 +29,8 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/transport/service_config.h"
@ -37,27 +39,29 @@ typedef struct {
int max_recv_size;
} message_size_limits;
typedef struct {
gpr_refcount refs;
message_size_limits limits;
} refcounted_message_size_limits;
namespace grpc_core {
namespace {
static void* refcounted_message_size_limits_ref(void* value) {
refcounted_message_size_limits* limits =
static_cast<refcounted_message_size_limits*>(value);
gpr_ref(&limits->refs);
return value;
}
class MessageSizeLimits : public RefCounted<MessageSizeLimits> {
public:
static RefCountedPtr<MessageSizeLimits> CreateFromJson(const grpc_json* json);
static void refcounted_message_size_limits_unref(void* value) {
refcounted_message_size_limits* limits =
static_cast<refcounted_message_size_limits*>(value);
if (gpr_unref(&limits->refs)) {
gpr_free(value);
const message_size_limits& limits() const { return limits_; }
private:
// So New() can call our private ctor.
template <typename T, typename... Args>
friend T* grpc_core::New(Args&&... args);
MessageSizeLimits(int max_send_size, int max_recv_size) {
limits_.max_send_size = max_send_size;
limits_.max_recv_size = max_recv_size;
}
}
static void* refcounted_message_size_limits_create_from_json(
message_size_limits limits_;
};
RefCountedPtr<MessageSizeLimits> MessageSizeLimits::CreateFromJson(
const grpc_json* json) {
int max_request_message_bytes = -1;
int max_response_message_bytes = -1;
@ -79,16 +83,15 @@ static void* refcounted_message_size_limits_create_from_json(
if (max_response_message_bytes == -1) return nullptr;
}
}
refcounted_message_size_limits* value =
static_cast<refcounted_message_size_limits*>(
gpr_malloc(sizeof(refcounted_message_size_limits)));
gpr_ref_init(&value->refs, 1);
value->limits.max_send_size = max_request_message_bytes;
value->limits.max_recv_size = max_response_message_bytes;
return value;
return MakeRefCounted<MessageSizeLimits>(max_request_message_bytes,
max_response_message_bytes);
}
} // namespace
} // namespace grpc_core
namespace {
struct call_data {
grpc_call_combiner* call_combiner;
message_size_limits limits;
@ -105,8 +108,11 @@ struct call_data {
struct channel_data {
message_size_limits limits;
// Maps path names to refcounted_message_size_limits structs.
grpc_slice_hash_table* method_limit_table;
grpc_core::RefCountedPtr<grpc_core::SliceHashTable<
grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>>
method_limit_table;
};
} // namespace
// Callback invoked when we receive a message. Here we check the max
@ -185,20 +191,19 @@ static grpc_error* init_call_elem(grpc_call_element* elem,
// size to the receive limit.
calld->limits = chand->limits;
if (chand->method_limit_table != nullptr) {
refcounted_message_size_limits* limits =
static_cast<refcounted_message_size_limits*>(
grpc_method_config_table_get(chand->method_limit_table,
args->path));
grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits> limits =
grpc_core::ServiceConfig::MethodConfigTableLookup(
*chand->method_limit_table, args->path);
if (limits != nullptr) {
if (limits->limits.max_send_size >= 0 &&
(limits->limits.max_send_size < calld->limits.max_send_size ||
if (limits->limits().max_send_size >= 0 &&
(limits->limits().max_send_size < calld->limits.max_send_size ||
calld->limits.max_send_size < 0)) {
calld->limits.max_send_size = limits->limits.max_send_size;
calld->limits.max_send_size = limits->limits().max_send_size;
}
if (limits->limits.max_recv_size >= 0 &&
(limits->limits.max_recv_size < calld->limits.max_recv_size ||
if (limits->limits().max_recv_size >= 0 &&
(limits->limits().max_recv_size < calld->limits.max_recv_size ||
calld->limits.max_recv_size < 0)) {
calld->limits.max_recv_size = limits->limits.max_recv_size;
calld->limits.max_recv_size = limits->limits().max_recv_size;
}
}
}
@ -253,15 +258,11 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
const char* service_config_str = grpc_channel_arg_get_string(channel_arg);
if (service_config_str != nullptr) {
grpc_service_config* service_config =
grpc_service_config_create(service_config_str);
grpc_core::UniquePtr<grpc_core::ServiceConfig> service_config =
grpc_core::ServiceConfig::Create(service_config_str);
if (service_config != nullptr) {
chand->method_limit_table =
grpc_service_config_create_method_config_table(
service_config, refcounted_message_size_limits_create_from_json,
refcounted_message_size_limits_ref,
refcounted_message_size_limits_unref);
grpc_service_config_destroy(service_config);
chand->method_limit_table = service_config->CreateMethodConfigTable(
grpc_core::MessageSizeLimits::CreateFromJson);
}
}
return GRPC_ERROR_NONE;
@ -270,7 +271,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
// Destructor for channel_data.
static void destroy_channel_elem(grpc_channel_element* elem) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
grpc_slice_hash_table_unref(chand->method_limit_table);
chand->method_limit_table.reset();
}
const grpc_channel_filter grpc_message_size_filter = {

@ -30,10 +30,11 @@
#include "src/core/ext/filters/client_channel/uri_parser.h"
#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/lib/slice/slice_hash_table.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
@ -73,11 +74,11 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args(
const char* server_uri_path;
server_uri_path =
server_uri->path[0] == '/' ? server_uri->path + 1 : server_uri->path;
const grpc_slice_hash_table* targets_info =
grpc_lb_targets_info_find_in_args(args->args);
char* target_name_to_check = nullptr;
if (targets_info != nullptr) { // LB channel
// Find the balancer name for the target.
const grpc_core::TargetAuthorityTable* target_authority_table =
grpc_core::FindTargetAuthorityTableInArgs(args->args);
grpc_core::UniquePtr<char> authority;
if (target_authority_table != nullptr) {
// Find the authority for the target.
const char* target_uri_str =
grpc_get_subchannel_address_uri_arg(args->args);
grpc_uri* target_uri =
@ -86,37 +87,33 @@ static grpc_subchannel_args* get_secure_naming_subchannel_args(
if (target_uri->path[0] != '\0') { // "path" may be empty
const grpc_slice key = grpc_slice_from_static_string(
target_uri->path[0] == '/' ? target_uri->path + 1 : target_uri->path);
const char* value = static_cast<const char*>(
grpc_slice_hash_table_get(targets_info, key));
if (value != nullptr) target_name_to_check = gpr_strdup(value);
const grpc_core::UniquePtr<char>* value =
target_authority_table->Get(key);
if (value != nullptr) authority.reset(gpr_strdup(value->get()));
grpc_slice_unref_internal(key);
}
if (target_name_to_check == nullptr) {
// If the target name to check hasn't already been set, fall back to using
// SERVER_URI
target_name_to_check = gpr_strdup(server_uri_path);
}
grpc_uri_destroy(target_uri);
} else { // regular channel: the secure name is the original server URI.
target_name_to_check = gpr_strdup(server_uri_path);
}
// If the authority hasn't already been set (either because no target
// authority table was present or because the target was not present
// in the table), fall back to using the original server URI.
if (authority == nullptr) {
authority.reset(gpr_strdup(server_uri_path));
}
grpc_uri_destroy(server_uri);
GPR_ASSERT(target_name_to_check != nullptr);
grpc_channel_security_connector* subchannel_security_connector = nullptr;
// Create the security connector using the credentials and target name.
grpc_channel_args* new_args_from_connector = nullptr;
const grpc_security_status security_status =
grpc_channel_credentials_create_security_connector(
channel_credentials, target_name_to_check, args->args,
channel_credentials, authority.get(), args->args,
&subchannel_security_connector, &new_args_from_connector);
if (security_status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR,
"Failed to create secure subchannel for secure name '%s'",
target_name_to_check);
gpr_free(target_name_to_check);
authority.get());
return nullptr;
}
gpr_free(target_name_to_check);
grpc_arg new_security_connector_arg =
grpc_security_connector_to_arg(&subchannel_security_connector->base);

@ -1456,8 +1456,10 @@ static void perform_stream_op_locked(void* stream_op,
}
}
if (op_payload->send_initial_metadata.peer_string != nullptr) {
gpr_atm_rel_store(op_payload->send_initial_metadata.peer_string,
(gpr_atm)gpr_strdup(t->peer_string));
char* old_peer_string = (char*)gpr_atm_full_xchg(
op_payload->send_initial_metadata.peer_string,
(gpr_atm)gpr_strdup(t->peer_string));
gpr_free(old_peer_string);
}
}
@ -1571,8 +1573,10 @@ static void perform_stream_op_locked(void* stream_op,
s->trailing_metadata_available =
op_payload->recv_initial_metadata.trailing_metadata_available;
if (op_payload->recv_initial_metadata.peer_string != nullptr) {
gpr_atm_rel_store(op_payload->recv_initial_metadata.peer_string,
(gpr_atm)gpr_strdup(t->peer_string));
char* old_peer_string = (char*)gpr_atm_full_xchg(
op_payload->recv_initial_metadata.peer_string,
(gpr_atm)gpr_strdup(t->peer_string));
gpr_free(old_peer_string);
}
grpc_chttp2_maybe_complete_recv_initial_metadata(t, s);
}

@ -69,6 +69,5 @@ void grpc_chttp2_incoming_metadata_buffer_set_deadline(
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch) {
*batch = buffer->batch;
grpc_metadata_batch_init(&buffer->batch);
grpc_metadata_batch_move(&buffer->batch, batch);
}

@ -26,6 +26,49 @@
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
// Uncomment this to use a simple arena that simply allocates the
// requested amount of memory for each call to gpr_arena_alloc(). This
// effectively eliminates the efficiency gain of using an arena, but it
// may be useful for debugging purposes.
//#define SIMPLE_ARENA_FOR_DEBUGGING
#ifdef SIMPLE_ARENA_FOR_DEBUGGING
#include <grpc/support/sync.h>
struct gpr_arena {
gpr_mu mu;
void** ptrs;
size_t num_ptrs;
};
gpr_arena* gpr_arena_create(size_t ignored_initial_size) {
gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena));
gpr_mu_init(&arena->mu);
return arena;
}
size_t gpr_arena_destroy(gpr_arena* arena) {
gpr_mu_destroy(&arena->mu);
for (size_t i = 0; i < arena->num_ptrs; ++i) {
gpr_free(arena->ptrs[i]);
}
gpr_free(arena->ptrs);
gpr_free(arena);
return 1; // Value doesn't matter, since it won't be used.
}
void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
gpr_mu_lock(&arena->mu);
arena->ptrs =
(void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1));
void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size);
gpr_mu_unlock(&arena->mu);
return retval;
}
#else // SIMPLE_ARENA_FOR_DEBUGGING
// TODO(roth): We currently assume that all callers need alignment of 16
// bytes, which may be wrong in some cases. As part of converting the
// arena API to C++, we should consider replacing gpr_arena_alloc() with a
@ -105,3 +148,5 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone));
return ptr + start - z->size_begin;
}
#endif // SIMPLE_ARENA_FOR_DEBUGGING

@ -24,6 +24,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <cinttypes>
#include <memory>
#include "src/core/lib/debug/trace.h"

@ -24,6 +24,8 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <cinttypes>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/abstract.h"
#include "src/core/lib/gprpp/debug_location.h"

@ -33,6 +33,7 @@ template <typename T>
class RefCountedPtr {
public:
RefCountedPtr() {}
RefCountedPtr(std::nullptr_t) {}
// If value is non-null, we take ownership of a ref to it.
explicit RefCountedPtr(T* value) { value_ = value; }

@ -32,9 +32,6 @@
/* -- Fake transport security credentials. -- */
#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
"grpc.fake_security.expected_targets"
static grpc_security_status fake_transport_security_create_security_connector(
grpc_channel_credentials* c, grpc_call_credentials* call_creds,
const char* target, const grpc_channel_args* args,

@ -23,6 +23,9 @@
#include "src/core/lib/security/credentials/credentials.h"
#define GRPC_ARG_FAKE_SECURITY_EXPECTED_TARGETS \
"grpc.fake_security.expected_targets"
/* -- Fake transport security credentials. -- */
/* Creates a fake transport security credentials object for testing. */

@ -39,9 +39,9 @@
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
#include "src/core/lib/security/transport/lb_targets_info.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/security/transport/target_authority_table.h"
#include "src/core/tsi/fake_transport_security.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_adapter.h"
@ -463,6 +463,15 @@ static bool fake_channel_check_call_host(grpc_channel_security_connector* sc,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error** error) {
grpc_fake_channel_security_connector* c =
reinterpret_cast<grpc_fake_channel_security_connector*>(sc);
if (c->is_lb_channel) {
// TODO(dgq): verify that the host (ie, authority header) matches that of
// the LB, as opposed to that of the backends.
} else {
// TODO(dgq): verify that the host (ie, authority header) matches that of
// the backend, not the LB's.
}
return true;
}
@ -514,7 +523,7 @@ grpc_channel_security_connector* grpc_fake_channel_security_connector_create(
c->target = gpr_strdup(target);
const char* expected_targets = grpc_fake_transport_get_expected_targets(args);
c->expected_targets = gpr_strdup(expected_targets);
c->is_lb_channel = (grpc_lb_targets_info_find_in_args(args) != nullptr);
c->is_lb_channel = grpc_core::FindTargetAuthorityTableInArgs(args) != nullptr;
return &c->base;
}

@ -1,61 +0,0 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/security/transport/lb_targets_info.h"
/* Channel arg key for the mapping of LB server addresses to their names for
* secure naming purposes. */
#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map"
static void* targets_info_copy(void* p) {
return grpc_slice_hash_table_ref(static_cast<grpc_slice_hash_table*>(p));
}
static void targets_info_destroy(void* p) {
grpc_slice_hash_table_unref(static_cast<grpc_slice_hash_table*>(p));
}
static int targets_info_cmp(void* a, void* b) {
return grpc_slice_hash_table_cmp(
static_cast<const grpc_slice_hash_table*>(a),
static_cast<const grpc_slice_hash_table*>(b));
}
static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = {
targets_info_copy, targets_info_destroy, targets_info_cmp};
grpc_arg grpc_lb_targets_info_create_channel_arg(
grpc_slice_hash_table* targets_info) {
return grpc_channel_arg_pointer_create((char*)GRPC_ARG_LB_SECURE_NAMING_MAP,
targets_info,
&server_to_balancer_names_vtable);
}
grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
const grpc_channel_args* args) {
const grpc_arg* targets_info_arg =
grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP);
if (targets_info_arg != nullptr) {
GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER);
return static_cast<grpc_slice_hash_table*>(
targets_info_arg->value.pointer.p);
}
return nullptr;
}

@ -0,0 +1,75 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/security/transport/target_authority_table.h"
// Channel arg key for the mapping of target addresses to their authorities.
#define GRPC_ARG_TARGET_AUTHORITY_TABLE "grpc.target_authority_table"
namespace grpc_core {
namespace {
void* target_authority_table_copy(void* p) {
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
// TODO(roth): When channel_args are converted to C++, pass the
// RefCountedPtr<> directly instead of managing the ref manually.
table->Ref().release();
return p;
}
void target_authority_table_destroy(void* p) {
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p);
table->Unref();
}
int target_authority_table_cmp(void* a, void* b) {
return TargetAuthorityTable::Cmp(
*static_cast<const TargetAuthorityTable*>(a),
*static_cast<const TargetAuthorityTable*>(b));
}
const grpc_arg_pointer_vtable target_authority_table_arg_vtable = {
target_authority_table_copy, target_authority_table_destroy,
target_authority_table_cmp};
} // namespace
grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table) {
return grpc_channel_arg_pointer_create((char*)GRPC_ARG_TARGET_AUTHORITY_TABLE,
table,
&target_authority_table_arg_vtable);
}
TargetAuthorityTable* FindTargetAuthorityTableInArgs(
const grpc_channel_args* args) {
const grpc_arg* arg =
grpc_channel_args_find(args, GRPC_ARG_TARGET_AUTHORITY_TABLE);
if (arg != nullptr) {
if (arg->type == GRPC_ARG_POINTER) {
return static_cast<TargetAuthorityTable*>(arg->value.pointer.p);
} else {
gpr_log(GPR_ERROR, "value of " GRPC_ARG_TARGET_AUTHORITY_TABLE
" channel arg was not pointer type; ignoring");
}
}
return nullptr;
}
} // namespace grpc_core

@ -0,0 +1,40 @@
/*
*
* Copyright 2017 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 GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice_hash_table.h"
namespace grpc_core {
/// A hash table mapping target addresses to authorities.
typedef SliceHashTable<UniquePtr<char>> TargetAuthorityTable;
/// Returns a channel argument containing \a table.
grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table);
/// Returns the target authority table from \a args or nullptr.
TargetAuthorityTable* FindTargetAuthorityTableInArgs(
const grpc_channel_args* args);
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TARGET_AUTHORITY_TABLE_H */

@ -1,147 +0,0 @@
//
// Copyright 2016 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice_hash_table.h"
#include <stdbool.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/metadata.h"
struct grpc_slice_hash_table {
gpr_refcount refs;
void (*destroy_value)(void* value);
int (*value_cmp)(void* a, void* b);
size_t size;
size_t max_num_probes;
grpc_slice_hash_table_entry* entries;
};
static bool is_empty(grpc_slice_hash_table_entry* entry) {
return entry->value == nullptr;
}
static void grpc_slice_hash_table_add(grpc_slice_hash_table* table,
grpc_slice key, void* value) {
GPR_ASSERT(value != nullptr);
const size_t hash = grpc_slice_hash(key);
for (size_t offset = 0; offset < table->size; ++offset) {
const size_t idx = (hash + offset) % table->size;
if (is_empty(&table->entries[idx])) {
table->entries[idx].key = key;
table->entries[idx].value = value;
// Keep track of the maximum number of probes needed, since this
// provides an upper bound for lookups.
if (offset > table->max_num_probes) table->max_num_probes = offset;
return;
}
}
GPR_ASSERT(false); // Table should never be full.
}
grpc_slice_hash_table* grpc_slice_hash_table_create(
size_t num_entries, grpc_slice_hash_table_entry* entries,
void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b)) {
grpc_slice_hash_table* table =
static_cast<grpc_slice_hash_table*>(gpr_zalloc(sizeof(*table)));
gpr_ref_init(&table->refs, 1);
table->destroy_value = destroy_value;
table->value_cmp = value_cmp;
// Keep load factor low to improve performance of lookups.
table->size = num_entries * 2;
const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size;
table->entries =
static_cast<grpc_slice_hash_table_entry*>(gpr_zalloc(entry_size));
for (size_t i = 0; i < num_entries; ++i) {
grpc_slice_hash_table_entry* entry = &entries[i];
grpc_slice_hash_table_add(table, entry->key, entry->value);
}
return table;
}
grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) {
if (table != nullptr) gpr_ref(&table->refs);
return table;
}
void grpc_slice_hash_table_unref(grpc_slice_hash_table* table) {
if (table != nullptr && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->size; ++i) {
grpc_slice_hash_table_entry* entry = &table->entries[i];
if (!is_empty(entry)) {
grpc_slice_unref_internal(entry->key);
table->destroy_value(entry->value);
}
}
gpr_free(table->entries);
gpr_free(table);
}
}
void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
const grpc_slice key) {
const size_t hash = grpc_slice_hash(key);
// We cap the number of probes at the max number recorded when
// populating the table.
for (size_t offset = 0; offset <= table->max_num_probes; ++offset) {
const size_t idx = (hash + offset) % table->size;
if (is_empty(&table->entries[idx])) break;
if (grpc_slice_eq(table->entries[idx].key, key)) {
return table->entries[idx].value;
}
}
return nullptr; // Not found.
}
static int pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); }
int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
const grpc_slice_hash_table* b) {
int (*const value_cmp_fn_a)(void* a, void* b) =
a->value_cmp != nullptr ? a->value_cmp : pointer_cmp;
int (*const value_cmp_fn_b)(void* a, void* b) =
b->value_cmp != nullptr ? b->value_cmp : pointer_cmp;
// Compare value_fns
const int value_fns_cmp =
GPR_ICMP((void*)value_cmp_fn_a, (void*)value_cmp_fn_b);
if (value_fns_cmp != 0) return value_fns_cmp;
// Compare sizes
if (a->size < b->size) return -1;
if (a->size > b->size) return 1;
// Compare rows.
for (size_t i = 0; i < a->size; ++i) {
if (is_empty(&a->entries[i])) {
if (!is_empty(&b->entries[i])) {
return -1; // a empty but b non-empty
}
continue; // both empty, no need to check key or value
} else if (is_empty(&b->entries[i])) {
return 1; // a non-empty but b empty
}
// neither entry is empty
const int key_cmp = grpc_slice_cmp(a->entries[i].key, b->entries[i].key);
if (key_cmp != 0) return key_cmp;
const int value_cmp =
value_cmp_fn_a(a->entries[i].value, b->entries[i].value);
if (value_cmp != 0) return value_cmp;
}
return 0;
}

@ -19,52 +19,183 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/transport/metadata.h"
#include <string.h>
/** Hash table implementation.
*
* This implementation uses open addressing
* (https://en.wikipedia.org/wiki/Open_addressing) with linear
* probing (https://en.wikipedia.org/wiki/Linear_probing).
*
* The keys are \a grpc_slice objects. The values are arbitrary pointers
* with a common destroy function.
*
* Hash tables are intentionally immutable, to avoid the need for locking.
*/
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/slice/slice_internal.h"
/// Hash table implementation.
///
/// This implementation uses open addressing
/// (https://en.wikipedia.org/wiki/Open_addressing) with linear
/// probing (https://en.wikipedia.org/wiki/Linear_probing).
///
/// The keys are \a grpc_slice objects. The values can be any type.
///
/// Hash tables are intentionally immutable, to avoid the need for locking.
namespace grpc_core {
template <typename T>
class SliceHashTable : public RefCounted<SliceHashTable<T>> {
public:
struct Entry {
grpc_slice key;
T value;
bool is_set;
};
// Function for comparing values.
// TODO(roth): Eliminate this and the Cmp() method from this API once
// grpc_channel_args is redesigned to require that keys are unique.
typedef int (*ValueCmp)(const T&, const T&);
/// Creates a new hash table containing \a entries, which is an array
/// of length \a num_entries. Takes ownership of all keys and values in \a
/// entries. If not null, \a value_cmp will be used to compare values in
/// the context of \a Cmp(). If null, raw pointer (\a GPR_ICMP) comparison
/// will be used.
static RefCountedPtr<SliceHashTable> Create(size_t num_entries,
Entry* entries,
ValueCmp value_cmp);
/// Returns the value from the table associated with \a key.
/// Returns null if \a key is not found.
const T* Get(const grpc_slice& key) const;
/// Compares \a a vs. \a b.
/// A table is considered "smaller" (resp. "greater") if:
/// - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
/// - else, it contains fewer (resp. more) entries,
/// - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
/// - else, if value_cmp(a_value, b_value) < 1 (resp. > 1).
static int Cmp(const SliceHashTable& a, const SliceHashTable& b);
private:
// So New() can call our private ctor.
template <typename T2, typename... Args>
friend T2* New(Args&&... args);
SliceHashTable(size_t num_entries, Entry* entries, ValueCmp value_cmp);
virtual ~SliceHashTable();
void Add(grpc_slice key, T& value);
// Default value comparison function, if none specified by caller.
static int DefaultValueCmp(const T& a, const T& b) { return GPR_ICMP(a, b); }
const ValueCmp value_cmp_;
const size_t size_;
size_t max_num_probes_;
Entry* entries_;
};
//
// implementation -- no user-serviceable parts below
//
template <typename T>
RefCountedPtr<SliceHashTable<T>> SliceHashTable<T>::Create(size_t num_entries,
Entry* entries,
ValueCmp value_cmp) {
return MakeRefCounted<SliceHashTable<T>>(num_entries, entries, value_cmp);
}
template <typename T>
SliceHashTable<T>::SliceHashTable(size_t num_entries, Entry* entries,
ValueCmp value_cmp)
: value_cmp_(value_cmp),
// Keep load factor low to improve performance of lookups.
size_(num_entries * 2),
max_num_probes_(0) {
entries_ = static_cast<Entry*>(gpr_zalloc(sizeof(Entry) * size_));
for (size_t i = 0; i < num_entries; ++i) {
Entry* entry = &entries[i];
Add(entry->key, entry->value);
}
}
template <typename T>
SliceHashTable<T>::~SliceHashTable() {
for (size_t i = 0; i < size_; ++i) {
Entry& entry = entries_[i];
if (entry.is_set) {
grpc_slice_unref_internal(entry.key);
entry.value.~T();
}
}
gpr_free(entries_);
}
template <typename T>
void SliceHashTable<T>::Add(grpc_slice key, T& value) {
const size_t hash = grpc_slice_hash(key);
for (size_t offset = 0; offset < size_; ++offset) {
const size_t idx = (hash + offset) % size_;
if (!entries_[idx].is_set) {
entries_[idx].is_set = true;
entries_[idx].key = key;
entries_[idx].value = std::move(value);
// Keep track of the maximum number of probes needed, since this
// provides an upper bound for lookups.
if (offset > max_num_probes_) max_num_probes_ = offset;
return;
}
}
GPR_ASSERT(false); // Table should never be full.
}
template <typename T>
const T* SliceHashTable<T>::Get(const grpc_slice& key) const {
const size_t hash = grpc_slice_hash(key);
// We cap the number of probes at the max number recorded when
// populating the table.
for (size_t offset = 0; offset <= max_num_probes_; ++offset) {
const size_t idx = (hash + offset) % size_;
if (!entries_[idx].is_set) break;
if (grpc_slice_eq(entries_[idx].key, key)) {
return &entries_[idx].value;
}
}
return nullptr; // Not found.
}
template <typename T>
int SliceHashTable<T>::Cmp(const SliceHashTable& a, const SliceHashTable& b) {
ValueCmp value_cmp_a =
a.value_cmp_ != nullptr ? a.value_cmp_ : DefaultValueCmp;
ValueCmp value_cmp_b =
b.value_cmp_ != nullptr ? b.value_cmp_ : DefaultValueCmp;
// Compare value_fns
const int value_fns_cmp = GPR_ICMP((void*)value_cmp_a, (void*)value_cmp_b);
if (value_fns_cmp != 0) return value_fns_cmp;
// Compare sizes
if (a.size_ < b.size_) return -1;
if (a.size_ > b.size_) return 1;
// Compare rows.
for (size_t i = 0; i < a.size_; ++i) {
if (!a.entries_[i].is_set) {
if (b.entries_[i].is_set) {
return -1; // a empty but b non-empty
}
continue; // both empty, no need to check key or value
} else if (!b.entries_[i].is_set) {
return 1; // a non-empty but b empty
}
// neither entry is empty
const int key_cmp = grpc_slice_cmp(a.entries_[i].key, b.entries_[i].key);
if (key_cmp != 0) return key_cmp;
const int value_cmp = value_cmp_a(a.entries_[i].value, b.entries_[i].value);
if (value_cmp != 0) return value_cmp;
}
return 0;
}
typedef struct grpc_slice_hash_table grpc_slice_hash_table;
typedef struct grpc_slice_hash_table_entry {
grpc_slice key;
void* value; /* Must not be NULL. */
} grpc_slice_hash_table_entry;
/** Creates a new hash table of containing \a entries, which is an array
of length \a num_entries. Takes ownership of all keys and values in \a
entries. Values will be cleaned up via \a destroy_value(). If not NULL, \a
value_cmp will be used to compare values in the context of \a
grpc_slice_hash_table_cmp. If NULL, raw pointer (\a GPR_ICMP) comparison
will be used. */
grpc_slice_hash_table* grpc_slice_hash_table_create(
size_t num_entries, grpc_slice_hash_table_entry* entries,
void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b));
grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table);
void grpc_slice_hash_table_unref(grpc_slice_hash_table* table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table,
const grpc_slice key);
/** Compares \a a vs. \a b.
* A table is considered "smaller" (resp. "greater") if:
* - GPR_ICMP(a->value_cmp, b->value_cmp) < 1 (resp. > 1),
* - else, it contains fewer (resp. more) entries,
* - else, if strcmp(a_key, b_key) < 1 (resp. > 1),
* - else, if value_cmp(a_value, b_value) < 1 (resp. > 1). */
int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
const grpc_slice_hash_table* b);
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */

@ -0,0 +1,105 @@
/*
* Copyright 2016 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
#define GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/slice/slice_internal.h"
/// Weak hash table implementation.
///
/// This entries in this table are weak: an entry may be removed at any time due
/// to a number of reasons: memory pressure, hash collisions, etc.
///
/// The keys are \a grpc_slice objects. The values are of arbitrary type.
///
/// This class is thread unsafe. It's the caller's responsibility to ensure
/// proper locking when accessing its methods.
namespace grpc_core {
template <typename T, size_t Size>
class SliceWeakHashTable : public RefCounted<SliceWeakHashTable<T, Size>> {
public:
/// Creates a new table of at most \a size entries.
static RefCountedPtr<SliceWeakHashTable> Create() {
return MakeRefCounted<SliceWeakHashTable<T, Size>>();
}
/// Add a mapping from \a key to \a value, taking ownership of \a key. This
/// operation will always succeed. It may discard older entries.
void Add(grpc_slice key, T value) {
const size_t idx = grpc_slice_hash(key) % Size;
entries_[idx].Set(key, std::move(value));
return;
}
/// Returns the value from the table associated with / \a key or null if not
/// found.
const T* Get(const grpc_slice key) const {
const size_t idx = grpc_slice_hash(key) % Size;
const auto& entry = entries_[idx];
return grpc_slice_eq(entry.key(), key) ? entry.value() : nullptr;
}
private:
// So New() can call our private ctor.
template <typename T2, typename... Args>
friend T2* New(Args&&... args);
SliceWeakHashTable() = default;
~SliceWeakHashTable() = default;
/// The type of the table "rows".
class Entry {
public:
Entry() = default;
~Entry() {
if (is_set_) grpc_slice_unref_internal(key_);
}
grpc_slice key() const { return key_; }
/// Return the entry's value, or null if unset.
const T* value() const {
if (!is_set_) return nullptr;
return &value_;
}
/// Set the \a key and \a value (which is moved) for the entry.
void Set(grpc_slice key, T&& value) {
if (is_set_) grpc_slice_unref_internal(key_);
key_ = key;
value_ = std::move(value);
is_set_ = true;
}
private:
grpc_slice key_;
T value_;
bool is_set_ = false;
};
Entry entries_[Size];
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SLICE_SLICE_WEAK_HASH_TABLE_H */

@ -50,6 +50,7 @@
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/status_metadata.h"
#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
@ -976,32 +977,6 @@ static int prepare_application_metadata(grpc_call* call, int count,
return 1;
}
/* we offset status by a small amount when storing it into transport metadata
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
*/
#define STATUS_OFFSET 1
static void destroy_status(void* ignored) {}
static uint32_t decode_status(grpc_mdelem md) {
uint32_t status;
void* user_data;
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) return 0;
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) return 1;
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) return 2;
user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data != nullptr) {
status = (static_cast<uint32_t>((intptr_t)user_data)) - STATUS_OFFSET;
} else {
if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
}
grpc_mdelem_set_user_data(
md, destroy_status,
(void*)static_cast<intptr_t>(status + STATUS_OFFSET));
}
return status;
}
static grpc_message_compression_algorithm decode_message_compression(
grpc_mdelem md) {
grpc_message_compression_algorithm algorithm =
@ -1093,7 +1068,8 @@ static void recv_initial_filter(grpc_call* call, grpc_metadata_batch* b) {
static void recv_trailing_filter(void* args, grpc_metadata_batch* b) {
grpc_call* call = static_cast<grpc_call*>(args);
if (b->idx.named.grpc_status != nullptr) {
uint32_t status_code = decode_status(b->idx.named.grpc_status->md);
grpc_status_code status_code =
grpc_get_status_code_from_metadata(b->idx.named.grpc_status->md);
grpc_error* error =
status_code == GRPC_STATUS_OK
? GRPC_ERROR_NONE

@ -303,3 +303,27 @@ grpc_error* grpc_metadata_batch_filter(grpc_metadata_batch* batch,
}
return error;
}
void grpc_metadata_batch_copy(grpc_metadata_batch* src,
grpc_metadata_batch* dst,
grpc_linked_mdelem* storage) {
grpc_metadata_batch_init(dst);
dst->deadline = src->deadline;
size_t i = 0;
for (grpc_linked_mdelem* elem = src->list.head; elem != nullptr;
elem = elem->next) {
grpc_error* error = grpc_metadata_batch_add_tail(dst, &storage[i++],
GRPC_MDELEM_REF(elem->md));
// The only way that grpc_metadata_batch_add_tail() can fail is if
// there's a duplicate entry for a callout. However, that can't be
// the case here, because we would not have been allowed to create
// a source batch that had that kind of conflict.
GPR_ASSERT(error == GRPC_ERROR_NONE);
}
}
void grpc_metadata_batch_move(grpc_metadata_batch* src,
grpc_metadata_batch* dst) {
*dst = *src;
grpc_metadata_batch_init(src);
}

@ -137,4 +137,13 @@ void grpc_metadata_batch_assert_ok(grpc_metadata_batch* comd);
} while (0)
#endif
/// Copies \a src to \a dst. \a storage must point to an array of
/// \a grpc_linked_mdelem structs of at least the same size as \a src.
void grpc_metadata_batch_copy(grpc_metadata_batch* src,
grpc_metadata_batch* dst,
grpc_linked_mdelem* storage);
void grpc_metadata_batch_move(grpc_metadata_batch* src,
grpc_metadata_batch* dst);
#endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */

@ -31,74 +31,30 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
// The main purpose of the code here is to parse the service config in
// JSON form, which will look like this:
//
// {
// "loadBalancingPolicy": "string", // optional
// "methodConfig": [ // array of one or more method_config objects
// {
// "name": [ // array of one or more name objects
// {
// "service": "string", // required
// "method": "string", // optional
// }
// ],
// // remaining fields are optional.
// // see https://developers.google.com/protocol-buffers/docs/proto3#json
// // for format details.
// "waitForReady": bool,
// "timeout": "duration_string",
// "maxRequestMessageBytes": "int64_string",
// "maxResponseMessageBytes": "int64_string",
// }
// ]
// }
struct grpc_service_config {
char* json_string; // Underlying storage for json_tree.
grpc_json* json_tree;
};
namespace grpc_core {
grpc_service_config* grpc_service_config_create(const char* json_string) {
grpc_service_config* service_config =
static_cast<grpc_service_config*>(gpr_malloc(sizeof(*service_config)));
service_config->json_string = gpr_strdup(json_string);
service_config->json_tree =
grpc_json_parse_string(service_config->json_string);
if (service_config->json_tree == nullptr) {
UniquePtr<ServiceConfig> ServiceConfig::Create(const char* json) {
UniquePtr<char> json_string(gpr_strdup(json));
grpc_json* json_tree = grpc_json_parse_string(json_string.get());
if (json_tree == nullptr) {
gpr_log(GPR_INFO, "failed to parse JSON for service config");
gpr_free(service_config->json_string);
gpr_free(service_config);
return nullptr;
}
return service_config;
return MakeUnique<ServiceConfig>(std::move(json_string), json_tree);
}
void grpc_service_config_destroy(grpc_service_config* service_config) {
grpc_json_destroy(service_config->json_tree);
gpr_free(service_config->json_string);
gpr_free(service_config);
}
ServiceConfig::ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree)
: json_string_(std::move(json_string)), json_tree_(json_tree) {}
void grpc_service_config_parse_global_params(
const grpc_service_config* service_config,
void (*process_json)(const grpc_json* json, void* arg), void* arg) {
const grpc_json* json = service_config->json_tree;
if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key == nullptr) return;
if (strcmp(field->key, "methodConfig") == 0) continue;
process_json(field, arg);
}
}
ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
const char* grpc_service_config_get_lb_policy_name(
const grpc_service_config* service_config) {
const grpc_json* json = service_config->json_tree;
if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
const char* ServiceConfig::GetLoadBalancingPolicyName() const {
if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
return nullptr;
}
const char* lb_policy_name = nullptr;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
for (grpc_json* field = json_tree_->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) return nullptr;
if (strcmp(field->key, "loadBalancingPolicy") == 0) {
if (lb_policy_name != nullptr) return nullptr; // Duplicate.
@ -109,8 +65,7 @@ const char* grpc_service_config_get_lb_policy_name(
return lb_policy_name;
}
// Returns the number of names specified in the method config \a json.
static size_t count_names_in_method_config_json(grpc_json* json) {
size_t ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
size_t num_names = 0;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key != nullptr && strcmp(field->key, "name") == 0) {
@ -124,9 +79,7 @@ static size_t count_names_in_method_config_json(grpc_json* json) {
return num_names;
}
// Returns a path string for the JSON name object specified by \a json.
// Returns NULL on error. Caller takes ownership of result.
static char* parse_json_method_name(grpc_json* json) {
UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json) {
if (json->type != GRPC_JSON_OBJECT) return nullptr;
const char* service_name = nullptr;
const char* method_name = nullptr;
@ -147,116 +100,7 @@ static char* parse_json_method_name(grpc_json* json) {
char* path;
gpr_asprintf(&path, "/%s/%s", service_name,
method_name == nullptr ? "*" : method_name);
return path;
return UniquePtr<char>(path);
}
// Parses the method config from \a json. Adds an entry to \a entries for
// each name found, incrementing \a idx for each entry added.
// Returns false on error.
static bool parse_json_method_config(
grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
void* (*ref_value)(void* value), void (*unref_value)(void* value),
grpc_slice_hash_table_entry* entries, size_t* idx) {
// Construct value.
void* method_config = create_value(json);
if (method_config == nullptr) return false;
// Construct list of paths.
bool success = false;
gpr_strvec paths;
gpr_strvec_init(&paths);
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) continue;
if (strcmp(child->key, "name") == 0) {
if (child->type != GRPC_JSON_ARRAY) goto done;
for (grpc_json* name = child->child; name != nullptr; name = name->next) {
char* path = parse_json_method_name(name);
if (path == nullptr) goto done;
gpr_strvec_add(&paths, path);
}
}
}
if (paths.count == 0) goto done; // No names specified.
// Add entry for each path.
for (size_t i = 0; i < paths.count; ++i) {
entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
entries[*idx].value = ref_value(method_config);
++*idx;
}
success = true;
done:
unref_value(method_config);
gpr_strvec_destroy(&paths);
return success;
}
grpc_slice_hash_table* grpc_service_config_create_method_config_table(
const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
void* (*ref_value)(void* value), void (*unref_value)(void* value)) {
const grpc_json* json = service_config->json_tree;
// Traverse parsed JSON tree.
if (json->type != GRPC_JSON_OBJECT || json->key != nullptr) return nullptr;
size_t num_entries = 0;
grpc_slice_hash_table_entry* entries = nullptr;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key == nullptr) return nullptr;
if (strcmp(field->key, "methodConfig") == 0) {
if (entries != nullptr) return nullptr; // Duplicate.
if (field->type != GRPC_JSON_ARRAY) return nullptr;
// Find number of entries.
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
size_t count = count_names_in_method_config_json(method);
if (count <= 0) return nullptr;
num_entries += count;
}
// Populate method config table entries.
entries = static_cast<grpc_slice_hash_table_entry*>(
gpr_malloc(num_entries * sizeof(grpc_slice_hash_table_entry)));
size_t idx = 0;
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
if (!parse_json_method_config(method, create_value, ref_value,
unref_value, entries, &idx)) {
for (size_t i = 0; i < idx; ++i) {
grpc_slice_unref_internal(entries[i].key);
unref_value(entries[i].value);
}
gpr_free(entries);
return nullptr;
}
}
GPR_ASSERT(idx == num_entries);
}
}
// Instantiate method config table.
grpc_slice_hash_table* method_config_table = nullptr;
if (entries != nullptr) {
method_config_table = grpc_slice_hash_table_create(num_entries, entries,
unref_value, nullptr);
gpr_free(entries);
}
return method_config_table;
}
void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
grpc_slice path) {
void* value = grpc_slice_hash_table_get(table, path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (value == nullptr) {
char* path_str = grpc_slice_to_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = static_cast<size_t>(sep - path_str);
char* buf = static_cast<char*>(gpr_malloc(len + 2)); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
gpr_free(buf);
value = grpc_slice_hash_table_get(table, wildcard_path);
grpc_slice_unref_internal(wildcard_path);
gpr_free(path_str);
}
return value;
}
} // namespace grpc_core

@ -20,44 +20,230 @@
#include <grpc/support/port_platform.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gprpp/inlined_vector.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/slice/slice_hash_table.h"
typedef struct grpc_service_config grpc_service_config;
grpc_service_config* grpc_service_config_create(const char* json_string);
void grpc_service_config_destroy(grpc_service_config* service_config);
/// Invokes \a process_json() for each global parameter in the service
/// config. \a arg is passed as the second argument to \a process_json().
void grpc_service_config_parse_global_params(
const grpc_service_config* service_config,
void (*process_json)(const grpc_json* json, void* arg), void* arg);
/// Gets the LB policy name from \a service_config.
/// Returns NULL if no LB policy name was specified.
/// Caller does NOT take ownership.
const char* grpc_service_config_get_lb_policy_name(
const grpc_service_config* service_config);
/// Creates a method config table based on the data in \a json.
/// The table's keys are request paths. The table's value type is
/// returned by \a create_value(), based on data parsed from the JSON tree.
/// \a ref_value() and \a unref_value() are used to ref and unref values.
/// Returns NULL on error.
grpc_slice_hash_table* grpc_service_config_create_method_config_table(
const grpc_service_config* service_config,
void* (*create_value)(const grpc_json* method_config_json),
void* (*ref_value)(void* value), void (*unref_value)(void* value));
/// A helper function for looking up values in the table returned by
/// \a grpc_service_config_create_method_config_table().
/// Gets the method config for the specified \a path, which should be of
/// the form "/service/method".
/// Returns NULL if the method has no config.
/// Caller does NOT own a reference to the result.
void* grpc_method_config_table_get(const grpc_slice_hash_table* table,
grpc_slice path);
// The main purpose of the code here is to parse the service config in
// JSON form, which will look like this:
//
// {
// "loadBalancingPolicy": "string", // optional
// "methodConfig": [ // array of one or more method_config objects
// {
// "name": [ // array of one or more name objects
// {
// "service": "string", // required
// "method": "string", // optional
// }
// ],
// // remaining fields are optional.
// // see
// https://developers.google.com/protocol-buffers/docs/proto3#json
// // for format details.
// "waitForReady": bool,
// "timeout": "duration_string",
// "maxRequestMessageBytes": "int64_string",
// "maxResponseMessageBytes": "int64_string",
// }
// ]
// }
namespace grpc_core {
class ServiceConfig {
public:
/// Creates a new service config from parsing \a json_string.
/// Returns null on parse error.
static UniquePtr<ServiceConfig> Create(const char* json);
~ServiceConfig();
/// Invokes \a process_json() for each global parameter in the service
/// config. \a arg is passed as the second argument to \a process_json().
template <typename T>
using ProcessJson = void (*)(const grpc_json*, T*);
template <typename T>
void ParseGlobalParams(ProcessJson<T> process_json, T* arg) const;
/// Gets the LB policy name from \a service_config.
/// Returns NULL if no LB policy name was specified.
/// Caller does NOT take ownership.
const char* GetLoadBalancingPolicyName() const;
/// Creates a method config table based on the data in \a json.
/// The table's keys are request paths. The table's value type is
/// returned by \a create_value(), based on data parsed from the JSON tree.
/// Returns null on error.
template <typename T>
using CreateValue = RefCountedPtr<T> (*)(const grpc_json* method_config_json);
template <typename T>
RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> CreateMethodConfigTable(
CreateValue<T> create_value);
/// A helper function for looking up values in the table returned by
/// \a CreateMethodConfigTable().
/// Gets the method config for the specified \a path, which should be of
/// the form "/service/method".
/// Returns null if the method has no config.
/// Caller does NOT own a reference to the result.
template <typename T>
static RefCountedPtr<T> MethodConfigTableLookup(
const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path);
private:
// So New() can call our private ctor.
template <typename T, typename... Args>
friend T* New(Args&&... args);
// Takes ownership of \a json_tree.
ServiceConfig(UniquePtr<char> json_string, grpc_json* json_tree);
// Returns the number of names specified in the method config \a json.
static size_t CountNamesInMethodConfig(grpc_json* json);
// Returns a path string for the JSON name object specified by \a json.
// Returns null on error.
static UniquePtr<char> ParseJsonMethodName(grpc_json* json);
// Parses the method config from \a json. Adds an entry to \a entries for
// each name found, incrementing \a idx for each entry added.
// Returns false on error.
template <typename T>
static bool ParseJsonMethodConfig(
grpc_json* json, CreateValue<T> create_value,
typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx);
UniquePtr<char> json_string_; // Underlying storage for json_tree.
grpc_json* json_tree_;
};
//
// implementation -- no user-serviceable parts below
//
template <typename T>
void ServiceConfig::ParseGlobalParams(ProcessJson<T> process_json,
T* arg) const {
if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
return;
}
for (grpc_json* field = json_tree_->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) return;
if (strcmp(field->key, "methodConfig") == 0) continue;
process_json(field, arg);
}
}
template <typename T>
bool ServiceConfig::ParseJsonMethodConfig(
grpc_json* json, CreateValue<T> create_value,
typename SliceHashTable<RefCountedPtr<T>>::Entry* entries, size_t* idx) {
// Construct value.
RefCountedPtr<T> method_config = create_value(json);
if (method_config == nullptr) return false;
// Construct list of paths.
InlinedVector<UniquePtr<char>, 10> paths;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) continue;
if (strcmp(child->key, "name") == 0) {
if (child->type != GRPC_JSON_ARRAY) return false;
for (grpc_json* name = child->child; name != nullptr; name = name->next) {
UniquePtr<char> path = ParseJsonMethodName(name);
if (path == nullptr) return false;
paths.push_back(std::move(path));
}
}
}
if (paths.size() == 0) return false; // No names specified.
// Add entry for each path.
for (size_t i = 0; i < paths.size(); ++i) {
entries[*idx].key = grpc_slice_from_copied_string(paths[i].get());
entries[*idx].value = method_config; // Takes a new ref.
++*idx;
}
// Success.
return true;
}
template <typename T>
RefCountedPtr<SliceHashTable<RefCountedPtr<T>>>
ServiceConfig::CreateMethodConfigTable(CreateValue<T> create_value) {
// Traverse parsed JSON tree.
if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) {
return nullptr;
}
size_t num_entries = 0;
typename SliceHashTable<RefCountedPtr<T>>::Entry* entries = nullptr;
for (grpc_json* field = json_tree_->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) return nullptr;
if (strcmp(field->key, "methodConfig") == 0) {
if (entries != nullptr) return nullptr; // Duplicate.
if (field->type != GRPC_JSON_ARRAY) return nullptr;
// Find number of entries.
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
size_t count = CountNamesInMethodConfig(method);
if (count <= 0) return nullptr;
num_entries += count;
}
// Populate method config table entries.
entries = static_cast<typename SliceHashTable<RefCountedPtr<T>>::Entry*>(
gpr_zalloc(num_entries *
sizeof(typename SliceHashTable<RefCountedPtr<T>>::Entry)));
size_t idx = 0;
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
if (!ParseJsonMethodConfig(method, create_value, entries, &idx)) {
for (size_t i = 0; i < idx; ++i) {
grpc_slice_unref_internal(entries[i].key);
entries[i].value.reset();
}
gpr_free(entries);
return nullptr;
}
}
GPR_ASSERT(idx == num_entries);
}
}
// Instantiate method config table.
RefCountedPtr<SliceHashTable<RefCountedPtr<T>>> method_config_table;
if (entries != nullptr) {
method_config_table =
SliceHashTable<RefCountedPtr<T>>::Create(num_entries, entries, nullptr);
gpr_free(entries);
}
return method_config_table;
}
template <typename T>
RefCountedPtr<T> ServiceConfig::MethodConfigTableLookup(
const SliceHashTable<RefCountedPtr<T>>& table, grpc_slice path) {
const RefCountedPtr<T>* value = table.Get(path);
// If we didn't find a match for the path, try looking for a wildcard
// entry (i.e., change "/service/method" to "/service/*").
if (value == nullptr) {
char* path_str = grpc_slice_to_c_string(path);
const char* sep = strrchr(path_str, '/') + 1;
const size_t len = (size_t)(sep - path_str);
char* buf = (char*)gpr_malloc(len + 2); // '*' and NUL
memcpy(buf, path_str, len);
buf[len] = '*';
buf[len + 1] = '\0';
grpc_slice wildcard_path = grpc_slice_from_copied_string(buf);
gpr_free(buf);
value = table.Get(wildcard_path);
grpc_slice_unref_internal(wildcard_path);
gpr_free(path_str);
}
return RefCountedPtr<T>(*value);
}
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */

@ -50,61 +50,64 @@ static uint8_t g_bytes[] = {
114, 110, 97, 108, 45, 115, 116, 114, 101, 97, 109, 45, 101, 110, 99,
111, 100, 105, 110, 103, 45, 114, 101, 113, 117, 101, 115, 116, 117, 115,
101, 114, 45, 97, 103, 101, 110, 116, 104, 111, 115, 116, 108, 98, 45,
116, 111, 107, 101, 110, 103, 114, 112, 99, 45, 116, 105, 109, 101, 111,
117, 116, 103, 114, 112, 99, 46, 119, 97, 105, 116, 95, 102, 111, 114,
95, 114, 101, 97, 100, 121, 103, 114, 112, 99, 46, 116, 105, 109, 101,
111, 117, 116, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 113,
117, 101, 115, 116, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98, 121,
116, 101, 115, 103, 114, 112, 99, 46, 109, 97, 120, 95, 114, 101, 115,
112, 111, 110, 115, 101, 95, 109, 101, 115, 115, 97, 103, 101, 95, 98,
121, 116, 101, 115, 47, 103, 114, 112, 99, 46, 108, 98, 46, 118, 49,
46, 76, 111, 97, 100, 66, 97, 108, 97, 110, 99, 101, 114, 47, 66,
97, 108, 97, 110, 99, 101, 76, 111, 97, 100, 100, 101, 102, 108, 97,
116, 101, 103, 122, 105, 112, 115, 116, 114, 101, 97, 109, 47, 103, 122,
105, 112, 48, 49, 50, 105, 100, 101, 110, 116, 105, 116, 121, 116, 114,
97, 105, 108, 101, 114, 115, 97, 112, 112, 108, 105, 99, 97, 116, 105,
111, 110, 47, 103, 114, 112, 99, 80, 79, 83, 84, 50, 48, 48, 52,
48, 52, 104, 116, 116, 112, 104, 116, 116, 112, 115, 103, 114, 112, 99,
71, 69, 84, 80, 85, 84, 47, 47, 105, 110, 100, 101, 120, 46, 104,
116, 109, 108, 50, 48, 52, 50, 48, 54, 51, 48, 52, 52, 48, 48,
53, 48, 48, 97, 99, 99, 101, 112, 116, 45, 99, 104, 97, 114, 115,
101, 116, 103, 122, 105, 112, 44, 32, 100, 101, 102, 108, 97, 116, 101,
97, 99, 99, 101, 112, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
97, 99, 99, 101, 112, 116, 45, 114, 97, 110, 103, 101, 115, 97, 99,
99, 101, 112, 116, 97, 99, 99, 101, 115, 115, 45, 99, 111, 110, 116,
114, 111, 108, 45, 97, 108, 108, 111, 119, 45, 111, 114, 105, 103, 105,
110, 97, 103, 101, 97, 108, 108, 111, 119, 97, 117, 116, 104, 111, 114,
105, 122, 97, 116, 105, 111, 110, 99, 97, 99, 104, 101, 45, 99, 111,
110, 116, 114, 111, 108, 99, 111, 110, 116, 101, 110, 116, 45, 100, 105,
115, 112, 111, 115, 105, 116, 105, 111, 110, 99, 111, 110, 116, 101, 110,
116, 45, 108, 97, 110, 103, 117, 97, 103, 101, 99, 111, 110, 116, 101,
110, 116, 45, 108, 101, 110, 103, 116, 104, 99, 111, 110, 116, 101, 110,
116, 45, 108, 111, 99, 97, 116, 105, 111, 110, 99, 111, 110, 116, 101,
110, 116, 45, 114, 97, 110, 103, 101, 99, 111, 111, 107, 105, 101, 100,
97, 116, 101, 101, 116, 97, 103, 101, 120, 112, 101, 99, 116, 101, 120,
112, 105, 114, 101, 115, 102, 114, 111, 109, 105, 102, 45, 109, 97, 116,
99, 104, 105, 102, 45, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
105, 110, 99, 101, 105, 102, 45, 110, 111, 110, 101, 45, 109, 97, 116,
99, 104, 105, 102, 45, 114, 97, 110, 103, 101, 105, 102, 45, 117, 110,
109, 111, 100, 105, 102, 105, 101, 100, 45, 115, 105, 110, 99, 101, 108,
97, 115, 116, 45, 109, 111, 100, 105, 102, 105, 101, 100, 108, 98, 45,
99, 111, 115, 116, 45, 98, 105, 110, 108, 105, 110, 107, 108, 111, 99,
97, 116, 105, 111, 110, 109, 97, 120, 45, 102, 111, 114, 119, 97, 114,
100, 115, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104, 101, 110, 116,
105, 99, 97, 116, 101, 112, 114, 111, 120, 121, 45, 97, 117, 116, 104,
111, 114, 105, 122, 97, 116, 105, 111, 110, 114, 97, 110, 103, 101, 114,
101, 102, 101, 114, 101, 114, 114, 101, 102, 114, 101, 115, 104, 114, 101,
116, 114, 121, 45, 97, 102, 116, 101, 114, 115, 101, 114, 118, 101, 114,
115, 101, 116, 45, 99, 111, 111, 107, 105, 101, 115, 116, 114, 105, 99,
116, 45, 116, 114, 97, 110, 115, 112, 111, 114, 116, 45, 115, 101, 99,
117, 114, 105, 116, 121, 116, 114, 97, 110, 115, 102, 101, 114, 45, 101,
110, 99, 111, 100, 105, 110, 103, 118, 97, 114, 121, 118, 105, 97, 119,
119, 119, 45, 97, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101,
105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116,
101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 103, 122, 105, 112, 100,
101, 102, 108, 97, 116, 101, 44, 103, 122, 105, 112, 105, 100, 101, 110,
116, 105, 116, 121, 44, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122,
105, 112};
116, 111, 107, 101, 110, 103, 114, 112, 99, 45, 112, 114, 101, 118, 105,
111, 117, 115, 45, 114, 112, 99, 45, 97, 116, 116, 101, 109, 112, 116,
115, 103, 114, 112, 99, 45, 114, 101, 116, 114, 121, 45, 112, 117, 115,
104, 98, 97, 99, 107, 45, 109, 115, 103, 114, 112, 99, 45, 116, 105,
109, 101, 111, 117, 116, 49, 50, 51, 52, 103, 114, 112, 99, 46, 119,
97, 105, 116, 95, 102, 111, 114, 95, 114, 101, 97, 100, 121, 103, 114,
112, 99, 46, 116, 105, 109, 101, 111, 117, 116, 103, 114, 112, 99, 46,
109, 97, 120, 95, 114, 101, 113, 117, 101, 115, 116, 95, 109, 101, 115,
115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 103, 114, 112, 99, 46,
109, 97, 120, 95, 114, 101, 115, 112, 111, 110, 115, 101, 95, 109, 101,
115, 115, 97, 103, 101, 95, 98, 121, 116, 101, 115, 47, 103, 114, 112,
99, 46, 108, 98, 46, 118, 49, 46, 76, 111, 97, 100, 66, 97, 108,
97, 110, 99, 101, 114, 47, 66, 97, 108, 97, 110, 99, 101, 76, 111,
97, 100, 100, 101, 102, 108, 97, 116, 101, 103, 122, 105, 112, 115, 116,
114, 101, 97, 109, 47, 103, 122, 105, 112, 48, 105, 100, 101, 110, 116,
105, 116, 121, 116, 114, 97, 105, 108, 101, 114, 115, 97, 112, 112, 108,
105, 99, 97, 116, 105, 111, 110, 47, 103, 114, 112, 99, 80, 79, 83,
84, 50, 48, 48, 52, 48, 52, 104, 116, 116, 112, 104, 116, 116, 112,
115, 103, 114, 112, 99, 71, 69, 84, 80, 85, 84, 47, 47, 105, 110,
100, 101, 120, 46, 104, 116, 109, 108, 50, 48, 52, 50, 48, 54, 51,
48, 52, 52, 48, 48, 53, 48, 48, 97, 99, 99, 101, 112, 116, 45,
99, 104, 97, 114, 115, 101, 116, 103, 122, 105, 112, 44, 32, 100, 101,
102, 108, 97, 116, 101, 97, 99, 99, 101, 112, 116, 45, 108, 97, 110,
103, 117, 97, 103, 101, 97, 99, 99, 101, 112, 116, 45, 114, 97, 110,
103, 101, 115, 97, 99, 99, 101, 112, 116, 97, 99, 99, 101, 115, 115,
45, 99, 111, 110, 116, 114, 111, 108, 45, 97, 108, 108, 111, 119, 45,
111, 114, 105, 103, 105, 110, 97, 103, 101, 97, 108, 108, 111, 119, 97,
117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 99, 97, 99,
104, 101, 45, 99, 111, 110, 116, 114, 111, 108, 99, 111, 110, 116, 101,
110, 116, 45, 100, 105, 115, 112, 111, 115, 105, 116, 105, 111, 110, 99,
111, 110, 116, 101, 110, 116, 45, 108, 97, 110, 103, 117, 97, 103, 101,
99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 99,
111, 110, 116, 101, 110, 116, 45, 108, 111, 99, 97, 116, 105, 111, 110,
99, 111, 110, 116, 101, 110, 116, 45, 114, 97, 110, 103, 101, 99, 111,
111, 107, 105, 101, 100, 97, 116, 101, 101, 116, 97, 103, 101, 120, 112,
101, 99, 116, 101, 120, 112, 105, 114, 101, 115, 102, 114, 111, 109, 105,
102, 45, 109, 97, 116, 99, 104, 105, 102, 45, 109, 111, 100, 105, 102,
105, 101, 100, 45, 115, 105, 110, 99, 101, 105, 102, 45, 110, 111, 110,
101, 45, 109, 97, 116, 99, 104, 105, 102, 45, 114, 97, 110, 103, 101,
105, 102, 45, 117, 110, 109, 111, 100, 105, 102, 105, 101, 100, 45, 115,
105, 110, 99, 101, 108, 97, 115, 116, 45, 109, 111, 100, 105, 102, 105,
101, 100, 108, 98, 45, 99, 111, 115, 116, 45, 98, 105, 110, 108, 105,
110, 107, 108, 111, 99, 97, 116, 105, 111, 110, 109, 97, 120, 45, 102,
111, 114, 119, 97, 114, 100, 115, 112, 114, 111, 120, 121, 45, 97, 117,
116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 112, 114, 111, 120, 121,
45, 97, 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, 114,
97, 110, 103, 101, 114, 101, 102, 101, 114, 101, 114, 114, 101, 102, 114,
101, 115, 104, 114, 101, 116, 114, 121, 45, 97, 102, 116, 101, 114, 115,
101, 114, 118, 101, 114, 115, 101, 116, 45, 99, 111, 111, 107, 105, 101,
115, 116, 114, 105, 99, 116, 45, 116, 114, 97, 110, 115, 112, 111, 114,
116, 45, 115, 101, 99, 117, 114, 105, 116, 121, 116, 114, 97, 110, 115,
102, 101, 114, 45, 101, 110, 99, 111, 100, 105, 110, 103, 118, 97, 114,
121, 118, 105, 97, 119, 119, 119, 45, 97, 117, 116, 104, 101, 110, 116,
105, 99, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100,
101, 102, 108, 97, 116, 101, 105, 100, 101, 110, 116, 105, 116, 121, 44,
103, 122, 105, 112, 100, 101, 102, 108, 97, 116, 101, 44, 103, 122, 105,
112, 105, 100, 101, 110, 116, 105, 116, 121, 44, 100, 101, 102, 108, 97,
116, 101, 44, 103, 122, 105, 112};
static void static_ref(void* unused) {}
static void static_unref(void* unused) {}
@ -217,6 +220,10 @@ grpc_slice_refcount grpc_static_metadata_refcounts[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
{&grpc_static_metadata_vtable, &static_sub_refcnt},
};
const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
@ -242,85 +249,89 @@ const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT] = {
{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
{&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 12}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}},
{&grpc_static_metadata_refcounts[24], {{g_bytes + 302, 19}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 321, 12}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 333, 30}}},
{&grpc_static_metadata_refcounts[27], {{g_bytes + 363, 31}}},
{&grpc_static_metadata_refcounts[28], {{g_bytes + 394, 36}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}},
{&grpc_static_metadata_refcounts[31], {{g_bytes + 441, 11}}},
{&grpc_static_metadata_refcounts[32], {{g_bytes + 452, 1}}},
{&grpc_static_metadata_refcounts[33], {{g_bytes + 453, 1}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 454, 1}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 463, 8}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 471, 16}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 487, 4}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 491, 3}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 494, 3}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 497, 4}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 501, 5}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 506, 4}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 510, 3}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 513, 3}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 516, 1}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 517, 11}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 528, 3}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 531, 3}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 534, 3}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 537, 3}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 540, 3}}},
{&grpc_static_metadata_refcounts[53], {{g_bytes + 543, 14}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 557, 13}}},
{&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 15}}},
{&grpc_static_metadata_refcounts[56], {{g_bytes + 585, 13}}},
{&grpc_static_metadata_refcounts[57], {{g_bytes + 598, 6}}},
{&grpc_static_metadata_refcounts[58], {{g_bytes + 604, 27}}},
{&grpc_static_metadata_refcounts[59], {{g_bytes + 631, 3}}},
{&grpc_static_metadata_refcounts[60], {{g_bytes + 634, 5}}},
{&grpc_static_metadata_refcounts[61], {{g_bytes + 639, 13}}},
{&grpc_static_metadata_refcounts[62], {{g_bytes + 652, 13}}},
{&grpc_static_metadata_refcounts[63], {{g_bytes + 665, 19}}},
{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 16}}},
{&grpc_static_metadata_refcounts[65], {{g_bytes + 700, 14}}},
{&grpc_static_metadata_refcounts[66], {{g_bytes + 714, 16}}},
{&grpc_static_metadata_refcounts[67], {{g_bytes + 730, 13}}},
{&grpc_static_metadata_refcounts[68], {{g_bytes + 743, 6}}},
{&grpc_static_metadata_refcounts[69], {{g_bytes + 749, 4}}},
{&grpc_static_metadata_refcounts[70], {{g_bytes + 753, 4}}},
{&grpc_static_metadata_refcounts[71], {{g_bytes + 757, 6}}},
{&grpc_static_metadata_refcounts[72], {{g_bytes + 763, 7}}},
{&grpc_static_metadata_refcounts[73], {{g_bytes + 770, 4}}},
{&grpc_static_metadata_refcounts[74], {{g_bytes + 774, 8}}},
{&grpc_static_metadata_refcounts[75], {{g_bytes + 782, 17}}},
{&grpc_static_metadata_refcounts[76], {{g_bytes + 799, 13}}},
{&grpc_static_metadata_refcounts[77], {{g_bytes + 812, 8}}},
{&grpc_static_metadata_refcounts[78], {{g_bytes + 820, 19}}},
{&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 13}}},
{&grpc_static_metadata_refcounts[80], {{g_bytes + 852, 11}}},
{&grpc_static_metadata_refcounts[81], {{g_bytes + 863, 4}}},
{&grpc_static_metadata_refcounts[82], {{g_bytes + 867, 8}}},
{&grpc_static_metadata_refcounts[83], {{g_bytes + 875, 12}}},
{&grpc_static_metadata_refcounts[84], {{g_bytes + 887, 18}}},
{&grpc_static_metadata_refcounts[85], {{g_bytes + 905, 19}}},
{&grpc_static_metadata_refcounts[86], {{g_bytes + 924, 5}}},
{&grpc_static_metadata_refcounts[87], {{g_bytes + 929, 7}}},
{&grpc_static_metadata_refcounts[88], {{g_bytes + 936, 7}}},
{&grpc_static_metadata_refcounts[89], {{g_bytes + 943, 11}}},
{&grpc_static_metadata_refcounts[90], {{g_bytes + 954, 6}}},
{&grpc_static_metadata_refcounts[91], {{g_bytes + 960, 10}}},
{&grpc_static_metadata_refcounts[92], {{g_bytes + 970, 25}}},
{&grpc_static_metadata_refcounts[93], {{g_bytes + 995, 17}}},
{&grpc_static_metadata_refcounts[94], {{g_bytes + 1012, 4}}},
{&grpc_static_metadata_refcounts[95], {{g_bytes + 1016, 3}}},
{&grpc_static_metadata_refcounts[96], {{g_bytes + 1019, 16}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1035, 16}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}},
{&grpc_static_metadata_refcounts[99], {{g_bytes + 1064, 12}}},
{&grpc_static_metadata_refcounts[100], {{g_bytes + 1076, 21}}},
{&grpc_static_metadata_refcounts[22], {{g_bytes + 290, 26}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 316, 22}}},
{&grpc_static_metadata_refcounts[24], {{g_bytes + 338, 12}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}},
{&grpc_static_metadata_refcounts[27], {{g_bytes + 352, 1}}},
{&grpc_static_metadata_refcounts[28], {{g_bytes + 353, 1}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 354, 19}}},
{&grpc_static_metadata_refcounts[31], {{g_bytes + 373, 12}}},
{&grpc_static_metadata_refcounts[32], {{g_bytes + 385, 30}}},
{&grpc_static_metadata_refcounts[33], {{g_bytes + 415, 31}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 446, 36}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 493, 11}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}},
{&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}},
{&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}},
{&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}},
{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
{&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}},
{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
{&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}},
{&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}},
{&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}},
};
uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
@ -330,50 +341,51 @@ uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 6, 6, 8, 8, 2, 4, 4};
static const int8_t elems_r[] = {
13, 2, 1, 0, 15, 4, 0, 21, 0, 23, -3, 0, 0, 0, 10, 19, -4,
0, 0, 1, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, -52, 0, -55, -36, -57, -58, -58, -58, 0, 40, 39, 38, 37, 36, 35,
34, 33, 32, 31, 30, 29, 28, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
18, 17, 16, 15, 18, 17, 16, 15, 14, 13, 12, 11, 11, 0};
16, 11, -1, 0, 15, 2, -78, 24, 0, 18, -5, 0, 0, 0, 17, 14, -8, 0,
0, 27, 8, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, -64, 0, -44, -43, -70, 0, 34, 33, 33, 32, 31, 30, 29, 28, 27,
27, 26, 25, 24, 23, 22, 21, 20, 20, 19, 19, 18, 17, 16, 15, 14, 13, 12,
11, 14, 13, 12, 11, 10, 9, 9, 8, 7, 6, 5, 0};
static uint32_t elems_phash(uint32_t i) {
i -= 46;
uint32_t x = i % 99;
uint32_t y = i / 99;
i -= 50;
uint32_t x = i % 103;
uint32_t y = i / 103;
uint32_t h = x;
if (y < GPR_ARRAY_SIZE(elems_r)) {
uint32_t delta = static_cast<uint32_t>(elems_r[y]);
uint32_t delta = (uint32_t)elems_r[y];
h += delta;
}
return h;
}
static const uint16_t elem_keys[] = {
1039, 1040, 145, 146, 541, 1639, 1045, 250, 251, 252, 253, 254,
1646, 46, 47, 1437, 1942, 1651, 445, 446, 447, 739, 740, 741,
938, 939, 1538, 2043, 2144, 1451, 944, 5376, 5578, 1545, 5780, 5881,
1670, 5982, 1550, 6083, 6184, 6285, 6386, 6487, 6588, 6689, 6790, 6891,
6992, 7093, 7194, 7295, 7396, 5679, 7497, 7598, 7699, 7800, 7901, 8002,
8103, 8204, 8305, 8406, 8507, 8608, 8709, 8810, 1107, 1108, 1109, 1110,
8911, 9012, 9113, 9214, 9315, 9416, 9517, 9618, 1714, 9719, 0, 326,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 241, 242, 0, 0, 0, 0, 0, 0, 139, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0};
1085, 1086, 565, 1709, 1089, 262, 263, 264, 265, 266, 1716,
153, 154, 1719, 760, 761, 50, 51, 465, 466, 467, 980,
981, 1604, 1499, 984, 773, 2129, 2234, 6014, 1611, 6434, 1738,
1614, 6539, 6644, 1511, 6749, 6854, 6959, 7064, 7169, 7274, 7379,
2024, 7484, 7589, 7694, 7799, 7904, 8009, 8114, 8219, 6224, 8324,
8429, 6329, 8534, 8639, 8744, 8849, 8954, 9059, 9164, 9269, 9374,
1151, 1152, 1153, 1154, 9479, 9584, 9689, 9794, 9899, 10004, 1782,
10109, 10214, 10319, 10424, 10529, 0, 0, 0, 0, 0, 344,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 253, 254, 147, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0};
static const uint8_t elem_idxs[] = {
77, 79, 15, 16, 6, 25, 76, 19, 20, 21, 22, 23, 84, 17,
18, 43, 72, 83, 11, 12, 13, 0, 1, 2, 5, 4, 38, 50,
57, 7, 3, 24, 27, 37, 29, 30, 26, 31, 36, 32, 33, 34,
35, 39, 40, 41, 42, 44, 45, 46, 47, 48, 49, 28, 51, 52,
53, 54, 55, 56, 58, 59, 60, 61, 62, 63, 64, 65, 78, 80,
81, 82, 66, 67, 68, 69, 70, 71, 73, 74, 85, 75, 255, 14,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
9, 10, 255, 255, 255, 255, 255, 255, 8};
77, 79, 6, 25, 76, 19, 20, 21, 22, 23, 84, 15, 16, 83, 1,
2, 17, 18, 11, 12, 13, 5, 4, 38, 43, 3, 0, 50, 57, 24,
37, 29, 26, 36, 30, 31, 7, 32, 33, 34, 35, 39, 40, 41, 72,
42, 44, 45, 46, 47, 48, 49, 51, 27, 52, 53, 28, 54, 55, 56,
58, 59, 60, 61, 62, 63, 78, 80, 81, 82, 64, 65, 66, 67, 68,
69, 85, 70, 71, 73, 74, 75, 255, 255, 255, 255, 255, 14, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 9, 10, 8};
grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
if (a == -1 || b == -1) return GRPC_MDNULL;
uint32_t k = static_cast<uint32_t>(a * 101 + b);
uint32_t k = (uint32_t)(a * 105 + b);
uint32_t h = elems_phash(k);
return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k &&
elem_idxs[h] != 255
@ -384,177 +396,177 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {
grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT] = {
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[32], {{g_bytes + 452, 1}}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 504, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[33], {{g_bytes + 453, 1}}}},
{&grpc_static_metadata_refcounts[25], {{g_bytes + 350, 1}}}},
{{&grpc_static_metadata_refcounts[7], {{g_bytes + 50, 11}}},
{&grpc_static_metadata_refcounts[34], {{g_bytes + 454, 1}}}},
{&grpc_static_metadata_refcounts[26], {{g_bytes + 351, 1}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[9], {{g_bytes + 77, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
{{&grpc_static_metadata_refcounts[5], {{g_bytes + 36, 2}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 463, 8}}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 513, 8}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[37], {{g_bytes + 471, 16}}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 521, 16}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[38], {{g_bytes + 487, 4}}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 537, 4}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 491, 3}}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 541, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[40], {{g_bytes + 494, 3}}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 544, 3}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[41], {{g_bytes + 497, 4}}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 547, 4}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[42], {{g_bytes + 501, 5}}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 551, 5}}}},
{{&grpc_static_metadata_refcounts[4], {{g_bytes + 29, 7}}},
{&grpc_static_metadata_refcounts[43], {{g_bytes + 506, 4}}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 556, 4}}}},
{{&grpc_static_metadata_refcounts[3], {{g_bytes + 19, 10}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[44], {{g_bytes + 510, 3}}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 560, 3}}}},
{{&grpc_static_metadata_refcounts[1], {{g_bytes + 5, 7}}},
{&grpc_static_metadata_refcounts[45], {{g_bytes + 513, 3}}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 563, 3}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
{&grpc_static_metadata_refcounts[46], {{g_bytes + 516, 1}}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 566, 1}}}},
{{&grpc_static_metadata_refcounts[0], {{g_bytes + 0, 5}}},
{&grpc_static_metadata_refcounts[47], {{g_bytes + 517, 11}}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 567, 11}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[48], {{g_bytes + 528, 3}}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 578, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[49], {{g_bytes + 531, 3}}}},
{&grpc_static_metadata_refcounts[53], {{g_bytes + 581, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[50], {{g_bytes + 534, 3}}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 584, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[51], {{g_bytes + 537, 3}}}},
{&grpc_static_metadata_refcounts[55], {{g_bytes + 587, 3}}}},
{{&grpc_static_metadata_refcounts[2], {{g_bytes + 12, 7}}},
{&grpc_static_metadata_refcounts[52], {{g_bytes + 540, 3}}}},
{{&grpc_static_metadata_refcounts[53], {{g_bytes + 543, 14}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[56], {{g_bytes + 590, 3}}}},
{{&grpc_static_metadata_refcounts[57], {{g_bytes + 593, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[54], {{g_bytes + 557, 13}}}},
{{&grpc_static_metadata_refcounts[55], {{g_bytes + 570, 15}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[56], {{g_bytes + 585, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[57], {{g_bytes + 598, 6}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[58], {{g_bytes + 604, 27}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[59], {{g_bytes + 631, 3}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[60], {{g_bytes + 634, 5}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[61], {{g_bytes + 639, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[62], {{g_bytes + 652, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[63], {{g_bytes + 665, 19}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[58], {{g_bytes + 607, 13}}}},
{{&grpc_static_metadata_refcounts[59], {{g_bytes + 620, 15}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[60], {{g_bytes + 635, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[61], {{g_bytes + 648, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[62], {{g_bytes + 654, 27}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[63], {{g_bytes + 681, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[65], {{g_bytes + 689, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[66], {{g_bytes + 702, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[67], {{g_bytes + 715, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[15], {{g_bytes + 170, 16}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[64], {{g_bytes + 684, 16}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[65], {{g_bytes + 700, 14}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[66], {{g_bytes + 714, 16}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[67], {{g_bytes + 730, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[68], {{g_bytes + 734, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[69], {{g_bytes + 750, 14}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[70], {{g_bytes + 764, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[71], {{g_bytes + 780, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[14], {{g_bytes + 158, 12}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[68], {{g_bytes + 743, 6}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[69], {{g_bytes + 749, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[70], {{g_bytes + 753, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[71], {{g_bytes + 757, 6}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[72], {{g_bytes + 763, 7}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[73], {{g_bytes + 770, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[72], {{g_bytes + 793, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[73], {{g_bytes + 799, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[74], {{g_bytes + 803, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[75], {{g_bytes + 807, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[76], {{g_bytes + 813, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[77], {{g_bytes + 820, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[20], {{g_bytes + 278, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[74], {{g_bytes + 774, 8}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[75], {{g_bytes + 782, 17}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[76], {{g_bytes + 799, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[77], {{g_bytes + 812, 8}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[78], {{g_bytes + 820, 19}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[79], {{g_bytes + 839, 13}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[78], {{g_bytes + 824, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[79], {{g_bytes + 832, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[80], {{g_bytes + 849, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[81], {{g_bytes + 862, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[82], {{g_bytes + 870, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[83], {{g_bytes + 889, 13}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[21], {{g_bytes + 282, 8}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[80], {{g_bytes + 852, 11}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[81], {{g_bytes + 863, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[82], {{g_bytes + 867, 8}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[83], {{g_bytes + 875, 12}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[84], {{g_bytes + 887, 18}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[85], {{g_bytes + 905, 19}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[86], {{g_bytes + 924, 5}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[87], {{g_bytes + 929, 7}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[88], {{g_bytes + 936, 7}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[89], {{g_bytes + 943, 11}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[90], {{g_bytes + 954, 6}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[91], {{g_bytes + 960, 10}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[92], {{g_bytes + 970, 25}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[93], {{g_bytes + 995, 17}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[84], {{g_bytes + 902, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[85], {{g_bytes + 913, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[86], {{g_bytes + 917, 8}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[87], {{g_bytes + 925, 12}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[88], {{g_bytes + 937, 18}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[89], {{g_bytes + 955, 19}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[90], {{g_bytes + 974, 5}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[91], {{g_bytes + 979, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[92], {{g_bytes + 986, 7}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[93], {{g_bytes + 993, 11}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[94], {{g_bytes + 1004, 6}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[95], {{g_bytes + 1010, 10}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[96], {{g_bytes + 1020, 25}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[97], {{g_bytes + 1045, 17}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[19], {{g_bytes + 268, 10}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[94], {{g_bytes + 1012, 4}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[95], {{g_bytes + 1016, 3}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{{&grpc_static_metadata_refcounts[96], {{g_bytes + 1019, 16}}},
{&grpc_static_metadata_refcounts[23], {{g_bytes + 302, 0}}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[98], {{g_bytes + 1062, 4}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[99], {{g_bytes + 1066, 3}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[100], {{g_bytes + 1069, 16}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 354, 0}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[29], {{g_bytes + 430, 7}}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 482, 7}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[97], {{g_bytes + 1035, 16}}}},
{&grpc_static_metadata_refcounts[101], {{g_bytes + 1085, 16}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[99], {{g_bytes + 1064, 12}}}},
{&grpc_static_metadata_refcounts[103], {{g_bytes + 1114, 12}}}},
{{&grpc_static_metadata_refcounts[10], {{g_bytes + 90, 20}}},
{&grpc_static_metadata_refcounts[100], {{g_bytes + 1076, 21}}}},
{&grpc_static_metadata_refcounts[104], {{g_bytes + 1126, 21}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[35], {{g_bytes + 455, 8}}}},
{&grpc_static_metadata_refcounts[39], {{g_bytes + 505, 8}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[30], {{g_bytes + 437, 4}}}},
{&grpc_static_metadata_refcounts[36], {{g_bytes + 489, 4}}}},
{{&grpc_static_metadata_refcounts[16], {{g_bytes + 186, 15}}},
{&grpc_static_metadata_refcounts[98], {{g_bytes + 1051, 13}}}},
{&grpc_static_metadata_refcounts[102], {{g_bytes + 1101, 13}}}},
};
bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
true, // :path
@ -579,6 +591,8 @@ bool grpc_static_callout_is_default[GRPC_BATCH_CALLOUTS_COUNT] = {
true, // user-agent
true, // host
true, // lb-token
true, // grpc-previous-rpc-attempts
true, // grpc-retry-pushback-ms
};
const uint8_t grpc_static_accept_encoding_metadata[8] = {0, 76, 77, 78,

@ -31,7 +31,7 @@
#include "src/core/lib/transport/metadata.h"
#define GRPC_STATIC_MDSTR_COUNT 101
#define GRPC_STATIC_MDSTR_COUNT 105
extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
/* ":path" */
#define GRPC_MDSTR_PATH (grpc_static_slice_table[0])
@ -78,168 +78,176 @@ extern const grpc_slice grpc_static_slice_table[GRPC_STATIC_MDSTR_COUNT];
#define GRPC_MDSTR_HOST (grpc_static_slice_table[20])
/* "lb-token" */
#define GRPC_MDSTR_LB_TOKEN (grpc_static_slice_table[21])
/* "grpc-previous-rpc-attempts" */
#define GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS (grpc_static_slice_table[22])
/* "grpc-retry-pushback-ms" */
#define GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS (grpc_static_slice_table[23])
/* "grpc-timeout" */
#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[22])
#define GRPC_MDSTR_GRPC_TIMEOUT (grpc_static_slice_table[24])
/* "1" */
#define GRPC_MDSTR_1 (grpc_static_slice_table[25])
/* "2" */
#define GRPC_MDSTR_2 (grpc_static_slice_table[26])
/* "3" */
#define GRPC_MDSTR_3 (grpc_static_slice_table[27])
/* "4" */
#define GRPC_MDSTR_4 (grpc_static_slice_table[28])
/* "" */
#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[23])
#define GRPC_MDSTR_EMPTY (grpc_static_slice_table[29])
/* "grpc.wait_for_ready" */
#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[24])
#define GRPC_MDSTR_GRPC_DOT_WAIT_FOR_READY (grpc_static_slice_table[30])
/* "grpc.timeout" */
#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[25])
#define GRPC_MDSTR_GRPC_DOT_TIMEOUT (grpc_static_slice_table[31])
/* "grpc.max_request_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_REQUEST_MESSAGE_BYTES \
(grpc_static_slice_table[26])
(grpc_static_slice_table[32])
/* "grpc.max_response_message_bytes" */
#define GRPC_MDSTR_GRPC_DOT_MAX_RESPONSE_MESSAGE_BYTES \
(grpc_static_slice_table[27])
(grpc_static_slice_table[33])
/* "/grpc.lb.v1.LoadBalancer/BalanceLoad" */
#define GRPC_MDSTR_SLASH_GRPC_DOT_LB_DOT_V1_DOT_LOADBALANCER_SLASH_BALANCELOAD \
(grpc_static_slice_table[28])
(grpc_static_slice_table[34])
/* "deflate" */
#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[29])
#define GRPC_MDSTR_DEFLATE (grpc_static_slice_table[35])
/* "gzip" */
#define GRPC_MDSTR_GZIP (grpc_static_slice_table[30])
#define GRPC_MDSTR_GZIP (grpc_static_slice_table[36])
/* "stream/gzip" */
#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[31])
#define GRPC_MDSTR_STREAM_SLASH_GZIP (grpc_static_slice_table[37])
/* "0" */
#define GRPC_MDSTR_0 (grpc_static_slice_table[32])
/* "1" */
#define GRPC_MDSTR_1 (grpc_static_slice_table[33])
/* "2" */
#define GRPC_MDSTR_2 (grpc_static_slice_table[34])
#define GRPC_MDSTR_0 (grpc_static_slice_table[38])
/* "identity" */
#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[35])
#define GRPC_MDSTR_IDENTITY (grpc_static_slice_table[39])
/* "trailers" */
#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[36])
#define GRPC_MDSTR_TRAILERS (grpc_static_slice_table[40])
/* "application/grpc" */
#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[37])
#define GRPC_MDSTR_APPLICATION_SLASH_GRPC (grpc_static_slice_table[41])
/* "POST" */
#define GRPC_MDSTR_POST (grpc_static_slice_table[38])
#define GRPC_MDSTR_POST (grpc_static_slice_table[42])
/* "200" */
#define GRPC_MDSTR_200 (grpc_static_slice_table[39])
#define GRPC_MDSTR_200 (grpc_static_slice_table[43])
/* "404" */
#define GRPC_MDSTR_404 (grpc_static_slice_table[40])
#define GRPC_MDSTR_404 (grpc_static_slice_table[44])
/* "http" */
#define GRPC_MDSTR_HTTP (grpc_static_slice_table[41])
#define GRPC_MDSTR_HTTP (grpc_static_slice_table[45])
/* "https" */
#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[42])
#define GRPC_MDSTR_HTTPS (grpc_static_slice_table[46])
/* "grpc" */
#define GRPC_MDSTR_GRPC (grpc_static_slice_table[43])
#define GRPC_MDSTR_GRPC (grpc_static_slice_table[47])
/* "GET" */
#define GRPC_MDSTR_GET (grpc_static_slice_table[44])
#define GRPC_MDSTR_GET (grpc_static_slice_table[48])
/* "PUT" */
#define GRPC_MDSTR_PUT (grpc_static_slice_table[45])
#define GRPC_MDSTR_PUT (grpc_static_slice_table[49])
/* "/" */
#define GRPC_MDSTR_SLASH (grpc_static_slice_table[46])
#define GRPC_MDSTR_SLASH (grpc_static_slice_table[50])
/* "/index.html" */
#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[47])
#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (grpc_static_slice_table[51])
/* "204" */
#define GRPC_MDSTR_204 (grpc_static_slice_table[48])
#define GRPC_MDSTR_204 (grpc_static_slice_table[52])
/* "206" */
#define GRPC_MDSTR_206 (grpc_static_slice_table[49])
#define GRPC_MDSTR_206 (grpc_static_slice_table[53])
/* "304" */
#define GRPC_MDSTR_304 (grpc_static_slice_table[50])
#define GRPC_MDSTR_304 (grpc_static_slice_table[54])
/* "400" */
#define GRPC_MDSTR_400 (grpc_static_slice_table[51])
#define GRPC_MDSTR_400 (grpc_static_slice_table[55])
/* "500" */
#define GRPC_MDSTR_500 (grpc_static_slice_table[52])
#define GRPC_MDSTR_500 (grpc_static_slice_table[56])
/* "accept-charset" */
#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[53])
#define GRPC_MDSTR_ACCEPT_CHARSET (grpc_static_slice_table[57])
/* "gzip, deflate" */
#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[54])
#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (grpc_static_slice_table[58])
/* "accept-language" */
#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[55])
#define GRPC_MDSTR_ACCEPT_LANGUAGE (grpc_static_slice_table[59])
/* "accept-ranges" */
#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[56])
#define GRPC_MDSTR_ACCEPT_RANGES (grpc_static_slice_table[60])
/* "accept" */
#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[57])
#define GRPC_MDSTR_ACCEPT (grpc_static_slice_table[61])
/* "access-control-allow-origin" */
#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[58])
#define GRPC_MDSTR_ACCESS_CONTROL_ALLOW_ORIGIN (grpc_static_slice_table[62])
/* "age" */
#define GRPC_MDSTR_AGE (grpc_static_slice_table[59])
#define GRPC_MDSTR_AGE (grpc_static_slice_table[63])
/* "allow" */
#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[60])
#define GRPC_MDSTR_ALLOW (grpc_static_slice_table[64])
/* "authorization" */
#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[61])
#define GRPC_MDSTR_AUTHORIZATION (grpc_static_slice_table[65])
/* "cache-control" */
#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[62])
#define GRPC_MDSTR_CACHE_CONTROL (grpc_static_slice_table[66])
/* "content-disposition" */
#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[63])
#define GRPC_MDSTR_CONTENT_DISPOSITION (grpc_static_slice_table[67])
/* "content-language" */
#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[64])
#define GRPC_MDSTR_CONTENT_LANGUAGE (grpc_static_slice_table[68])
/* "content-length" */
#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[65])
#define GRPC_MDSTR_CONTENT_LENGTH (grpc_static_slice_table[69])
/* "content-location" */
#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[66])
#define GRPC_MDSTR_CONTENT_LOCATION (grpc_static_slice_table[70])
/* "content-range" */
#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[67])
#define GRPC_MDSTR_CONTENT_RANGE (grpc_static_slice_table[71])
/* "cookie" */
#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[68])
#define GRPC_MDSTR_COOKIE (grpc_static_slice_table[72])
/* "date" */
#define GRPC_MDSTR_DATE (grpc_static_slice_table[69])
#define GRPC_MDSTR_DATE (grpc_static_slice_table[73])
/* "etag" */
#define GRPC_MDSTR_ETAG (grpc_static_slice_table[70])
#define GRPC_MDSTR_ETAG (grpc_static_slice_table[74])
/* "expect" */
#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[71])
#define GRPC_MDSTR_EXPECT (grpc_static_slice_table[75])
/* "expires" */
#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[72])
#define GRPC_MDSTR_EXPIRES (grpc_static_slice_table[76])
/* "from" */
#define GRPC_MDSTR_FROM (grpc_static_slice_table[73])
#define GRPC_MDSTR_FROM (grpc_static_slice_table[77])
/* "if-match" */
#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[74])
#define GRPC_MDSTR_IF_MATCH (grpc_static_slice_table[78])
/* "if-modified-since" */
#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[75])
#define GRPC_MDSTR_IF_MODIFIED_SINCE (grpc_static_slice_table[79])
/* "if-none-match" */
#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[76])
#define GRPC_MDSTR_IF_NONE_MATCH (grpc_static_slice_table[80])
/* "if-range" */
#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[77])
#define GRPC_MDSTR_IF_RANGE (grpc_static_slice_table[81])
/* "if-unmodified-since" */
#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[78])
#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (grpc_static_slice_table[82])
/* "last-modified" */
#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[79])
#define GRPC_MDSTR_LAST_MODIFIED (grpc_static_slice_table[83])
/* "lb-cost-bin" */
#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[80])
#define GRPC_MDSTR_LB_COST_BIN (grpc_static_slice_table[84])
/* "link" */
#define GRPC_MDSTR_LINK (grpc_static_slice_table[81])
#define GRPC_MDSTR_LINK (grpc_static_slice_table[85])
/* "location" */
#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[82])
#define GRPC_MDSTR_LOCATION (grpc_static_slice_table[86])
/* "max-forwards" */
#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[83])
#define GRPC_MDSTR_MAX_FORWARDS (grpc_static_slice_table[87])
/* "proxy-authenticate" */
#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[84])
#define GRPC_MDSTR_PROXY_AUTHENTICATE (grpc_static_slice_table[88])
/* "proxy-authorization" */
#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[85])
#define GRPC_MDSTR_PROXY_AUTHORIZATION (grpc_static_slice_table[89])
/* "range" */
#define GRPC_MDSTR_RANGE (grpc_static_slice_table[86])
#define GRPC_MDSTR_RANGE (grpc_static_slice_table[90])
/* "referer" */
#define GRPC_MDSTR_REFERER (grpc_static_slice_table[87])
#define GRPC_MDSTR_REFERER (grpc_static_slice_table[91])
/* "refresh" */
#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[88])
#define GRPC_MDSTR_REFRESH (grpc_static_slice_table[92])
/* "retry-after" */
#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[89])
#define GRPC_MDSTR_RETRY_AFTER (grpc_static_slice_table[93])
/* "server" */
#define GRPC_MDSTR_SERVER (grpc_static_slice_table[90])
#define GRPC_MDSTR_SERVER (grpc_static_slice_table[94])
/* "set-cookie" */
#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[91])
#define GRPC_MDSTR_SET_COOKIE (grpc_static_slice_table[95])
/* "strict-transport-security" */
#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[92])
#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (grpc_static_slice_table[96])
/* "transfer-encoding" */
#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[93])
#define GRPC_MDSTR_TRANSFER_ENCODING (grpc_static_slice_table[97])
/* "vary" */
#define GRPC_MDSTR_VARY (grpc_static_slice_table[94])
#define GRPC_MDSTR_VARY (grpc_static_slice_table[98])
/* "via" */
#define GRPC_MDSTR_VIA (grpc_static_slice_table[95])
#define GRPC_MDSTR_VIA (grpc_static_slice_table[99])
/* "www-authenticate" */
#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[96])
#define GRPC_MDSTR_WWW_AUTHENTICATE (grpc_static_slice_table[100])
/* "identity,deflate" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[97])
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (grpc_static_slice_table[101])
/* "identity,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[98])
#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (grpc_static_slice_table[102])
/* "deflate,gzip" */
#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[99])
#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (grpc_static_slice_table[103])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
(grpc_static_slice_table[100])
(grpc_static_slice_table[104])
extern const grpc_slice_refcount_vtable grpc_static_metadata_vtable;
extern grpc_slice_refcount
@ -537,6 +545,8 @@ typedef enum {
GRPC_BATCH_USER_AGENT,
GRPC_BATCH_HOST,
GRPC_BATCH_LB_TOKEN,
GRPC_BATCH_GRPC_PREVIOUS_RPC_ATTEMPTS,
GRPC_BATCH_GRPC_RETRY_PUSHBACK_MS,
GRPC_BATCH_CALLOUTS_COUNT
} grpc_metadata_batch_callouts_index;
@ -565,6 +575,8 @@ typedef union {
struct grpc_linked_mdelem* user_agent;
struct grpc_linked_mdelem* host;
struct grpc_linked_mdelem* lb_token;
struct grpc_linked_mdelem* grpc_previous_rpc_attempts;
struct grpc_linked_mdelem* grpc_retry_pushback_ms;
} named;
} grpc_metadata_batch_callouts;

@ -0,0 +1,54 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/transport/status_metadata.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/transport/static_metadata.h"
/* we offset status by a small amount when storing it into transport metadata
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
*/
#define STATUS_OFFSET 1
static void destroy_status(void* ignored) {}
grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md) {
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) {
return GRPC_STATUS_OK;
}
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_1)) {
return GRPC_STATUS_CANCELLED;
}
if (grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_2)) {
return GRPC_STATUS_UNKNOWN;
}
void* user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data != nullptr) {
return static_cast<grpc_status_code>((intptr_t)user_data - STATUS_OFFSET);
}
uint32_t status;
if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(md), &status)) {
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
}
grpc_mdelem_set_user_data(
md, destroy_status, (void*)static_cast<intptr_t>(status + STATUS_OFFSET));
return static_cast<grpc_status_code>(status);
}

@ -16,19 +16,15 @@
*
*/
#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H
#ifndef GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
#define GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/slice/slice_hash_table.h"
#include <grpc/status.h>
/** Return a channel argument containing \a targets_info. */
grpc_arg grpc_lb_targets_info_create_channel_arg(
grpc_slice_hash_table* targets_info);
#include "src/core/lib/transport/metadata.h"
/** Return the instance of targets info in \a args or NULL */
grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
const grpc_channel_args* args);
grpc_status_code grpc_get_status_code_from_metadata(grpc_mdelem md);
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */
#endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_METADATA_H */

@ -98,6 +98,19 @@ void grpc_transport_move_one_way_stats(grpc_transport_one_way_stats* from,
void grpc_transport_move_stats(grpc_transport_stream_stats* from,
grpc_transport_stream_stats* to);
// This struct (which is present in both grpc_transport_stream_op_batch
// and grpc_transport_op_batch) is a convenience to allow filters or
// transports to schedule a closure related to a particular batch without
// having to allocate memory. The general pattern is to initialize the
// closure with the callback arg set to the batch and extra_arg set to
// whatever state is associated with the handler (e.g., the call element
// or the transport stream object).
//
// Note that this can only be used by the current handler of a given
// batch on the way down the stack (i.e., whichever filter or transport is
// currently handling the batch). Once a filter or transport passes control
// of the batch to the next handler, it cannot depend on the contents of
// this struct anymore, because the next handler may reuse it.
typedef struct {
void* extra_arg;
grpc_closure closure;
@ -157,6 +170,11 @@ struct grpc_transport_stream_op_batch_payload {
uint32_t send_initial_metadata_flags;
// If non-NULL, will be set by the transport to the peer string
// (a char*, which the caller takes ownership of).
// Note: This pointer may be used by the transport after the
// send_initial_metadata op is completed. It must remain valid
// until the call is destroyed.
// Note: When a transport sets this, it must free the previous
// value, if any.
gpr_atm* peer_string;
} send_initial_metadata;
@ -175,6 +193,9 @@ struct grpc_transport_stream_op_batch_payload {
struct {
grpc_metadata_batch* recv_initial_metadata;
// Flags are used only on the server side. If non-null, will be set to
// a bitfield of the GRPC_INITIAL_METADATA_xxx macros (e.g., to
// indicate if the call is idempotent).
uint32_t* recv_flags;
/** Should be enqueued when initial metadata is ready to be processed. */
grpc_closure* recv_initial_metadata_ready;
@ -184,6 +205,11 @@ struct grpc_transport_stream_op_batch_payload {
bool* trailing_metadata_available;
// If non-NULL, will be set by the transport to the peer string
// (a char*, which the caller takes ownership of).
// Note: This pointer may be used by the transport after the
// recv_initial_metadata op is completed. It must remain valid
// until the call is destroyed.
// Note: When a transport sets this, it must free the previous
// value, if any.
gpr_atm* peer_string;
} recv_initial_metadata;
@ -192,6 +218,7 @@ struct grpc_transport_stream_op_batch_payload {
// containing a received message.
// The caller is responsible for calling grpc_byte_stream_destroy()
// on this byte stream.
// Will be NULL if trailing metadata is received instead of a message.
grpc_byte_stream** recv_message;
/** Should be enqueued when one message is ready to be processed. */
grpc_closure* recv_message_ready;

@ -20,9 +20,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Math {
@ -159,7 +156,7 @@ namespace Math {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Math.DivReply Div(global::Math.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Div(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -183,7 +180,7 @@ namespace Math {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return DivAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -208,7 +205,7 @@ namespace Math {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return DivMany(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -234,7 +231,7 @@ namespace Math {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Fib(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -258,7 +255,7 @@ namespace Math {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Sum(new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -20,9 +20,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Grpc.Health.V1 {
@ -79,7 +76,7 @@ namespace Grpc.Health.V1 {
{
}
public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Check(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -87,7 +84,7 @@ namespace Grpc.Health.V1 {
{
return CallInvoker.BlockingUnaryCall(__Method_Check, null, options, request);
}
public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CheckAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -32,7 +32,7 @@ namespace Grpc.Testing {
"U2VjdXJpdHlQYXJhbXMSEwoLdXNlX3Rlc3RfY2EYASABKAgSHAoUc2VydmVy",
"X2hvc3Rfb3ZlcnJpZGUYAiABKAkSEQoJY3JlZF90eXBlGAMgASgJIk0KCkNo",
"YW5uZWxBcmcSDAoEbmFtZRgBIAEoCRITCglzdHJfdmFsdWUYAiABKAlIABIT",
"CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSLVBAoMQ2xpZW50Q29uZmln",
"CglpbnRfdmFsdWUYAyABKAVIAEIHCgV2YWx1ZSLvBAoMQ2xpZW50Q29uZmln",
"EhYKDnNlcnZlcl90YXJnZXRzGAEgAygJEi0KC2NsaWVudF90eXBlGAIgASgO",
"MhguZ3JwYy50ZXN0aW5nLkNsaWVudFR5cGUSNQoPc2VjdXJpdHlfcGFyYW1z",
"GAMgASgLMhwuZ3JwYy50ZXN0aW5nLlNlY3VyaXR5UGFyYW1zEiQKHG91dHN0",
@ -45,59 +45,60 @@ namespace Grpc.Testing {
"dG9ncmFtUGFyYW1zEhEKCWNvcmVfbGlzdBgNIAMoBRISCgpjb3JlX2xpbWl0",
"GA4gASgFEhgKEG90aGVyX2NsaWVudF9hcGkYDyABKAkSLgoMY2hhbm5lbF9h",
"cmdzGBAgAygLMhguZ3JwYy50ZXN0aW5nLkNoYW5uZWxBcmcSFgoOdGhyZWFk",
"c19wZXJfY3EYESABKAUSGwoTbWVzc2FnZXNfcGVyX3N0cmVhbRgSIAEoBSI4",
"CgxDbGllbnRTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRlc3Rpbmcu",
"Q2xpZW50U3RhdHMiFQoETWFyaxINCgVyZXNldBgBIAEoCCJoCgpDbGllbnRB",
"cmdzEisKBXNldHVwGAEgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVudENvbmZp",
"Z0gAEiIKBG1hcmsYAiABKAsyEi5ncnBjLnRlc3RpbmcuTWFya0gAQgkKB2Fy",
"Z3R5cGUi/QIKDFNlcnZlckNvbmZpZxItCgtzZXJ2ZXJfdHlwZRgBIAEoDjIY",
"LmdycGMudGVzdGluZy5TZXJ2ZXJUeXBlEjUKD3NlY3VyaXR5X3BhcmFtcxgC",
"IAEoCzIcLmdycGMudGVzdGluZy5TZWN1cml0eVBhcmFtcxIMCgRwb3J0GAQg",
"ASgFEhwKFGFzeW5jX3NlcnZlcl90aHJlYWRzGAcgASgFEhIKCmNvcmVfbGlt",
"aXQYCCABKAUSMwoOcGF5bG9hZF9jb25maWcYCSABKAsyGy5ncnBjLnRlc3Rp",
"bmcuUGF5bG9hZENvbmZpZxIRCgljb3JlX2xpc3QYCiADKAUSGAoQb3RoZXJf",
"c2VydmVyX2FwaRgLIAEoCRIWCg50aHJlYWRzX3Blcl9jcRgMIAEoBRIcChNy",
"ZXNvdXJjZV9xdW90YV9zaXplGOkHIAEoBRIvCgxjaGFubmVsX2FyZ3MY6gcg",
"AygLMhguZ3JwYy50ZXN0aW5nLkNoYW5uZWxBcmciaAoKU2VydmVyQXJncxIr",
"CgVzZXR1cBgBIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJDb25maWdIABIi",
"CgRtYXJrGAIgASgLMhIuZ3JwYy50ZXN0aW5nLk1hcmtIAEIJCgdhcmd0eXBl",
"IlUKDFNlcnZlclN0YXR1cxIoCgVzdGF0cxgBIAEoCzIZLmdycGMudGVzdGlu",
"Zy5TZXJ2ZXJTdGF0cxIMCgRwb3J0GAIgASgFEg0KBWNvcmVzGAMgASgFIg0K",
"C0NvcmVSZXF1ZXN0Ih0KDENvcmVSZXNwb25zZRINCgVjb3JlcxgBIAEoBSIG",
"CgRWb2lkIv0BCghTY2VuYXJpbxIMCgRuYW1lGAEgASgJEjEKDWNsaWVudF9j",
"b25maWcYAiABKAsyGi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnEhMKC251",
"bV9jbGllbnRzGAMgASgFEjEKDXNlcnZlcl9jb25maWcYBCABKAsyGi5ncnBj",
"LnRlc3RpbmcuU2VydmVyQ29uZmlnEhMKC251bV9zZXJ2ZXJzGAUgASgFEhYK",
"Dndhcm11cF9zZWNvbmRzGAYgASgFEhkKEWJlbmNobWFya19zZWNvbmRzGAcg",
"ASgFEiAKGHNwYXduX2xvY2FsX3dvcmtlcl9jb3VudBgIIAEoBSI2CglTY2Vu",
"YXJpb3MSKQoJc2NlbmFyaW9zGAEgAygLMhYuZ3JwYy50ZXN0aW5nLlNjZW5h",
"cmlvIoQEChVTY2VuYXJpb1Jlc3VsdFN1bW1hcnkSCwoDcXBzGAEgASgBEhsK",
"E3Fwc19wZXJfc2VydmVyX2NvcmUYAiABKAESGgoSc2VydmVyX3N5c3RlbV90",
"aW1lGAMgASgBEhgKEHNlcnZlcl91c2VyX3RpbWUYBCABKAESGgoSY2xpZW50",
"X3N5c3RlbV90aW1lGAUgASgBEhgKEGNsaWVudF91c2VyX3RpbWUYBiABKAES",
"EgoKbGF0ZW5jeV81MBgHIAEoARISCgpsYXRlbmN5XzkwGAggASgBEhIKCmxh",
"dGVuY3lfOTUYCSABKAESEgoKbGF0ZW5jeV85ORgKIAEoARITCgtsYXRlbmN5",
"Xzk5ORgLIAEoARIYChBzZXJ2ZXJfY3B1X3VzYWdlGAwgASgBEiYKHnN1Y2Nl",
"c3NmdWxfcmVxdWVzdHNfcGVyX3NlY29uZBgNIAEoARIiChpmYWlsZWRfcmVx",
"dWVzdHNfcGVyX3NlY29uZBgOIAEoARIgChhjbGllbnRfcG9sbHNfcGVyX3Jl",
"cXVlc3QYDyABKAESIAoYc2VydmVyX3BvbGxzX3Blcl9yZXF1ZXN0GBAgASgB",
"EiIKGnNlcnZlcl9xdWVyaWVzX3Blcl9jcHVfc2VjGBEgASgBEiIKGmNsaWVu",
"dF9xdWVyaWVzX3Blcl9jcHVfc2VjGBIgASgBIoMDCg5TY2VuYXJpb1Jlc3Vs",
"dBIoCghzY2VuYXJpbxgBIAEoCzIWLmdycGMudGVzdGluZy5TY2VuYXJpbxIu",
"CglsYXRlbmNpZXMYAiABKAsyGy5ncnBjLnRlc3RpbmcuSGlzdG9ncmFtRGF0",
"YRIvCgxjbGllbnRfc3RhdHMYAyADKAsyGS5ncnBjLnRlc3RpbmcuQ2xpZW50",
"U3RhdHMSLwoMc2VydmVyX3N0YXRzGAQgAygLMhkuZ3JwYy50ZXN0aW5nLlNl",
"cnZlclN0YXRzEhQKDHNlcnZlcl9jb3JlcxgFIAMoBRI0CgdzdW1tYXJ5GAYg",
"ASgLMiMuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvUmVzdWx0U3VtbWFyeRIWCg5j",
"bGllbnRfc3VjY2VzcxgHIAMoCBIWCg5zZXJ2ZXJfc3VjY2VzcxgIIAMoCBI5",
"Cg9yZXF1ZXN0X3Jlc3VsdHMYCSADKAsyIC5ncnBjLnRlc3RpbmcuUmVxdWVz",
"dFJlc3VsdENvdW50KkEKCkNsaWVudFR5cGUSDwoLU1lOQ19DTElFTlQQABIQ",
"CgxBU1lOQ19DTElFTlQQARIQCgxPVEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJU",
"eXBlEg8KC1NZTkNfU0VSVkVSEAASEAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZ",
"TkNfR0VORVJJQ19TRVJWRVIQAhIQCgxPVEhFUl9TRVJWRVIQAypyCgdScGNU",
"eXBlEgkKBVVOQVJZEAASDQoJU1RSRUFNSU5HEAESGQoVU1RSRUFNSU5HX0ZS",
"T01fQ0xJRU5UEAISGQoVU1RSRUFNSU5HX0ZST01fU0VSVkVSEAMSFwoTU1RS",
"RUFNSU5HX0JPVEhfV0FZUxAEYgZwcm90bzM="));
"c19wZXJfY3EYESABKAUSGwoTbWVzc2FnZXNfcGVyX3N0cmVhbRgSIAEoBRIY",
"ChB1c2VfY29hbGVzY2VfYXBpGBMgASgIIjgKDENsaWVudFN0YXR1cxIoCgVz",
"dGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIVCgRNYXJr",
"Eg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAYASABKAsy",
"Gi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgCIAEoCzIS",
"LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSL9AgoMU2VydmVyQ29u",
"ZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5nLlNlcnZl",
"clR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50ZXN0aW5n",
"LlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVy",
"X3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2Fk",
"X2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnEhEK",
"CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJEhYK",
"DnRocmVhZHNfcGVyX2NxGAwgASgFEhwKE3Jlc291cmNlX3F1b3RhX3NpemUY",
"6QcgASgFEi8KDGNoYW5uZWxfYXJncxjqByADKAsyGC5ncnBjLnRlc3Rpbmcu",
"Q2hhbm5lbEFyZyJoCgpTZXJ2ZXJBcmdzEisKBXNldHVwGAEgASgLMhouZ3Jw",
"Yy50ZXN0aW5nLlNlcnZlckNvbmZpZ0gAEiIKBG1hcmsYAiABKAsyEi5ncnBj",
"LnRlc3RpbmcuTWFya0gAQgkKB2FyZ3R5cGUiVQoMU2VydmVyU3RhdHVzEigK",
"BXN0YXRzGAEgASgLMhkuZ3JwYy50ZXN0aW5nLlNlcnZlclN0YXRzEgwKBHBv",
"cnQYAiABKAUSDQoFY29yZXMYAyABKAUiDQoLQ29yZVJlcXVlc3QiHQoMQ29y",
"ZVJlc3BvbnNlEg0KBWNvcmVzGAEgASgFIgYKBFZvaWQi/QEKCFNjZW5hcmlv",
"EgwKBG5hbWUYASABKAkSMQoNY2xpZW50X2NvbmZpZxgCIAEoCzIaLmdycGMu",
"dGVzdGluZy5DbGllbnRDb25maWcSEwoLbnVtX2NsaWVudHMYAyABKAUSMQoN",
"c2VydmVyX2NvbmZpZxgEIAEoCzIaLmdycGMudGVzdGluZy5TZXJ2ZXJDb25m",
"aWcSEwoLbnVtX3NlcnZlcnMYBSABKAUSFgoOd2FybXVwX3NlY29uZHMYBiAB",
"KAUSGQoRYmVuY2htYXJrX3NlY29uZHMYByABKAUSIAoYc3Bhd25fbG9jYWxf",
"d29ya2VyX2NvdW50GAggASgFIjYKCVNjZW5hcmlvcxIpCglzY2VuYXJpb3MY",
"ASADKAsyFi5ncnBjLnRlc3RpbmcuU2NlbmFyaW8ihAQKFVNjZW5hcmlvUmVz",
"dWx0U3VtbWFyeRILCgNxcHMYASABKAESGwoTcXBzX3Blcl9zZXJ2ZXJfY29y",
"ZRgCIAEoARIaChJzZXJ2ZXJfc3lzdGVtX3RpbWUYAyABKAESGAoQc2VydmVy",
"X3VzZXJfdGltZRgEIAEoARIaChJjbGllbnRfc3lzdGVtX3RpbWUYBSABKAES",
"GAoQY2xpZW50X3VzZXJfdGltZRgGIAEoARISCgpsYXRlbmN5XzUwGAcgASgB",
"EhIKCmxhdGVuY3lfOTAYCCABKAESEgoKbGF0ZW5jeV85NRgJIAEoARISCgps",
"YXRlbmN5Xzk5GAogASgBEhMKC2xhdGVuY3lfOTk5GAsgASgBEhgKEHNlcnZl",
"cl9jcHVfdXNhZ2UYDCABKAESJgoec3VjY2Vzc2Z1bF9yZXF1ZXN0c19wZXJf",
"c2Vjb25kGA0gASgBEiIKGmZhaWxlZF9yZXF1ZXN0c19wZXJfc2Vjb25kGA4g",
"ASgBEiAKGGNsaWVudF9wb2xsc19wZXJfcmVxdWVzdBgPIAEoARIgChhzZXJ2",
"ZXJfcG9sbHNfcGVyX3JlcXVlc3QYECABKAESIgoac2VydmVyX3F1ZXJpZXNf",
"cGVyX2NwdV9zZWMYESABKAESIgoaY2xpZW50X3F1ZXJpZXNfcGVyX2NwdV9z",
"ZWMYEiABKAEigwMKDlNjZW5hcmlvUmVzdWx0EigKCHNjZW5hcmlvGAEgASgL",
"MhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxhdGVuY2llcxgCIAEoCzIb",
"LmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8KDGNsaWVudF9zdGF0cxgD",
"IAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cxIvCgxzZXJ2ZXJfc3Rh",
"dHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSFAoMc2VydmVy",
"X2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsyIy5ncnBjLnRlc3Rpbmcu",
"U2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVudF9zdWNjZXNzGAcgAygI",
"EhYKDnNlcnZlcl9zdWNjZXNzGAggAygIEjkKD3JlcXVlc3RfcmVzdWx0cxgJ",
"IAMoCzIgLmdycGMudGVzdGluZy5SZXF1ZXN0UmVzdWx0Q291bnQqQQoKQ2xp",
"ZW50VHlwZRIPCgtTWU5DX0NMSUVOVBAAEhAKDEFTWU5DX0NMSUVOVBABEhAK",
"DE9USEVSX0NMSUVOVBACKlsKClNlcnZlclR5cGUSDwoLU1lOQ19TRVJWRVIQ",
"ABIQCgxBU1lOQ19TRVJWRVIQARIYChRBU1lOQ19HRU5FUklDX1NFUlZFUhAC",
"EhAKDE9USEVSX1NFUlZFUhADKnIKB1JwY1R5cGUSCQoFVU5BUlkQABINCglT",
"VFJFQU1JTkcQARIZChVTVFJFQU1JTkdfRlJPTV9DTElFTlQQAhIZChVTVFJF",
"QU1JTkdfRlJPTV9TRVJWRVIQAxIXChNTVFJFQU1JTkdfQk9USF9XQVlTEARi",
"BnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] {
@ -106,7 +107,7 @@ namespace Grpc.Testing {
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.LoadParams), global::Grpc.Testing.LoadParams.Parser, new[]{ "ClosedLoop", "Poisson" }, new[]{ "Load" }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SecurityParams), global::Grpc.Testing.SecurityParams.Parser, new[]{ "UseTestCa", "ServerHostOverride", "CredType" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ChannelArg), global::Grpc.Testing.ChannelArg.Parser, new[]{ "Name", "StrValue", "IntValue" }, new[]{ "Value" }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientConfig), global::Grpc.Testing.ClientConfig.Parser, new[]{ "ServerTargets", "ClientType", "SecurityParams", "OutstandingRpcsPerChannel", "ClientChannels", "AsyncClientThreads", "RpcType", "LoadParams", "PayloadConfig", "HistogramParams", "CoreList", "CoreLimit", "OtherClientApi", "ChannelArgs", "ThreadsPerCq", "MessagesPerStream", "UseCoalesceApi" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
@ -989,6 +990,7 @@ namespace Grpc.Testing {
channelArgs_ = other.channelArgs_.Clone();
threadsPerCq_ = other.threadsPerCq_;
messagesPerStream_ = other.messagesPerStream_;
useCoalesceApi_ = other.useCoalesceApi_;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -1198,6 +1200,20 @@ namespace Grpc.Testing {
}
}
/// <summary>Field number for the "use_coalesce_api" field.</summary>
public const int UseCoalesceApiFieldNumber = 19;
private bool useCoalesceApi_;
/// <summary>
/// Use coalescing API when possible.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool UseCoalesceApi {
get { return useCoalesceApi_; }
set {
useCoalesceApi_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ClientConfig);
@ -1227,6 +1243,7 @@ namespace Grpc.Testing {
if(!channelArgs_.Equals(other.channelArgs_)) return false;
if (ThreadsPerCq != other.ThreadsPerCq) return false;
if (MessagesPerStream != other.MessagesPerStream) return false;
if (UseCoalesceApi != other.UseCoalesceApi) return false;
return true;
}
@ -1249,6 +1266,7 @@ namespace Grpc.Testing {
hash ^= channelArgs_.GetHashCode();
if (ThreadsPerCq != 0) hash ^= ThreadsPerCq.GetHashCode();
if (MessagesPerStream != 0) hash ^= MessagesPerStream.GetHashCode();
if (UseCoalesceApi != false) hash ^= UseCoalesceApi.GetHashCode();
return hash;
}
@ -1314,6 +1332,10 @@ namespace Grpc.Testing {
output.WriteRawTag(144, 1);
output.WriteInt32(MessagesPerStream);
}
if (UseCoalesceApi != false) {
output.WriteRawTag(152, 1);
output.WriteBool(UseCoalesceApi);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -1361,6 +1383,9 @@ namespace Grpc.Testing {
if (MessagesPerStream != 0) {
size += 2 + pb::CodedOutputStream.ComputeInt32Size(MessagesPerStream);
}
if (UseCoalesceApi != false) {
size += 2 + 1;
}
return size;
}
@ -1423,6 +1448,9 @@ namespace Grpc.Testing {
if (other.MessagesPerStream != 0) {
MessagesPerStream = other.MessagesPerStream;
}
if (other.UseCoalesceApi != false) {
UseCoalesceApi = other.UseCoalesceApi;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@ -1510,6 +1538,10 @@ namespace Grpc.Testing {
MessagesPerStream = input.ReadInt32();
break;
}
case 152: {
UseCoalesceApi = input.ReadBool();
break;
}
}
}
}

@ -19,7 +19,7 @@
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
<PackageReference Include="Moq" Version="4.7.0" />
<PackageReference Include="Moq" Version="4.8.2" />
<PackageReference Include="NUnit" Version="3.6.0" />
<PackageReference Include="NUnitLite" Version="3.6.0" />
</ItemGroup>

@ -26,9 +26,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Grpc.Testing {
@ -121,7 +118,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return GetAllGauges(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -144,7 +141,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return GetGauge(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -166,7 +163,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return GetGaugeAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -22,9 +22,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Grpc.Testing {
@ -177,7 +174,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -201,7 +198,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -225,7 +222,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingCall(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -248,7 +245,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingFromClient(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingFromClient(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingFromClient(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -271,7 +268,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.SimpleResponse> StreamingFromServer(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.SimpleResponse> StreamingFromServer(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingFromServer(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -294,7 +291,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingBothWays(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingBothWays(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingBothWays(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -470,7 +467,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return RunServer(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -500,7 +497,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return RunClient(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -526,7 +523,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CoreCount(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -548,7 +545,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CoreCountAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -570,7 +567,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return QuitWorker(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -592,7 +589,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return QuitWorkerAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -692,7 +689,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.Void ReportScenario(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Void ReportScenario(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return ReportScenario(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -714,7 +711,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> ReportScenarioAsync(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Void> ReportScenarioAsync(global::Grpc.Testing.ScenarioResult request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return ReportScenarioAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -23,9 +23,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Grpc.Testing {
@ -244,7 +241,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return EmptyCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -266,7 +263,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return EmptyCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -288,7 +285,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -310,7 +307,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -334,7 +331,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CacheableUnaryCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -360,7 +357,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return CacheableUnaryCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -385,7 +382,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingOutputCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -408,7 +405,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StreamingInputCall(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -431,7 +428,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return FullDuplexCall(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -456,7 +453,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return HalfDuplexCall(new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -481,7 +478,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnimplementedCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -505,7 +502,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnimplementedCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -613,7 +610,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The response received from the server.</returns>
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnimplementedCall(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -635,7 +632,7 @@ namespace Grpc.Testing {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return UnimplementedCallAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -734,7 +731,7 @@ namespace Grpc.Testing {
{
}
public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Start(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -742,7 +739,7 @@ namespace Grpc.Testing {
{
return CallInvoker.BlockingUnaryCall(__Method_Start, null, options, request);
}
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StartAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -750,7 +747,7 @@ namespace Grpc.Testing {
{
return CallInvoker.AsyncUnaryCall(__Method_Start, null, options, request);
}
public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return Stop(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}
@ -758,7 +755,7 @@ namespace Grpc.Testing {
{
return CallInvoker.BlockingUnaryCall(__Method_Stop, null, options, request);
}
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return StopAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -22,9 +22,6 @@
#pragma warning disable 1591
#region Designer generated code
using System;
using System.Threading;
using System.Threading.Tasks;
using grpc = global::Grpc.Core;
namespace Grpc.Reflection.V1Alpha {
@ -97,7 +94,7 @@ namespace Grpc.Reflection.V1Alpha {
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
/// <param name="cancellationToken">An optional token for canceling the call.</param>
/// <returns>The call object.</returns>
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(grpc::Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
public virtual grpc::AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
{
return ServerReflectionInfo(new grpc::CallOptions(headers, deadline, cancellationToken));
}

@ -1,5 +1,5 @@
{
"sdk": {
"version": "1.0.0"
"version": "2.1.4"
}
}

@ -108,6 +108,9 @@ static NSString * const kBearerPrefix = @"Bearer ";
// The dispatch queue to be used for enqueuing responses to user. Defaulted to the main dispatch
// queue
dispatch_queue_t _responseQueue;
// Whether the call is finished. If it is, should not call finishWithError again.
BOOL _finished;
}
@synthesize state = _state;
@ -206,6 +209,8 @@ static NSString * const kBearerPrefix = @"Bearer ";
} else {
[_responseWriteable enqueueSuccessfulCompletion];
}
[GRPCConnectivityMonitor unregisterObserver:self];
}
- (void)cancelCall {
@ -214,9 +219,10 @@ static NSString * const kBearerPrefix = @"Bearer ";
}
- (void)cancel {
[self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
[self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
if (!self.isWaitingForToken) {
[self cancelCall];
} else {
@ -224,6 +230,19 @@ static NSString * const kBearerPrefix = @"Bearer ";
}
}
- (void)maybeFinishWithError:(NSError *)errorOrNil {
BOOL toFinish = NO;
@synchronized(self) {
if (_finished == NO) {
_finished = YES;
toFinish = YES;
}
}
if (toFinish == YES) {
[self finishWithError:errorOrNil];
}
}
- (void)dealloc {
__block GRPCWrappedCall *wrappedCall = _wrappedCall;
dispatch_async(_callQueue, ^{
@ -250,11 +269,13 @@ static NSString * const kBearerPrefix = @"Bearer ";
if (self.state == GRXWriterStatePaused) {
return;
}
__weak GRPCCall *weakSelf = self;
__weak GRXConcurrentWriteable *weakWriteable = _responseWriteable;
dispatch_async(_callQueue, ^{
[weakSelf startReadWithHandler:^(grpc_byte_buffer *message) {
__weak GRPCCall *weakSelf = self;
__weak GRXConcurrentWriteable *weakWriteable = self->_responseWriteable;
[self startReadWithHandler:^(grpc_byte_buffer *message) {
__strong GRPCCall *strongSelf = weakSelf;
__strong GRXConcurrentWriteable *strongWriteable = weakWriteable;
if (message == NULL) {
// No more messages from the server
return;
@ -266,14 +287,14 @@ static NSString * const kBearerPrefix = @"Bearer ";
// don't want to throw, because the app shouldn't crash for a behavior
// that's on the hands of any server to have. Instead we finish and ask
// the server to cancel.
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeResourceExhausted
userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]];
[weakSelf cancelCall];
[strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeResourceExhausted
userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]];
[strongSelf cancelCall];
return;
}
[weakWriteable enqueueValue:data completionHandler:^{
[weakSelf startNextRead];
[strongWriteable enqueueValue:data completionHandler:^{
[strongSelf startNextRead];
}];
}];
});
@ -333,12 +354,17 @@ static NSString * const kBearerPrefix = @"Bearer ";
_requestWriter.state = GRXWriterStatePaused;
}
__weak GRPCCall *weakSelf = self;
dispatch_async(_callQueue, ^{
[weakSelf writeMessage:value withErrorHandler:^{
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
__weak GRPCCall *weakSelf = self;
[self writeMessage:value withErrorHandler:^{
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
// Wrapped call must be canceled when error is reported to upper layers
[strongSelf cancelCall];
}
}];
});
}
@ -360,12 +386,15 @@ static NSString * const kBearerPrefix = @"Bearer ";
if (errorOrNil) {
[self cancel];
} else {
__weak GRPCCall *weakSelf = self;
dispatch_async(_callQueue, ^{
[weakSelf finishRequestWithErrorHandler:^{
[weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
__weak GRPCCall *weakSelf = self;
[self finishRequestWithErrorHandler:^{
__strong GRPCCall *strongSelf = weakSelf;
[strongSelf maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeInternal
userInfo:nil]];
// Wrapped call must be canceled when error is reported to upper layers
[strongSelf cancelCall];
}];
});
}
@ -387,30 +416,37 @@ static NSString * const kBearerPrefix = @"Bearer ";
}
- (void)invokeCall {
__weak GRPCCall *weakSelf = self;
[self invokeCallWithHeadersHandler:^(NSDictionary *headers) {
// Response headers received.
self.responseHeaders = headers;
[self startNextRead];
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseHeaders = headers;
[strongSelf startNextRead];
}
} completionHandler:^(NSError *error, NSDictionary *trailers) {
self.responseTrailers = trailers;
__strong GRPCCall *strongSelf = weakSelf;
if (strongSelf) {
strongSelf.responseTrailers = trailers;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = self.responseTrailers;
// TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
// called before this one, so an error might end up with trailers but no headers. We
// shouldn't call finishWithError until ater both blocks are called. It is also when this is
// done that we can provide a merged view of response headers and trailers in a thread-safe
// way.
if (self.responseHeaders) {
userInfo[kGRPCHeadersKey] = self.responseHeaders;
if (error) {
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
if (error.userInfo) {
[userInfo addEntriesFromDictionary:error.userInfo];
}
userInfo[kGRPCTrailersKey] = strongSelf.responseTrailers;
// TODO(jcanizales): The C gRPC library doesn't guarantee that the headers block will be
// called before this one, so an error might end up with trailers but no headers. We
// shouldn't call finishWithError until ater both blocks are called. It is also when this is
// done that we can provide a merged view of response headers and trailers in a thread-safe
// way.
if (strongSelf.responseHeaders) {
userInfo[kGRPCHeadersKey] = strongSelf.responseHeaders;
}
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
}
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
[strongSelf maybeFinishWithError:error];
}
[self finishWithError:error];
}];
// Now that the RPC has been initiated, request writes can start.
@synchronized(_requestWriter) {
@ -439,16 +475,8 @@ static NSString * const kBearerPrefix = @"Bearer ";
// TODO(jcanizales): Check this on init.
[NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host];
}
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
__weak typeof(self) weakSelf = self;
void (^handler)(void) = ^{
typeof(self) strongSelf = weakSelf;
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]];
};
[_connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:nil];
[GRPCConnectivityMonitor registerObserver:self
selector:@selector(connectivityChanged:)];
}
- (void)startWithWriteable:(id<GRXWriteable>)writeable {
@ -512,4 +540,12 @@ static NSString * const kBearerPrefix = @"Bearer ";
}
}
- (void)connectivityChanged:(NSNotification *)note {
[self maybeFinishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable
userInfo:@{ NSLocalizedDescriptionKey : @"Connectivity lost." }]];
// Cancel underlying call upon this notification
[self cancelCall];
}
@end

@ -19,44 +19,30 @@
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
@interface GRPCReachabilityFlags : NSObject
+ (nonnull instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags;
/**
* One accessor method to query each of the different flags. Example:
@property(nonatomic, readonly) BOOL isCell;
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
@property(nonatomic, readonly) BOOL methodName;
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
@property(nonatomic, readonly) BOOL isHostReachable;
@end
typedef NS_ENUM(NSInteger, GRPCConnectivityStatus) {
GRPCConnectivityUnknown = 0,
GRPCConnectivityNoNetwork = 1,
GRPCConnectivityCellular = 2,
GRPCConnectivityWiFi = 3,
};
extern NSString * _Nonnull kGRPCConnectivityNotification;
// This interface monitors OS reachability interface for any network status
// change. Parties interested in these events should register themselves as
// observer.
@interface GRPCConnectivityMonitor : NSObject
+ (nullable instancetype)monitorWithHost:(nonnull NSString *)hostName;
- (nonnull instancetype)init NS_UNAVAILABLE;
/**
* Queue on which callbacks will be dispatched. Default is the main queue. Set it before calling
* handleLossWithHandler:.
*/
// TODO(jcanizales): Default to a serial background queue instead.
@property(nonatomic, strong, null_resettable) dispatch_queue_t queue;
/**
* Calls handler every time the connectivity to this instance's host is lost. If this instance is
* released before that happens, the handler won't be called.
* Only one handler is active at a time, so if this method is called again before the previous
* handler has been called, it might never be called at all (or yes, if it has already been queued).
*/
- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler;
// Register an object as observer of network status change. \a observer
// must have a notification method with one parameter of type
// (NSNotification *) and should pass it to parameter \a selector. The
// parameter of this notification method is not used for now.
+ (void)registerObserver:(_Nonnull id)observer
selector:(_Nonnull SEL)selector;
// Ungegister an object from observers of network status change.
+ (void)unregisterObserver:(_Nonnull id)observer;
@end

@ -18,175 +18,74 @@
#import "GRPCConnectivityMonitor.h"
#pragma mark Flags
#include <netinet/in.h>
@implementation GRPCReachabilityFlags {
SCNetworkReachabilityFlags _flags;
}
NSString *kGRPCConnectivityNotification = @"kGRPCConnectivityNotification";
+ (instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags {
return [[self alloc] initWithFlags:flags];
}
static SCNetworkReachabilityRef reachability;
static GRPCConnectivityStatus currentStatus;
- (instancetype)initWithFlags:(SCNetworkReachabilityFlags)flags {
if ((self = [super init])) {
_flags = flags;
// Aggregate information in flags into network status.
GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags flags) {
GRPCConnectivityStatus result = GRPCConnectivityUnknown;
if (((flags & kSCNetworkReachabilityFlagsReachable) == 0) ||
((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0)) {
return GRPCConnectivityNoNetwork;
}
return self;
}
/*
* One accessor method implementation per flag. Example:
- (BOOL)isCell { \
return !!(_flags & kSCNetworkReachabilityFlagsIsWWAN); \
}
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
- (BOOL)methodName { \
return !!(_flags & kSCNetworkReachabilityFlags ## FlagName); \
}
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
- (BOOL)isHostReachable {
// Note: connectionOnDemand means it'll be reachable only if using the CFSocketStream API or APIs
// on top of it.
// connectionRequired means we can't tell until a connection is attempted (e.g. for VPN on
// demand).
return self.reachable && !self.interventionRequired && !self.connectionOnDemand;
}
- (NSString *)description {
NSMutableArray *activeOptions = [NSMutableArray arrayWithCapacity:9];
/*
* For each flag, add its name to the array if it's ON. Example:
if (self.isCell) {
[activeOptions addObject:@"isCell"];
result = GRPCConnectivityWiFi;
#if TARGET_OS_IPHONE
if (flags & kSCNetworkReachabilityFlagsIsWWAN) {
return result = GRPCConnectivityCellular;
}
*/
#define GRPC_XMACRO_ITEM(methodName, FlagName) \
if (self.methodName) { \
[activeOptions addObject:@ #methodName]; \
}
#include "GRPCReachabilityFlagNames.xmacro.h"
#undef GRPC_XMACRO_ITEM
return activeOptions.count == 0 ? @"(none)" : [activeOptions componentsJoinedByString:@", "];
}
- (BOOL)isEqual:(id)object {
return [object isKindOfClass:[GRPCReachabilityFlags class]] &&
_flags == ((GRPCReachabilityFlags *)object)->_flags;
}
- (NSUInteger)hash {
return _flags;
}
@end
#pragma mark Connectivity Monitor
// Assumes the third argument is a block that accepts a GRPCReachabilityFlags object, and passes the
// received ones to it.
static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void *info) {
#pragma unused (target)
// This can be called many times with the same info. The info is retained by SCNetworkReachability
// while this function is being executed.
void (^handler)(GRPCReachabilityFlags *) = (__bridge void (^)(GRPCReachabilityFlags *))info;
handler([[GRPCReachabilityFlags alloc] initWithFlags:flags]);
#endif
return result;
}
@implementation GRPCConnectivityMonitor {
SCNetworkReachabilityRef _reachabilityRef;
GRPCReachabilityFlags *_previousReachabilityFlags;
}
static void ReachabilityCallback(
SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags);
- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
if (!reachability) {
return nil;
if (newStatus != currentStatus) {
[[NSNotificationCenter defaultCenter] postNotificationName:kGRPCConnectivityNotification
object:nil];
currentStatus = newStatus;
}
if ((self = [super init])) {
_reachabilityRef = CFRetain(reachability);
_queue = dispatch_get_main_queue();
_previousReachabilityFlags = nil;
}
return self;
}
+ (nullable instancetype)monitorWithHost:(nonnull NSString *)host {
const char *hostName = host.UTF8String;
if (!hostName) {
[NSException raise:NSInvalidArgumentException
format:@"host.UTF8String returns NULL for %@", host];
}
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, hostName);
@implementation GRPCConnectivityMonitor
GRPCConnectivityMonitor *returnValue = [[self alloc] initWithReachability:reachability];
if (reachability) {
CFRelease(reachability);
}
return returnValue;
}
+ (void)initialize {
if (self == [GRPCConnectivityMonitor self]) {
struct sockaddr_in addr = {0};
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&addr);
currentStatus = GRPCConnectivityUnknown;
- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler {
__weak typeof(self) weakSelf = self;
[self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
if (lossHandler && !flags.reachable) {
lossHandler();
#if TARGET_OS_IPHONE
} else if (wifiStatusChangeHandler &&
strongSelf->_previousReachabilityFlags &&
(flags.isWWAN ^
strongSelf->_previousReachabilityFlags.isWWAN)) {
wifiStatusChangeHandler();
#endif
}
strongSelf->_previousReachabilityFlags = flags;
SCNetworkConnectionFlags flags;
if (SCNetworkReachabilityGetFlags(reachability, &flags)) {
currentStatus = CalculateConnectivityStatus(flags);
}
}];
}
- (void)startListeningWithHandler:(void (^)(GRPCReachabilityFlags *))handler {
// Copy to ensure the handler block is in the heap (and so can't be deallocated when this method
// returns).
void (^copiedHandler)(GRPCReachabilityFlags *) = [handler copy];
SCNetworkReachabilityContext context = {
.version = 0,
.info = (__bridge void *)copiedHandler,
.retain = CFRetain,
.release = CFRelease,
};
// The following will retain context.info, and release it when the callback is set to NULL.
SCNetworkReachabilitySetCallback(_reachabilityRef, PassFlagsToContextInfoBlock, &context);
SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _queue);
}
- (void)stopListening {
// This releases the block on context.info.
SCNetworkReachabilitySetCallback(_reachabilityRef, NULL, NULL);
SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL);
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) ||
!SCNetworkReachabilityScheduleWithRunLoop(
reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)) {
NSLog(@"gRPC connectivity monitor fail to set");
}
}
}
- (void)setQueue:(dispatch_queue_t)queue {
_queue = queue ?: dispatch_get_main_queue();
+ (void)registerObserver:(_Nonnull id)observer
selector:(SEL)selector {
[[NSNotificationCenter defaultCenter] addObserver:observer
selector:selector
name:kGRPCConnectivityNotification
object:nil];
}
- (void)dealloc {
if (_reachabilityRef) {
[self stopListening];
CFRelease(_reachabilityRef);
}
+ (void)unregisterObserver:(_Nonnull id)observer {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
@end

@ -37,12 +37,6 @@ NS_ASSUME_NONNULL_BEGIN
static NSMutableDictionary *kHostCache;
// This connectivity monitor flushes the host cache when connectivity status
// changes or when connection switch between Wifi and Cellular data, so that a
// new call will use a new channel. Otherwise, a new call will still use the
// cached channel which is no longer available and will cause gRPC to hang.
static GRPCConnectivityMonitor *connectivityMonitor = nil;
@implementation GRPCHost {
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
GRPCChannel *_channel;
@ -90,17 +84,7 @@ static GRPCConnectivityMonitor *connectivityMonitor = nil;
kHostCache[address] = self;
_compressAlgorithm = GRPC_COMPRESS_NONE;
}
// Keep a single monitor to flush the cache if the connectivity status changes
// Thread safety guarded by @synchronized(kHostCache)
if (!connectivityMonitor) {
connectivityMonitor =
[GRPCConnectivityMonitor monitorWithHost:hostURL.host];
void (^handler)(void) = ^{
[GRPCHost flushChannelCache];
};
[connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:handler];
}
[GRPCConnectivityMonitor registerObserver:self selector:@selector(connectivityChange:)];
}
return self;
}
@ -281,6 +265,13 @@ static GRPCConnectivityMonitor *connectivityMonitor = nil;
}
}
// Flushes the host cache when connectivity status changes or when connection switch between Wifi
// and Cellular data, so that a new call will use a new channel. Otherwise, a new call will still
// use the cached channel which is no longer available and will cause gRPC to hang.
- (void)connectivityChange:(NSNotification *)note {
[GRPCHost flushChannelCache];
}
@end
NS_ASSUME_NONNULL_END

@ -155,7 +155,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
'src/core/lib/slice/slice_buffer.cc',
'src/core/lib/slice/slice_hash_table.cc',
'src/core/lib/slice/slice_intern.cc',
'src/core/lib/slice/slice_string_helpers.cc',
'src/core/lib/surface/api_trace.cc',
@ -186,6 +185,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/service_config.cc',
'src/core/lib/transport/static_metadata.cc',
'src/core/lib/transport/status_conversion.cc',
'src/core/lib/transport/status_metadata.cc',
'src/core/lib/transport/timeout_encoding.cc',
'src/core/lib/transport/transport.cc',
'src/core/lib/transport/transport_op_string.cc',
@ -235,10 +235,10 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/ssl/ssl_credentials.cc',
'src/core/lib/security/security_connector/security_connector.cc',
'src/core/lib/security/transport/client_auth_filter.cc',
'src/core/lib/security/transport/lb_targets_info.cc',
'src/core/lib/security/transport/secure_endpoint.cc',
'src/core/lib/security/transport/security_handshaker.cc',
'src/core/lib/security/transport/server_auth_filter.cc',
'src/core/lib/security/transport/target_authority_table.cc',
'src/core/lib/security/transport/tsi_error.cc',
'src/core/lib/security/util/json_util.cc',
'src/core/lib/surface/init_secure.cc',
@ -261,12 +261,14 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy.cc',
'src/core/ext/filters/client_channel/lb_policy_factory.cc',
'src/core/ext/filters/client_channel/lb_policy_registry.cc',
'src/core/ext/filters/client_channel/method_params.cc',
'src/core/ext/filters/client_channel/parse_address.cc',
'src/core/ext/filters/client_channel/proxy_mapper.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver_registry.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc',
'src/core/ext/filters/client_channel/status_util.cc',
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel_index.cc',
'src/core/ext/filters/client_channel/uri_parser.cc',

@ -29,8 +29,8 @@ gRPC Python:
1. Support static type-checking of both gRPC Python itself and of code that uses gRPC Python. No one likes dynamic typing and Python is finally outgrowing it! There are probably errors in the implementation of gRPC Python that [pytype](https://github.com/google/pytype) or [mypy](http://mypy-lang.org/) could detect. There are certainly errors in other code that uses gRPC Python that they could detect.
* **Required skills:** Python programming language, open source development across multiple repositories and projects.
* **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Kailash Sethuraman](https://github.com/hsaliak), [Ken Payson](https://github.com/kpayson64), [Mehrdad Afshari](https://github.com/mehrdada).
* **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Kailash Sethuraman](https://github.com/hsaliak).
1. [Enable building of gRPC Python with Bazel](https://github.com/grpc/grpc/issues/8079). Bazel is the designated replacement for our constellation of crufty build scripts, but it's still under active development itself. Up for a challenge? gRPC Python could easily be the most complex codebase to be built with Bazel.
* **Required skills:** Python programming language, Bazel toolchain, Cython, open source development across multiple repositories and projects.
* **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Ken Payson](https://github.com/kpayson64), [Mehrdad Afshari](https://github.com/mehrdada).
* **Likely mentors:** [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle).

@ -54,3 +54,14 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "status_util_test",
srcs = ["status_util_test.cc"],
language = "C++",
deps = [
"//:grpc",
],
external_deps = [
"gtest",
],
)

@ -0,0 +1,49 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/ext/filters/client_channel/status_util.h"
#include <gtest/gtest.h>
namespace grpc_core {
namespace internal {
namespace {
TEST(StatusCodeSet, Basic) {
StatusCodeSet set;
EXPECT_TRUE(set.Empty());
EXPECT_FALSE(set.Contains(GRPC_STATUS_OK));
EXPECT_FALSE(set.Contains(GRPC_STATUS_UNAVAILABLE));
set.Add(GRPC_STATUS_OK);
EXPECT_FALSE(set.Empty());
EXPECT_TRUE(set.Contains(GRPC_STATUS_OK));
EXPECT_FALSE(set.Contains(GRPC_STATUS_UNAVAILABLE));
set.Add(GRPC_STATUS_UNAVAILABLE);
EXPECT_FALSE(set.Empty());
EXPECT_TRUE(set.Contains(GRPC_STATUS_OK));
EXPECT_TRUE(set.Contains(GRPC_STATUS_UNAVAILABLE));
}
} // namespace
} // namespace internal
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

@ -118,6 +118,36 @@ extern void request_with_payload(grpc_end2end_test_config config);
extern void request_with_payload_pre_init(void);
extern void resource_quota_server(grpc_end2end_test_config config);
extern void resource_quota_server_pre_init(void);
extern void retry(grpc_end2end_test_config config);
extern void retry_pre_init(void);
extern void retry_cancellation(grpc_end2end_test_config config);
extern void retry_cancellation_pre_init(void);
extern void retry_disabled(grpc_end2end_test_config config);
extern void retry_disabled_pre_init(void);
extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config config);
extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
extern void retry_non_retriable_status(grpc_end2end_test_config config);
extern void retry_non_retriable_status_pre_init(void);
extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
extern void retry_recv_initial_metadata_pre_init(void);
extern void retry_recv_message(grpc_end2end_test_config config);
extern void retry_recv_message_pre_init(void);
extern void retry_server_pushback_delay(grpc_end2end_test_config config);
extern void retry_server_pushback_delay_pre_init(void);
extern void retry_server_pushback_disabled(grpc_end2end_test_config config);
extern void retry_server_pushback_disabled_pre_init(void);
extern void retry_streaming(grpc_end2end_test_config config);
extern void retry_streaming_pre_init(void);
extern void retry_streaming_after_commit(grpc_end2end_test_config config);
extern void retry_streaming_after_commit_pre_init(void);
extern void retry_streaming_succeeds_before_replay_finished(grpc_end2end_test_config config);
extern void retry_streaming_succeeds_before_replay_finished_pre_init(void);
extern void retry_throttled(grpc_end2end_test_config config);
extern void retry_throttled_pre_init(void);
extern void retry_too_many_attempts(grpc_end2end_test_config config);
extern void retry_too_many_attempts_pre_init(void);
extern void server_finishes_request(grpc_end2end_test_config config);
extern void server_finishes_request_pre_init(void);
extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@ -197,6 +227,21 @@ void grpc_end2end_tests_pre_init(void) {
request_with_flags_pre_init();
request_with_payload_pre_init();
resource_quota_server_pre_init();
retry_pre_init();
retry_cancellation_pre_init();
retry_disabled_pre_init();
retry_exceeds_buffer_size_in_initial_batch_pre_init();
retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
retry_non_retriable_status_pre_init();
retry_recv_initial_metadata_pre_init();
retry_recv_message_pre_init();
retry_server_pushback_delay_pre_init();
retry_server_pushback_disabled_pre_init();
retry_streaming_pre_init();
retry_streaming_after_commit_pre_init();
retry_streaming_succeeds_before_replay_finished_pre_init();
retry_throttled_pre_init();
retry_too_many_attempts_pre_init();
server_finishes_request_pre_init();
shutdown_finishes_calls_pre_init();
shutdown_finishes_tags_pre_init();
@ -265,6 +310,21 @@ void grpc_end2end_tests(int argc, char **argv,
request_with_flags(config);
request_with_payload(config);
resource_quota_server(config);
retry(config);
retry_cancellation(config);
retry_disabled(config);
retry_exceeds_buffer_size_in_initial_batch(config);
retry_exceeds_buffer_size_in_subsequent_batch(config);
retry_non_retriable_status(config);
retry_recv_initial_metadata(config);
retry_recv_message(config);
retry_server_pushback_delay(config);
retry_server_pushback_disabled(config);
retry_streaming(config);
retry_streaming_after_commit(config);
retry_streaming_succeeds_before_replay_finished(config);
retry_throttled(config);
retry_too_many_attempts(config);
server_finishes_request(config);
shutdown_finishes_calls(config);
shutdown_finishes_tags(config);
@ -460,6 +520,66 @@ void grpc_end2end_tests(int argc, char **argv,
resource_quota_server(config);
continue;
}
if (0 == strcmp("retry", argv[i])) {
retry(config);
continue;
}
if (0 == strcmp("retry_cancellation", argv[i])) {
retry_cancellation(config);
continue;
}
if (0 == strcmp("retry_disabled", argv[i])) {
retry_disabled(config);
continue;
}
if (0 == strcmp("retry_exceeds_buffer_size_in_initial_batch", argv[i])) {
retry_exceeds_buffer_size_in_initial_batch(config);
continue;
}
if (0 == strcmp("retry_exceeds_buffer_size_in_subsequent_batch", argv[i])) {
retry_exceeds_buffer_size_in_subsequent_batch(config);
continue;
}
if (0 == strcmp("retry_non_retriable_status", argv[i])) {
retry_non_retriable_status(config);
continue;
}
if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
retry_recv_initial_metadata(config);
continue;
}
if (0 == strcmp("retry_recv_message", argv[i])) {
retry_recv_message(config);
continue;
}
if (0 == strcmp("retry_server_pushback_delay", argv[i])) {
retry_server_pushback_delay(config);
continue;
}
if (0 == strcmp("retry_server_pushback_disabled", argv[i])) {
retry_server_pushback_disabled(config);
continue;
}
if (0 == strcmp("retry_streaming", argv[i])) {
retry_streaming(config);
continue;
}
if (0 == strcmp("retry_streaming_after_commit", argv[i])) {
retry_streaming_after_commit(config);
continue;
}
if (0 == strcmp("retry_streaming_succeeds_before_replay_finished", argv[i])) {
retry_streaming_succeeds_before_replay_finished(config);
continue;
}
if (0 == strcmp("retry_throttled", argv[i])) {
retry_throttled(config);
continue;
}
if (0 == strcmp("retry_too_many_attempts", argv[i])) {
retry_too_many_attempts(config);
continue;
}
if (0 == strcmp("server_finishes_request", argv[i])) {
server_finishes_request(config);
continue;

@ -120,6 +120,36 @@ extern void request_with_payload(grpc_end2end_test_config config);
extern void request_with_payload_pre_init(void);
extern void resource_quota_server(grpc_end2end_test_config config);
extern void resource_quota_server_pre_init(void);
extern void retry(grpc_end2end_test_config config);
extern void retry_pre_init(void);
extern void retry_cancellation(grpc_end2end_test_config config);
extern void retry_cancellation_pre_init(void);
extern void retry_disabled(grpc_end2end_test_config config);
extern void retry_disabled_pre_init(void);
extern void retry_exceeds_buffer_size_in_initial_batch(grpc_end2end_test_config config);
extern void retry_exceeds_buffer_size_in_initial_batch_pre_init(void);
extern void retry_exceeds_buffer_size_in_subsequent_batch(grpc_end2end_test_config config);
extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
extern void retry_non_retriable_status(grpc_end2end_test_config config);
extern void retry_non_retriable_status_pre_init(void);
extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
extern void retry_recv_initial_metadata_pre_init(void);
extern void retry_recv_message(grpc_end2end_test_config config);
extern void retry_recv_message_pre_init(void);
extern void retry_server_pushback_delay(grpc_end2end_test_config config);
extern void retry_server_pushback_delay_pre_init(void);
extern void retry_server_pushback_disabled(grpc_end2end_test_config config);
extern void retry_server_pushback_disabled_pre_init(void);
extern void retry_streaming(grpc_end2end_test_config config);
extern void retry_streaming_pre_init(void);
extern void retry_streaming_after_commit(grpc_end2end_test_config config);
extern void retry_streaming_after_commit_pre_init(void);
extern void retry_streaming_succeeds_before_replay_finished(grpc_end2end_test_config config);
extern void retry_streaming_succeeds_before_replay_finished_pre_init(void);
extern void retry_throttled(grpc_end2end_test_config config);
extern void retry_throttled_pre_init(void);
extern void retry_too_many_attempts(grpc_end2end_test_config config);
extern void retry_too_many_attempts_pre_init(void);
extern void server_finishes_request(grpc_end2end_test_config config);
extern void server_finishes_request_pre_init(void);
extern void shutdown_finishes_calls(grpc_end2end_test_config config);
@ -200,6 +230,21 @@ void grpc_end2end_tests_pre_init(void) {
request_with_flags_pre_init();
request_with_payload_pre_init();
resource_quota_server_pre_init();
retry_pre_init();
retry_cancellation_pre_init();
retry_disabled_pre_init();
retry_exceeds_buffer_size_in_initial_batch_pre_init();
retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
retry_non_retriable_status_pre_init();
retry_recv_initial_metadata_pre_init();
retry_recv_message_pre_init();
retry_server_pushback_delay_pre_init();
retry_server_pushback_disabled_pre_init();
retry_streaming_pre_init();
retry_streaming_after_commit_pre_init();
retry_streaming_succeeds_before_replay_finished_pre_init();
retry_throttled_pre_init();
retry_too_many_attempts_pre_init();
server_finishes_request_pre_init();
shutdown_finishes_calls_pre_init();
shutdown_finishes_tags_pre_init();
@ -269,6 +314,21 @@ void grpc_end2end_tests(int argc, char **argv,
request_with_flags(config);
request_with_payload(config);
resource_quota_server(config);
retry(config);
retry_cancellation(config);
retry_disabled(config);
retry_exceeds_buffer_size_in_initial_batch(config);
retry_exceeds_buffer_size_in_subsequent_batch(config);
retry_non_retriable_status(config);
retry_recv_initial_metadata(config);
retry_recv_message(config);
retry_server_pushback_delay(config);
retry_server_pushback_disabled(config);
retry_streaming(config);
retry_streaming_after_commit(config);
retry_streaming_succeeds_before_replay_finished(config);
retry_throttled(config);
retry_too_many_attempts(config);
server_finishes_request(config);
shutdown_finishes_calls(config);
shutdown_finishes_tags(config);
@ -468,6 +528,66 @@ void grpc_end2end_tests(int argc, char **argv,
resource_quota_server(config);
continue;
}
if (0 == strcmp("retry", argv[i])) {
retry(config);
continue;
}
if (0 == strcmp("retry_cancellation", argv[i])) {
retry_cancellation(config);
continue;
}
if (0 == strcmp("retry_disabled", argv[i])) {
retry_disabled(config);
continue;
}
if (0 == strcmp("retry_exceeds_buffer_size_in_initial_batch", argv[i])) {
retry_exceeds_buffer_size_in_initial_batch(config);
continue;
}
if (0 == strcmp("retry_exceeds_buffer_size_in_subsequent_batch", argv[i])) {
retry_exceeds_buffer_size_in_subsequent_batch(config);
continue;
}
if (0 == strcmp("retry_non_retriable_status", argv[i])) {
retry_non_retriable_status(config);
continue;
}
if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
retry_recv_initial_metadata(config);
continue;
}
if (0 == strcmp("retry_recv_message", argv[i])) {
retry_recv_message(config);
continue;
}
if (0 == strcmp("retry_server_pushback_delay", argv[i])) {
retry_server_pushback_delay(config);
continue;
}
if (0 == strcmp("retry_server_pushback_disabled", argv[i])) {
retry_server_pushback_disabled(config);
continue;
}
if (0 == strcmp("retry_streaming", argv[i])) {
retry_streaming(config);
continue;
}
if (0 == strcmp("retry_streaming_after_commit", argv[i])) {
retry_streaming_after_commit(config);
continue;
}
if (0 == strcmp("retry_streaming_succeeds_before_replay_finished", argv[i])) {
retry_streaming_succeeds_before_replay_finished(config);
continue;
}
if (0 == strcmp("retry_throttled", argv[i])) {
retry_throttled(config);
continue;
}
if (0 == strcmp("retry_too_many_attempts", argv[i])) {
retry_too_many_attempts(config);
continue;
}
if (0 == strcmp("server_finishes_request", argv[i])) {
server_finishes_request(config);
continue;

@ -48,7 +48,17 @@ static grpc_server* create_proxy_server(const char* port,
static grpc_channel* create_proxy_client(const char* target,
grpc_channel_args* client_args) {
return grpc_insecure_channel_create(target, client_args, nullptr);
// Disable retries in proxy client.
grpc_arg arg;
arg.type = GRPC_ARG_INTEGER;
arg.key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
arg.value.integer = 0;
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(client_args, &arg, 1);
grpc_channel* channel =
grpc_insecure_channel_create(target, new_args, nullptr);
grpc_channel_args_destroy(new_args);
return channel;
}
static const grpc_end2end_proxy_def proxy_def = {create_proxy_server,

@ -21,7 +21,13 @@
"\x0Auser-agent"
"\x04host"
"\x08lb-token"
"\x1Agrpc-previous-rpc-attempts"
"\x16grpc-retry-pushback-ms"
"\x0Cgrpc-timeout"
"\x011"
"\x012"
"\x013"
"\x014"
"\x00"
"\x13grpc.wait_for_ready"
"\x0Cgrpc.timeout"
@ -32,8 +38,6 @@
"\x04gzip"
"\x0Bstream/gzip"
"\x010"
"\x011"
"\x012"
"\x08identity"
"\x08trailers"
"\x10application/grpc"

@ -24,15 +24,24 @@ import hashlib
FixtureOptions = collections.namedtuple(
'FixtureOptions',
'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth supports_write_buffering')
'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2 supports_proxy_auth supports_write_buffering client_channel')
default_unsecure_fixture_options = FixtureOptions(
True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False, True, False, True, False, True)
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'],
True, False, [], [], True, False, True, False, True, False, True, True)
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(
fullstack=False, dns_resolver=False, client_channel=False)
default_secure_fixture_options = default_unsecure_fixture_options._replace(
secure=True)
uds_fixture_options = default_unsecure_fixture_options._replace(
dns_resolver=False, platforms=['linux', 'mac', 'posix'],
exclude_iomgrs=['uv'])
fd_unsecure_fixture_options = default_unsecure_fixture_options._replace(
dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
inproc_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, fullstack=False, name_resolution=False, supports_compression=False, is_inproc=True, is_http2=False, supports_write_buffering=False)
dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'],
exclude_iomgrs=['uv'], client_channel=False)
inproc_fixture_options = default_unsecure_fixture_options._replace(
dns_resolver=False, fullstack=False, name_resolution=False,
supports_compression=False, is_inproc=True, is_http2=False,
supports_write_buffering=False, client_channel=False)
# maps fixture name to whether it requires the security library
END2END_FIXTURES = {
@ -68,9 +77,12 @@ END2END_FIXTURES = {
TestOptions = collections.namedtuple(
'TestOptions',
'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth needs_write_buffering')
default_test_options = TestOptions(False, False, False, True, False, True, 1.0, [], False, False, True, False, False, False, False, False)
connectivity_test_options = default_test_options._replace(needs_fullstack=True)
'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2 needs_proxy_auth needs_write_buffering needs_client_channel')
default_test_options = TestOptions(
False, False, False, True, False, True, 1.0, [], False, False, True,
False, False, False, False, False, False)
connectivity_test_options = default_test_options._replace(
needs_fullstack=True)
LOWCPU = 0.1
@ -80,9 +92,8 @@ END2END_TESTS = {
'bad_hostname': default_test_options._replace(needs_names=True),
'bad_ping': connectivity_test_options._replace(proxyable=False),
'binary_metadata': default_test_options._replace(cpu_cost=LOWCPU),
'resource_quota_server': default_test_options._replace(large_writes=True,
proxyable=False,
allows_compression=False),
'resource_quota_server': default_test_options._replace(
large_writes=True, proxyable=False, allows_compression=False),
'call_creds': default_test_options._replace(secure=True),
'cancel_after_accept': default_test_options._replace(cpu_cost=LOWCPU),
'cancel_after_client_done': default_test_options._replace(cpu_cost=LOWCPU),
@ -91,18 +102,21 @@ END2END_TESTS = {
'cancel_before_invoke': default_test_options._replace(cpu_cost=LOWCPU),
'cancel_in_a_vacuum': default_test_options._replace(cpu_cost=LOWCPU),
'cancel_with_status': default_test_options._replace(cpu_cost=LOWCPU),
'compressed_payload': default_test_options._replace(proxyable=False,needs_compression=True),
'compressed_payload': default_test_options._replace(proxyable=False,
needs_compression=True),
'connectivity': connectivity_test_options._replace(needs_names=True,
proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
'default_host': default_test_options._replace(needs_fullstack=True,
needs_dns=True,needs_names=True),
'disappearing_server': connectivity_test_options._replace(flaky=True,needs_names=True),
'default_host': default_test_options._replace(
needs_fullstack=True, needs_dns=True, needs_names=True),
'disappearing_server': connectivity_test_options._replace(flaky=True,
needs_names=True),
'empty_batch': default_test_options._replace(cpu_cost=LOWCPU),
'filter_causes_close': default_test_options._replace(cpu_cost=LOWCPU),
'filter_call_init_fails': default_test_options,
'filter_latency': default_test_options._replace(cpu_cost=LOWCPU),
'filter_status_code': default_test_options._replace(cpu_cost=LOWCPU),
'graceful_server_shutdown': default_test_options._replace(cpu_cost=LOWCPU,exclude_inproc=True),
'graceful_server_shutdown': default_test_options._replace(
cpu_cost=LOWCPU, exclude_inproc=True),
'hpack_size': default_test_options._replace(proxyable=False,
traceable=False,
cpu_cost=LOWCPU),
@ -127,30 +141,75 @@ END2END_TESTS = {
'payload': default_test_options,
'load_reporting_hook': default_test_options,
'ping_pong_streaming': default_test_options._replace(cpu_cost=LOWCPU),
'ping': connectivity_test_options._replace(proxyable=False, cpu_cost=LOWCPU),
'ping': connectivity_test_options._replace(proxyable=False,
cpu_cost=LOWCPU),
'proxy_auth': default_test_options._replace(needs_proxy_auth=True),
'registered_call': default_test_options,
'request_with_flags': default_test_options._replace(
proxyable=False, cpu_cost=LOWCPU),
'request_with_payload': default_test_options._replace(cpu_cost=LOWCPU),
# TODO(roth): Remove proxyable=False for all retry tests once we
# have a way for the proxy to propagate the fact that trailing
# metadata is available when initial metadata is returned.
# See https://github.com/grpc/grpc/issues/14467 for context.
'retry': default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_cancellation': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_disabled': default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_exceeds_buffer_size_in_initial_batch': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_exceeds_buffer_size_in_subsequent_batch':
default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_non_retriable_status': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_recv_initial_metadata': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_recv_message': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_server_pushback_delay': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_server_pushback_disabled': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_streaming': default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_streaming_after_commit': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'retry_streaming_succeeds_before_replay_finished':
default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_throttled': default_test_options._replace(cpu_cost=LOWCPU,
needs_client_channel=True,
proxyable=False),
'retry_too_many_attempts': default_test_options._replace(
cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
'server_finishes_request': default_test_options._replace(cpu_cost=LOWCPU),
'shutdown_finishes_calls': default_test_options._replace(cpu_cost=LOWCPU),
'shutdown_finishes_tags': default_test_options._replace(cpu_cost=LOWCPU),
'simple_cacheable_request': default_test_options._replace(cpu_cost=LOWCPU),
'stream_compression_compressed_payload': default_test_options._replace(proxyable=False,
exclude_inproc=True),
'stream_compression_payload': default_test_options._replace(exclude_inproc=True),
'stream_compression_ping_pong_streaming': default_test_options._replace(exclude_inproc=True),
'stream_compression_compressed_payload': default_test_options._replace(
proxyable=False, exclude_inproc=True),
'stream_compression_payload': default_test_options._replace(
exclude_inproc=True),
'stream_compression_ping_pong_streaming': default_test_options._replace(
exclude_inproc=True),
'simple_delayed_request': connectivity_test_options,
'simple_metadata': default_test_options,
'simple_request': default_test_options,
'streaming_error_response': default_test_options._replace(cpu_cost=LOWCPU),
'trailing_metadata': default_test_options,
'workaround_cronet_compression': default_test_options,
'write_buffering': default_test_options._replace(cpu_cost=LOWCPU,
needs_write_buffering=True),
'write_buffering_at_end': default_test_options._replace(cpu_cost=LOWCPU,
needs_write_buffering=True),
'write_buffering': default_test_options._replace(
cpu_cost=LOWCPU, needs_write_buffering=True),
'write_buffering_at_end': default_test_options._replace(
cpu_cost=LOWCPU, needs_write_buffering=True),
}
@ -191,6 +250,9 @@ def compatible(f, t):
if END2END_TESTS[t].needs_write_buffering:
if not END2END_FIXTURES[f].supports_write_buffering:
return False
if END2END_TESTS[t].needs_client_channel:
if not END2END_FIXTURES[f].client_channel:
return False
return True

@ -24,7 +24,7 @@ def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
name_resolution=True, secure=True, tracing=False,
platforms=['windows', 'linux', 'mac', 'posix'],
is_inproc=False, is_http2=True, supports_proxy_auth=False,
supports_write_buffering=True):
supports_write_buffering=True, client_channel=True):
return struct(
fullstack=fullstack,
includes_proxy=includes_proxy,
@ -35,8 +35,9 @@ def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
is_inproc=is_inproc,
is_http2=is_http2,
supports_proxy_auth=supports_proxy_auth,
supports_write_buffering=supports_write_buffering
#platforms=platforms
supports_write_buffering=supports_write_buffering,
client_channel=client_channel,
#platforms=platforms,
)
@ -47,6 +48,7 @@ END2END_FIXTURES = {
'h2_load_reporting': fixture_options(),
'h2_fakesec': fixture_options(),
'h2_fd': fixture_options(dns_resolver=False, fullstack=False,
client_channel=False,
platforms=['linux', 'mac', 'posix']),
'h2_full': fixture_options(),
'h2_full+pipe': fixture_options(platforms=['linux']),
@ -55,24 +57,28 @@ END2END_FIXTURES = {
'h2_http_proxy': fixture_options(supports_proxy_auth=True),
'h2_oauth2': fixture_options(),
'h2_proxy': fixture_options(includes_proxy=True),
'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False),
'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False),
'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False,
client_channel=False),
'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False,
client_channel=False),
'h2_sockpair+trace': fixture_options(fullstack=False, dns_resolver=False,
tracing=True),
tracing=True, client_channel=False),
'h2_ssl': fixture_options(secure=True),
'h2_ssl_proxy': fixture_options(includes_proxy=True, secure=True),
'h2_uds': fixture_options(dns_resolver=False,
platforms=['linux', 'mac', 'posix']),
'inproc': fixture_options(fullstack=False, dns_resolver=False,
name_resolution=False, is_inproc=True,
is_http2=False, supports_write_buffering=False),
is_http2=False, supports_write_buffering=False,
client_channel=False),
}
def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
proxyable=True, secure=False, traceable=False,
exclude_inproc=False, needs_http2=False,
needs_proxy_auth=False, needs_write_buffering=False):
needs_proxy_auth=False, needs_write_buffering=False,
needs_client_channel=False):
return struct(
needs_fullstack=needs_fullstack,
needs_dns=needs_dns,
@ -83,7 +89,8 @@ def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
exclude_inproc=exclude_inproc,
needs_http2=needs_http2,
needs_proxy_auth=needs_proxy_auth,
needs_write_buffering=needs_write_buffering
needs_write_buffering=needs_write_buffering,
needs_client_channel=needs_client_channel,
)
@ -118,7 +125,8 @@ END2END_TESTS = {
'invoke_large_request': test_options(),
'keepalive_timeout': test_options(proxyable=False, needs_http2=True),
'large_metadata': test_options(),
'max_concurrent_streams': test_options(proxyable=False, exclude_inproc=True),
'max_concurrent_streams': test_options(proxyable=False,
exclude_inproc=True),
'max_connection_age': test_options(exclude_inproc=True),
'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
'max_message_length': test_options(),
@ -134,6 +142,37 @@ END2END_TESTS = {
'registered_call': test_options(),
'request_with_flags': test_options(proxyable=False),
'request_with_payload': test_options(),
# TODO(roth): Remove proxyable=False for all retry tests once we
# have a way for the proxy to propagate the fact that trailing
# metadata is available when initial metadata is returned.
# See https://github.com/grpc/grpc/issues/14467 for context.
'retry': test_options(needs_client_channel=True, proxyable=False),
'retry_cancellation': test_options(needs_client_channel=True,
proxyable=False),
'retry_disabled': test_options(needs_client_channel=True, proxyable=False),
'retry_exceeds_buffer_size_in_initial_batch': test_options(
needs_client_channel=True, proxyable=False),
'retry_exceeds_buffer_size_in_subsequent_batch': test_options(
needs_client_channel=True, proxyable=False),
'retry_non_retriable_status': test_options(needs_client_channel=True,
proxyable=False),
'retry_recv_initial_metadata': test_options(needs_client_channel=True,
proxyable=False),
'retry_recv_message': test_options(needs_client_channel=True,
proxyable=False),
'retry_server_pushback_delay': test_options(needs_client_channel=True,
proxyable=False),
'retry_server_pushback_disabled': test_options(needs_client_channel=True,
proxyable=False),
'retry_streaming': test_options(needs_client_channel=True, proxyable=False),
'retry_streaming_after_commit': test_options(needs_client_channel=True,
proxyable=False),
'retry_streaming_succeeds_before_replay_finished': test_options(
needs_client_channel=True, proxyable=False),
'retry_throttled': test_options(needs_client_channel=True,
proxyable=False),
'retry_too_many_attempts': test_options(needs_client_channel=True,
proxyable=False),
'server_finishes_request': test_options(),
'shutdown_finishes_calls': test_options(),
'shutdown_finishes_tags': test_options(),
@ -142,7 +181,8 @@ END2END_TESTS = {
'simple_metadata': test_options(),
'simple_request': test_options(),
'streaming_error_response': test_options(),
'stream_compression_compressed_payload': test_options(proxyable=False, exclude_inproc=True),
'stream_compression_compressed_payload': test_options(proxyable=False,
exclude_inproc=True),
'stream_compression_payload': test_options(exclude_inproc=True),
'stream_compression_ping_pong_streaming': test_options(exclude_inproc=True),
'trailing_metadata': test_options(),
@ -183,6 +223,9 @@ def compatible(fopt, topt):
if topt.needs_write_buffering:
if not fopt.supports_write_buffering:
return False
if topt.needs_client_channel:
if not fopt.client_channel:
return False
return True

@ -0,0 +1,325 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests a basic retry scenario:
// - 2 retries allowed for ABORTED status
// - first attempt returns ABORTED
// - second attempt returns OK
static void test_retry(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
// Make sure the "grpc-previous-rpc-attempts" header was not sent in the
// initial attempt.
for (size_t i = 0; i < request_metadata_recv.count; ++i) {
GPR_ASSERT(!grpc_slice_eq(request_metadata_recv.metadata[i].key,
GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS));
}
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
// Make sure the "grpc-previous-rpc-attempts" header was sent in the retry.
bool found_retry_header = false;
for (size_t i = 0; i < request_metadata_recv.count; ++i) {
if (grpc_slice_eq(request_metadata_recv.metadata[i].key,
GRPC_MDSTR_GRPC_PREVIOUS_RPC_ATTEMPTS)) {
GPR_ASSERT(
grpc_slice_eq(request_metadata_recv.metadata[i].value, GRPC_MDSTR_1));
found_retry_header = true;
break;
}
}
GPR_ASSERT(found_retry_header);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_OK;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_OK);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 0);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry(config);
}
void retry_pre_init(void) {}

@ -0,0 +1,277 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests retry cancellation.
static void test_retry_cancellation(grpc_end2end_test_config config,
cancellation_mode mode) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" },\n"
" \"timeout\": \"5s\"\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
char* name;
gpr_asprintf(&name, "retry_cancellation/%s", mode.name);
grpc_end2end_test_fixture f = begin_test(config, name, &client_args, nullptr);
gpr_free(name);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
// Client starts a batch with all 6 ops.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
// Server gets a call and fails with retryable status.
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
// Server gets a second call (the retry).
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
// Initiate cancellation.
GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, nullptr));
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == mode.expect_status);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_cancellation(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
for (size_t i = 0; i < GPR_ARRAY_SIZE(cancellation_modes); ++i) {
test_retry_cancellation(config, cancellation_modes[i]);
}
}
void retry_cancellation_pre_init(void) {}

@ -0,0 +1,262 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we don't retry when retries are disabled via the
// GRPC_ARG_ENABLE_RETRIES channel arg, even when there is retry
// configuration in the service config.
// - 1 retry allowed for ABORTED status
// - first attempt returns ABORTED but does not retry
static void test_retry_disabled(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg args[2];
args[0].type = GRPC_ARG_STRING;
args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
args[0].value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
args[1].type = GRPC_ARG_INTEGER;
args[1].key = const_cast<char*>(GRPC_ARG_ENABLE_RETRIES);
args[1].value.integer = 0;
grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f =
begin_test(config, "retry_disabled", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_disabled(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_disabled(config);
}
void retry_disabled_pre_init(void) {}

@ -0,0 +1,266 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we don't make any further attempts after we exceed the
// max buffer size.
// - 1 retry allowed for ABORTED status
// - buffer size set to 2 bytes
// - client sends a 3-byte message
// - first attempt gets ABORTED but is not retried
static void test_retry_exceeds_buffer_size_in_initial_batch(
grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg args[2];
args[0].type = GRPC_ARG_STRING;
args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
args[0].value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
args[1].type = GRPC_ARG_INTEGER;
args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
args[1].value.integer = 2;
grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f =
begin_test(config, "retry_exceeds_buffer_size_in_initial_batch",
&client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_exceeds_buffer_size_in_initial_batch(
grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_exceeds_buffer_size_in_initial_batch(config);
}
void retry_exceeds_buffer_size_in_initial_batch_pre_init(void) {}

@ -0,0 +1,276 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Similar to the retry_exceeds_buffer_size_in_initial_batch test, but we
// don't exceed the buffer size until the second batch.
// - 1 retry allowed for ABORTED status
// - buffer size set to 100 KiB (larger than initial metadata)
// - client sends a 100 KiB message
// - first attempt gets ABORTED but is not retried
static void test_retry_exceeds_buffer_size_in_subsequent_batch(
grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
char buf[102401];
memset(buf, 'a', sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
grpc_slice request_payload_slice = grpc_slice_from_static_string(buf);
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg args[2];
args[0].type = GRPC_ARG_STRING;
args[0].key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
args[0].value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
args[1].type = GRPC_ARG_INTEGER;
args[1].key = const_cast<char*>(GRPC_ARG_PER_RPC_RETRY_BUFFER_SIZE);
args[1].value.integer = 102400;
grpc_channel_args client_args = {GPR_ARRAY_SIZE(args), args};
grpc_end2end_test_fixture f =
begin_test(config, "retry_exceeds_buffer_size_in_subsequent_batch",
&client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(2), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_exceeds_buffer_size_in_subsequent_batch(
grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_exceeds_buffer_size_in_subsequent_batch(config);
}
void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void) {}

@ -0,0 +1,257 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we don't retry for non-retryable status codes.
// - 1 retry allowed for ABORTED status
// - first attempt gets INVALID_ARGUMENT, so no retry is done
static void test_retry_non_retriable_status(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_non_retriable_status", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_INVALID_ARGUMENT;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_non_retriable_status(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_non_retriable_status(config);
}
void retry_non_retriable_status_pre_init(void) {}

@ -0,0 +1,268 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that receiving initial metadata commits the call.
// - 1 retry allowed for ABORTED status
// - first attempt receives initial metadata before trailing metadata,
// so no retry is done even though status was ABORTED
static void test_retry_recv_initial_metadata(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_recv_initial_metadata", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server sends initial metadata in its own batch, before sending
// trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(103), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_recv_initial_metadata(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_recv_initial_metadata(config);
}
void retry_recv_initial_metadata_pre_init(void) {}

@ -0,0 +1,261 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that receiving a message commits the call.
// - 1 retry allowed for ABORTED status
// - first attempt receives a message and therefore does not retry even
// though the final status is ABORTED
static void test_retry_recv_message(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_recv_message", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(103), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_recv_message(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_recv_message(config);
}
void retry_recv_message_pre_init(void) {}

@ -0,0 +1,318 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we honor server push-back delay.
// - 2 retries allowed for ABORTED status
// - first attempt gets ABORTED with a long delay
// - second attempt succeeds
static void test_retry_server_pushback_delay(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_metadata pushback_md;
memset(&pushback_md, 0, sizeof(pushback_md));
pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
pushback_md.value = grpc_slice_from_static_string("2000");
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_server_pushback_delay", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 1;
op->data.send_status_from_server.trailing_metadata = &pushback_md;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
gpr_timespec before_retry = gpr_now(GPR_CLOCK_MONOTONIC);
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
gpr_timespec after_retry = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec retry_delay = gpr_time_sub(after_retry, before_retry);
// Configured back-off was 1 second, server push-back said 2 seconds.
// To avoid flakiness, we allow some fudge factor here.
gpr_log(GPR_INFO, "retry delay was {.tv_sec=%" PRId64 ", .tv_nsec=%d}",
retry_delay.tv_sec, retry_delay.tv_nsec);
GPR_ASSERT(retry_delay.tv_sec >= 1);
if (retry_delay.tv_sec == 1) {
GPR_ASSERT(retry_delay.tv_nsec >= 900000000);
}
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_OK;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_OK);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 0);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_server_pushback_delay(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_server_pushback_delay(config);
}
void retry_server_pushback_delay_pre_init(void) {}

@ -0,0 +1,306 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we don't retry when disabled by server push-back.
// - 2 retries allowed for ABORTED status
// - first attempt gets ABORTED
// - second attempt gets ABORTED but server push back disables retrying
static void test_retry_server_pushback_disabled(
grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_metadata pushback_md;
memset(&pushback_md, 0, sizeof(pushback_md));
pushback_md.key = GRPC_MDSTR_GRPC_RETRY_PUSHBACK_MS;
pushback_md.value = grpc_slice_from_static_string("-1");
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f = begin_test(
config, "retry_server_pushback_disabled", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 1;
op->data.send_status_from_server.trailing_metadata = &pushback_md;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_server_pushback_disabled(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_server_pushback_disabled(config);
}
void retry_server_pushback_disabled_pre_init(void) {}

@ -0,0 +1,424 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests retrying a streaming RPC. This is the same as
// the basic retry test, except that the client sends two messages on the
// call before the initial attempt fails.
// FIXME: We should also test the case where the retry is committed after
// replaying 1 of 2 previously-completed send_message ops. However,
// there's no way to trigger that from an end2end test, because the
// replayed ops happen under the hood -- they are not surfaced to the
// C-core API, and therefore we have no way to inject the commit at the
// right point.
static void test_retry_streaming(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
grpc_slice request3_payload_slice = grpc_slice_from_static_string("baz");
grpc_slice response_payload_slice = grpc_slice_from_static_string("quux");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* request2_payload =
grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
grpc_byte_buffer* request3_payload =
grpc_raw_byte_buffer_create(&request3_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* request2_payload_recv = nullptr;
grpc_byte_buffer* request3_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_streaming", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
// Client starts a batch for receiving initial metadata, a message,
// and trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
// Client sends initial metadata and a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(2), true);
cq_verify(cqv);
// Server gets a call with received initial metadata.
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server receives a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
// Client sends a second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request2_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(3), true);
cq_verify(cqv);
// Server receives the second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request2_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(103), true);
cq_verify(cqv);
// Server sends both initial and trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(104), true);
cq_verify(cqv);
// Clean up from first attempt.
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
grpc_byte_buffer_destroy(request_payload_recv);
request_payload_recv = nullptr;
GPR_ASSERT(
byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
grpc_byte_buffer_destroy(request2_payload_recv);
request2_payload_recv = nullptr;
// Server gets a second call (the retry).
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server receives a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
cq_verify(cqv);
// Server receives a second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request2_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(203), true);
cq_verify(cqv);
// Client sends a third message and a close.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request3_payload;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(4), true);
cq_verify(cqv);
// Server receives a third message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request3_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(204), true);
cq_verify(cqv);
// Server receives a close and sends initial metadata, a message, and
// trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
// Returning a retriable code, but because we are also sending a
// message, the client will commit instead of retrying again.
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(205), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(205), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(request2_payload);
grpc_byte_buffer_destroy(request3_payload);
grpc_byte_buffer_destroy(response_payload);
GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
grpc_byte_buffer_destroy(request_payload_recv);
GPR_ASSERT(
byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
grpc_byte_buffer_destroy(request2_payload_recv);
GPR_ASSERT(
byte_buffer_eq_slice(request3_payload_recv, request3_payload_slice));
grpc_byte_buffer_destroy(request3_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_streaming(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_streaming(config);
}
void retry_streaming_pre_init(void) {}

@ -0,0 +1,354 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we can continue to send/recv messages on a streaming call
// after retries are committed.
static void test_retry_streaming_after_commit(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
grpc_slice response_payload_slice = grpc_slice_from_static_string("baz");
grpc_slice response2_payload_slice = grpc_slice_from_static_string("quux");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* request2_payload =
grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* response2_payload =
grpc_raw_byte_buffer_create(&response2_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* request2_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_byte_buffer* response2_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_streaming_after_commit", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
// Client starts a batch for receiving initial metadata and a message.
// This will commit retries.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
// Client sends initial metadata and a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(3), true);
cq_verify(cqv);
// Server gets a call with received initial metadata.
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server receives a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
// Server sends initial metadata and a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(103), true);
// Client receives initial metadata and a message.
CQ_EXPECT_COMPLETION(cqv, tag(2), true);
cq_verify(cqv);
// Client sends a second message and a close.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request2_payload;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(4), true);
cq_verify(cqv);
// Server receives a second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request2_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(104), true);
cq_verify(cqv);
// Server receives a close, sends a second message, and sends status.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response2_payload;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
// Returning a retriable code, but because retries are already
// committed, the client will not retry.
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(105), true);
cq_verify(cqv);
// Client receives a second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response2_payload_recv;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(5), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(5), true);
cq_verify(cqv);
// Client receives status.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(request2_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(response2_payload);
GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
grpc_byte_buffer_destroy(request_payload_recv);
GPR_ASSERT(
byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
grpc_byte_buffer_destroy(request2_payload_recv);
GPR_ASSERT(
byte_buffer_eq_slice(response_payload_recv, response_payload_slice));
grpc_byte_buffer_destroy(response_payload_recv);
GPR_ASSERT(
byte_buffer_eq_slice(response2_payload_recv, response2_payload_slice));
grpc_byte_buffer_destroy(response2_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_streaming_after_commit(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_streaming_after_commit(config);
}
void retry_streaming_after_commit_pre_init(void) {}

@ -0,0 +1,400 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we correctly clean up if the second attempt finishes
// before we have finished replaying all of the send ops.
static void test_retry_streaming_succeeds_before_replay_finished(
grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice request2_payload_slice = grpc_slice_from_static_string("bar");
grpc_slice request3_payload_slice = grpc_slice_from_static_string("baz");
grpc_slice response_payload_slice = grpc_slice_from_static_string("quux");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* request2_payload =
grpc_raw_byte_buffer_create(&request2_payload_slice, 1);
grpc_byte_buffer* request3_payload =
grpc_raw_byte_buffer_create(&request3_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* request2_payload_recv = nullptr;
grpc_byte_buffer* request3_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 3,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_streaming", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
// Client starts a batch for receiving initial metadata, a message,
// and trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
// Client sends initial metadata and a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(2), true);
cq_verify(cqv);
// Server gets a call with received initial metadata.
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server receives a message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
// Client sends a second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request2_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(3), true);
cq_verify(cqv);
// Server receives the second message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request2_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(103), true);
cq_verify(cqv);
// Client sends a third message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request3_payload;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(4), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(4), true);
cq_verify(cqv);
// Server receives the third message.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request3_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(104), true);
cq_verify(cqv);
// Server sends both initial and trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(105), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(105), true);
cq_verify(cqv);
// Clean up from first attempt.
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
grpc_byte_buffer_destroy(request_payload_recv);
request_payload_recv = nullptr;
GPR_ASSERT(
byte_buffer_eq_slice(request2_payload_recv, request2_payload_slice));
grpc_byte_buffer_destroy(request2_payload_recv);
request2_payload_recv = nullptr;
GPR_ASSERT(
byte_buffer_eq_slice(request3_payload_recv, request3_payload_slice));
grpc_byte_buffer_destroy(request3_payload_recv);
request3_payload_recv = nullptr;
// Server gets a second call (the retry).
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
// Server receives the first message (and does not receive any others).
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &request_payload_recv;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
cq_verify(cqv);
// Server sends initial metadata, a message, and trailing metadata.
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = response_payload;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
// Returning a retriable code, but because we are also sending a
// message, the client will commit instead of retrying again.
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(205), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(205), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(request2_payload);
grpc_byte_buffer_destroy(request3_payload);
grpc_byte_buffer_destroy(response_payload);
GPR_ASSERT(byte_buffer_eq_slice(request_payload_recv, request_payload_slice));
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_streaming_succeeds_before_replay_finished(
grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_streaming_succeeds_before_replay_finished(config);
}
void retry_streaming_succeeds_before_replay_finished_pre_init(void) {}

@ -0,0 +1,264 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we don't retry when throttled.
// - 1 retry allowed for ABORTED status
// - first attempt gets ABORTED but is over limit, so no retry is done
static void test_retry_throttled(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ],\n"
// A single failure will cause us to be throttled.
// (This is not a very realistic config, but it works for the
// purposes of this test.)
" \"retryThrottling\": {\n"
" \"maxTokens\": 2,\n"
" \"tokenRatio\": 1.0,\n"
" }\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_throttled", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_throttled(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_throttled(config);
}
void retry_throttled_pre_init(void) {}

@ -0,0 +1,299 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include <grpc/byte_buffer.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/static_metadata.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/tests/cancel_test_helpers.h"
static void* tag(intptr_t t) { return (void*)t; }
static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
const char* test_name,
grpc_channel_args* client_args,
grpc_channel_args* server_args) {
grpc_end2end_test_fixture f;
gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
f = config.create_fixture(client_args, server_args);
config.init_server(&f, server_args);
config.init_client(&f, client_args);
return f;
}
static gpr_timespec n_seconds_from_now(int n) {
return grpc_timeout_seconds_to_deadline(n);
}
static gpr_timespec five_seconds_from_now(void) {
return n_seconds_from_now(5);
}
static void drain_cq(grpc_completion_queue* cq) {
grpc_event ev;
do {
ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
} while (ev.type != GRPC_QUEUE_SHUTDOWN);
}
static void shutdown_server(grpc_end2end_test_fixture* f) {
if (!f->server) return;
grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
grpc_timeout_seconds_to_deadline(5),
nullptr)
.type == GRPC_OP_COMPLETE);
grpc_server_destroy(f->server);
f->server = nullptr;
}
static void shutdown_client(grpc_end2end_test_fixture* f) {
if (!f->client) return;
grpc_channel_destroy(f->client);
f->client = nullptr;
}
static void end_test(grpc_end2end_test_fixture* f) {
shutdown_server(f);
shutdown_client(f);
grpc_completion_queue_shutdown(f->cq);
drain_cq(f->cq);
grpc_completion_queue_destroy(f->cq);
grpc_completion_queue_destroy(f->shutdown_cq);
}
// Tests that we stop retrying after the configured number of attempts.
// - 1 retry allowed for ABORTED status
// - first attempt gets ABORTED
// - second attempt gets ABORTED but does not retry
static void test_retry_too_many_attempts(grpc_end2end_test_config config) {
grpc_call* c;
grpc_call* s;
grpc_op ops[6];
grpc_op* op;
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array request_metadata_recv;
grpc_call_details call_details;
grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
grpc_byte_buffer* request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer* response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
grpc_byte_buffer* request_payload_recv = nullptr;
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_status_code status;
grpc_call_error error;
grpc_slice details;
int was_cancelled = 2;
char* peer;
grpc_arg arg;
arg.type = GRPC_ARG_STRING;
arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
arg.value.string = const_cast<char*>(
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"service\", \"method\": \"method\" }\n"
" ],\n"
" \"retryPolicy\": {\n"
" \"maxAttempts\": 2,\n"
" \"initialBackoff\": \"1s\",\n"
" \"maxBackoff\": \"120s\",\n"
" \"backoffMultiplier\": 1.6,\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}");
grpc_channel_args client_args = {1, &arg};
grpc_end2end_test_fixture f =
begin_test(config, "retry_too_many_attempts", &client_args, nullptr);
cq_verifier* cqv = cq_verifier_create(f.cq);
gpr_timespec deadline = five_seconds_from_now();
c = grpc_channel_create_call(
f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/service/method"),
get_host_override_slice("foo.test.google.fr:1234", config), deadline,
nullptr);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
gpr_free(peer);
grpc_metadata_array_init(&initial_metadata_recv);
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_init(&call_details);
grpc_slice status_details = grpc_slice_from_static_string("xyz");
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_MESSAGE;
op->data.send_message.send_message = request_payload;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op++;
error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(102), true);
cq_verify(cqv);
grpc_call_unref(s);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_metadata_array_init(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_details_init(&call_details);
error =
grpc_server_request_call(f.server, &s, &call_details,
&request_metadata_recv, f.cq, f.cq, tag(201));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(201), true);
cq_verify(cqv);
peer = grpc_call_get_peer(s);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "server_peer=%s", peer);
gpr_free(peer);
peer = grpc_call_get_peer(c);
GPR_ASSERT(peer != nullptr);
gpr_log(GPR_DEBUG, "client_peer=%s", peer);
gpr_free(peer);
memset(ops, 0, sizeof(ops));
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op++;
op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op->data.send_status_from_server.trailing_metadata_count = 0;
op->data.send_status_from_server.status = GRPC_STATUS_ABORTED;
op->data.send_status_from_server.status_details = &status_details;
op++;
op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op->data.recv_close_on_server.cancelled = &was_cancelled;
op++;
error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), nullptr);
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(202), true);
CQ_EXPECT_COMPLETION(cqv, tag(1), true);
cq_verify(cqv);
GPR_ASSERT(status == GRPC_STATUS_ABORTED);
GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
validate_host_override_string("foo.test.google.fr:1234", call_details.host,
config);
GPR_ASSERT(0 == call_details.flags);
GPR_ASSERT(was_cancelled == 1);
grpc_slice_unref(details);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_byte_buffer_destroy(request_payload);
grpc_byte_buffer_destroy(response_payload);
grpc_byte_buffer_destroy(request_payload_recv);
grpc_byte_buffer_destroy(response_payload_recv);
grpc_call_unref(c);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
end_test(&f);
config.tear_down_data(&f);
}
void retry_too_many_attempts(grpc_end2end_test_config config) {
GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
test_retry_too_many_attempts(config);
}
void retry_too_many_attempts_pre_init(void) {}

@ -23,8 +23,8 @@ load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
grpc_fuzzer(
name = "percent_encode_fuzzer",
srcs = ["percent_encode_fuzzer.cc"],
language = "C++",
corpus = "percent_encode_corpus",
language = "C++",
deps = [
"//:gpr",
"//:grpc",
@ -35,8 +35,8 @@ grpc_fuzzer(
grpc_fuzzer(
name = "percent_decode_fuzzer",
srcs = ["percent_decode_fuzzer.cc"],
language = "C++",
corpus = "percent_decode_corpus",
language = "C++",
deps = [
"//:gpr",
"//:grpc",
@ -59,8 +59,13 @@ grpc_cc_test(
grpc_cc_test(
name = "slice_test",
srcs = ["slice_test.cc"],
deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
@ -78,15 +83,43 @@ grpc_cc_test(
grpc_cc_test(
name = "slice_buffer_test",
srcs = ["slice_buffer_test.cc"],
deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "slice_hash_table_test",
srcs = ["slice_hash_table_test.cc"],
deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "slice_weak_hash_table_test",
srcs = ["slice_weak_hash_table_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:gpr_test_util",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(

@ -20,6 +20,10 @@
#include <string.h>
#include <vector>
#include <gtest/gtest.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
@ -27,56 +31,55 @@
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
typedef struct {
const char* key;
const char* value;
} test_entry;
namespace grpc_core {
namespace {
static void populate_entries(const test_entry* input, size_t num_entries,
grpc_slice_hash_table_entry* output) {
for (size_t i = 0; i < num_entries; ++i) {
output[i].key = grpc_slice_from_copied_string(input[i].key);
output[i].value = gpr_strdup(input[i].value);
}
}
typedef SliceHashTable<UniquePtr<char>> TestHashTable;
static void check_values(const test_entry* input, size_t num_entries,
grpc_slice_hash_table* table) {
for (size_t i = 0; i < num_entries; ++i) {
grpc_slice key = grpc_slice_from_static_string(input[i].key);
const char* actual =
static_cast<const char*>(grpc_slice_hash_table_get(table, key));
GPR_ASSERT(actual != nullptr);
GPR_ASSERT(strcmp(actual, input[i].value) == 0);
struct TestEntry {
const char* key;
const char* value;
};
void CheckValues(const std::vector<TestEntry>& input,
const TestHashTable& table) {
for (const TestEntry& expected : input) {
grpc_slice key = grpc_slice_from_static_string(expected.key);
const UniquePtr<char>* actual = table.Get(key);
ASSERT_NE(actual, nullptr);
EXPECT_STREQ(expected.value, actual->get());
grpc_slice_unref(key);
}
}
static void check_non_existent_value(const char* key_string,
grpc_slice_hash_table* table) {
void CheckNonExistentValue(const char* key_string, const TestHashTable& table) {
grpc_slice key = grpc_slice_from_static_string(key_string);
GPR_ASSERT(grpc_slice_hash_table_get(table, key) == nullptr);
ASSERT_EQ(nullptr, table.Get(key));
grpc_slice_unref(key);
}
static void destroy_string(void* value) { gpr_free(value); }
static grpc_slice_hash_table* create_table_from_entries(
const test_entry* test_entries, size_t num_test_entries,
int (*value_cmp_fn)(void*, void*)) {
// Construct table.
grpc_slice_hash_table_entry* entries =
static_cast<grpc_slice_hash_table_entry*>(
gpr_zalloc(sizeof(*entries) * num_test_entries));
populate_entries(test_entries, num_test_entries, entries);
grpc_slice_hash_table* table = grpc_slice_hash_table_create(
num_test_entries, entries, destroy_string, value_cmp_fn);
void PopulateEntries(const std::vector<TestEntry>& input,
TestHashTable::Entry* output) {
for (size_t i = 0; i < input.size(); ++i) {
output[i].key = grpc_slice_from_copied_string(input[i].key);
output[i].value = UniquePtr<char>(gpr_strdup(input[i].value));
}
}
RefCountedPtr<TestHashTable> CreateTableFromEntries(
const std::vector<TestEntry>& test_entries,
TestHashTable::ValueCmp value_cmp) {
TestHashTable::Entry* entries = static_cast<TestHashTable::Entry*>(
gpr_zalloc(sizeof(*entries) * test_entries.size()));
PopulateEntries(test_entries, entries);
RefCountedPtr<TestHashTable> table =
TestHashTable::Create(test_entries.size(), entries, value_cmp);
gpr_free(entries);
return table;
}
static void test_slice_hash_table() {
const test_entry test_entries[] = {
TEST(SliceHashTable, Basic) {
const std::vector<TestEntry> test_entries = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"},
{"key_3", "value_3"}, {"key_4", "value_4"}, {"key_5", "value_5"},
{"key_6", "value_6"}, {"key_7", "value_7"}, {"key_8", "value_8"},
@ -112,129 +115,110 @@ static void test_slice_hash_table() {
{"key_96", "value_96"}, {"key_97", "value_97"}, {"key_98", "value_98"},
{"key_99", "value_99"},
};
const size_t num_entries = GPR_ARRAY_SIZE(test_entries);
grpc_slice_hash_table* table =
create_table_from_entries(test_entries, num_entries, nullptr);
RefCountedPtr<TestHashTable> table =
CreateTableFromEntries(test_entries, nullptr);
// Check contents of table.
check_values(test_entries, num_entries, table);
check_non_existent_value("XX", table);
// Clean up.
grpc_core::ExecCtx exec_ctx;
grpc_slice_hash_table_unref(table);
CheckValues(test_entries, *table);
CheckNonExistentValue("XX", *table);
}
static int value_cmp_fn(void* a, void* b) {
const char* a_str = static_cast<const char*>(a);
const char* b_str = static_cast<const char*>(b);
return strcmp(a_str, b_str);
int StringCmp(const UniquePtr<char>& a, const UniquePtr<char>& b) {
return strcmp(a.get(), b.get());
}
static int pointer_cmp_fn(void* a, void* b) { return GPR_ICMP(a, b); }
int PointerCmp(const UniquePtr<char>& a, const UniquePtr<char>& b) {
return GPR_ICMP(a.get(), b.get());
}
static void test_slice_hash_table_eq() {
const test_entry test_entries_a[] = {
TEST(SliceHashTable, CmpEqual) {
const std::vector<TestEntry> test_entries_a = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_a = GPR_ARRAY_SIZE(test_entries_a);
grpc_slice_hash_table* table_a =
create_table_from_entries(test_entries_a, num_entries_a, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_a) == 0);
const test_entry test_entries_b[] = {
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_b = GPR_ARRAY_SIZE(test_entries_b);
grpc_slice_hash_table* table_b =
create_table_from_entries(test_entries_b, num_entries_b, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b) == 0);
grpc_core::ExecCtx exec_ctx;
grpc_slice_hash_table_unref(table_a);
grpc_slice_hash_table_unref(table_b);
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, StringCmp);
// table_a equals itself.
EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_a));
// table_a equals table_b.
EXPECT_EQ(0, TestHashTable::Cmp(*table_a, *table_b));
}
static void test_slice_hash_table_not_eq() {
const test_entry test_entries_a[] = {
TEST(SliceHashTable, CmpDifferentSizes) {
// table_a has 3 entries, table_b has only 2.
const std::vector<TestEntry> test_entries_a = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_a = GPR_ARRAY_SIZE(test_entries_a);
grpc_slice_hash_table* table_a =
create_table_from_entries(test_entries_a, num_entries_a, value_cmp_fn);
// Different sizes.
const test_entry test_entries_b_smaller[] = {{"key_0", "value_0"},
{"key_1", "value_1"}};
const size_t num_entries_b_smaller = GPR_ARRAY_SIZE(test_entries_b_smaller);
grpc_slice_hash_table* table_b_smaller = create_table_from_entries(
test_entries_b_smaller, num_entries_b_smaller, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b_smaller) > 0);
const test_entry test_entries_b_larger[] = {{"key_0", "value_0"},
{"key_1", "value_1"},
{"key_2", "value_2"},
{"key_3", "value_3"}};
const size_t num_entries_b_larger = GPR_ARRAY_SIZE(test_entries_b_larger);
grpc_slice_hash_table* table_b_larger = create_table_from_entries(
test_entries_b_larger, num_entries_b_larger, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_b_larger) < 0);
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {{"key_0", "value_0"},
{"key_1", "value_1"}};
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, StringCmp);
EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0);
EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0);
}
TEST(SliceHashTable, CmpDifferentKey) {
// One key doesn't match and is lexicographically "smaller".
const test_entry test_entries_c[] = {
const std::vector<TestEntry> test_entries_a = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {
{"key_zz", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_c = GPR_ARRAY_SIZE(test_entries_c);
grpc_slice_hash_table* table_c =
create_table_from_entries(test_entries_c, num_entries_c, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_c) > 0);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_c, table_a) < 0);
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, StringCmp);
EXPECT_GT(TestHashTable::Cmp(*table_a, *table_b), 0);
EXPECT_LT(TestHashTable::Cmp(*table_b, *table_a), 0);
}
TEST(SliceHashTable, CmpDifferentValue) {
// One value doesn't match.
const test_entry test_entries_d[] = {
const std::vector<TestEntry> test_entries_a = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {
{"key_0", "value_z"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_d = GPR_ARRAY_SIZE(test_entries_d);
grpc_slice_hash_table* table_d =
create_table_from_entries(test_entries_d, num_entries_d, value_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_a, table_d) < 0);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_d, table_a) > 0);
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, StringCmp);
EXPECT_LT(TestHashTable::Cmp(*table_a, *table_b), 0);
EXPECT_GT(TestHashTable::Cmp(*table_b, *table_a), 0);
}
TEST(SliceHashTable, CmpDifferentCmpFunctions) {
// Same values but different "equals" functions.
const test_entry test_entries_e[] = {
const std::vector<TestEntry> test_entries_a = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_e = GPR_ARRAY_SIZE(test_entries_e);
grpc_slice_hash_table* table_e =
create_table_from_entries(test_entries_e, num_entries_e, value_cmp_fn);
const test_entry test_entries_f[] = {
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {
{"key_0", "value_0"}, {"key_1", "value_1"}, {"key_2", "value_2"}};
const size_t num_entries_f = GPR_ARRAY_SIZE(test_entries_f);
grpc_slice_hash_table* table_f =
create_table_from_entries(test_entries_f, num_entries_f, pointer_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_e, table_f) != 0);
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, PointerCmp);
EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0);
}
TEST(SliceHashTable, CmpEmptyKeysDifferentValue) {
// Same (empty) key, different values.
const test_entry test_entries_g[] = {{"", "value_0"}};
const size_t num_entries_g = GPR_ARRAY_SIZE(test_entries_g);
grpc_slice_hash_table* table_g =
create_table_from_entries(test_entries_g, num_entries_g, value_cmp_fn);
const test_entry test_entries_h[] = {{"", "value_1"}};
const size_t num_entries_h = GPR_ARRAY_SIZE(test_entries_h);
grpc_slice_hash_table* table_h =
create_table_from_entries(test_entries_h, num_entries_h, pointer_cmp_fn);
GPR_ASSERT(grpc_slice_hash_table_cmp(table_g, table_h) != 0);
grpc_core::ExecCtx exec_ctx;
grpc_slice_hash_table_unref(table_a);
grpc_slice_hash_table_unref(table_b_larger);
grpc_slice_hash_table_unref(table_b_smaller);
grpc_slice_hash_table_unref(table_c);
grpc_slice_hash_table_unref(table_d);
grpc_slice_hash_table_unref(table_e);
grpc_slice_hash_table_unref(table_f);
grpc_slice_hash_table_unref(table_g);
grpc_slice_hash_table_unref(table_h);
const std::vector<TestEntry> test_entries_a = {{"", "value_0"}};
RefCountedPtr<TestHashTable> table_a =
CreateTableFromEntries(test_entries_a, StringCmp);
const std::vector<TestEntry> test_entries_b = {{"", "value_1"}};
RefCountedPtr<TestHashTable> table_b =
CreateTableFromEntries(test_entries_b, PointerCmp);
EXPECT_NE(TestHashTable::Cmp(*table_a, *table_b), 0);
}
} // namespace
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_test_init(argc, argv);
grpc_core::ExecCtx::GlobalInit();
test_slice_hash_table();
test_slice_hash_table_eq();
test_slice_hash_table_not_eq();
int result = RUN_ALL_TESTS();
grpc_core::ExecCtx::GlobalShutdown();
return 0;
return result;
}

@ -0,0 +1,105 @@
/*
*
* Copyright 2017 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "src/core/lib/slice/slice_weak_hash_table.h"
#include <cstring>
#include <sstream>
#include <gtest/gtest.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/slice/slice_internal.h"
#include "test/core/util/test_config.h"
namespace grpc_core {
namespace {
grpc_slice BuildRefCountedKey(const char* key_str) {
const size_t key_length = strlen(key_str);
grpc_slice key = grpc_slice_malloc_large(key_length);
memcpy(GRPC_SLICE_START_PTR(key), key_str, key_length);
return key;
}
TEST(SliceWeakHashTable, Basic) {
auto table = SliceWeakHashTable<UniquePtr<char>, 10>::Create();
// Single key-value insertion.
grpc_slice key = BuildRefCountedKey("key");
grpc_slice_ref(key); // Get doesn't own.
table->Add(key, UniquePtr<char>(gpr_strdup("value")));
ASSERT_NE(table->Get(key), nullptr);
ASSERT_STREQ(table->Get(key)->get(), "value");
grpc_slice_unref(key);
// Unknown key.
ASSERT_EQ(table->Get(grpc_slice_from_static_string("unknown_key")), nullptr);
}
TEST(SliceWeakHashTable, ValueTypeConstructor) {
struct Value {
Value() : a(123) {}
int a;
};
auto table = SliceWeakHashTable<Value, 1>::Create();
grpc_slice key = BuildRefCountedKey("key");
grpc_slice_ref(key); // Get doesn't own.
table->Add(key, Value());
ASSERT_EQ(table->Get(key)->a, 123);
grpc_slice_unref(key);
}
TEST(SliceWeakHashTable, ForceOverload) {
constexpr int kTableSize = 10;
auto table = SliceWeakHashTable<UniquePtr<char>, kTableSize>::Create();
// Insert a multiple of the maximum size table.
for (int i = 0; i < kTableSize * 2; ++i) {
std::ostringstream oss;
oss << "key-" << i;
grpc_slice key = BuildRefCountedKey(oss.str().c_str());
oss.clear();
oss << "value-" << i;
table->Add(key, UniquePtr<char>(gpr_strdup(oss.str().c_str())));
}
// Verify that some will have been replaced.
int num_missing = 0;
for (int i = 0; i < kTableSize * 2; ++i) {
std::ostringstream oss;
oss << "key-" << i;
grpc_slice key = BuildRefCountedKey(oss.str().c_str());
if (table->Get(key) == nullptr) num_missing++;
grpc_slice_unref(key);
}
// At least kTableSize elements will be missing.
ASSERT_GE(num_missing, kTableSize);
}
} // namespace
} // namespace grpc_core
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc_test_init(argc, argv);
grpc_core::ExecCtx::GlobalInit();
int result = RUN_ALL_TESTS();
grpc_core::ExecCtx::GlobalShutdown();
return result;
}

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

Loading…
Cancel
Save