Merge remote-tracking branch 'upstream/master'

pull/18881/head
Na-Na Pang 6 years ago
commit 4198c4fcc6
  1. 1
      .gitignore
  2. 12
      BUILD
  3. 16
      BUILD.gn
  4. 92
      CMakeLists.txt
  5. 112
      Makefile
  6. 7
      WORKSPACE
  7. 202
      bazel/generate_cc.bzl
  8. 14
      bazel/grpc_python_deps.bzl
  9. 84
      bazel/protobuf.bzl
  10. 203
      bazel/python_rules.bzl
  11. 30
      build.yaml
  12. 4
      config.m4
  13. 4
      config.w32
  14. 12
      examples/BUILD
  15. 4
      examples/python/errors/client.py
  16. 4
      examples/python/errors/server.py
  17. 2
      examples/python/errors/test/_error_handling_example_test.py
  18. 17
      examples/python/multiprocessing/BUILD
  19. 11
      examples/python/wait_for_ready/wait_for_ready_example.py
  20. 12
      gRPC-C++.podspec
  21. 14
      gRPC-Core.podspec
  22. 9
      grpc.gemspec
  23. 7
      grpc.gyp
  24. 3
      include/grpc/impl/codegen/port_platform.h
  25. 2
      include/grpc/support/alloc.h
  26. 12
      include/grpcpp/create_channel.h
  27. 14
      include/grpcpp/create_channel_impl.h
  28. 10
      include/grpcpp/impl/codegen/async_generic_service.h
  29. 2
      include/grpcpp/impl/codegen/async_stream.h
  30. 2
      include/grpcpp/impl/codegen/client_callback.h
  31. 10
      include/grpcpp/impl/codegen/client_context.h
  32. 10
      include/grpcpp/impl/codegen/completion_queue.h
  33. 7
      include/grpcpp/impl/codegen/server_context.h
  34. 7
      include/grpcpp/impl/codegen/service_type.h
  35. 5
      include/grpcpp/impl/server_builder_plugin.h
  36. 2
      include/grpcpp/impl/server_initializer_impl.h
  37. 321
      include/grpcpp/security/credentials.h
  38. 281
      include/grpcpp/security/credentials_impl.h
  39. 4
      include/grpcpp/security/server_credentials.h
  40. 4
      include/grpcpp/security/server_credentials_impl.h
  41. 328
      include/grpcpp/server.h
  42. 1
      include/grpcpp/server_builder.h
  43. 2
      include/grpcpp/server_builder_impl.h
  44. 6
      include/grpcpp/server_impl.h
  45. 123
      include/grpcpp/support/channel_arguments.h
  46. 152
      include/grpcpp/support/channel_arguments_impl.h
  47. 9
      package.xml
  48. 27
      src/core/ext/filters/client_channel/backup_poller.cc
  49. 3
      src/core/ext/filters/client_channel/backup_poller.h
  50. 115
      src/core/ext/filters/client_channel/client_channel.cc
  51. 2
      src/core/ext/filters/client_channel/client_channel_plugin.cc
  52. 26
      src/core/ext/filters/client_channel/lb_policy.cc
  53. 37
      src/core/ext/filters/client_channel/lb_policy.h
  54. 81
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  55. 14
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  56. 14
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  57. 150
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  58. 5
      src/core/ext/filters/client_channel/lb_policy_factory.h
  59. 107
      src/core/ext/filters/client_channel/lb_policy_registry.cc
  60. 11
      src/core/ext/filters/client_channel/lb_policy_registry.h
  61. 14
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  62. 6
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
  63. 179
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
  64. 3
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
  65. 4
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
  66. 4
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
  67. 52
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
  68. 83
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
  69. 34
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h
  70. 51
      src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
  71. 589
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  72. 183
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  73. 12
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  74. 26
      src/core/ext/filters/client_channel/resolving_lb_policy.h
  75. 79
      src/core/ext/filters/client_channel/service_config.cc
  76. 273
      src/core/ext/filters/client_channel/service_config.h
  77. 59
      src/core/ext/filters/client_channel/subchannel.cc
  78. 193
      src/core/ext/filters/message_size/message_size_filter.cc
  79. 33
      src/core/ext/filters/message_size/message_size_filter.h
  80. 13
      src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
  81. 2
      src/core/ext/transport/chttp2/transport/internal.h
  82. 43
      src/core/lib/channel/channel_stack.cc
  83. 3
      src/core/lib/channel/context.h
  84. 73
      src/core/lib/gpr/alloc.cc
  85. 10
      src/core/lib/gpr/alloc.h
  86. 3
      src/core/lib/gpr/env.h
  87. 5
      src/core/lib/gpr/env_linux.cc
  88. 5
      src/core/lib/gpr/env_posix.cc
  89. 7
      src/core/lib/gpr/env_windows.cc
  90. 18
      src/core/lib/gpr/string.cc
  91. 6
      src/core/lib/gpr/string.h
  92. 41
      src/core/lib/gprpp/arena.cc
  93. 30
      src/core/lib/gprpp/arena.h
  94. 87
      src/core/lib/gprpp/global_config.h
  95. 29
      src/core/lib/gprpp/global_config_custom.h
  96. 135
      src/core/lib/gprpp/global_config_env.cc
  97. 131
      src/core/lib/gprpp/global_config_env.h
  98. 44
      src/core/lib/gprpp/global_config_generic.h
  99. 1
      src/core/lib/gprpp/optional.h
  100. 2
      src/core/lib/iomgr/combiner.h
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -115,6 +115,7 @@ bazel-genfiles
bazel-grpc
bazel-out
bazel-testlogs
bazel_format_virtual_environment/
# Debug output
gdb.txt

12
BUILD

@ -252,9 +252,11 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/security/auth_metadata_processor.h",
"include/grpcpp/security/auth_metadata_processor_impl.h",
"include/grpcpp/security/credentials.h",
"include/grpcpp/security/credentials_impl.h",
"include/grpcpp/security/server_credentials.h",
"include/grpcpp/security/server_credentials_impl.h",
"include/grpcpp/server.h",
"include/grpcpp/server_impl.h",
"include/grpcpp/server_builder.h",
"include/grpcpp/server_builder_impl.h",
"include/grpcpp/server_context.h",
@ -264,6 +266,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
@ -575,6 +578,7 @@ grpc_cc_library(
"src/core/lib/gpr/wrap_memcpy.cc",
"src/core/lib/gprpp/arena.cc",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/global_config_env.cc",
"src/core/lib/gprpp/thd_posix.cc",
"src/core/lib/gprpp/thd_windows.cc",
"src/core/lib/profiling/basic_timers.cc",
@ -601,6 +605,10 @@ grpc_cc_library(
"src/core/lib/gprpp/arena.h",
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",
"src/core/lib/gprpp/memory.h",
@ -1568,16 +1576,20 @@ grpc_cc_library(
srcs = [
"src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc",
],
hdrs = [
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h",
],
external_deps = [
"cares",

@ -184,6 +184,11 @@ config("grpc_config") {
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/fork.cc",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.cc",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",
"src/core/lib/gprpp/memory.h",
@ -310,11 +315,15 @@ config("grpc_config") {
"src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc",
"src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc",
"src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc",
@ -1096,18 +1105,21 @@ config("grpc_config") {
"include/grpcpp/security/auth_metadata_processor.h",
"include/grpcpp/security/auth_metadata_processor_impl.h",
"include/grpcpp/security/credentials.h",
"include/grpcpp/security/credentials_impl.h",
"include/grpcpp/security/server_credentials.h",
"include/grpcpp/security/server_credentials_impl.h",
"include/grpcpp/server.h",
"include/grpcpp/server_builder.h",
"include/grpcpp/server_builder_impl.h",
"include/grpcpp/server_context.h",
"include/grpcpp/server_impl.h",
"include/grpcpp/server_posix.h",
"include/grpcpp/server_posix_impl.h",
"include/grpcpp/support/async_stream.h",
"include/grpcpp/support/async_unary_call.h",
"include/grpcpp/support/byte_buffer.h",
"include/grpcpp/support/channel_arguments.h",
"include/grpcpp/support/channel_arguments_impl.h",
"include/grpcpp/support/client_callback.h",
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
@ -1170,6 +1182,10 @@ config("grpc_config") {
"src/core/lib/gprpp/atomic.h",
"src/core/lib/gprpp/debug_location.h",
"src/core/lib/gprpp/fork.h",
"src/core/lib/gprpp/global_config.h",
"src/core/lib/gprpp/global_config_custom.h",
"src/core/lib/gprpp/global_config_env.h",
"src/core/lib/gprpp/global_config_generic.h",
"src/core/lib/gprpp/inlined_vector.h",
"src/core/lib/gprpp/manual_constructor.h",
"src/core/lib/gprpp/map.h",

@ -638,6 +638,8 @@ add_dependencies(buildtests_cxx error_details_test)
add_dependencies(buildtests_cxx exception_test)
add_dependencies(buildtests_cxx filter_end2end_test)
add_dependencies(buildtests_cxx generic_end2end_test)
add_dependencies(buildtests_cxx global_config_env_test)
add_dependencies(buildtests_cxx global_config_test)
add_dependencies(buildtests_cxx golden_file_test)
add_dependencies(buildtests_cxx grpc_alts_credentials_options_test)
add_dependencies(buildtests_cxx grpc_cli)
@ -882,6 +884,7 @@ add_library(gpr
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/arena.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/profiling/basic_timers.cc
@ -1298,10 +1301,13 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@ -2691,10 +2697,13 @@ add_library(grpc_unsecure
src/core/ext/transport/inproc/inproc_transport.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@ -3124,18 +3133,21 @@ foreach(_hdr
include/grpcpp/security/auth_metadata_processor.h
include/grpcpp/security/auth_metadata_processor_impl.h
include/grpcpp/security/credentials.h
include/grpcpp/security/credentials_impl.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/server_credentials_impl.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_builder_impl.h
include/grpcpp/server_context.h
include/grpcpp/server_impl.h
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
@ -3735,18 +3747,21 @@ foreach(_hdr
include/grpcpp/security/auth_metadata_processor.h
include/grpcpp/security/auth_metadata_processor_impl.h
include/grpcpp/security/credentials.h
include/grpcpp/security/credentials_impl.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/server_credentials_impl.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_builder_impl.h
include/grpcpp/server_context.h
include/grpcpp/server_impl.h
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
@ -4718,18 +4733,21 @@ foreach(_hdr
include/grpcpp/security/auth_metadata_processor.h
include/grpcpp/security/auth_metadata_processor_impl.h
include/grpcpp/security/credentials.h
include/grpcpp/security/credentials_impl.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/server_credentials_impl.h
include/grpcpp/server.h
include/grpcpp/server_builder.h
include/grpcpp/server_builder_impl.h
include/grpcpp/server_context.h
include/grpcpp/server_impl.h
include/grpcpp/server_posix.h
include/grpcpp/server_posix_impl.h
include/grpcpp/support/async_stream.h
include/grpcpp/support/async_unary_call.h
include/grpcpp/support/byte_buffer.h
include/grpcpp/support/channel_arguments.h
include/grpcpp/support/channel_arguments_impl.h
include/grpcpp/support/client_callback.h
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
@ -13619,6 +13637,80 @@ target_link_libraries(generic_end2end_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(global_config_env_test
test/core/gprpp/global_config_env_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(global_config_env_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(global_config_env_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
grpc_test_util_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(global_config_test
test/core/gprpp/global_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(global_config_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR}
PRIVATE third_party/googletest/googletest/include
PRIVATE third_party/googletest/googletest
PRIVATE third_party/googletest/googlemock/include
PRIVATE third_party/googletest/googlemock
PRIVATE ${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(global_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
gpr
grpc_test_util_unsecure
${_gRPC_GFLAGS_LIBRARIES}
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

@ -1209,6 +1209,8 @@ error_details_test: $(BINDIR)/$(CONFIG)/error_details_test
exception_test: $(BINDIR)/$(CONFIG)/exception_test
filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
global_config_env_test: $(BINDIR)/$(CONFIG)/global_config_env_test
global_config_test: $(BINDIR)/$(CONFIG)/global_config_test
golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
grpc_alts_credentials_options_test: $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test
grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
@ -1688,6 +1690,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/exception_test \
$(BINDIR)/$(CONFIG)/filter_end2end_test \
$(BINDIR)/$(CONFIG)/generic_end2end_test \
$(BINDIR)/$(CONFIG)/global_config_env_test \
$(BINDIR)/$(CONFIG)/global_config_test \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
@ -1835,6 +1839,8 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/exception_test \
$(BINDIR)/$(CONFIG)/filter_end2end_test \
$(BINDIR)/$(CONFIG)/generic_end2end_test \
$(BINDIR)/$(CONFIG)/global_config_env_test \
$(BINDIR)/$(CONFIG)/global_config_test \
$(BINDIR)/$(CONFIG)/golden_file_test \
$(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \
$(BINDIR)/$(CONFIG)/grpc_cli \
@ -2333,6 +2339,10 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing generic_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing global_config_env_test"
$(Q) $(BINDIR)/$(CONFIG)/global_config_env_test || ( echo test global_config_env_test failed ; exit 1 )
$(E) "[RUN] Testing global_config_test"
$(Q) $(BINDIR)/$(CONFIG)/global_config_test || ( echo test global_config_test failed ; exit 1 )
$(E) "[RUN] Testing golden_file_test"
$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
$(E) "[RUN] Testing grpc_alts_credentials_options_test"
@ -3369,6 +3379,7 @@ LIBGPR_SRC = \
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/arena.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/global_config_env.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \
@ -3764,10 +3775,13 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
@ -5105,10 +5119,13 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/inproc/inproc_transport.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \
@ -5469,18 +5486,21 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/security/auth_metadata_processor.h \
include/grpcpp/security/auth_metadata_processor_impl.h \
include/grpcpp/security/credentials.h \
include/grpcpp/security/credentials_impl.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/server_credentials_impl.h \
include/grpcpp/server.h \
include/grpcpp/server_builder.h \
include/grpcpp/server_builder_impl.h \
include/grpcpp/server_context.h \
include/grpcpp/server_impl.h \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
@ -6088,18 +6108,21 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/security/auth_metadata_processor.h \
include/grpcpp/security/auth_metadata_processor_impl.h \
include/grpcpp/security/credentials.h \
include/grpcpp/security/credentials_impl.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/server_credentials_impl.h \
include/grpcpp/server.h \
include/grpcpp/server_builder.h \
include/grpcpp/server_builder_impl.h \
include/grpcpp/server_context.h \
include/grpcpp/server_impl.h \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
@ -7020,18 +7043,21 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/security/auth_metadata_processor.h \
include/grpcpp/security/auth_metadata_processor_impl.h \
include/grpcpp/security/credentials.h \
include/grpcpp/security/credentials_impl.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/server_credentials_impl.h \
include/grpcpp/server.h \
include/grpcpp/server_builder.h \
include/grpcpp/server_builder_impl.h \
include/grpcpp/server_context.h \
include/grpcpp/server_impl.h \
include/grpcpp/server_posix.h \
include/grpcpp/server_posix_impl.h \
include/grpcpp/support/async_stream.h \
include/grpcpp/support/async_unary_call.h \
include/grpcpp/support/byte_buffer.h \
include/grpcpp/support/channel_arguments.h \
include/grpcpp/support/channel_arguments_impl.h \
include/grpcpp/support/client_callback.h \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
@ -16587,6 +16613,92 @@ endif
endif
GLOBAL_CONFIG_ENV_TEST_SRC = \
test/core/gprpp/global_config_env_test.cc \
GLOBAL_CONFIG_ENV_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_ENV_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/global_config_env_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/global_config_env_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/global_config_env_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_env_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_env_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
deps_global_config_env_test: $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep)
endif
endif
GLOBAL_CONFIG_TEST_SRC = \
test/core/gprpp/global_config_test.cc \
GLOBAL_CONFIG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/global_config_test: openssl_dep_error
else
ifeq ($(NO_PROTOBUF),true)
# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+.
$(BINDIR)/$(CONFIG)/global_config_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/global_config_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
deps_global_config_test: $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep)
endif
endif
GOLDEN_FILE_TEST_SRC = \
$(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc \
test/cpp/codegen/golden_file_test.cc \

@ -18,13 +18,6 @@ register_toolchains(
"//third_party/toolchains/bazel_0.23.2_rbe_windows:cc-toolchain-x64_windows",
)
# TODO(https://github.com/grpc/grpc/issues/18331): Move off of this dependency.
git_repository(
name = "org_pubref_rules_protobuf",
remote = "https://github.com/ghostwriternr/rules_protobuf",
tag = "v0.8.2.1-alpha",
)
git_repository(
name = "io_bazel_rules_python",
commit = "8b5d0683a7d878b28fffe464779c8a53659fc645",

@ -4,81 +4,132 @@ This is an internal rule used by cc_grpc_library, and shouldn't be used
directly.
"""
def generate_cc_impl(ctx):
"""Implementation of the generate_cc rule."""
protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports]
outs = []
# label_len is length of the path from WORKSPACE root to the location of this build file
label_len = 0
# proto_root is the directory relative to which generated include paths should be
proto_root = ""
if ctx.label.package:
# The +1 is for the trailing slash.
label_len += len(ctx.label.package) + 1
if ctx.label.workspace_root:
label_len += len(ctx.label.workspace_root) + 1
proto_root = "/" + ctx.label.workspace_root
load(
"//bazel:protobuf.bzl",
"get_include_protoc_args",
"get_plugin_args",
"get_proto_root",
"proto_path_to_generated_filename",
)
_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h"
_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc"
_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h"
_PROTO_HEADER_FMT = "{}.pb.h"
_PROTO_SRC_FMT = "{}.pb.cc"
if ctx.executable.plugin:
outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos]
outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
if ctx.attr.generate_mocks:
outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos]
else:
outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos]
outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos]
out_files = [ctx.actions.declare_file(out) for out in outs]
dir_out = str(ctx.genfiles_dir.path + proto_root)
def _strip_package_from_path(label_package, path):
if len(label_package) == 0:
return path
if not path.startswith(label_package + "/"):
fail("'{}' does not lie within '{}'.".format(path, label_package))
return path[len(label_package + "/"):]
arguments = []
if ctx.executable.plugin:
arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
flags = list(ctx.attr.flags)
if ctx.attr.generate_mocks:
flags.append("generate_mock_code=true")
arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out]
tools = [ctx.executable.plugin]
else:
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
tools = []
def _join_directories(directories):
massaged_directories = [directory for directory in directories if len(directory) != 0]
return "/".join(massaged_directories)
# Import protos relative to their workspace root so that protoc prints the
# right include paths.
for include in includes:
directory = include.path
if directory.startswith("external"):
external_sep = directory.find("/")
repository_sep = directory.find("/", external_sep + 1)
arguments += ["--proto_path=" + directory[:repository_sep]]
def generate_cc_impl(ctx):
"""Implementation of the generate_cc rule."""
protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
includes = [
f
for src in ctx.attr.srcs
for f in src.proto.transitive_imports
]
outs = []
proto_root = get_proto_root(
ctx.label.workspace_root,
)
label_package = _join_directories([ctx.label.workspace_root, ctx.label.package])
if ctx.executable.plugin:
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_HEADER_FMT,
)
for proto in protos
]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_SRC_FMT,
)
for proto in protos
]
if ctx.attr.generate_mocks:
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_GRPC_PROTO_MOCK_HEADER_FMT,
)
for proto in protos
]
else:
arguments += ["--proto_path=."]
# Include the output directory so that protoc puts the generated code in the
# right directory.
arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
arguments += [proto.path for proto in protos]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_PROTO_HEADER_FMT,
)
for proto in protos
]
outs += [
proto_path_to_generated_filename(
_strip_package_from_path(label_package, proto.path),
_PROTO_SRC_FMT,
)
for proto in protos
]
out_files = [ctx.actions.declare_file(out) for out in outs]
dir_out = str(ctx.genfiles_dir.path + proto_root)
# create a list of well known proto files if the argument is non-None
well_known_proto_files = []
if ctx.attr.well_known_protos:
f = ctx.attr.well_known_protos.files.to_list()[0].dirname
if f != "external/com_google_protobuf/src/google/protobuf":
print("Error: Only @com_google_protobuf//:well_known_protos is supported")
arguments = []
if ctx.executable.plugin:
arguments += get_plugin_args(
ctx.executable.plugin,
ctx.attr.flags,
dir_out,
ctx.attr.generate_mocks,
)
tools = [ctx.executable.plugin]
else:
# f points to "external/com_google_protobuf/src/google/protobuf"
# add -I argument to protoc so it knows where to look for the proto files.
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = [f for f in ctx.attr.well_known_protos.files]
arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
tools = []
arguments += get_include_protoc_args(includes)
ctx.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,
)
# Include the output directory so that protoc puts the generated code in the
# right directory.
arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)]
arguments += [proto.path for proto in protos]
return struct(files=depset(out_files))
# create a list of well known proto files if the argument is non-None
well_known_proto_files = []
if ctx.attr.well_known_protos:
f = ctx.attr.well_known_protos.files.to_list()[0].dirname
if f != "external/com_google_protobuf/src/google/protobuf":
print(
"Error: Only @com_google_protobuf//:well_known_protos is supported",
)
else:
# f points to "external/com_google_protobuf/src/google/protobuf"
# add -I argument to protoc so it knows where to look for the proto files.
arguments += ["-I{0}".format(f + "/../..")]
well_known_proto_files = [
f
for f in ctx.attr.well_known_protos.files
]
ctx.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = ctx.executable._protoc,
arguments = arguments,
)
return struct(files = depset(out_files))
_generate_cc = rule(
attrs = {
@ -96,10 +147,8 @@ _generate_cc = rule(
mandatory = False,
allow_empty = True,
),
"well_known_protos" : attr.label(
mandatory = False,
),
"generate_mocks" : attr.bool(
"well_known_protos": attr.label(mandatory = False),
"generate_mocks": attr.bool(
default = False,
mandatory = False,
),
@ -115,7 +164,10 @@ _generate_cc = rule(
)
def generate_cc(well_known_protos, **kwargs):
if well_known_protos:
_generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs)
else:
_generate_cc(**kwargs)
if well_known_protos:
_generate_cc(
well_known_protos = "@com_google_protobuf//:well_known_protos",
**kwargs
)
else:
_generate_cc(**kwargs)

@ -1,16 +1,8 @@
load("//third_party/py:python_configure.bzl", "python_configure")
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories")
load("@grpc_python_dependencies//:requirements.bzl", "pip_install")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories")
def grpc_python_deps():
# TODO(https://github.com/grpc/grpc/issues/18256): Remove conditional.
if hasattr(native, "http_archive"):
python_configure(name = "local_config_python")
pip_repositories()
pip_install()
py_proto_repositories()
else:
print("Building Python gRPC with bazel 23.0+ is disabled pending " +
"resolution of https://github.com/grpc/grpc/issues/18256.")
python_configure(name = "local_config_python")
pip_repositories()
pip_install()

@ -0,0 +1,84 @@
"""Utility functions for generating protobuf code."""
_PROTO_EXTENSION = ".proto"
def get_proto_root(workspace_root):
"""Gets the root protobuf directory.
Args:
workspace_root: context.label.workspace_root
Returns:
The directory relative to which generated include paths should be.
"""
if workspace_root:
return "/{}".format(workspace_root)
else:
return ""
def _strip_proto_extension(proto_filename):
if not proto_filename.endswith(_PROTO_EXTENSION):
fail('"{}" does not end with "{}"'.format(
proto_filename,
_PROTO_EXTENSION,
))
return proto_filename[:-len(_PROTO_EXTENSION)]
def proto_path_to_generated_filename(proto_path, fmt_str):
"""Calculates the name of a generated file for a protobuf path.
For example, "examples/protos/helloworld.proto" might map to
"helloworld.pb.h".
Args:
proto_path: The path to the .proto file.
fmt_str: A format string used to calculate the generated filename. For
example, "{}.pb.h" might be used to calculate a C++ header filename.
Returns:
The generated filename.
"""
return fmt_str.format(_strip_proto_extension(proto_path))
def _get_include_directory(include):
directory = include.path
if directory.startswith("external"):
external_separator = directory.find("/")
repository_separator = directory.find("/", external_separator + 1)
return directory[:repository_separator]
else:
return "."
def get_include_protoc_args(includes):
"""Returns protoc args that imports protos relative to their import root.
Args:
includes: A list of included proto files.
Returns:
A list of arguments to be passed to protoc. For example, ["--proto_path=."].
"""
return [
"--proto_path={}".format(_get_include_directory(include))
for include in includes
]
def get_plugin_args(plugin, flags, dir_out, generate_mocks):
"""Returns arguments configuring protoc to use a plugin for a language.
Args:
plugin: An executable file to run as the protoc plugin.
flags: The plugin flags to be passed to protoc.
dir_out: The output directory for the plugin.
generate_mocks: A bool indicating whether to generate mocks.
Returns:
A list of protoc arguments configuring the plugin.
"""
augmented_flags = list(flags)
if generate_mocks:
augmented_flags.append("generate_mock_code=true")
return [
"--plugin=protoc-gen-PLUGIN=" + plugin.path,
"--PLUGIN_out=" + ",".join(augmented_flags) + ":" + dir_out,
]

@ -0,0 +1,203 @@
"""Generates and compiles Python gRPC stubs from proto_library rules."""
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load(
"//bazel:protobuf.bzl",
"get_include_protoc_args",
"get_plugin_args",
"get_proto_root",
"proto_path_to_generated_filename",
)
_GENERATED_PROTO_FORMAT = "{}_pb2.py"
_GENERATED_GRPC_PROTO_FORMAT = "{}_pb2_grpc.py"
def _get_staged_proto_file(context, source_file):
if source_file.dirname == context.label.package:
return source_file
else:
copied_proto = context.actions.declare_file(source_file.basename)
context.actions.run_shell(
inputs = [source_file],
outputs = [copied_proto],
command = "cp {} {}".format(source_file.path, copied_proto.path),
mnemonic = "CopySourceProto",
)
return copied_proto
def _generate_py_impl(context):
protos = []
for src in context.attr.deps:
for file in src.proto.direct_sources:
protos.append(_get_staged_proto_file(context, file))
includes = [
file
for src in context.attr.deps
for file in src.proto.transitive_imports
]
proto_root = get_proto_root(context.label.workspace_root)
format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT)
out_files = [
context.actions.declare_file(
proto_path_to_generated_filename(
proto.basename,
format_str,
),
)
for proto in protos
]
arguments = []
tools = [context.executable._protoc]
if context.executable.plugin:
arguments += get_plugin_args(
context.executable.plugin,
context.attr.flags,
context.genfiles_dir.path,
False,
)
tools += [context.executable.plugin]
else:
arguments += [
"--python_out={}:{}".format(
",".join(context.attr.flags),
context.genfiles_dir.path,
),
]
arguments += get_include_protoc_args(includes)
arguments += [
"--proto_path={}".format(context.genfiles_dir.path)
for proto in protos
]
for proto in protos:
massaged_path = proto.path
if massaged_path.startswith(context.genfiles_dir.path):
massaged_path = proto.path[len(context.genfiles_dir.path) + 1:]
arguments.append(massaged_path)
well_known_proto_files = []
if context.attr.well_known_protos:
well_known_proto_directory = context.attr.well_known_protos.files.to_list(
)[0].dirname
arguments += ["-I{}".format(well_known_proto_directory + "/../..")]
well_known_proto_files = context.attr.well_known_protos.files.to_list()
context.actions.run(
inputs = protos + includes + well_known_proto_files,
tools = tools,
outputs = out_files,
executable = context.executable._protoc,
arguments = arguments,
mnemonic = "ProtocInvocation",
)
return struct(files = depset(out_files))
__generate_py = rule(
attrs = {
"deps": attr.label_list(
mandatory = True,
allow_empty = False,
providers = ["proto"],
),
"plugin": attr.label(
executable = True,
providers = ["files_to_run"],
cfg = "host",
),
"flags": attr.string_list(
mandatory = False,
allow_empty = True,
),
"well_known_protos": attr.label(mandatory = False),
"_protoc": attr.label(
default = Label("//external:protocol_compiler"),
executable = True,
cfg = "host",
),
},
output_to_genfiles = True,
implementation = _generate_py_impl,
)
def _generate_py(well_known_protos, **kwargs):
if well_known_protos:
__generate_py(
well_known_protos = "@com_google_protobuf//:well_known_protos",
**kwargs
)
else:
__generate_py(**kwargs)
_WELL_KNOWN_PROTO_LIBS = [
"@com_google_protobuf//:any_proto",
"@com_google_protobuf//:api_proto",
"@com_google_protobuf//:compiler_plugin_proto",
"@com_google_protobuf//:descriptor_proto",
"@com_google_protobuf//:duration_proto",
"@com_google_protobuf//:empty_proto",
"@com_google_protobuf//:field_mask_proto",
"@com_google_protobuf//:source_context_proto",
"@com_google_protobuf//:struct_proto",
"@com_google_protobuf//:timestamp_proto",
"@com_google_protobuf//:type_proto",
"@com_google_protobuf//:wrappers_proto",
]
def py_proto_library(
name,
deps,
well_known_protos = True,
proto_only = False,
**kwargs):
"""Generate python code for a protobuf.
Args:
name: The name of the target.
deps: A list of dependencies. Must contain a single element.
well_known_protos: A bool indicating whether or not to include well-known
protos.
proto_only: A bool indicating whether to generate vanilla protobuf code
or to also generate gRPC code.
"""
if len(deps) > 1:
fail("The supported length of 'deps' is 1.")
codegen_target = "_{}_codegen".format(name)
codegen_grpc_target = "_{}_grpc_codegen".format(name)
well_known_proto_rules = _WELL_KNOWN_PROTO_LIBS if well_known_protos else []
_generate_py(
name = codegen_target,
deps = deps,
well_known_protos = well_known_protos,
**kwargs
)
if not proto_only:
_generate_py(
name = codegen_grpc_target,
deps = deps,
plugin = "//:grpc_python_plugin",
well_known_protos = well_known_protos,
**kwargs
)
native.py_library(
name = name,
srcs = [
":{}".format(codegen_grpc_target),
":{}".format(codegen_target),
],
deps = [requirement("protobuf")],
**kwargs
)
else:
native.py_library(
name = name,
srcs = [":{}".format(codegen_target), ":{}".format(codegen_target)],
deps = [requirement("protobuf")],
**kwargs
)

@ -148,6 +148,7 @@ filegroups:
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/arena.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/profiling/basic_timers.cc
@ -194,6 +195,10 @@ filegroups:
- src/core/lib/gprpp/arena.h
- src/core/lib/gprpp/atomic.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/map.h
- src/core/lib/gprpp/memory.h
@ -775,13 +780,17 @@ filegroups:
headers:
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h
src:
- src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc
plugin: grpc_resolver_dns_ares
@ -1376,18 +1385,21 @@ filegroups:
- include/grpcpp/security/auth_metadata_processor.h
- include/grpcpp/security/auth_metadata_processor_impl.h
- include/grpcpp/security/credentials.h
- include/grpcpp/security/credentials_impl.h
- include/grpcpp/security/server_credentials.h
- include/grpcpp/security/server_credentials_impl.h
- include/grpcpp/server.h
- include/grpcpp/server_builder.h
- include/grpcpp/server_builder_impl.h
- include/grpcpp/server_context.h
- include/grpcpp/server_impl.h
- include/grpcpp/server_posix.h
- include/grpcpp/server_posix_impl.h
- include/grpcpp/support/async_stream.h
- include/grpcpp/support/async_unary_call.h
- include/grpcpp/support/byte_buffer.h
- include/grpcpp/support/channel_arguments.h
- include/grpcpp/support/channel_arguments_impl.h
- include/grpcpp/support/client_callback.h
- include/grpcpp/support/client_interceptor.h
- include/grpcpp/support/config.h
@ -4814,6 +4826,24 @@ targets:
- grpc++
- grpc
- gpr
- name: global_config_env_test
build: test
language: c++
src:
- test/core/gprpp/global_config_env_test.cc
deps:
- gpr
- grpc_test_util_unsecure
uses_polling: false
- name: global_config_test
build: test
language: c++
src:
- test/core/gprpp/global_config_test.cc
deps:
- gpr
- grpc_test_util_unsecure
uses_polling: false
- name: golden_file_test
gtest: true
build: test

@ -79,6 +79,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/gpr/wrap_memcpy.cc \
src/core/lib/gprpp/arena.cc \
src/core/lib/gprpp/fork.cc \
src/core/lib/gprpp/global_config_env.cc \
src/core/lib/gprpp/thd_posix.cc \
src/core/lib/gprpp/thd_windows.cc \
src/core/lib/profiling/basic_timers.cc \
@ -402,10 +403,13 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \
src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \

@ -54,6 +54,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\gpr\\wrap_memcpy.cc " +
"src\\core\\lib\\gprpp\\arena.cc " +
"src\\core\\lib\\gprpp\\fork.cc " +
"src\\core\\lib\\gprpp\\global_config_env.cc " +
"src\\core\\lib\\gprpp\\thd_posix.cc " +
"src\\core\\lib\\gprpp\\thd_windows.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +
@ -377,10 +378,13 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_libuv.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_libuv.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_libuv_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_posix.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_windows.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.cc " +

@ -16,9 +16,8 @@ licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
load("//bazel:python_rules.bzl", "py_proto_library")
grpc_proto_library(
name = "auth_sample",
@ -45,11 +44,14 @@ grpc_proto_library(
srcs = ["protos/keyvaluestore.proto"],
)
proto_library(
name = "helloworld_proto_descriptor",
srcs = ["protos/helloworld.proto"],
)
py_proto_library(
name = "py_helloworld",
protos = ["protos/helloworld.proto"],
with_grpc = True,
deps = [requirement('protobuf'),],
deps = [":helloworld_proto_descriptor"],
)
cc_binary(

@ -20,8 +20,8 @@ import grpc
from grpc_status import rpc_status
from google.rpc import error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)

@ -24,8 +24,8 @@ from grpc_status import rpc_status
from google.protobuf import any_pb2
from google.rpc import code_pb2, status_pb2, error_details_pb2
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24

@ -26,7 +26,7 @@ import logging
import grpc
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2_grpc
from examples.python.errors import client as error_handling_client
from examples.python.errors import server as error_handling_server

@ -15,12 +15,17 @@
# limitations under the License.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library")
load("//bazel:python_rules.bzl", "py_proto_library")
py_proto_library(
proto_library(
name = "prime_proto",
protos = ["prime.proto",],
deps = [requirement("protobuf")],
srcs = ["prime.proto"]
)
py_proto_library(
name = "prime_proto_pb2",
deps = [":prime_proto"],
well_known_protos = False,
)
py_binary(
@ -29,7 +34,7 @@ py_binary(
srcs = ["client.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
":prime_proto",
":prime_proto_pb2",
],
default_python_version = "PY3",
)
@ -40,7 +45,7 @@ py_binary(
srcs = ["server.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
":prime_proto"
":prime_proto_pb2"
] + select({
"//conditions:default": [requirement("futures")],
"//:python3": [],

@ -22,8 +22,8 @@ import threading
import grpc
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
from examples import helloworld_pb2
from examples import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel(logging.INFO)
@ -33,10 +33,13 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
@contextmanager
def get_free_loopback_tcp_port():
tcp_socket = socket.socket(socket.AF_INET6)
if socket.has_ipv6:
tcp_socket = socket.socket(socket.AF_INET6)
else:
tcp_socket = socket.socket(socket.AF_INET)
tcp_socket.bind(('', 0))
address_tuple = tcp_socket.getsockname()
yield "[::1]:%s" % (address_tuple[1])
yield "localhost:%s" % (address_tuple[1])
tcp_socket.close()

@ -116,18 +116,21 @@ Pod::Spec.new do |s|
'include/grpcpp/security/auth_metadata_processor.h',
'include/grpcpp/security/auth_metadata_processor_impl.h',
'include/grpcpp/security/credentials.h',
'include/grpcpp/security/credentials_impl.h',
'include/grpcpp/security/server_credentials.h',
'include/grpcpp/security/server_credentials_impl.h',
'include/grpcpp/server.h',
'include/grpcpp/server_builder.h',
'include/grpcpp/server_builder_impl.h',
'include/grpcpp/server_context.h',
'include/grpcpp/server_impl.h',
'include/grpcpp/server_posix.h',
'include/grpcpp/server_posix_impl.h',
'include/grpcpp/support/async_stream.h',
'include/grpcpp/support/async_unary_call.h',
'include/grpcpp/support/byte_buffer.h',
'include/grpcpp/support/channel_arguments.h',
'include/grpcpp/support/channel_arguments_impl.h',
'include/grpcpp/support/client_callback.h',
'include/grpcpp/support/client_interceptor.h',
'include/grpcpp/support/config.h',
@ -267,6 +270,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -553,6 +560,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
@ -589,6 +597,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',

@ -208,6 +208,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -250,6 +254,7 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/arena.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/global_config_env.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',
@ -533,6 +538,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',
@ -854,10 +860,13 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
@ -890,6 +899,10 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic.h',
'src/core/lib/gprpp/fork.h',
'src/core/lib/gprpp/global_config.h',
'src/core/lib/gprpp/global_config_custom.h',
'src/core/lib/gprpp/global_config_env.h',
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/manual_constructor.h',
'src/core/lib/gprpp/map.h',
'src/core/lib/gprpp/memory.h',
@ -1176,6 +1189,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h',
'src/core/ext/filters/max_age/max_age_filter.h',
'src/core/ext/filters/message_size/message_size_filter.h',
'src/core/ext/filters/http/client_authority_filter.h',

@ -102,6 +102,10 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/arena.h )
s.files += %w( src/core/lib/gprpp/atomic.h )
s.files += %w( src/core/lib/gprpp/fork.h )
s.files += %w( src/core/lib/gprpp/global_config.h )
s.files += %w( src/core/lib/gprpp/global_config_custom.h )
s.files += %w( src/core/lib/gprpp/global_config_env.h )
s.files += %w( src/core/lib/gprpp/global_config_generic.h )
s.files += %w( src/core/lib/gprpp/manual_constructor.h )
s.files += %w( src/core/lib/gprpp/map.h )
s.files += %w( src/core/lib/gprpp/memory.h )
@ -144,6 +148,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gpr/wrap_memcpy.cc )
s.files += %w( src/core/lib/gprpp/arena.cc )
s.files += %w( src/core/lib/gprpp/fork.cc )
s.files += %w( src/core/lib/gprpp/global_config_env.cc )
s.files += %w( src/core/lib/gprpp/thd_posix.cc )
s.files += %w( src/core/lib/gprpp/thd_windows.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc )
@ -467,6 +472,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h )
s.files += %w( src/core/ext/filters/max_age/max_age_filter.h )
s.files += %w( src/core/ext/filters/message_size/message_size_filter.h )
s.files += %w( src/core/ext/filters/http/client_authority_filter.h )
@ -791,10 +797,13 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc )

@ -252,6 +252,7 @@
'src/core/lib/gpr/wrap_memcpy.cc',
'src/core/lib/gprpp/arena.cc',
'src/core/lib/gprpp/fork.cc',
'src/core/lib/gprpp/global_config_env.cc',
'src/core/lib/gprpp/thd_posix.cc',
'src/core/lib/gprpp/thd_windows.cc',
'src/core/lib/profiling/basic_timers.cc',
@ -584,10 +585,13 @@
'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',
@ -1341,10 +1345,13 @@
'src/core/ext/transport/inproc/inproc_transport.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc',
'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc',

@ -77,6 +77,7 @@
#define GPR_WINDOWS 1
#define GPR_WINDOWS_SUBPROCESS 1
#define GPR_WINDOWS_ENV
#define GPR_HAS_ALIGNED_MALLOC 1
#ifdef __MSYS__
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_MSYS_TMPFILE
@ -173,6 +174,7 @@
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_HAS_ALIGNED_ALLOC 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -238,6 +240,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_POSIX_MEMALIGN 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifndef GRPC_CFSTREAM

@ -32,6 +32,8 @@ typedef struct gpr_allocation_functions {
void* (*zalloc_fn)(size_t size); /** if NULL, uses malloc_fn then memset */
void* (*realloc_fn)(void* ptr, size_t size);
void (*free_fn)(void* ptr);
void* (*aligned_alloc_fn)(size_t size, size_t alignment);
void (*aligned_free_fn)(void* ptr);
} gpr_allocation_functions;
/** malloc.

@ -20,25 +20,27 @@
#define GRPCPP_CREATE_CHANNEL_H
#include <grpcpp/create_channel_impl.h>
#include <grpcpp/support/channel_arguments.h>
namespace grpc {
static inline std::shared_ptr<Channel> CreateChannel(
static inline std::shared_ptr<::grpc::Channel> CreateChannel(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds) {
return ::grpc_impl::CreateChannel(target, creds);
return ::grpc_impl::CreateChannelImpl(target, creds);
}
static inline std::shared_ptr<Channel> CreateCustomChannel(
static inline std::shared_ptr<::grpc::Channel> CreateCustomChannel(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args) {
return ::grpc_impl::CreateCustomChannel(target, creds, args);
return ::grpc_impl::CreateCustomChannelImpl(target, creds, args);
}
namespace experimental {
static inline std::shared_ptr<Channel> CreateCustomChannelWithInterceptors(
static inline std::shared_ptr<::grpc::Channel>
CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const ChannelArguments& args,

@ -35,9 +35,9 @@ namespace grpc_impl {
/// \param creds Credentials to use for the created channel. If it does not
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
std::shared_ptr<grpc::Channel> CreateChannel(
std::shared_ptr<::grpc::Channel> CreateChannelImpl(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds);
const std::shared_ptr<::grpc::ChannelCredentials>& creds);
/// Create a new \em custom \a Channel pointing to \a target.
///
@ -49,10 +49,10 @@ std::shared_ptr<grpc::Channel> CreateChannel(
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
/// \param args Options for channel creation.
std::shared_ptr<grpc::Channel> CreateCustomChannel(
std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const grpc::ChannelArguments& args);
const std::shared_ptr<::grpc::ChannelCredentials>& creds,
const ::grpc::ChannelArguments& args);
namespace experimental {
/// Create a new \em custom \a Channel pointing to \a target with \a
@ -66,10 +66,10 @@ namespace experimental {
/// hold an object or is invalid, a lame channel (one on which all operations
/// fail) is returned.
/// \param args Options for channel creation.
std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
std::shared_ptr<::grpc::Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const grpc::ChannelArguments& args,
const ::grpc::ChannelArguments& args,
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);

@ -39,7 +39,7 @@ class GenericServerContext final : public ServerContext {
const grpc::string& host() const { return host_; }
private:
friend class Server;
friend class grpc_impl::Server;
friend class ServerInterface;
void Clear() {
@ -79,8 +79,8 @@ class AsyncGenericService final {
ServerCompletionQueue* notification_cq, void* tag);
private:
friend class Server;
Server* server_;
friend class grpc_impl::Server;
grpc_impl::Server* server_;
};
namespace experimental {
@ -135,14 +135,14 @@ class CallbackGenericService {
}
private:
friend class ::grpc::Server;
friend class ::grpc_impl::Server;
internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>* Handler() {
return new internal::CallbackBidiHandler<ByteBuffer, ByteBuffer>(
[this] { return CreateReactor(); });
}
Server* server_{nullptr};
grpc_impl::Server* server_{nullptr};
};
} // namespace experimental
} // namespace grpc

@ -1099,7 +1099,7 @@ class ServerAsyncReaderWriter final
}
private:
friend class ::grpc::Server;
friend class ::grpc_impl::Server;
void BindCall(::grpc::internal::Call* call) override { call_ = *call; }

@ -174,6 +174,8 @@ class ClientCallbackUnary {
// StartWrite, or AddHold operations on the streaming object. Note that none of
// the classes are pure; all reactions have a default empty reaction so that the
// user class only needs to override those classes that it cares about.
// The reactor must be passed to the stub invocation before any of the below
// operations can be called.
/// \a ClientBidiReactor is the interface for a bidirectional streaming RPC.
template <class Request, class Response>

@ -57,12 +57,15 @@
struct census_context;
struct grpc_call;
namespace grpc_impl {
class CallCredentials;
} // namespace grpc_impl
namespace grpc {
class Channel;
class ChannelInterface;
class CompletionQueue;
class CallCredentials;
class ClientContext;
namespace internal {
@ -306,7 +309,8 @@ class ClientContext {
/// call.
///
/// \see https://grpc.io/docs/guides/auth.html
void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
void set_credentials(
const std::shared_ptr<grpc_impl::CallCredentials>& creds) {
creds_ = creds;
}
@ -465,7 +469,7 @@ class ClientContext {
bool call_canceled_;
gpr_timespec deadline_;
grpc::string authority_;
std::shared_ptr<CallCredentials> creds_;
std::shared_ptr<grpc_impl::CallCredentials> creds_;
mutable std::shared_ptr<const AuthContext> auth_context_;
struct census_context* census_context_;
std::multimap<grpc::string, grpc::string> send_initial_metadata_;

@ -43,8 +43,9 @@ struct grpc_completion_queue;
namespace grpc_impl {
class Server;
class ServerBuilder;
}
} // namespace grpc_impl
namespace grpc {
template <class R>
@ -66,7 +67,6 @@ class Channel;
class ChannelInterface;
class ClientContext;
class CompletionQueue;
class Server;
class ServerContext;
class ServerInterface;
@ -274,7 +274,7 @@ class CompletionQueue : private GrpcLibraryCodegen {
friend class ::grpc::internal::TemplatedBidiStreamingHandler;
template <StatusCode code>
friend class ::grpc::internal::ErrorMethodHandler;
friend class ::grpc::Server;
friend class ::grpc_impl::Server;
friend class ::grpc::ServerContext;
friend class ::grpc::ServerInterface;
template <class InputMessage, class OutputMessage>
@ -408,8 +408,8 @@ class ServerCompletionQueue : public CompletionQueue {
polling_type_(polling_type) {}
grpc_cq_polling_type polling_type_;
friend class ::grpc_impl::ServerBuilder;
friend class Server;
friend class grpc_impl::ServerBuilder;
friend class grpc_impl::Server;
};
} // namespace grpc

@ -41,11 +41,14 @@ struct grpc_metadata;
struct grpc_call;
struct census_context;
namespace grpc_impl {
class Server;
} // namespace grpc_impl
namespace grpc {
class ClientContext;
class GenericServerContext;
class CompletionQueue;
class Server;
class ServerInterface;
template <class W, class R>
class ServerAsyncReader;
@ -269,7 +272,7 @@ class ServerContext {
friend class ::grpc::testing::InteropServerContextInspector;
friend class ::grpc::testing::ServerContextTestSpouse;
friend class ::grpc::ServerInterface;
friend class ::grpc::Server;
friend class ::grpc_impl::Server;
template <class W, class R>
friend class ::grpc::ServerAsyncReader;
template <class W>

@ -26,10 +26,13 @@
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/codegen/status.h>
namespace grpc_impl {
class Server;
} // namespace grpc_impl
namespace grpc {
class CompletionQueue;
class Server;
class ServerInterface;
class ServerCompletionQueue;
class ServerContext;
@ -233,7 +236,7 @@ class Service {
}
private:
friend class Server;
friend class grpc_impl::Server;
friend class ServerInterface;
ServerInterface* server_;
std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;

@ -25,13 +25,12 @@
namespace grpc_impl {
class ChannelArguments;
class ServerBuilder;
class ServerInitializer;
} // namespace grpc_impl
namespace grpc {
class ChannelArguments;
/// This interface is meant for internal usage only. Implementations of this
/// interface should add themselves to a \a ServerBuilder instance through the
/// \a InternalAddPluginFactory method.
@ -58,7 +57,7 @@ class ServerBuilderPlugin {
/// UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(),
/// before the Server instance is created.
virtual void UpdateChannelArguments(ChannelArguments* args) {}
virtual void UpdateChannelArguments(grpc_impl::ChannelArguments* args) {}
virtual bool has_sync_methods() const { return false; }
virtual bool has_async_methods() const { return false; }

@ -26,10 +26,10 @@
namespace grpc {
class Server;
class Service;
} // namespace grpc
namespace grpc_impl {
class Server;
class ServerInitializer {
public:

@ -19,265 +19,104 @@
#ifndef GRPCPP_SECURITY_CREDENTIALS_H
#define GRPCPP_SECURITY_CREDENTIALS_H
#include <map>
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/string_ref.h>
struct grpc_call;
#include <grpcpp/security/credentials_impl.h>
namespace grpc {
class CallCredentials;
class ChannelArguments;
class ChannelCredentials;
} // namespace grpc
namespace grpc_impl {
std::shared_ptr<grpc::Channel> CreateCustomChannel(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const grpc::ChannelArguments& args);
namespace experimental {
std::shared_ptr<grpc::Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<grpc::ChannelCredentials>& creds,
const grpc::ChannelArguments& args,
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
} // namespace experimental
} // namespace grpc_impl
namespace grpc {
class Channel;
class SecureChannelCredentials;
class SecureCallCredentials;
/// A channel credentials object encapsulates all the state needed by a client
/// to authenticate with a server for a given channel.
/// It can make various assertions, e.g., about the client’s identity, role
/// for all the calls on that channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class ChannelCredentials : private GrpcLibraryCodegen {
public:
ChannelCredentials();
~ChannelCredentials();
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
virtual SecureChannelCredentials* AsSecureCredentials() = 0;
private:
friend std::shared_ptr<Channel> grpc_impl::CreateCustomChannel(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args);
friend std::shared_ptr<Channel>
grpc_impl::experimental::CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
virtual std::shared_ptr<Channel> CreateChannel(
const grpc::string& target, const ChannelArguments& args) = 0;
// This function should have been a pure virtual function, but it is
// implemented as a virtual function so that it does not break API.
virtual std::shared_ptr<Channel> CreateChannelWithInterceptors(
const grpc::string& /* target */, const ChannelArguments& /* args */,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
/* interceptor_creators */) {
return nullptr;
}
};
/// A call credentials object encapsulates the state needed by a client to
/// authenticate with a server for a given call on a channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class CallCredentials : private GrpcLibraryCodegen {
public:
CallCredentials();
~CallCredentials();
/// Apply this instance's credentials to \a call.
virtual bool ApplyToCall(grpc_call* call) = 0;
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
typedef ::grpc_impl::ChannelCredentials ChannelCredentials;
typedef ::grpc_impl::CallCredentials CallCredentials;
typedef ::grpc_impl::SslCredentialsOptions SslCredentialsOptions;
typedef ::grpc_impl::SecureCallCredentials SecureCallCredentials;
typedef ::grpc_impl::SecureChannelCredentials SecureChannelCredentials;
friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
static inline std::shared_ptr<grpc_impl::ChannelCredentials>
GoogleDefaultCredentials() {
return ::grpc_impl::GoogleDefaultCredentials();
}
virtual SecureCallCredentials* AsSecureCredentials() = 0;
};
static inline std::shared_ptr<ChannelCredentials> SslCredentials(
const SslCredentialsOptions& options) {
return ::grpc_impl::SslCredentials(options);
}
/// Options used to build SslCredentials.
struct SslCredentialsOptions {
/// The buffer containing the PEM encoding of the server root certificates. If
/// this parameter is empty, the default roots will be used. The default
/// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
/// environment variable pointing to a file on the file system containing the
/// roots.
grpc::string pem_root_certs;
/// The buffer containing the PEM encoding of the client's private key. This
/// parameter can be empty if the client does not have a private key.
grpc::string pem_private_key;
/// The buffer containing the PEM encoding of the client's certificate chain.
/// This parameter can be empty if the client does not have a certificate
/// chain.
grpc::string pem_cert_chain;
};
// Factories for building different types of Credentials The functions may
// return empty shared_ptr when credentials cannot be created. If a
// Credentials pointer is returned, it can still be invalid when used to create
// a channel. A lame channel will be created then and all rpcs will fail on it.
/// Builds credentials with reasonable defaults.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
/// Builds SSL Credentials given SSL specific options
std::shared_ptr<ChannelCredentials> SslCredentials(
const SslCredentialsOptions& options);
/// Builds credentials for use when running in GCE
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
static inline std::shared_ptr<grpc_impl::CallCredentials>
GoogleComputeEngineCredentials() {
return ::grpc_impl::GoogleComputeEngineCredentials();
}
/// Constant for maximum auth token lifetime.
constexpr long kMaxAuthTokenLifetimeSecs = 3600;
constexpr long kMaxAuthTokenLifetimeSecs =
::grpc_impl::kMaxAuthTokenLifetimeSecs;
/// Builds Service Account JWT Access credentials.
/// json_key is the JSON key string containing the client's private key.
/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
/// (JWT) created with this credentials. It should not exceed
/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
static inline std::shared_ptr<grpc_impl::CallCredentials>
ServiceAccountJWTAccessCredentials(
const grpc::string& json_key,
long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs);
/// Builds refresh token credentials.
/// json_refresh_token is the JSON string containing the refresh token along
/// with a client_id and client_secret.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
const grpc::string& json_refresh_token);
/// Builds access token credentials.
/// access_token is an oauth2 access token that was fetched using an out of band
/// mechanism.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> AccessTokenCredentials(
const grpc::string& access_token);
/// Builds IAM credentials.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleIAMCredentials(
long token_lifetime_seconds = grpc::kMaxAuthTokenLifetimeSecs) {
return ::grpc_impl::ServiceAccountJWTAccessCredentials(
json_key, token_lifetime_seconds);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
GoogleRefreshTokenCredentials(const grpc::string& json_refresh_token) {
return ::grpc_impl::GoogleRefreshTokenCredentials(json_refresh_token);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
AccessTokenCredentials(const grpc::string& access_token) {
return ::grpc_impl::AccessTokenCredentials(access_token);
}
static inline std::shared_ptr<grpc_impl::CallCredentials> GoogleIAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector);
const grpc::string& authority_selector) {
return ::grpc_impl::GoogleIAMCredentials(authorization_token,
authority_selector);
}
/// Combines a channel credentials and a call credentials into a composite
/// channel credentials.
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
static inline std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
/// Combines two call credentials objects into a composite call credentials.
std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
/// Credentials for an unencrypted, unauthenticated channel
std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
/// Credentials for a channel using Cronet.
std::shared_ptr<ChannelCredentials> CronetChannelCredentials(void* engine);
/// User defined metadata credentials.
class MetadataCredentialsPlugin {
public:
virtual ~MetadataCredentialsPlugin() {}
/// If this method returns true, the Process function will be scheduled in
/// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
/// Type of credentials this plugin is implementing.
virtual const char* GetType() const { return ""; }
/// Gets the auth metatada produced by this plugin.
/// The fully qualified method name is:
/// service_url + "/" + method_name.
/// The channel_auth_context contains (among other things), the identity of
/// the server.
virtual Status GetMetadata(
grpc::string_ref service_url, grpc::string_ref method_name,
const AuthContext& channel_auth_context,
std::multimap<grpc::string, grpc::string>* metadata) = 0;
};
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
const std::shared_ptr<CallCredentials>& call_creds) {
return ::grpc_impl::CompositeChannelCredentials(channel_creds, call_creds);
}
static inline std::shared_ptr<grpc_impl::CallCredentials>
CompositeCallCredentials(const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2) {
return ::grpc_impl::CompositeCallCredentials(creds1, creds2);
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials>
InsecureChannelCredentials() {
return ::grpc_impl::InsecureChannelCredentials();
}
static inline std::shared_ptr<grpc_impl::ChannelCredentials>
CronetChannelCredentials(void* engine) {
return ::grpc_impl::CronetChannelCredentials(engine);
}
typedef ::grpc_impl::MetadataCredentialsPlugin MetadataCredentialsPlugin;
static inline std::shared_ptr<grpc_impl::CallCredentials>
MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin) {
return ::grpc_impl::MetadataCredentialsFromPlugin(std::move(plugin));
}
namespace experimental {
/// Options used to build AltsCredentials.
struct AltsCredentialsOptions {
/// service accounts of target endpoint that will be acceptable
/// by the client. If service accounts are provided and none of them matches
/// that of the server, authentication will fail.
std::vector<grpc::string> target_service_accounts;
};
typedef ::grpc_impl::experimental::AltsCredentialsOptions
AltsCredentialsOptions;
/// Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options);
static inline std::shared_ptr<grpc_impl::ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options) {
return ::grpc_impl::experimental::AltsCredentials(options);
}
/// Builds Local Credentials.
std::shared_ptr<ChannelCredentials> LocalCredentials(
grpc_local_connect_type type);
static inline std::shared_ptr<grpc_impl::ChannelCredentials> LocalCredentials(
grpc_local_connect_type type) {
return ::grpc_impl::experimental::LocalCredentials(type);
}
} // namespace experimental
} // namespace grpc

@ -0,0 +1,281 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SECURITY_CREDENTIALS_IMPL_H
#define GRPCPP_SECURITY_CREDENTIALS_IMPL_H
#include <map>
#include <memory>
#include <vector>
#include <grpc/grpc_security_constants.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/security/auth_context.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/status.h>
#include <grpcpp/support/string_ref.h>
struct grpc_call;
namespace grpc_impl {
class Channel;
class ChannelCredentials;
class CallCredentials;
class SecureCallCredentials;
class SecureChannelCredentials;
std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args);
namespace experimental {
std::shared_ptr<::grpc::Channel> CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args,
std::vector<
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
}
/// A channel credentials object encapsulates all the state needed by a client
/// to authenticate with a server for a given channel.
/// It can make various assertions, e.g., about the client’s identity, role
/// for all the calls on that channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class ChannelCredentials : private grpc::GrpcLibraryCodegen {
public:
ChannelCredentials();
~ChannelCredentials();
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
virtual SecureChannelCredentials* AsSecureCredentials() = 0;
private:
friend std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args);
friend std::shared_ptr<::grpc::Channel>
grpc_impl::experimental::CreateCustomChannelWithInterceptors(
const grpc::string& target,
const std::shared_ptr<ChannelCredentials>& creds,
const grpc::ChannelArguments& args,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
virtual std::shared_ptr<::grpc::Channel> CreateChannelImpl(
const grpc::string& target, const grpc::ChannelArguments& args) = 0;
// This function should have been a pure virtual function, but it is
// implemented as a virtual function so that it does not break API.
virtual std::shared_ptr<::grpc::Channel> CreateChannelWithInterceptors(
const grpc::string& target, const grpc::ChannelArguments& args,
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
return nullptr;
}
};
/// A call credentials object encapsulates the state needed by a client to
/// authenticate with a server for a given call on a channel.
///
/// \see https://grpc.io/docs/guides/auth.html
class CallCredentials : private grpc::GrpcLibraryCodegen {
public:
CallCredentials();
~CallCredentials();
/// Apply this instance's credentials to \a call.
virtual bool ApplyToCall(grpc_call* call) = 0;
protected:
friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
virtual SecureCallCredentials* AsSecureCredentials() = 0;
};
/// Options used to build SslCredentials.
struct SslCredentialsOptions {
/// The buffer containing the PEM encoding of the server root certificates. If
/// this parameter is empty, the default roots will be used. The default
/// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH
/// environment variable pointing to a file on the file system containing the
/// roots.
grpc::string pem_root_certs;
/// The buffer containing the PEM encoding of the client's private key. This
/// parameter can be empty if the client does not have a private key.
grpc::string pem_private_key;
/// The buffer containing the PEM encoding of the client's certificate chain.
/// This parameter can be empty if the client does not have a certificate
/// chain.
grpc::string pem_cert_chain;
};
// Factories for building different types of Credentials The functions may
// return empty shared_ptr when credentials cannot be created. If a
// Credentials pointer is returned, it can still be invalid when used to create
// a channel. A lame channel will be created then and all rpcs will fail on it.
/// Builds credentials with reasonable defaults.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
/// Builds SSL Credentials given SSL specific options
std::shared_ptr<ChannelCredentials> SslCredentials(
const SslCredentialsOptions& options);
/// Builds credentials for use when running in GCE
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
constexpr long kMaxAuthTokenLifetimeSecs = 3600;
/// Builds Service Account JWT Access credentials.
/// json_key is the JSON key string containing the client's private key.
/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
/// (JWT) created with this credentials. It should not exceed
/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
const grpc::string& json_key,
long token_lifetime_seconds = grpc_impl::kMaxAuthTokenLifetimeSecs);
/// Builds refresh token credentials.
/// json_refresh_token is the JSON string containing the refresh token along
/// with a client_id and client_secret.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
const grpc::string& json_refresh_token);
/// Builds access token credentials.
/// access_token is an oauth2 access token that was fetched using an out of band
/// mechanism.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> AccessTokenCredentials(
const grpc::string& access_token);
/// Builds IAM credentials.
///
/// \warning Only use these credentials when connecting to a Google endpoint.
/// Using these credentials to connect to any other service may result in this
/// service being able to impersonate your client for requests to Google
/// services.
std::shared_ptr<CallCredentials> GoogleIAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector);
/// Combines a channel credentials and a call credentials into a composite
/// channel credentials.
std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
const std::shared_ptr<ChannelCredentials>& channel_creds,
const std::shared_ptr<CallCredentials>& call_creds);
/// Combines two call credentials objects into a composite call credentials.
std::shared_ptr<CallCredentials> CompositeCallCredentials(
const std::shared_ptr<CallCredentials>& creds1,
const std::shared_ptr<CallCredentials>& creds2);
/// Credentials for an unencrypted, unauthenticated channel
std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
/// Credentials for a channel using Cronet.
std::shared_ptr<ChannelCredentials> CronetChannelCredentials(void* engine);
/// User defined metadata credentials.
class MetadataCredentialsPlugin {
public:
virtual ~MetadataCredentialsPlugin() {}
/// If this method returns true, the Process function will be scheduled in
/// a different thread from the one processing the call.
virtual bool IsBlocking() const { return true; }
/// Type of credentials this plugin is implementing.
virtual const char* GetType() const { return ""; }
/// Gets the auth metatada produced by this plugin.
/// The fully qualified method name is:
/// service_url + "/" + method_name.
/// The channel_auth_context contains (among other things), the identity of
/// the server.
virtual grpc::Status GetMetadata(
grpc::string_ref service_url, grpc::string_ref method_name,
const grpc::AuthContext& channel_auth_context,
std::multimap<grpc::string, grpc::string>* metadata) = 0;
};
std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
std::unique_ptr<MetadataCredentialsPlugin> plugin);
namespace experimental {
/// Options used to build AltsCredentials.
struct AltsCredentialsOptions {
/// service accounts of target endpoint that will be acceptable
/// by the client. If service accounts are provided and none of them matches
/// that of the server, authentication will fail.
std::vector<grpc::string> target_service_accounts;
};
/// Builds ALTS Credentials given ALTS specific options
std::shared_ptr<ChannelCredentials> AltsCredentials(
const AltsCredentialsOptions& options);
/// Builds Local Credentials.
std::shared_ptr<ChannelCredentials> LocalCredentials(
grpc_local_connect_type type);
} // namespace experimental
} // namespace grpc_impl
#endif // GRPCPP_SECURITY_CREDENTIALS_IMPL_H

@ -21,6 +21,10 @@
#include <grpcpp/security/server_credentials_impl.h>
namespace grpc_impl {
class Server;
} // namespace grpc_impl
namespace grpc {
typedef ::grpc_impl::ServerCredentials ServerCredentials;

@ -30,10 +30,10 @@ struct grpc_server;
namespace grpc {
class Server;
struct SslServerCredentialsOptions;
} // namespace grpc
namespace grpc_impl {
class Server;
/// Wrapper around \a grpc_server_credentials, a way to authenticate a server.
class ServerCredentials {
@ -46,7 +46,7 @@ class ServerCredentials {
const std::shared_ptr<grpc::AuthMetadataProcessor>& processor) = 0;
private:
friend class ::grpc::Server;
friend class ::grpc_impl::Server;
/// Tries to bind \a server to the given \a addr (eg, localhost:1234,
/// 192.168.1.1:31416, [::1]:27182, etc.)

@ -1,6 +1,6 @@
/*
*
* Copyright 2015 gRPC authors.
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,333 +19,11 @@
#ifndef GRPCPP_SERVER_H
#define GRPCPP_SERVER_H
#include <condition_variable>
#include <list>
#include <memory>
#include <mutex>
#include <vector>
#include <grpcpp/server_impl.h>
#include <grpc/compression.h>
#include <grpc/support/atm.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/rpc_service_method.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/support/channel_arguments.h>
#include <grpcpp/support/config.h>
#include <grpcpp/support/status.h>
struct grpc_server;
namespace grpc_impl {
class ServerInitializer;
}
namespace grpc {
class AsyncGenericService;
class ServerContext;
/// Represents a gRPC server.
///
/// Use a \a grpc::ServerBuilder to create, configure, and start
/// \a Server instances.
class Server : public ServerInterface, private GrpcLibraryCodegen {
public:
~Server();
/// Block until the server shuts down.
///
/// \warning The server must be either shutting down or some other thread must
/// call \a Shutdown for this function to ever return.
void Wait() override;
/// Global callbacks are a set of hooks that are called when server
/// events occur. \a SetGlobalCallbacks method is used to register
/// the hooks with gRPC. Note that
/// the \a GlobalCallbacks instance will be shared among all
/// \a Server instances in an application and can be set exactly
/// once per application.
class GlobalCallbacks {
public:
virtual ~GlobalCallbacks() {}
/// Called before server is created.
virtual void UpdateArguments(ChannelArguments* args) {}
/// Called before application callback for each synchronous server request
virtual void PreSynchronousRequest(ServerContext* context) = 0;
/// Called after application callback for each synchronous server request
virtual void PostSynchronousRequest(ServerContext* context) = 0;
/// Called before server is started.
virtual void PreServerStart(Server* server) {}
/// Called after a server port is added.
virtual void AddPort(Server* server, const grpc::string& addr,
ServerCredentials* creds, int port) {}
};
/// Set the global callback object. Can only be called once per application.
/// Does not take ownership of callbacks, and expects the pointed to object
/// to be alive until all server objects in the process have been destroyed.
/// The same \a GlobalCallbacks object will be used throughout the
/// application and is shared among all \a Server objects.
static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
/// Returns a \em raw pointer to the underlying \a grpc_server instance.
/// EXPERIMENTAL: for internal/test use only
grpc_server* c_server();
/// Returns the health check service.
HealthCheckServiceInterface* GetHealthCheckService() const {
return health_check_service_.get();
}
/// Establish a channel for in-process communication
std::shared_ptr<Channel> InProcessChannel(const ChannelArguments& args);
/// NOTE: class experimental_type is not part of the public API of this class.
/// TODO(yashykt): Integrate into public API when this is no longer
/// experimental.
class experimental_type {
public:
explicit experimental_type(Server* server) : server_(server) {}
/// Establish a channel for in-process communication with client
/// interceptors
std::shared_ptr<Channel> InProcessChannelWithInterceptors(
const ChannelArguments& args,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators);
private:
Server* server_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
/// to the experimental components of this class. It may be changed or removed
/// at any time.
experimental_type experimental() { return experimental_type(this); }
protected:
/// Register a service. This call does not take ownership of the service.
/// The service must exist for the lifetime of the Server instance.
bool RegisterService(const grpc::string* host, Service* service) override;
/// Try binding the server to the given \a addr endpoint
/// (port, and optionally including IP address to bind to).
///
/// It can be invoked multiple times. Should be used before
/// starting the server.
///
/// \param addr The address to try to bind to the server (eg, localhost:1234,
/// 192.168.1.1:31416, [::1]:27182, etc.).
/// \param creds The credentials associated with the server.
///
/// \return bound port number on success, 0 on failure.
///
/// \warning It is an error to call this method on an already started server.
int AddListeningPort(const grpc::string& addr,
ServerCredentials* creds) override;
/// NOTE: This is *NOT* a public API. The server constructors are supposed to
/// be used by \a ServerBuilder class only. The constructor will be made
/// 'private' very soon.
///
/// Server constructors. To be used by \a ServerBuilder only.
///
/// \param max_message_size Maximum message length that the channel can
/// receive.
///
/// \param args The channel args
///
/// \param sync_server_cqs The completion queues to use if the server is a
/// synchronous server (or a hybrid server). The server polls for new RPCs on
/// these queues
///
/// \param min_pollers The minimum number of polling threads per server
/// completion queue (in param sync_server_cqs) to use for listening to
/// incoming requests (used only in case of sync server)
///
/// \param max_pollers The maximum number of polling threads per server
/// completion queue (in param sync_server_cqs) to use for listening to
/// incoming requests (used only in case of sync server)
///
/// \param sync_cq_timeout_msec The timeout to use when calling AsyncNext() on
/// server completion queues passed via sync_server_cqs param.
Server(int max_message_size, ChannelArguments* args,
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs,
int min_pollers, int max_pollers, int sync_cq_timeout_msec,
grpc_resource_quota* server_rq = nullptr,
std::vector<
std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
interceptor_creators = std::vector<std::unique_ptr<
experimental::ServerInterceptorFactoryInterface>>());
/// Start the server.
///
/// \param cqs Completion queues for handling asynchronous services. The
/// caller is required to keep all completion queues live until the server is
/// destroyed.
/// \param num_cqs How many completion queues does \a cqs hold.
void Start(ServerCompletionQueue** cqs, size_t num_cqs) override;
grpc_server* server() override { return server_; }
private:
std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>*
interceptor_creators() override {
return &interceptor_creators_;
}
friend class AsyncGenericService;
friend class grpc_impl::ServerBuilder;
friend class grpc_impl::ServerInitializer;
class SyncRequest;
class CallbackRequestBase;
template <class ServerContextType>
class CallbackRequest;
class UnimplementedAsyncRequest;
class UnimplementedAsyncResponse;
/// SyncRequestThreadManager is an implementation of ThreadManager. This class
/// is responsible for polling for incoming RPCs and calling the RPC handlers.
/// This is only used in case of a Sync server (i.e a server exposing a sync
/// interface)
class SyncRequestThreadManager;
/// Register a generic service. This call does not take ownership of the
/// service. The service must exist for the lifetime of the Server instance.
void RegisterAsyncGenericService(AsyncGenericService* service) override;
/// NOTE: class experimental_registration_type is not part of the public API
/// of this class
/// TODO(vjpai): Move these contents to the public API of Server when
/// they are no longer experimental
class experimental_registration_type final
: public experimental_registration_interface {
public:
explicit experimental_registration_type(Server* server) : server_(server) {}
void RegisterCallbackGenericService(
experimental::CallbackGenericService* service) override {
server_->RegisterCallbackGenericService(service);
}
private:
Server* server_;
};
/// TODO(vjpai): Mark this override when experimental type above is deleted
void RegisterCallbackGenericService(
experimental::CallbackGenericService* service);
/// NOTE: The function experimental_registration() is not stable public API.
/// It is a view to the experimental components of this class. It may be
/// changed or removed at any time.
experimental_registration_interface* experimental_registration() override {
return &experimental_registration_;
}
void PerformOpsOnCall(internal::CallOpSetInterface* ops,
internal::Call* call) override;
void ShutdownInternal(gpr_timespec deadline) override;
int max_receive_message_size() const override {
return max_receive_message_size_;
}
CompletionQueue* CallbackCQ() override;
grpc_impl::ServerInitializer* initializer();
// A vector of interceptor factory objects.
// This should be destroyed after health_check_service_ and this requirement
// is satisfied by declaring interceptor_creators_ before
// health_check_service_. (C++ mandates that member objects be destroyed in
// the reverse order of initialization.)
std::vector<std::unique_ptr<experimental::ServerInterceptorFactoryInterface>>
interceptor_creators_;
const int max_receive_message_size_;
/// The following completion queues are ONLY used in case of Sync API
/// i.e. if the server has any services with sync methods. The server uses
/// these completion queues to poll for new RPCs
std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
sync_server_cqs_;
/// List of \a ThreadManager instances (one for each cq in
/// the \a sync_server_cqs)
std::vector<std::unique_ptr<SyncRequestThreadManager>> sync_req_mgrs_;
// Outstanding unmatched callback requests, indexed by method.
// NOTE: Using a gpr_atm rather than atomic_int because atomic_int isn't
// copyable or movable and thus will cause compilation errors. We
// actually only want to extend the vector before the threaded use
// starts, but this is still a limitation.
std::vector<gpr_atm> callback_unmatched_reqs_count_;
// List of callback requests to start when server actually starts.
std::list<CallbackRequestBase*> callback_reqs_to_start_;
// For registering experimental callback generic service; remove when that
// method longer experimental
experimental_registration_type experimental_registration_{this};
// Server status
grpc::internal::Mutex mu_;
bool started_;
bool shutdown_;
bool shutdown_notified_; // Was notify called on the shutdown_cv_
grpc::internal::CondVar shutdown_cv_;
// It is ok (but not required) to nest callback_reqs_mu_ under mu_ .
// Incrementing callback_reqs_outstanding_ is ok without a lock but it must be
// decremented under the lock in case it is the last request and enables the
// server shutdown. The increment is performance-critical since it happens
// during periods of increasing load; the decrement happens only when memory
// is maxed out, during server shutdown, or (possibly in a future version)
// during decreasing load, so it is less performance-critical.
grpc::internal::Mutex callback_reqs_mu_;
grpc::internal::CondVar callback_reqs_done_cv_;
std::atomic_int callback_reqs_outstanding_{0};
std::shared_ptr<GlobalCallbacks> global_callbacks_;
std::vector<grpc::string> services_;
bool has_async_generic_service_{false};
bool has_callback_generic_service_{false};
// Pointer to the wrapped grpc_server.
grpc_server* server_;
std::unique_ptr<grpc_impl::ServerInitializer> server_initializer_;
std::unique_ptr<HealthCheckServiceInterface> health_check_service_;
bool health_check_service_disabled_;
// When appropriate, use a default callback generic service to handle
// unimplemented methods
std::unique_ptr<experimental::CallbackGenericService> unimplemented_service_;
// A special handler for resource exhausted in sync case
std::unique_ptr<internal::MethodHandler> resource_exhausted_handler_;
// Handler for callback generic service, if any
std::unique_ptr<internal::MethodHandler> generic_handler_;
// callback_cq_ references the callbackable completion queue associated
// with this server (if any). It is set on the first call to CallbackCQ().
// It is _not owned_ by the server; ownership belongs with its internal
// shutdown callback tag (invoked when the CQ is fully shutdown).
// It is protected by mu_
CompletionQueue* callback_cq_ = nullptr;
};
typedef ::grpc_impl::Server Server;
} // namespace grpc

@ -23,6 +23,7 @@
namespace grpc_impl {
class Server;
class ServerCredentials;
class ResourceQuota;
} // namespace grpc_impl

@ -31,6 +31,7 @@
#include <grpcpp/impl/codegen/server_interceptor.h>
#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/impl/server_builder_plugin.h>
#include <grpcpp/server.h>
#include <grpcpp/support/config.h>
struct grpc_resource_quota;
@ -44,7 +45,6 @@ namespace grpc {
class AsyncGenericService;
class CompletionQueue;
class Server;
class ServerCompletionQueue;
class Service;

@ -28,6 +28,7 @@
#include <grpc/compression.h>
#include <grpc/support/atm.h>
#include <grpcpp/completion_queue.h>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/call.h>
#include <grpcpp/impl/codegen/client_interceptor.h>
#include <grpcpp/impl/codegen/grpc_library.h>
@ -49,7 +50,6 @@ class ServerContext;
namespace grpc_impl {
class HealthCheckServiceInterface;
class ServerInitializer;
/// Represents a gRPC server.
@ -99,7 +99,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
grpc_server* c_server();
/// Returns the health check service.
grpc_impl::HealthCheckServiceInterface* GetHealthCheckService() const {
grpc::HealthCheckServiceInterface* GetHealthCheckService() const {
return health_check_service_.get();
}
@ -333,7 +333,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen {
std::unique_ptr<grpc_impl::ServerInitializer> server_initializer_;
std::unique_ptr<grpc_impl::HealthCheckServiceInterface> health_check_service_;
std::unique_ptr<grpc::HealthCheckServiceInterface> health_check_service_;
bool health_check_service_disabled_;
// When appropriate, use a default callback generic service to handle

@ -19,132 +19,17 @@
#ifndef GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
#define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H
#include <list>
#include <vector>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpcpp/support/config.h>
#include <grpcpp/support/channel_arguments_impl.h>
namespace grpc_impl {
class SecureChannelCredentials;
class ResourceQuota;
}
} // namespace grpc_impl
namespace grpc {
namespace testing {
class ChannelArgumentsTest;
} // namespace testing
/// Options for channel creation. The user can use generic setters to pass
/// key value pairs down to C channel creation code. For gRPC related options,
/// concrete setters are provided.
class ChannelArguments {
public:
ChannelArguments();
~ChannelArguments();
ChannelArguments(const ChannelArguments& other);
ChannelArguments& operator=(ChannelArguments other) {
Swap(other);
return *this;
}
void Swap(ChannelArguments& other);
/// Dump arguments in this instance to \a channel_args. Does not take
/// ownership of \a channel_args.
///
/// Note that the underlying arguments are shared. Changes made to either \a
/// channel_args or this instance would be reflected on both.
void SetChannelArgs(grpc_channel_args* channel_args) const;
// gRPC specific channel argument setters
/// Set target name override for SSL host name checking. This option is for
/// testing only and should never be used in production.
void SetSslTargetNameOverride(const grpc::string& name);
// TODO(yangg) add flow control options
/// Set the compression algorithm for the channel.
void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
/// Set the grpclb fallback timeout (in ms) for the channel. If this amount
/// of time has passed but we have not gotten any non-empty \a serverlist from
/// the balancer, we will fall back to use the backend address(es) returned by
/// the resolver.
void SetGrpclbFallbackTimeout(int fallback_timeout);
/// For client channel's, the socket mutator operates on
/// "channel" sockets. For server's, the socket mutator operates
/// only on "listen" sockets.
/// TODO(apolcyn): allow socket mutators to also operate
/// on server "channel" sockets, and adjust the socket mutator
/// object to be more speficic about which type of socket
/// it should operate on.
void SetSocketMutator(grpc_socket_mutator* mutator);
/// Set the string to prepend to the user agent.
void SetUserAgentPrefix(const grpc::string& user_agent_prefix);
/// Set the buffer pool to be attached to the constructed channel.
void SetResourceQuota(const ::grpc_impl::ResourceQuota& resource_quota);
/// Set the max receive and send message sizes.
void SetMaxReceiveMessageSize(int size);
void SetMaxSendMessageSize(int size);
/// Set LB policy name.
/// Note that if the name resolver returns only balancer addresses, the
/// grpclb LB policy will be used, regardless of what is specified here.
void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name);
/// Set service config in JSON form.
/// Primarily meant for use in unit tests.
void SetServiceConfigJSON(const grpc::string& service_config_json);
// Generic channel argument setters. Only for advanced use cases.
/// Set an integer argument \a value under \a key.
void SetInt(const grpc::string& key, int value);
// Generic channel argument setter. Only for advanced use cases.
/// Set a pointer argument \a value under \a key. Owership is not transferred.
void SetPointer(const grpc::string& key, void* value);
void SetPointerWithVtable(const grpc::string& key, void* value,
const grpc_arg_pointer_vtable* vtable);
/// Set a textual argument \a value under \a key.
void SetString(const grpc::string& key, const grpc::string& value);
/// Return (by value) a C \a grpc_channel_args structure which points to
/// arguments owned by this \a ChannelArguments instance
grpc_channel_args c_channel_args() const {
grpc_channel_args out;
out.num_args = args_.size();
out.args = args_.empty() ? NULL : const_cast<grpc_arg*>(&args_[0]);
return out;
}
private:
friend class SecureChannelCredentials;
friend class testing::ChannelArgumentsTest;
/// Default pointer argument operations.
struct PointerVtableMembers {
static void* Copy(void* in) { return in; }
static void Destroy(void* in) {}
static int Compare(void* a, void* b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
};
// Returns empty string when it is not set.
grpc::string GetSslTargetNameOverride() const;
std::vector<grpc_arg> args_;
std::list<grpc::string> strings_;
};
typedef ::grpc_impl::ChannelArguments ChannelArguments;
} // namespace grpc

@ -0,0 +1,152 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H
#define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H
#include <list>
#include <vector>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpcpp/resource_quota.h>
#include <grpcpp/support/config.h>
namespace grpc {
namespace testing {
class ChannelArgumentsTest;
} // namespace testing
} // namespace grpc
namespace grpc_impl {
class SecureChannelCredentials;
/// Options for channel creation. The user can use generic setters to pass
/// key value pairs down to C channel creation code. For gRPC related options,
/// concrete setters are provided.
class ChannelArguments {
public:
ChannelArguments();
~ChannelArguments();
ChannelArguments(const ChannelArguments& other);
ChannelArguments& operator=(ChannelArguments other) {
Swap(other);
return *this;
}
void Swap(ChannelArguments& other);
/// Dump arguments in this instance to \a channel_args. Does not take
/// ownership of \a channel_args.
///
/// Note that the underlying arguments are shared. Changes made to either \a
/// channel_args or this instance would be reflected on both.
void SetChannelArgs(grpc_channel_args* channel_args) const;
// gRPC specific channel argument setters
/// Set target name override for SSL host name checking. This option is for
/// testing only and should never be used in production.
void SetSslTargetNameOverride(const grpc::string& name);
// TODO(yangg) add flow control options
/// Set the compression algorithm for the channel.
void SetCompressionAlgorithm(grpc_compression_algorithm algorithm);
/// Set the grpclb fallback timeout (in ms) for the channel. If this amount
/// of time has passed but we have not gotten any non-empty \a serverlist from
/// the balancer, we will fall back to use the backend address(es) returned by
/// the resolver.
void SetGrpclbFallbackTimeout(int fallback_timeout);
/// For client channel's, the socket mutator operates on
/// "channel" sockets. For server's, the socket mutator operates
/// only on "listen" sockets.
/// TODO(apolcyn): allow socket mutators to also operate
/// on server "channel" sockets, and adjust the socket mutator
/// object to be more speficic about which type of socket
/// it should operate on.
void SetSocketMutator(grpc_socket_mutator* mutator);
/// Set the string to prepend to the user agent.
void SetUserAgentPrefix(const grpc::string& user_agent_prefix);
/// Set the buffer pool to be attached to the constructed channel.
void SetResourceQuota(const grpc::ResourceQuota& resource_quota);
/// Set the max receive and send message sizes.
void SetMaxReceiveMessageSize(int size);
void SetMaxSendMessageSize(int size);
/// Set LB policy name.
/// Note that if the name resolver returns only balancer addresses, the
/// grpclb LB policy will be used, regardless of what is specified here.
void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name);
/// Set service config in JSON form.
/// Primarily meant for use in unit tests.
void SetServiceConfigJSON(const grpc::string& service_config_json);
// Generic channel argument setters. Only for advanced use cases.
/// Set an integer argument \a value under \a key.
void SetInt(const grpc::string& key, int value);
// Generic channel argument setter. Only for advanced use cases.
/// Set a pointer argument \a value under \a key. Owership is not transferred.
void SetPointer(const grpc::string& key, void* value);
void SetPointerWithVtable(const grpc::string& key, void* value,
const grpc_arg_pointer_vtable* vtable);
/// Set a textual argument \a value under \a key.
void SetString(const grpc::string& key, const grpc::string& value);
/// Return (by value) a C \a grpc_channel_args structure which points to
/// arguments owned by this \a ChannelArguments instance
grpc_channel_args c_channel_args() const {
grpc_channel_args out;
out.num_args = args_.size();
out.args = args_.empty() ? NULL : const_cast<grpc_arg*>(&args_[0]);
return out;
}
private:
friend class grpc_impl::SecureChannelCredentials;
friend class grpc::testing::ChannelArgumentsTest;
/// Default pointer argument operations.
struct PointerVtableMembers {
static void* Copy(void* in) { return in; }
static void Destroy(void* in) {}
static int Compare(void* a, void* b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
};
// Returns empty string when it is not set.
grpc::string GetSslTargetNameOverride() const;
std::vector<grpc_arg> args_;
std::list<grpc::string> strings_;
};
} // namespace grpc_impl
#endif // GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H

@ -107,6 +107,10 @@
<file baseinstalldir="/" name="src/core/lib/gprpp/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_custom.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_env.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_generic.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/manual_constructor.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/map.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/memory.h" role="src" />
@ -149,6 +153,7 @@
<file baseinstalldir="/" name="src/core/lib/gpr/wrap_memcpy.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/arena.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/fork.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/global_config_env.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/thd_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
@ -472,6 +477,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.h" role="src" />
@ -796,10 +802,13 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc" role="src" />

@ -25,8 +25,8 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/timer.h"
@ -56,21 +56,22 @@ static backup_poller* g_poller = nullptr; // guarded by g_poller_mu
// treated as const.
static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS;
GPR_GLOBAL_CONFIG_DEFINE_INT32(grpc_client_channel_backup_poll_interval_ms,
DEFAULT_POLL_INTERVAL_MS,
"Client channel backup poll interval (ms)");
static void init_globals() {
gpr_mu_init(&g_poller_mu);
char* env = gpr_getenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS");
if (env != nullptr) {
int poll_interval_ms = gpr_parse_nonnegative_int(env);
if (poll_interval_ms == -1) {
gpr_log(GPR_ERROR,
"Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %s, "
"default value %d will be used.",
env, g_poll_interval_ms);
} else {
g_poll_interval_ms = poll_interval_ms;
}
int32_t poll_interval_ms =
GPR_GLOBAL_CONFIG_GET(grpc_client_channel_backup_poll_interval_ms);
if (poll_interval_ms < 0) {
gpr_log(GPR_ERROR,
"Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %d, "
"default value %d will be used.",
poll_interval_ms, g_poll_interval_ms);
} else {
g_poll_interval_ms = poll_interval_ms;
}
gpr_free(env);
}
static void backup_poller_shutdown_unref(backup_poller* p) {

@ -23,6 +23,9 @@
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/gprpp/global_config.h"
GPR_GLOBAL_CONFIG_DECLARE_INT32(grpc_client_channel_backup_poll_interval_ms);
/* Start polling \a interested_parties periodically in the timer thread */
void grpc_client_channel_start_backup_polling(

@ -66,8 +66,7 @@
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/status_metadata.h"
using grpc_core::internal::ClientChannelMethodParams;
using grpc_core::internal::ClientChannelMethodParamsTable;
using grpc_core::internal::ClientChannelMethodParsedObject;
using grpc_core::internal::ProcessedResolverResult;
using grpc_core::internal::ServerRetryThrottleData;
@ -157,10 +156,8 @@ class ChannelData {
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data() const {
return retry_throttle_data_;
}
RefCountedPtr<ClientChannelMethodParams> GetMethodParams(
const grpc_slice& path) {
if (method_params_table_ == nullptr) return nullptr;
return ServiceConfig::MethodConfigTableLookup(*method_params_table_, path);
RefCountedPtr<ServiceConfig> service_config() const {
return service_config_;
}
grpc_connectivity_state CheckConnectivityState(bool try_to_connect);
@ -226,8 +223,8 @@ class ChannelData {
~ChannelData();
static bool ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config);
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
grpc_error* DoPingLocked(grpc_transport_op* op);
@ -243,6 +240,7 @@ class ChannelData {
const size_t per_rpc_retry_buffer_size_;
grpc_channel_stack* owning_stack_;
ClientChannelFactory* client_channel_factory_;
UniquePtr<char> server_name_;
// Initialized shortly after construction.
channelz::ClientChannelNode* channelz_node_ = nullptr;
@ -255,7 +253,7 @@ class ChannelData {
// Data from service config.
bool received_service_config_data_ = false;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
RefCountedPtr<ServiceConfig> service_config_;
//
// Fields used in the control plane. Guarded by combiner.
@ -266,6 +264,7 @@ class ChannelData {
OrphanablePtr<LoadBalancingPolicy> resolving_lb_policy_;
grpc_connectivity_state_tracker state_tracker_;
ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_;
UniquePtr<char> health_check_service_name_;
//
// Fields accessed from both data plane and control plane combiners.
@ -621,7 +620,8 @@ class CallData {
grpc_call_context_element* call_context_;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
RefCountedPtr<ClientChannelMethodParams> method_params_;
ServiceConfig::CallData service_config_call_data_;
const ClientChannelMethodParsedObject* method_params_ = nullptr;
RefCountedPtr<SubchannelCall> subchannel_call_;
@ -764,11 +764,12 @@ class ChannelData::ServiceConfigSetter {
public:
ServiceConfigSetter(
ChannelData* chand,
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data,
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table)
Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data,
RefCountedPtr<ServiceConfig> service_config)
: chand_(chand),
retry_throttle_data_(std::move(retry_throttle_data)),
method_params_table_(std::move(method_params_table)) {
retry_throttle_data_(retry_throttle_data),
service_config_(std::move(service_config)) {
GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "ServiceConfigSetter");
GRPC_CLOSURE_INIT(&closure_, SetServiceConfigData, this,
grpc_combiner_scheduler(chand->data_plane_combiner_));
@ -781,8 +782,14 @@ class ChannelData::ServiceConfigSetter {
ChannelData* chand = self->chand_;
// Update channel state.
chand->received_service_config_data_ = true;
chand->retry_throttle_data_ = std::move(self->retry_throttle_data_);
chand->method_params_table_ = std::move(self->method_params_table_);
if (self->retry_throttle_data_.has_value()) {
chand->retry_throttle_data_ =
internal::ServerRetryThrottleMap::GetDataForServer(
chand->server_name_.get(),
self->retry_throttle_data_.value().max_milli_tokens,
self->retry_throttle_data_.value().milli_token_ratio);
}
chand->service_config_ = std::move(self->service_config_);
// Apply service config to queued picks.
for (QueuedPick* pick = chand->queued_picks_; pick != nullptr;
pick = pick->next) {
@ -796,8 +803,9 @@ class ChannelData::ServiceConfigSetter {
}
ChannelData* chand_;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
Optional<internal::ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data_;
RefCountedPtr<ServiceConfig> service_config_;
grpc_closure closure_;
};
@ -934,10 +942,18 @@ class ChannelData::ClientChannelControlHelper
}
Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
grpc_arg arg = SubchannelPoolInterface::CreateChannelArg(
grpc_arg args_to_add[2];
int num_args_to_add = 0;
if (chand_->health_check_service_name_ != nullptr) {
args_to_add[0] = grpc_channel_arg_string_create(
const_cast<char*>("grpc.temp.health_check"),
const_cast<char*>(chand_->health_check_service_name_.get()));
num_args_to_add++;
}
args_to_add[num_args_to_add++] = SubchannelPoolInterface::CreateChannelArg(
chand_->subchannel_pool_.get());
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(&args, &arg, 1);
grpc_channel_args_copy_and_add(&args, args_to_add, num_args_to_add);
Subchannel* subchannel =
chand_->client_channel_factory_->CreateSubchannel(new_args);
grpc_channel_args_destroy(new_args);
@ -1050,6 +1066,12 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error)
"filter");
return;
}
grpc_uri* uri = grpc_uri_parse(server_uri, true);
if (uri != nullptr && uri->path[0] != '\0') {
server_name_.reset(
gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path));
}
grpc_uri_destroy(uri);
char* proxy_name = nullptr;
grpc_channel_args* new_args = nullptr;
grpc_proxy_mappers_map_name(server_uri, args->channel_args, &proxy_name,
@ -1109,19 +1131,21 @@ ChannelData::~ChannelData() {
// Synchronous callback from ResolvingLoadBalancingPolicy to process a
// resolver result update.
bool ChannelData::ProcessResolverResultLocked(
void* arg, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
void* arg, const Resolver::Result& result, const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config) {
ChannelData* chand = static_cast<ChannelData*>(arg);
ProcessedResolverResult resolver_result(result, chand->enable_retries_);
UniquePtr<char> service_config_json = resolver_result.service_config_json();
ProcessedResolverResult resolver_result(result);
char* service_config_json = gpr_strdup(resolver_result.service_config_json());
if (grpc_client_channel_routing_trace.enabled()) {
gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"",
chand, service_config_json.get());
chand, service_config_json);
}
chand->health_check_service_name_.reset(
gpr_strdup(resolver_result.health_check_service_name()));
// Create service config setter to update channel state in the data
// plane combiner. Destroys itself when done.
New<ServiceConfigSetter>(chand, resolver_result.retry_throttle_data(),
resolver_result.method_params_table());
resolver_result.service_config());
// Swap out the data used by GetChannelInfo().
bool service_config_changed;
{
@ -1131,9 +1155,9 @@ bool ChannelData::ProcessResolverResultLocked(
((service_config_json == nullptr) !=
(chand->info_service_config_json_ == nullptr)) ||
(service_config_json != nullptr &&
strcmp(service_config_json.get(),
chand->info_service_config_json_.get()) != 0);
chand->info_service_config_json_ = std::move(service_config_json);
strcmp(service_config_json, chand->info_service_config_json_.get()) !=
0);
chand->info_service_config_json_.reset(service_config_json);
}
// Return results.
*lb_policy_name = chand->info_lb_policy_name_.get();
@ -1840,8 +1864,7 @@ void CallData::DoRetry(grpc_call_element* elem,
grpc_millis server_pushback_ms) {
ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
GPR_ASSERT(method_params_ != nullptr);
const ClientChannelMethodParams::RetryPolicy* retry_policy =
method_params_->retry_policy();
const auto* retry_policy = method_params_->retry_policy();
GPR_ASSERT(retry_policy != nullptr);
// Reset subchannel call and connected subchannel.
subchannel_call_.reset();
@ -1849,7 +1872,7 @@ void CallData::DoRetry(grpc_call_element* elem,
// Compute backoff delay.
grpc_millis next_attempt_time;
if (server_pushback_ms >= 0) {
next_attempt_time = grpc_core::ExecCtx::Get()->Now() + server_pushback_ms;
next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms;
last_attempt_got_server_pushback_ = true;
} else {
if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) {
@ -1866,7 +1889,7 @@ void CallData::DoRetry(grpc_call_element* elem,
if (grpc_client_channel_call_trace.enabled()) {
gpr_log(GPR_INFO,
"chand=%p calld=%p: retrying failed call in %" PRId64 " ms", chand,
this, next_attempt_time - grpc_core::ExecCtx::Get()->Now());
this, next_attempt_time - ExecCtx::Get()->Now());
}
// Schedule retry after computed delay.
GRPC_CLOSURE_INIT(&pick_closure_, StartPickLocked, elem,
@ -1883,8 +1906,7 @@ bool CallData::MaybeRetry(grpc_call_element* elem,
ChannelData* chand = static_cast<ChannelData*>(elem->channel_data);
// Get retry policy.
if (method_params_ == nullptr) return false;
const ClientChannelMethodParams::RetryPolicy* retry_policy =
method_params_->retry_policy();
const auto* retry_policy = method_params_->retry_policy();
if (retry_policy == nullptr) return false;
// If we've already dispatched a retry from this call, return true.
// This catches the case where the batch has multiple callbacks
@ -3072,8 +3094,19 @@ void CallData::ApplyServiceConfigToCallLocked(grpc_call_element* elem) {
gpr_log(GPR_INFO, "chand=%p calld=%p: applying service config to call",
chand, this);
}
// Store a ref to the service_config in service_config_call_data_. Also, save
// a pointer to this in the call_context so that all future filters can access
// it.
service_config_call_data_ =
ServiceConfig::CallData(chand->service_config(), path_);
if (service_config_call_data_.service_config() != nullptr) {
call_context_[GRPC_SERVICE_CONFIG_CALL_DATA].value =
&service_config_call_data_;
method_params_ = static_cast<ClientChannelMethodParsedObject*>(
service_config_call_data_.GetMethodParsedObject(
internal::ClientChannelServiceConfigParser::ParserIndex()));
}
retry_throttle_data_ = chand->retry_throttle_data();
method_params_ = chand->GetMethodParams(path_);
if (method_params_ != nullptr) {
// If the deadline from the service config is shorter than the one
// from the client API, reset the deadline timer.
@ -3091,12 +3124,10 @@ void CallData::ApplyServiceConfigToCallLocked(grpc_call_element* elem) {
uint32_t* send_initial_metadata_flags =
&pending_batches_[0]
.batch->payload->send_initial_metadata.send_initial_metadata_flags;
if (GPR_UNLIKELY(method_params_->wait_for_ready() !=
ClientChannelMethodParams::WAIT_FOR_READY_UNSET &&
!(*send_initial_metadata_flags &
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET))) {
if (method_params_->wait_for_ready() ==
ClientChannelMethodParams::WAIT_FOR_READY_TRUE) {
if (method_params_->wait_for_ready().has_value() &&
!(*send_initial_metadata_flags &
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET)) {
if (method_params_->wait_for_ready().value()) {
*send_initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY;
} else {
*send_initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;

@ -32,6 +32,7 @@
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/proxy_mapper_registry.h"
#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
#include "src/core/ext/filters/client_channel/retry_throttle.h"
#include "src/core/lib/surface/channel_init.h"
@ -50,6 +51,7 @@ static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
void grpc_client_channel_init(void) {
grpc_core::ServiceConfig::Init();
grpc_core::internal::ClientChannelServiceConfigParser::Register();
grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry();
grpc_core::ResolverRegistry::Builder::InitRegistry();
grpc_core::internal::ServerRetryThrottleMap::Init();

@ -62,32 +62,6 @@ void LoadBalancingPolicy::ShutdownAndUnrefLocked(void* arg,
policy->Unref();
}
grpc_json* LoadBalancingPolicy::ParseLoadBalancingConfig(
const grpc_json* lb_config_array) {
if (lb_config_array == nullptr || lb_config_array->type != GRPC_JSON_ARRAY) {
return nullptr;
}
// Find the first LB policy that this client supports.
for (const grpc_json* lb_config = lb_config_array->child;
lb_config != nullptr; lb_config = lb_config->next) {
if (lb_config->type != GRPC_JSON_OBJECT) return nullptr;
grpc_json* policy = nullptr;
for (grpc_json* field = lb_config->child; field != nullptr;
field = field->next) {
if (field->key == nullptr || field->type != GRPC_JSON_OBJECT)
return nullptr;
if (policy != nullptr) return nullptr; // Violate "oneof" type.
policy = field;
}
if (policy == nullptr) return nullptr;
// If we support this policy, then select it.
if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key)) {
return policy;
}
}
return nullptr;
}
//
// LoadBalancingPolicy::UpdateArgs
//

@ -36,6 +36,18 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
namespace grpc_core {
/// Interface for parsed forms of load balancing configs found in a service
/// config.
class ParsedLoadBalancingConfig : public RefCounted<ParsedLoadBalancingConfig> {
public:
virtual ~ParsedLoadBalancingConfig() = default;
// Returns the load balancing policy name
virtual const char* name() const GRPC_ABSTRACT;
GRPC_ABSTRACT_BASE_CLASS;
};
/// Interface for load balancing policies.
///
/// The following concepts are used here:
@ -196,30 +208,11 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
GRPC_ABSTRACT_BASE_CLASS
};
/// Configuration for an LB policy instance.
// TODO(roth): Find a better JSON representation for this API.
class Config : public RefCounted<Config> {
public:
Config(const grpc_json* lb_config,
RefCountedPtr<ServiceConfig> service_config)
: json_(lb_config), service_config_(std::move(service_config)) {}
const char* name() const { return json_->key; }
const grpc_json* config() const { return json_->child; }
RefCountedPtr<ServiceConfig> service_config() const {
return service_config_;
}
private:
const grpc_json* json_;
RefCountedPtr<ServiceConfig> service_config_;
};
/// Data passed to the UpdateLocked() method when new addresses and
/// config are available.
struct UpdateArgs {
ServerAddressList addresses;
RefCountedPtr<Config> config;
RefCountedPtr<ParsedLoadBalancingConfig> config;
const grpc_channel_args* args = nullptr;
// TODO(roth): Remove everything below once channel args is
@ -290,10 +283,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
void Orphan() override;
/// Returns the JSON node of policy (with both policy name and config content)
/// given the JSON node of a LoadBalancingConfig array.
static grpc_json* ParseLoadBalancingConfig(const grpc_json* lb_config_array);
// A picker that returns PICK_QUEUE for all picks.
// Also calls the parent LB policy's ExitIdleLocked() method when the
// first pick is seen.

@ -118,6 +118,21 @@ namespace {
constexpr char kGrpclb[] = "grpclb";
class ParsedGrpcLbConfig : public ParsedLoadBalancingConfig {
public:
explicit ParsedGrpcLbConfig(
RefCountedPtr<ParsedLoadBalancingConfig> child_policy)
: child_policy_(std::move(child_policy)) {}
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
return child_policy_;
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
};
class GrpcLb : public LoadBalancingPolicy {
public:
explicit GrpcLb(Args args);
@ -302,7 +317,6 @@ class GrpcLb : public LoadBalancingPolicy {
// Helper functions used in UpdateLocked().
void ProcessAddressesAndChannelArgsLocked(const ServerAddressList& addresses,
const grpc_channel_args& args);
void ParseLbConfig(Config* grpclb_config);
static void OnBalancerChannelConnectivityChangedLocked(void* arg,
grpc_error* error);
void CancelBalancerChannelConnectivityWatchLocked();
@ -380,7 +394,7 @@ class GrpcLb : public LoadBalancingPolicy {
// until it reports READY, at which point it will be moved to child_policy_.
OrphanablePtr<LoadBalancingPolicy> pending_child_policy_;
// The child policy config.
RefCountedPtr<Config> child_policy_config_;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
// Child policy in state READY.
bool child_policy_ready_ = false;
};
@ -1373,7 +1387,13 @@ void GrpcLb::FillChildRefsForChannelz(
void GrpcLb::UpdateLocked(UpdateArgs args) {
const bool is_initial_update = lb_channel_ == nullptr;
ParseLbConfig(args.config.get());
auto* grpclb_config =
static_cast<const ParsedGrpcLbConfig*>(args.config.get());
if (grpclb_config != nullptr) {
child_policy_config_ = grpclb_config->child_policy();
} else {
child_policy_config_ = nullptr;
}
ProcessAddressesAndChannelArgsLocked(args.addresses, *args.args);
// Update the existing child policy.
if (child_policy_ != nullptr) CreateOrUpdateChildPolicyLocked();
@ -1462,27 +1482,6 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked(
response_generator_->SetResponse(std::move(result));
}
void GrpcLb::ParseLbConfig(Config* grpclb_config) {
const grpc_json* child_policy = nullptr;
if (grpclb_config != nullptr) {
const grpc_json* grpclb_config_json = grpclb_config->config();
for (const grpc_json* field = grpclb_config_json; field != nullptr;
field = field->next) {
if (field->key == nullptr) return;
if (strcmp(field->key, "childPolicy") == 0) {
if (child_policy != nullptr) return; // Duplicate.
child_policy = ParseLoadBalancingConfig(field);
}
}
}
if (child_policy != nullptr) {
child_policy_config_ =
MakeRefCounted<Config>(child_policy, grpclb_config->service_config());
} else {
child_policy_config_.reset();
}
}
void GrpcLb::OnBalancerChannelConnectivityChangedLocked(void* arg,
grpc_error* error) {
GrpcLb* self = static_cast<GrpcLb*>(arg);
@ -1800,6 +1799,40 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
}
const char* name() const override { return kGrpclb; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
New<ParsedGrpcLbConfig>(nullptr));
}
InlinedVector<grpc_error*, 2> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "childPolicy") == 0) {
if (child_policy != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:childPolicy error:Duplicate entry"));
}
grpc_error* parse_error = GRPC_ERROR_NONE;
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
field, &parse_error);
if (parse_error != GRPC_ERROR_NONE) {
error_list.push_back(parse_error);
}
}
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(
New<ParsedGrpcLbConfig>(std::move(child_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list);
return nullptr;
}
}
};
} // namespace

@ -526,6 +526,11 @@ void PickFirst::PickFirstSubchannelData::
}
}
class ParsedPickFirstConfig : public ParsedLoadBalancingConfig {
public:
const char* name() const override { return kPickFirst; }
};
//
// factory
//
@ -538,6 +543,15 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
}
const char* name() const override { return kPickFirst; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
New<ParsedPickFirstConfig>());
}
};
} // namespace

@ -503,6 +503,11 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
}
}
class ParsedRoundRobinConfig : public ParsedLoadBalancingConfig {
public:
const char* name() const override { return kRoundRobin; }
};
//
// factory
//
@ -515,6 +520,15 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
}
const char* name() const override { return kRoundRobin; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<ParsedLoadBalancingConfig>(
New<ParsedRoundRobinConfig>());
}
};
} // namespace

@ -120,6 +120,33 @@ constexpr char kXds[] = "xds_experimental";
constexpr char kDefaultLocalityName[] = "xds_default_locality";
constexpr uint32_t kDefaultLocalityWeight = 3;
class ParsedXdsConfig : public ParsedLoadBalancingConfig {
public:
ParsedXdsConfig(const char* balancer_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_policy,
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy)
: balancer_name_(balancer_name),
child_policy_(std::move(child_policy)),
fallback_policy_(std::move(fallback_policy)) {}
const char* name() const override { return kXds; }
const char* balancer_name() const { return balancer_name_; };
RefCountedPtr<ParsedLoadBalancingConfig> child_policy() const {
return child_policy_;
}
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy() const {
return fallback_policy_;
}
private:
const char* balancer_name_ = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_;
};
class XdsLb : public LoadBalancingPolicy {
public:
explicit XdsLb(Args args);
@ -336,7 +363,7 @@ class XdsLb : public LoadBalancingPolicy {
~LocalityEntry() = default;
void UpdateLocked(xds_grpclb_serverlist* serverlist,
LoadBalancingPolicy::Config* child_policy_config,
ParsedLoadBalancingConfig* child_policy_config,
const grpc_channel_args* args);
void ShutdownLocked();
void ResetBackoffLocked();
@ -383,7 +410,7 @@ class XdsLb : public LoadBalancingPolicy {
};
void UpdateLocked(const LocalityList& locality_list,
LoadBalancingPolicy::Config* child_policy_config,
ParsedLoadBalancingConfig* child_policy_config,
const grpc_channel_args* args, XdsLb* parent);
void ShutdownLocked();
void ResetBackoffLocked();
@ -423,7 +450,7 @@ class XdsLb : public LoadBalancingPolicy {
// If parsing succeeds, updates \a balancer_name, and updates \a
// child_policy_config_ and \a fallback_policy_config_ if they are also
// found. Does nothing upon failure.
void ParseLbConfig(Config* xds_config);
void ParseLbConfig(const ParsedXdsConfig* xds_config);
BalancerChannelState* LatestLbChannel() const {
return pending_lb_chand_ != nullptr ? pending_lb_chand_.get()
@ -480,7 +507,7 @@ class XdsLb : public LoadBalancingPolicy {
grpc_closure lb_on_fallback_;
// The policy to use for the fallback backends.
RefCountedPtr<Config> fallback_policy_config_;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy_config_;
// Lock held when modifying the value of fallback_policy_ or
// pending_fallback_policy_.
Mutex fallback_policy_mu_;
@ -489,7 +516,7 @@ class XdsLb : public LoadBalancingPolicy {
OrphanablePtr<LoadBalancingPolicy> pending_fallback_policy_;
// The policy to use for the backends.
RefCountedPtr<Config> child_policy_config_;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy_config_;
// Map of policies to use in the backend
LocalityMap locality_map_;
// TODO(mhaidry) : Add support for multiple maps of localities
@ -1485,41 +1512,17 @@ void XdsLb::ProcessAddressesAndChannelArgsLocked(
grpc_channel_args_destroy(lb_channel_args);
}
void XdsLb::ParseLbConfig(Config* xds_config) {
const grpc_json* xds_config_json = xds_config->config();
const char* balancer_name = nullptr;
grpc_json* child_policy = nullptr;
grpc_json* fallback_policy = nullptr;
for (const grpc_json* field = xds_config_json; field != nullptr;
field = field->next) {
if (field->key == nullptr) return;
if (strcmp(field->key, "balancerName") == 0) {
if (balancer_name != nullptr) return; // Duplicate.
if (field->type != GRPC_JSON_STRING) return;
balancer_name = field->value;
} else if (strcmp(field->key, "childPolicy") == 0) {
if (child_policy != nullptr) return; // Duplicate.
child_policy = ParseLoadBalancingConfig(field);
} else if (strcmp(field->key, "fallbackPolicy") == 0) {
if (fallback_policy != nullptr) return; // Duplicate.
fallback_policy = ParseLoadBalancingConfig(field);
}
}
if (balancer_name == nullptr) return; // Required field.
balancer_name_ = UniquePtr<char>(gpr_strdup(balancer_name));
if (child_policy != nullptr) {
child_policy_config_ =
MakeRefCounted<Config>(child_policy, xds_config->service_config());
}
if (fallback_policy != nullptr) {
fallback_policy_config_ =
MakeRefCounted<Config>(fallback_policy, xds_config->service_config());
}
void XdsLb::ParseLbConfig(const ParsedXdsConfig* xds_config) {
if (xds_config == nullptr || xds_config->balancer_name() == nullptr) return;
// TODO(yashykt) : does this need to be a gpr_strdup
balancer_name_ = UniquePtr<char>(gpr_strdup(xds_config->balancer_name()));
child_policy_config_ = xds_config->child_policy();
fallback_policy_config_ = xds_config->fallback_policy();
}
void XdsLb::UpdateLocked(UpdateArgs args) {
const bool is_initial_update = lb_chand_ == nullptr;
ParseLbConfig(args.config.get());
ParseLbConfig(static_cast<const ParsedXdsConfig*>(args.config.get()));
if (balancer_name_ == nullptr) {
gpr_log(GPR_ERROR, "[xdslb %p] LB config parsing fails.", this);
return;
@ -1745,7 +1748,7 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) {
void XdsLb::LocalityMap::UpdateLocked(
const LocalityList& locality_serverlist,
LoadBalancingPolicy::Config* child_policy_config,
ParsedLoadBalancingConfig* child_policy_config,
const grpc_channel_args* args, XdsLb* parent) {
if (parent->shutting_down_) return;
for (size_t i = 0; i < locality_serverlist.size(); i++) {
@ -1840,7 +1843,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked(
void XdsLb::LocalityMap::LocalityEntry::UpdateLocked(
xds_grpclb_serverlist* serverlist,
LoadBalancingPolicy::Config* child_policy_config,
ParsedLoadBalancingConfig* child_policy_config,
const grpc_channel_args* args_in) {
if (parent_->shutting_down_) return;
// Construct update args.
@ -2155,6 +2158,77 @@ class XdsFactory : public LoadBalancingPolicyFactory {
}
const char* name() const override { return kXds; }
RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
// xds was mentioned as a policy in the deprecated loadBalancingPolicy
// field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:Xds Parser has required field - "
"balancerName. Please use loadBalancingConfig field of service "
"config instead.");
return nullptr;
}
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
InlinedVector<grpc_error*, 3> error_list;
const char* balancer_name = nullptr;
RefCountedPtr<ParsedLoadBalancingConfig> child_policy;
RefCountedPtr<ParsedLoadBalancingConfig> fallback_policy;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "balancerName") == 0) {
if (balancer_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:balancerName error:Duplicate entry"));
}
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:balancerName error:type should be string"));
continue;
}
balancer_name = field->value;
} else if (strcmp(field->key, "childPolicy") == 0) {
if (child_policy != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:childPolicy error:Duplicate entry"));
}
grpc_error* parse_error = GRPC_ERROR_NONE;
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
field, &parse_error);
if (child_policy == nullptr) {
GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
error_list.push_back(parse_error);
}
} else if (strcmp(field->key, "fallbackPolicy") == 0) {
if (fallback_policy != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:fallbackPolicy error:Duplicate entry"));
}
grpc_error* parse_error = GRPC_ERROR_NONE;
fallback_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
field, &parse_error);
if (fallback_policy == nullptr) {
GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
error_list.push_back(parse_error);
}
}
}
if (balancer_name == nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:balancerName error:not found"));
}
if (error_list.empty()) {
return RefCountedPtr<ParsedLoadBalancingConfig>(New<ParsedXdsConfig>(
balancer_name, std::move(child_policy), std::move(fallback_policy)));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list);
return nullptr;
}
}
};
} // namespace

@ -37,9 +37,12 @@ class LoadBalancingPolicyFactory {
/// Caller does NOT take ownership of result.
virtual const char* name() const GRPC_ABSTRACT;
virtual RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const GRPC_ABSTRACT;
virtual ~LoadBalancingPolicyFactory() {}
GRPC_ABSTRACT_BASE_CLASS
GRPC_ABSTRACT_BASE_CLASS;
};
} // namespace grpc_core

@ -94,9 +94,112 @@ LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
return factory->CreateLoadBalancingPolicy(std::move(args));
}
bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(const char* name) {
bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
const char* name, bool* requires_config) {
GPR_ASSERT(g_state != nullptr);
return g_state->GetLoadBalancingPolicyFactory(name) != nullptr;
auto* factory = g_state->GetLoadBalancingPolicyFactory(name);
if (factory == nullptr) {
return false;
}
if (requires_config != nullptr) {
grpc_error* error = GRPC_ERROR_NONE;
// Check if the load balancing policy allows an empty config
*requires_config =
factory->ParseLoadBalancingConfig(nullptr, &error) == nullptr;
GRPC_ERROR_UNREF(error);
}
return true;
}
namespace {
// Returns the JSON node of policy (with both policy name and config content)
// given the JSON node of a LoadBalancingConfig array.
grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
char* error_msg;
if (lb_config_array == nullptr || lb_config_array->type != GRPC_JSON_ARRAY) {
gpr_asprintf(&error_msg, "field:%s error:type should be array",
lb_config_array->key);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
}
const char* field_name = lb_config_array->key;
// Find the first LB policy that this client supports.
for (const grpc_json* lb_config = lb_config_array->child;
lb_config != nullptr; lb_config = lb_config->next) {
if (lb_config->type != GRPC_JSON_OBJECT) {
gpr_asprintf(&error_msg,
"field:%s error:child entry should be of type object",
field_name);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
}
grpc_json* policy = nullptr;
for (grpc_json* field = lb_config->child; field != nullptr;
field = field->next) {
if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) {
gpr_asprintf(&error_msg,
"field:%s error:child entry should be of type object",
field_name);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
}
if (policy != nullptr) {
gpr_asprintf(&error_msg, "field:%s error:oneOf violation", field_name);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
} // Violate "oneof" type.
policy = field;
}
if (policy == nullptr) {
gpr_asprintf(&error_msg, "field:%s error:no policy found in child entry",
field_name);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
}
// If we support this policy, then select it.
if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key,
nullptr)) {
return policy;
}
}
gpr_asprintf(&error_msg, "field:%s error:No known policy", field_name);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg);
gpr_free(error_msg);
return nullptr;
}
} // namespace
RefCountedPtr<ParsedLoadBalancingConfig>
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
GPR_ASSERT(g_state != nullptr);
const grpc_json* policy = ParseLoadBalancingConfigHelper(json, error);
if (policy == nullptr) {
return nullptr;
} else {
GPR_DEBUG_ASSERT(*error == GRPC_ERROR_NONE && json != nullptr);
// Find factory.
LoadBalancingPolicyFactory* factory =
g_state->GetLoadBalancingPolicyFactory(policy->key);
if (factory == nullptr) {
char* msg;
gpr_asprintf(&msg, "field:%s error:Factory not found to create policy",
json->key);
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
return nullptr;
}
// Parse load balancing config via factory.
return factory->ParseLoadBalancingConfig(policy, error);
}
}
} // namespace grpc_core

@ -49,8 +49,15 @@ class LoadBalancingPolicyRegistry {
const char* name, LoadBalancingPolicy::Args args);
/// Returns true if the LB policy factory specified by \a name exists in this
/// registry.
static bool LoadBalancingPolicyExists(const char* name);
/// registry. If the load balancing policy requires a config to be specified
/// then sets \a requires_config to true.
static bool LoadBalancingPolicyExists(const char* name,
bool* requires_config);
/// Returns a parsed object of the load balancing policy to be used from a
/// LoadBalancingConfig array \a json.
static RefCountedPtr<ParsedLoadBalancingConfig> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error);
};
} // namespace grpc_core

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include <limits.h>
#include <stdio.h>
@ -430,6 +430,13 @@ static grpc_error* blocking_resolve_address_ares(
static grpc_address_resolver_vtable ares_resolver = {
grpc_resolve_address_ares, blocking_resolve_address_ares};
#ifdef GRPC_UV
/* TODO(murgatroid99): Remove this when we want the cares resolver to be the
* default when using libuv */
static bool should_use_ares(const char* resolver_env) {
return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0;
}
#else /* GRPC_UV */
static bool should_use_ares(const char* resolver_env) {
// TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support
// custom IO managers (e.g. gevent).
@ -437,6 +444,7 @@ static bool should_use_ares(const char* resolver_env) {
(resolver_env == nullptr || strlen(resolver_env) == 0 ||
gpr_stricmp(resolver_env, "ares") == 0);
}
#endif /* GRPC_UV */
void grpc_resolver_dns_ares_init() {
char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER");
@ -468,10 +476,10 @@ void grpc_resolver_dns_ares_shutdown() {
gpr_free(resolver_env);
}
#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#else /* GRPC_ARES == 1 */
void grpc_resolver_dns_ares_init(void) {}
void grpc_resolver_dns_ares_shutdown(void) {}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include <ares.h>
#include <string.h>
@ -218,6 +218,7 @@ static void on_timeout_locked(void* arg, grpc_error* error) {
static void on_readable_locked(void* arg, grpc_error* error) {
fd_node* fdn = static_cast<fd_node*>(arg);
GPR_ASSERT(fdn->readable_registered);
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->readable_registered = false;
@ -242,6 +243,7 @@ static void on_readable_locked(void* arg, grpc_error* error) {
static void on_writable_locked(void* arg, grpc_error* error) {
fd_node* fdn = static_cast<fd_node*>(arg);
GPR_ASSERT(fdn->writable_registered);
grpc_ares_ev_driver* ev_driver = fdn->ev_driver;
const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked();
fdn->writable_registered = false;
@ -365,4 +367,4 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) {
}
}
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -0,0 +1,179 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GRPC_UV)
#include <ares.h>
#include <uv.h>
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.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/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/combiner.h"
namespace grpc_core {
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events);
void ares_uv_poll_close_cb(uv_handle_t* handle) { Delete(handle); }
class GrpcPolledFdLibuv : public GrpcPolledFd {
public:
GrpcPolledFdLibuv(ares_socket_t as, grpc_combiner* combiner)
: as_(as), combiner_(combiner) {
gpr_asprintf(&name_, "c-ares socket: %" PRIdPTR, (intptr_t)as);
handle_ = New<uv_poll_t>();
uv_poll_init_socket(uv_default_loop(), handle_, as);
handle_->data = this;
GRPC_COMBINER_REF(combiner_, "libuv ares event driver");
}
~GrpcPolledFdLibuv() {
gpr_free(name_);
GRPC_COMBINER_UNREF(combiner_, "libuv ares event driver");
}
void RegisterForOnReadableLocked(grpc_closure* read_closure) override {
GPR_ASSERT(read_closure_ == nullptr);
GPR_ASSERT((poll_events_ & UV_READABLE) == 0);
read_closure_ = read_closure;
poll_events_ |= UV_READABLE;
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb);
}
void RegisterForOnWriteableLocked(grpc_closure* write_closure) override {
GPR_ASSERT(write_closure_ == nullptr);
GPR_ASSERT((poll_events_ & UV_WRITABLE) == 0);
write_closure_ = write_closure;
poll_events_ |= UV_WRITABLE;
uv_poll_start(handle_, poll_events_, ares_uv_poll_cb);
}
bool IsFdStillReadableLocked() override {
/* uv_poll_t is based on poll, which is level triggered. So, if cares
* leaves some data unread, the event will trigger again. */
return false;
}
void ShutdownInternalLocked(grpc_error* error) {
uv_poll_stop(handle_);
uv_close(reinterpret_cast<uv_handle_t*>(handle_), ares_uv_poll_close_cb);
if (read_closure_ != nullptr) {
GRPC_CLOSURE_SCHED(read_closure_, GRPC_ERROR_CANCELLED);
}
if (write_closure_ != nullptr) {
GRPC_CLOSURE_SCHED(write_closure_, GRPC_ERROR_CANCELLED);
}
}
void ShutdownLocked(grpc_error* error) override {
if (grpc_core::ExecCtx::Get() == nullptr) {
grpc_core::ExecCtx exec_ctx;
ShutdownInternalLocked(error);
} else {
ShutdownInternalLocked(error);
}
}
ares_socket_t GetWrappedAresSocketLocked() override { return as_; }
const char* GetName() override { return name_; }
char* name_;
ares_socket_t as_;
uv_poll_t* handle_;
grpc_closure* read_closure_ = nullptr;
grpc_closure* write_closure_ = nullptr;
int poll_events_ = 0;
grpc_combiner* combiner_;
};
struct AresUvPollCbArg {
AresUvPollCbArg(uv_poll_t* handle, int status, int events)
: handle(handle), status(status), events(events) {}
uv_poll_t* handle;
int status;
int events;
};
static void ares_uv_poll_cb_locked(void* arg, grpc_error* error) {
grpc_core::UniquePtr<AresUvPollCbArg> arg_struct(
reinterpret_cast<AresUvPollCbArg*>(arg));
uv_poll_t* handle = arg_struct->handle;
int status = arg_struct->status;
int events = arg_struct->events;
GrpcPolledFdLibuv* polled_fd =
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
if (status < 0) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error");
error =
grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
grpc_slice_from_static_string(uv_strerror(status)));
}
if (events & UV_READABLE) {
GPR_ASSERT(polled_fd->read_closure_ != nullptr);
GRPC_CLOSURE_SCHED(polled_fd->read_closure_, error);
polled_fd->read_closure_ = nullptr;
polled_fd->poll_events_ &= ~UV_READABLE;
}
if (events & UV_WRITABLE) {
GPR_ASSERT(polled_fd->write_closure_ != nullptr);
GRPC_CLOSURE_SCHED(polled_fd->write_closure_, error);
polled_fd->write_closure_ = nullptr;
polled_fd->poll_events_ &= ~UV_WRITABLE;
}
uv_poll_start(handle, polled_fd->poll_events_, ares_uv_poll_cb);
}
void ares_uv_poll_cb(uv_poll_t* handle, int status, int events) {
grpc_core::ExecCtx exec_ctx;
GrpcPolledFdLibuv* polled_fd =
reinterpret_cast<GrpcPolledFdLibuv*>(handle->data);
AresUvPollCbArg* arg = New<AresUvPollCbArg>(handle, status, events);
GRPC_CLOSURE_SCHED(
GRPC_CLOSURE_CREATE(ares_uv_poll_cb_locked, arg,
grpc_combiner_scheduler(polled_fd->combiner_)),
GRPC_ERROR_NONE);
}
class GrpcPolledFdFactoryLibuv : public GrpcPolledFdFactory {
public:
GrpcPolledFd* NewGrpcPolledFdLocked(ares_socket_t as,
grpc_pollset_set* driver_pollset_set,
grpc_combiner* combiner) override {
return New<GrpcPolledFdLibuv>(as, combiner);
}
void ConfigureAresChannelLocked(ares_channel channel) override {}
};
UniquePtr<GrpcPolledFdFactory> NewGrpcPolledFdFactory(grpc_combiner* combiner) {
return UniquePtr<GrpcPolledFdFactory>(New<GrpcPolledFdFactoryLibuv>());
}
} // namespace grpc_core
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */

@ -445,7 +445,8 @@ class SockToPolledFdMap {
*/
static ares_socket_t Socket(int af, int type, int protocol, void* user_data) {
SockToPolledFdMap* map = static_cast<SockToPolledFdMap*>(user_data);
SOCKET s = WSASocket(af, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED);
SOCKET s = WSASocket(af, type, protocol, nullptr, 0,
grpc_get_default_wsa_socket_flags());
if (s == INVALID_SOCKET) {
return s;
}

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES == 1 && !defined(GRPC_UV)
#if GRPC_ARES == 1
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/lib/iomgr/sockaddr.h"
@ -687,4 +687,4 @@ void (*grpc_resolve_address_ares)(
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl;
#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
#endif /* GRPC_ARES == 1 */

@ -18,7 +18,7 @@
#include <grpc/support/port_platform.h>
#if GRPC_ARES != 1 || defined(GRPC_UV)
#if GRPC_ARES != 1
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
@ -62,4 +62,4 @@ void (*grpc_resolve_address_ares)(
grpc_pollset_set* interested_parties, grpc_closure* on_done,
grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl;
#endif /* GRPC_ARES != 1 || defined(GRPC_UV) */
#endif /* GRPC_ARES != 1 */

@ -0,0 +1,52 @@
/*
*
* 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/iomgr/port.h"
#if GRPC_ARES == 1 && defined(GRPC_UV)
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
bool grpc_ares_query_ipv6() {
/* The libuv grpc code currently does not have the code to probe for this,
* so we assume for now that IPv6 is always available in contexts where this
* code will be used. */
return true;
}
bool grpc_ares_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs) {
char* host = nullptr;
char* port = nullptr;
bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port,
addrs, &host, &port);
gpr_free(host);
gpr_free(port);
return out;
}
#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */

@ -0,0 +1,83 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/iomgr/port.h"
#if GRPC_ARES == 1 && (defined(GRPC_UV) || defined(GPR_WINDOWS))
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port) {
gpr_split_host_port(name, host, port);
if (*host == nullptr) {
gpr_log(GPR_ERROR,
"Failed to parse %s into host:port during manual localhost "
"resolution check.",
name);
return false;
}
if (*port == nullptr) {
if (default_port == nullptr) {
gpr_log(GPR_ERROR,
"No port or default port for %s during manual localhost "
"resolution check.",
name);
return false;
}
*port = gpr_strdup(default_port);
}
if (gpr_stricmp(*host, "localhost") == 0) {
GPR_ASSERT(*addrs == nullptr);
*addrs = grpc_core::MakeUnique<grpc_core::ServerAddressList>();
uint16_t numeric_port = grpc_strhtons(*port);
// Append the ipv6 loopback address.
struct sockaddr_in6 ipv6_loopback_addr;
memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
ipv6_loopback_addr.sin6_family = AF_INET6;
ipv6_loopback_addr.sin6_port = numeric_port;
(*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
nullptr /* args */);
// Append the ipv4 loopback address.
struct sockaddr_in ipv4_loopback_addr;
memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
ipv4_loopback_addr.sin_family = AF_INET;
ipv4_loopback_addr.sin_port = numeric_port;
(*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
nullptr /* args */);
// Let the address sorter figure out which one should be tried first.
grpc_cares_wrapper_address_sorting_sort(addrs->get());
return true;
}
return false;
}
#endif /* GRPC_ARES == 1 && (defined(GRPC_UV) || defined(GPR_WINDOWS)) */

@ -0,0 +1,34 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H
#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port);
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_LIBUV_WINDOWS_H \
*/

@ -25,6 +25,7 @@
#include "src/core/ext/filters/client_channel/parse_address.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/lib/gpr/host_port.h"
#include "src/core/lib/gpr/string.h"
@ -32,56 +33,6 @@
bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); }
static bool inner_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs, char** host,
char** port) {
gpr_split_host_port(name, host, port);
if (*host == nullptr) {
gpr_log(GPR_ERROR,
"Failed to parse %s into host:port during Windows localhost "
"resolution check.",
name);
return false;
}
if (*port == nullptr) {
if (default_port == nullptr) {
gpr_log(GPR_ERROR,
"No port or default port for %s during Windows localhost "
"resolution check.",
name);
return false;
}
*port = gpr_strdup(default_port);
}
if (gpr_stricmp(*host, "localhost") == 0) {
GPR_ASSERT(*addrs == nullptr);
*addrs = grpc_core::MakeUnique<grpc_core::ServerAddressList>();
uint16_t numeric_port = grpc_strhtons(*port);
// Append the ipv6 loopback address.
struct sockaddr_in6 ipv6_loopback_addr;
memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr));
((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1;
ipv6_loopback_addr.sin6_family = AF_INET6;
ipv6_loopback_addr.sin6_port = numeric_port;
(*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr),
nullptr /* args */);
// Append the ipv4 loopback address.
struct sockaddr_in ipv4_loopback_addr;
memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr));
((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f;
((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01;
ipv4_loopback_addr.sin_family = AF_INET;
ipv4_loopback_addr.sin_port = numeric_port;
(*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr),
nullptr /* args */);
// Let the address sorter figure out which one should be tried first.
grpc_cares_wrapper_address_sorting_sort(addrs->get());
return true;
}
return false;
}
bool grpc_ares_maybe_resolve_localhost_manually_locked(
const char* name, const char* default_port,
grpc_core::UniquePtr<grpc_core::ServerAddressList>* addrs) {

@ -35,6 +35,7 @@
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/optional.h"
#include "src/core/lib/uri/uri_parser.h"
// As per the retry design, we do not allow more than 5 retry attempts.
@ -43,80 +44,68 @@
namespace grpc_core {
namespace internal {
namespace {
size_t g_client_channel_service_config_parser_index;
}
size_t ClientChannelServiceConfigParser::ParserIndex() {
return g_client_channel_service_config_parser_index;
}
void ClientChannelServiceConfigParser::Register() {
g_client_channel_service_config_parser_index =
ServiceConfig::RegisterParser(UniquePtr<ServiceConfig::Parser>(
New<ClientChannelServiceConfigParser>()));
}
ProcessedResolverResult::ProcessedResolverResult(
Resolver::Result* resolver_result, bool parse_retry)
: service_config_(resolver_result->service_config) {
const Resolver::Result& resolver_result)
: service_config_(resolver_result.service_config) {
// If resolver did not return a service config, use the default
// specified via the client API.
if (service_config_ == nullptr) {
const char* service_config_json = grpc_channel_arg_get_string(
grpc_channel_args_find(resolver_result->args, GRPC_ARG_SERVICE_CONFIG));
grpc_channel_args_find(resolver_result.args, GRPC_ARG_SERVICE_CONFIG));
if (service_config_json != nullptr) {
grpc_error* error = GRPC_ERROR_NONE;
service_config_ = ServiceConfig::Create(service_config_json, &error);
// Error is currently unused.
GRPC_ERROR_UNREF(error);
}
} else {
// Add the service config JSON to channel args so that it's
// accessible in the subchannel.
// TODO(roth): Consider whether there's a better way to pass the
// service config down into the subchannel stack, such as maybe via
// call context or metadata. This would avoid the problem of having
// to recreate all subchannels whenever the service config changes.
// It would also avoid the need to pass in the resolver result in
// mutable form, both here and in
// ResolvingLoadBalancingPolicy::ProcessResolverResultCallback().
grpc_arg arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_SERVICE_CONFIG),
const_cast<char*>(service_config_->service_config_json()));
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(resolver_result->args, &arg, 1);
grpc_channel_args_destroy(resolver_result->args);
resolver_result->args = new_args;
}
// Process service config.
ProcessServiceConfig(*resolver_result, parse_retry);
// If no LB config was found above, just find the LB policy name then.
if (lb_policy_name_ == nullptr) ProcessLbPolicyName(*resolver_result);
const ClientChannelGlobalParsedObject* parsed_object = nullptr;
if (service_config_ != nullptr) {
parsed_object = static_cast<const ClientChannelGlobalParsedObject*>(
service_config_->GetParsedGlobalServiceConfigObject(
ClientChannelServiceConfigParser::ParserIndex()));
ProcessServiceConfig(resolver_result, parsed_object);
}
ProcessLbPolicy(resolver_result, parsed_object);
}
void ProcessedResolverResult::ProcessServiceConfig(
const Resolver::Result& resolver_result, bool parse_retry) {
if (service_config_ == nullptr) return;
service_config_json_ =
UniquePtr<char>(gpr_strdup(service_config_->service_config_json()));
if (parse_retry) {
const grpc_arg* channel_arg =
grpc_channel_args_find(resolver_result.args, GRPC_ARG_SERVER_URI);
const char* server_uri = grpc_channel_arg_get_string(channel_arg);
GPR_ASSERT(server_uri != nullptr);
grpc_uri* uri = grpc_uri_parse(server_uri, true);
GPR_ASSERT(uri->path[0] != '\0');
server_name_ = uri->path[0] == '/' ? uri->path + 1 : uri->path;
service_config_->ParseGlobalParams(ParseServiceConfig, this);
grpc_uri_destroy(uri);
} else {
service_config_->ParseGlobalParams(ParseServiceConfig, this);
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object) {
health_check_service_name_ = parsed_object->health_check_service_name();
service_config_json_ = service_config_->service_config_json();
if (parsed_object != nullptr) {
retry_throttle_data_ = parsed_object->retry_throttling();
}
method_params_table_ = service_config_->CreateMethodConfigTable(
ClientChannelMethodParams::CreateFromJson);
}
void ProcessedResolverResult::ProcessLbPolicyName(
const Resolver::Result& resolver_result) {
// Prefer the LB policy name found in the service config. Note that this is
// checking the deprecated loadBalancingPolicy field, rather than the new
// loadBalancingConfig field.
if (service_config_ != nullptr) {
lb_policy_name_.reset(
gpr_strdup(service_config_->GetLoadBalancingPolicyName()));
// Convert to lower-case.
if (lb_policy_name_ != nullptr) {
char* lb_policy_name = lb_policy_name_.get();
for (size_t i = 0; i < strlen(lb_policy_name); ++i) {
lb_policy_name[i] = tolower(lb_policy_name[i]);
}
void ProcessedResolverResult::ProcessLbPolicy(
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object) {
// Prefer the LB policy name found in the service config.
if (parsed_object != nullptr) {
if (parsed_object->parsed_lb_config() != nullptr) {
lb_policy_name_.reset(
gpr_strdup(parsed_object->parsed_lb_config()->name()));
lb_policy_config_ = parsed_object->parsed_lb_config();
} else {
lb_policy_name_.reset(
gpr_strdup(parsed_object->parsed_deprecated_lb_policy()));
}
}
// Otherwise, find the LB policy name set by the client API.
@ -152,97 +141,8 @@ void ProcessedResolverResult::ProcessLbPolicyName(
}
}
void ProcessedResolverResult::ParseServiceConfig(
const grpc_json* field, ProcessedResolverResult* parsing_state) {
parsing_state->ParseLbConfigFromServiceConfig(field);
if (parsing_state->server_name_ != nullptr) {
parsing_state->ParseRetryThrottleParamsFromServiceConfig(field);
}
}
void ProcessedResolverResult::ParseLbConfigFromServiceConfig(
const grpc_json* field) {
if (lb_policy_config_ != nullptr) return; // Already found.
if (field->key == nullptr || strcmp(field->key, "loadBalancingConfig") != 0) {
return; // Not the LB config global parameter.
}
const grpc_json* policy =
LoadBalancingPolicy::ParseLoadBalancingConfig(field);
if (policy != nullptr) {
lb_policy_name_.reset(gpr_strdup(policy->key));
lb_policy_config_ =
MakeRefCounted<LoadBalancingPolicy::Config>(policy, service_config_);
}
}
void ProcessedResolverResult::ParseRetryThrottleParamsFromServiceConfig(
const grpc_json* field) {
if (strcmp(field->key, "retryThrottling") == 0) {
if (retry_throttle_data_ != nullptr) return; // Duplicate.
if (field->type != GRPC_JSON_OBJECT) return;
int max_milli_tokens = 0;
int milli_token_ratio = 0;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) return;
if (strcmp(sub_field->key, "maxTokens") == 0) {
if (max_milli_tokens != 0) return; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return;
max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value);
if (max_milli_tokens == -1) return;
max_milli_tokens *= 1000;
} else if (strcmp(sub_field->key, "tokenRatio") == 0) {
if (milli_token_ratio != 0) return; // Duplicate.
if (sub_field->type != GRPC_JSON_NUMBER) return;
// We support up to 3 decimal digits.
size_t whole_len = strlen(sub_field->value);
uint32_t multiplier = 1;
uint32_t decimal_value = 0;
const char* decimal_point = strchr(sub_field->value, '.');
if (decimal_point != nullptr) {
whole_len = static_cast<size_t>(decimal_point - sub_field->value);
multiplier = 1000;
size_t decimal_len = strlen(decimal_point + 1);
if (decimal_len > 3) decimal_len = 3;
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
&decimal_value)) {
return;
}
uint32_t decimal_multiplier = 1;
for (size_t i = 0; i < (3 - decimal_len); ++i) {
decimal_multiplier *= 10;
}
decimal_value *= decimal_multiplier;
}
uint32_t whole_value;
if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
&whole_value)) {
return;
}
milli_token_ratio =
static_cast<int>((whole_value * multiplier) + decimal_value);
if (milli_token_ratio <= 0) return;
}
}
retry_throttle_data_ =
grpc_core::internal::ServerRetryThrottleMap::GetDataForServer(
server_name_, max_milli_tokens, milli_token_ratio);
}
}
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
@ -275,18 +175,36 @@ bool ParseDuration(grpc_json* field, grpc_millis* duration) {
return true;
}
UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
grpc_json* field) {
auto retry_policy = MakeUnique<ClientChannelMethodParams::RetryPolicy>();
if (field->type != GRPC_JSON_OBJECT) return nullptr;
UniquePtr<ClientChannelMethodParsedObject::RetryPolicy> ParseRetryPolicy(
grpc_json* field, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
auto retry_policy =
MakeUnique<ClientChannelMethodParsedObject::RetryPolicy>();
if (field->type != GRPC_JSON_OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryPolicy error:should be of type object");
return nullptr;
}
InlinedVector<grpc_error*, 4> error_list;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) return nullptr;
if (sub_field->key == nullptr) continue;
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;
if (retry_policy->max_attempts != 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxAttempts error:Duplicate entry"));
} // Duplicate. Continue Parsing
if (sub_field->type != GRPC_JSON_NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxAttempts error:should be of type number"));
continue;
}
retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value);
if (retry_policy->max_attempts <= 1) return nullptr;
if (retry_policy->max_attempts <= 1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxAttempts error:should be at least 2"));
continue;
}
if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
gpr_log(GPR_ERROR,
"service config: clamped retryPolicy.maxAttempts at %d",
@ -294,78 +212,375 @@ UniquePtr<ClientChannelMethodParams::RetryPolicy> ParseRetryPolicy(
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 (retry_policy->initial_backoff > 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:Duplicate entry"));
} // Duplicate, continue parsing.
if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:Failed to parse"));
continue;
}
if (retry_policy->initial_backoff == 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:must be greater than 0"));
}
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 (retry_policy->max_backoff > 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:Duplicate entry"));
} // Duplicate, continue parsing.
if (!ParseDuration(sub_field, &retry_policy->max_backoff)) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:failed to parse"));
continue;
}
if (retry_policy->max_backoff == 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:should be greater than 0"));
}
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 (retry_policy->backoff_multiplier != 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:Duplicate entry"));
} // Duplicate, continue parsing.
if (sub_field->type != GRPC_JSON_NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:should be of type number"));
continue;
}
if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) !=
1) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:failed to parse"));
continue;
}
if (retry_policy->backoff_multiplier <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:should be greater than 0"));
}
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.
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:Duplicate entry"));
} // Duplicate, continue parsing.
if (sub_field->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:should be of type array"));
continue;
}
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;
if (element->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:status codes should be of type "
"string"));
continue;
}
grpc_status_code status;
if (!grpc_status_code_from_string(element->value, &status)) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:failed to parse status code"));
continue;
}
retry_policy->retryable_status_codes.Add(status);
}
if (retry_policy->retryable_status_codes.Empty()) return nullptr;
if (retry_policy->retryable_status_codes.Empty()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:should be non-empty"));
};
}
}
// 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()) {
if (error_list.empty()) {
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()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryPolicy error:Missing required field(s)");
return nullptr;
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr;
}
const char* ParseHealthCheckConfig(const grpc_json* field, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
const char* service_name = nullptr;
GPR_DEBUG_ASSERT(strcmp(field->key, "healthCheckConfig") == 0);
if (field->type != GRPC_JSON_OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:healthCheckConfig error:should be of type object");
return nullptr;
}
InlinedVector<grpc_error*, 2> error_list;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) {
GPR_DEBUG_ASSERT(false);
continue;
}
if (strcmp(sub_field->key, "serviceName") == 0) {
if (service_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceName error:Duplicate "
"entry"));
} // Duplicate. Continue parsing
if (sub_field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceName error:should be of type string"));
continue;
}
service_name = sub_field->value;
}
}
if (!error_list.empty()) {
return nullptr;
}
return retry_policy;
*error =
GRPC_ERROR_CREATE_FROM_VECTOR("field:healthCheckConfig", &error_list);
return service_name;
}
} // namespace
RefCountedPtr<ClientChannelMethodParams>
ClientChannelMethodParams::CreateFromJson(const grpc_json* json) {
RefCountedPtr<ClientChannelMethodParams> method_params =
MakeRefCounted<ClientChannelMethodParams>();
UniquePtr<ServiceConfig::ParsedConfig>
ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config;
UniquePtr<char> lb_policy_name;
Optional<ClientChannelGlobalParsedObject::RetryThrottling> retry_throttling;
const char* health_check_service_name = nullptr;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key == nullptr) {
continue; // Not the LB config global parameter
}
// Parsed Load balancing config
if (strcmp(field->key, "loadBalancingConfig") == 0) {
if (parsed_lb_config != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingConfig error:Duplicate entry"));
} // Duplicate, continue parsing.
grpc_error* parse_error = GRPC_ERROR_NONE;
parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
field, &parse_error);
if (parsed_lb_config == nullptr) {
error_list.push_back(parse_error);
}
}
// Parse deprecated loadBalancingPolicy
if (strcmp(field->key, "loadBalancingPolicy") == 0) {
if (lb_policy_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:Duplicate entry"));
} // Duplicate, continue parsing.
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:type should be string"));
continue;
}
lb_policy_name.reset(gpr_strdup(field->value));
char* lb_policy = lb_policy_name.get();
if (lb_policy != nullptr) {
for (size_t i = 0; i < strlen(lb_policy); ++i) {
lb_policy[i] = tolower(lb_policy[i]);
}
}
bool requires_config = false;
if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
lb_policy, &requires_config)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:Unknown lb policy"));
} else if (requires_config) {
char* error_msg;
gpr_asprintf(&error_msg,
"field:loadBalancingPolicy error:%s requires a config. "
"Please use loadBalancingConfig instead.",
lb_policy);
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg));
gpr_free(error_msg);
}
}
// Parse retry throttling
if (strcmp(field->key, "retryThrottling") == 0) {
if (retry_throttling.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling error:Duplicate entry"));
} // Duplicate, continue parsing.
if (field->type != GRPC_JSON_OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling error:Type should be object"));
continue;
}
Optional<int> max_milli_tokens;
Optional<int> milli_token_ratio;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) continue;
if (strcmp(sub_field->key, "maxTokens") == 0) {
if (max_milli_tokens.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:Duplicate "
"entry"));
} // Duplicate, continue parsing.
if (sub_field->type != GRPC_JSON_NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:Type should be "
"number"));
} else {
max_milli_tokens.set(gpr_parse_nonnegative_int(sub_field->value) *
1000);
if (max_milli_tokens.value() <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:should be "
"greater than zero"));
}
}
} else if (strcmp(sub_field->key, "tokenRatio") == 0) {
if (milli_token_ratio.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Duplicate "
"entry"));
} // Duplicate, continue parsing.
if (sub_field->type != GRPC_JSON_NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:type should be "
"number"));
} else {
// We support up to 3 decimal digits.
size_t whole_len = strlen(sub_field->value);
uint32_t multiplier = 1;
uint32_t decimal_value = 0;
const char* decimal_point = strchr(sub_field->value, '.');
if (decimal_point != nullptr) {
whole_len = static_cast<size_t>(decimal_point - sub_field->value);
multiplier = 1000;
size_t decimal_len = strlen(decimal_point + 1);
if (decimal_len > 3) decimal_len = 3;
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
&decimal_value)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
continue;
}
uint32_t decimal_multiplier = 1;
for (size_t i = 0; i < (3 - decimal_len); ++i) {
decimal_multiplier *= 10;
}
decimal_value *= decimal_multiplier;
}
uint32_t whole_value;
if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len,
&whole_value)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
continue;
}
milli_token_ratio.set(
static_cast<int>((whole_value * multiplier) + decimal_value));
if (milli_token_ratio.value() <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:value should "
"be greater than 0"));
}
}
}
}
ClientChannelGlobalParsedObject::RetryThrottling data;
if (!max_milli_tokens.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:Not found"));
} else {
data.max_milli_tokens = max_milli_tokens.value();
}
if (!milli_token_ratio.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Not found"));
} else {
data.milli_token_ratio = milli_token_ratio.value();
}
retry_throttling.set(data);
}
if (strcmp(field->key, "healthCheckConfig") == 0) {
if (health_check_service_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:healthCheckConfig error:Duplicate entry"));
} // Duplicate continue parsing
grpc_error* parsing_error = GRPC_ERROR_NONE;
health_check_service_name = ParseHealthCheckConfig(field, &parsing_error);
if (parsing_error != GRPC_ERROR_NONE) {
error_list.push_back(parsing_error);
}
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel global parser",
&error_list);
if (*error == GRPC_ERROR_NONE) {
return UniquePtr<ServiceConfig::ParsedConfig>(
New<ClientChannelGlobalParsedObject>(
std::move(parsed_lb_config), std::move(lb_policy_name),
retry_throttling, health_check_service_name));
}
return nullptr;
}
UniquePtr<ServiceConfig::ParsedConfig>
ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
Optional<bool> wait_for_ready;
grpc_millis timeout = 0;
UniquePtr<ClientChannelMethodParsedObject::RetryPolicy> retry_policy;
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;
if (wait_for_ready.has_value()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:waitForReady error:Duplicate entry"));
} // Duplicate, continue parsing.
if (field->type == GRPC_JSON_TRUE) {
wait_for_ready.set(true);
} else if (field->type == GRPC_JSON_FALSE) {
wait_for_ready.set(false);
} else {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:waitForReady error:Type should be true/false"));
}
} else if (strcmp(field->key, "timeout") == 0) {
if (method_params->timeout_ > 0) return nullptr; // Duplicate.
if (!ParseDuration(field, &method_params->timeout_)) return nullptr;
if (timeout > 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:timeout error:Duplicate entry"));
} // Duplicate, continue parsing.
if (!ParseDuration(field, &timeout)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:timeout error:Failed parsing"));
};
} else if (strcmp(field->key, "retryPolicy") == 0) {
if (method_params->retry_policy_ != nullptr) {
return nullptr; // Duplicate.
if (retry_policy != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryPolicy error:Duplicate entry"));
} // Duplicate, continue parsing.
grpc_error* error = GRPC_ERROR_NONE;
retry_policy = ParseRetryPolicy(field, &error);
if (retry_policy == nullptr) {
error_list.push_back(error);
}
method_params->retry_policy_ = ParseRetryPolicy(field);
if (method_params->retry_policy_ == nullptr) return nullptr;
}
}
return method_params;
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
if (*error == GRPC_ERROR_NONE) {
return UniquePtr<ServiceConfig::ParsedConfig>(
New<ClientChannelMethodParsedObject>(timeout, wait_for_ready,
std::move(retry_policy)));
}
return nullptr;
}
} // namespace internal

@ -22,10 +22,12 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/resolver.h"
#include "src/core/ext/filters/client_channel/retry_throttle.h"
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gprpp/optional.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
@ -35,44 +37,123 @@
namespace grpc_core {
namespace internal {
class ClientChannelMethodParams;
class ClientChannelGlobalParsedObject : public ServiceConfig::ParsedConfig {
public:
struct RetryThrottling {
intptr_t max_milli_tokens = 0;
intptr_t milli_token_ratio = 0;
};
ClientChannelGlobalParsedObject(
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config,
UniquePtr<char> parsed_deprecated_lb_policy,
const Optional<RetryThrottling>& retry_throttling,
const char* health_check_service_name)
: parsed_lb_config_(std::move(parsed_lb_config)),
parsed_deprecated_lb_policy_(std::move(parsed_deprecated_lb_policy)),
retry_throttling_(retry_throttling),
health_check_service_name_(health_check_service_name) {}
Optional<RetryThrottling> retry_throttling() const {
return retry_throttling_;
}
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config() const {
return parsed_lb_config_;
}
const char* parsed_deprecated_lb_policy() const {
return parsed_deprecated_lb_policy_.get();
}
const char* health_check_service_name() const {
return health_check_service_name_;
}
private:
RefCountedPtr<ParsedLoadBalancingConfig> parsed_lb_config_;
UniquePtr<char> parsed_deprecated_lb_policy_;
Optional<RetryThrottling> retry_throttling_;
const char* health_check_service_name_;
};
class ClientChannelMethodParsedObject : public ServiceConfig::ParsedConfig {
public:
struct RetryPolicy {
int max_attempts = 0;
grpc_millis initial_backoff = 0;
grpc_millis max_backoff = 0;
float backoff_multiplier = 0;
StatusCodeSet retryable_status_codes;
};
ClientChannelMethodParsedObject(grpc_millis timeout,
const Optional<bool>& wait_for_ready,
UniquePtr<RetryPolicy> retry_policy)
: timeout_(timeout),
wait_for_ready_(wait_for_ready),
retry_policy_(std::move(retry_policy)) {}
grpc_millis timeout() const { return timeout_; }
Optional<bool> wait_for_ready() const { return wait_for_ready_; }
const RetryPolicy* retry_policy() const { return retry_policy_.get(); }
private:
grpc_millis timeout_ = 0;
Optional<bool> wait_for_ready_;
UniquePtr<RetryPolicy> retry_policy_;
};
class ClientChannelServiceConfigParser : public ServiceConfig::Parser {
public:
UniquePtr<ServiceConfig::ParsedConfig> ParseGlobalParams(
const grpc_json* json, grpc_error** error) override;
UniquePtr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override;
// A table mapping from a method name to its method parameters.
typedef SliceHashTable<RefCountedPtr<ClientChannelMethodParams>>
ClientChannelMethodParamsTable;
static size_t ParserIndex();
static void Register();
};
// A container of processed fields from the resolver result. Simplifies the
// usage of resolver result.
// TODO(yashykt): It would be cleaner to move this logic to the client_channel
// code. A container of processed fields from the resolver result. Simplifies
// the usage of resolver result.
class ProcessedResolverResult {
public:
// Processes the resolver result and populates the relative members
// for later consumption. Tries to parse retry parameters only if parse_retry
// is true.
ProcessedResolverResult(Resolver::Result* resolver_result, bool parse_retry);
// for later consumption.
ProcessedResolverResult(const Resolver::Result& resolver_result);
// Getters. Any managed object's ownership is transferred.
UniquePtr<char> service_config_json() {
return std::move(service_config_json_);
}
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data() {
return std::move(retry_throttle_data_);
}
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table() {
return std::move(method_params_table_);
}
const char* service_config_json() { return service_config_json_; }
RefCountedPtr<ServiceConfig> service_config() { return service_config_; }
UniquePtr<char> lb_policy_name() { return std::move(lb_policy_name_); }
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config() {
return std::move(lb_policy_config_);
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config() {
return lb_policy_config_;
}
Optional<ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data() {
return retry_throttle_data_;
}
const char* health_check_service_name() { return health_check_service_name_; }
private:
// Finds the service config; extracts LB config and (maybe) retry throttle
// params from it.
void ProcessServiceConfig(const Resolver::Result& resolver_result,
bool parse_retry);
void ProcessServiceConfig(
const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object);
// Finds the LB policy name (when no LB config was found).
void ProcessLbPolicyName(const Resolver::Result& resolver_result);
// Extracts the LB policy.
void ProcessLbPolicy(const Resolver::Result& resolver_result,
const ClientChannelGlobalParsedObject* parsed_object);
// Parses the service config. Intended to be used by
// ServiceConfig::ParseGlobalParams.
@ -84,59 +165,15 @@ class ProcessedResolverResult {
void ParseRetryThrottleParamsFromServiceConfig(const grpc_json* field);
// Service config.
UniquePtr<char> service_config_json_;
const char* service_config_json_ = nullptr;
RefCountedPtr<ServiceConfig> service_config_;
// LB policy.
UniquePtr<char> lb_policy_name_;
RefCountedPtr<LoadBalancingPolicy::Config> lb_policy_config_;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config_;
// Retry throttle data.
char* server_name_ = nullptr;
RefCountedPtr<ServerRetryThrottleData> retry_throttle_data_;
// Method params table.
RefCountedPtr<ClientChannelMethodParamsTable> method_params_table_;
};
// The parameters of a method.
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);
// So Delete() can call our private dtor.
template <typename T>
friend void grpc_core::Delete(T*);
ClientChannelMethodParams() {}
virtual ~ClientChannelMethodParams() {}
grpc_millis timeout_ = 0;
WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET;
UniquePtr<RetryPolicy> retry_policy_;
Optional<ClientChannelGlobalParsedObject::RetryThrottling>
retry_throttle_data_;
const char* health_check_service_name_ = nullptr;
};
} // namespace internal

@ -183,7 +183,8 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name, RefCountedPtr<Config> child_lb_config,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
grpc_error** error)
: LoadBalancingPolicy(std::move(args)),
tracer_(tracer),
@ -331,7 +332,8 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
}
void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name, RefCountedPtr<Config> lb_policy_config,
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings) {
// If the child policy name changes, we need to create a new child
// policy. When this happens, we leave child_policy_ as-is and store
@ -528,11 +530,11 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
const bool resolution_contains_addresses = result.addresses.size() > 0;
// Process the resolver result.
const char* lb_policy_name = nullptr;
RefCountedPtr<Config> lb_policy_config;
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config;
bool service_config_changed = false;
if (process_resolver_result_ != nullptr) {
service_config_changed =
process_resolver_result_(process_resolver_result_user_data_, &result,
process_resolver_result_(process_resolver_result_user_data_, result,
&lb_policy_name, &lb_policy_config);
} else {
lb_policy_name = child_policy_name_.get();
@ -540,7 +542,7 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
}
GPR_ASSERT(lb_policy_name != nullptr);
// Create or update LB policy, as needed.
CreateOrUpdateLbPolicyLocked(lb_policy_name, std::move(lb_policy_config),
CreateOrUpdateLbPolicyLocked(lb_policy_name, lb_policy_config,
std::move(result), &trace_strings);
// Add channel trace event.
if (channelz_node() != nullptr) {

@ -23,6 +23,7 @@
#include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/resolver.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_stack.h"
@ -53,11 +54,11 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
public:
// If error is set when this returns, then construction failed, and
// the caller may not use the new object.
ResolvingLoadBalancingPolicy(Args args, TraceFlag* tracer,
UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<Config> child_lb_config,
grpc_error** error);
ResolvingLoadBalancingPolicy(
Args args, TraceFlag* tracer, UniquePtr<char> target_uri,
UniquePtr<char> child_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config,
grpc_error** error);
// Private ctor, to be used by client_channel only!
//
@ -65,8 +66,9 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
// lb_policy_name and lb_policy_config to point to the right data.
// Returns true if the service config has changed since the last result.
typedef bool (*ProcessResolverResultCallback)(
void* user_data, Resolver::Result* result, const char** lb_policy_name,
RefCountedPtr<Config>* lb_policy_config);
void* user_data, const Resolver::Result& result,
const char** lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig>* lb_policy_config);
// If error is set when this returns, then construction failed, and
// the caller may not use the new object.
ResolvingLoadBalancingPolicy(
@ -102,10 +104,10 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
void StartResolvingLocked();
void OnResolverError(grpc_error* error);
void CreateOrUpdateLbPolicyLocked(const char* lb_policy_name,
RefCountedPtr<Config> lb_policy_config,
Resolver::Result result,
TraceStringVector* trace_strings);
void CreateOrUpdateLbPolicyLocked(
const char* lb_policy_name,
RefCountedPtr<ParsedLoadBalancingConfig> lb_policy_config,
Resolver::Result result, TraceStringVector* trace_strings);
OrphanablePtr<LoadBalancingPolicy> CreateLbPolicyLocked(
const char* lb_policy_name, const grpc_channel_args& args,
TraceStringVector* trace_strings);
@ -121,7 +123,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy {
ProcessResolverResultCallback process_resolver_result_ = nullptr;
void* process_resolver_result_user_data_ = nullptr;
UniquePtr<char> child_policy_name_;
RefCountedPtr<Config> child_lb_config_;
RefCountedPtr<ParsedLoadBalancingConfig> child_lb_config_;
// Resolver and associated state.
OrphanablePtr<Resolver> resolver_;

@ -34,28 +34,10 @@
namespace grpc_core {
namespace {
typedef InlinedVector<UniquePtr<ServiceConfigParser>,
typedef InlinedVector<UniquePtr<ServiceConfig::Parser>,
ServiceConfig::kNumPreallocatedParsers>
ServiceConfigParserList;
ServiceConfigParserList* registered_parsers;
// Consumes all the errors in the vector and forms a referencing error from
// them. If the vector is empty, return GRPC_ERROR_NONE.
template <size_t N>
grpc_error* CreateErrorFromVector(const char* desc,
InlinedVector<grpc_error*, N>* error_list) {
grpc_error* error = GRPC_ERROR_NONE;
if (error_list->size() != 0) {
error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
desc, error_list->data(), error_list->size());
// Remove refs to all errors in error_list.
for (size_t i = 0; i < error_list->size(); i++) {
GRPC_ERROR_UNREF((*error_list)[i]);
}
error_list->clear();
}
return error;
}
ServiceConfigParserList* g_registered_parsers;
} // namespace
RefCountedPtr<ServiceConfig> ServiceConfig::Create(const char* json,
@ -107,16 +89,16 @@ grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) {
GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT);
GPR_DEBUG_ASSERT(json_tree_->key == nullptr);
InlinedVector<grpc_error*, 4> error_list;
for (size_t i = 0; i < registered_parsers->size(); i++) {
for (size_t i = 0; i < g_registered_parsers->size(); i++) {
grpc_error* parser_error = GRPC_ERROR_NONE;
auto parsed_obj =
(*registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error);
(*g_registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error);
if (parser_error != GRPC_ERROR_NONE) {
error_list.push_back(parser_error);
}
parsed_global_service_config_objects_.push_back(std::move(parsed_obj));
}
return CreateErrorFromVector("Global Params", &error_list);
return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list);
}
grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
@ -125,17 +107,20 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
size_t* idx) {
auto objs_vector = MakeUnique<ServiceConfigObjectsVector>();
InlinedVector<grpc_error*, 4> error_list;
for (size_t i = 0; i < registered_parsers->size(); i++) {
for (size_t i = 0; i < g_registered_parsers->size(); i++) {
grpc_error* parser_error = GRPC_ERROR_NONE;
auto parsed_obj =
(*registered_parsers)[i]->ParsePerMethodParams(json, &parser_error);
(*g_registered_parsers)[i]->ParsePerMethodParams(json, &parser_error);
if (parser_error != GRPC_ERROR_NONE) {
error_list.push_back(parser_error);
}
objs_vector->push_back(std::move(parsed_obj));
}
const auto* vector_ptr = objs_vector.get();
service_config_objects_vectors_storage_.push_back(std::move(objs_vector));
const auto* vector_ptr =
service_config_objects_vectors_storage_
[service_config_objects_vectors_storage_.size() - 1]
.get();
// Construct list of paths.
InlinedVector<UniquePtr<char>, 10> paths;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
@ -169,7 +154,7 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable(
++*idx;
}
wrap_error:
return CreateErrorFromVector("methodConfig", &error_list);
return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
}
grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
@ -226,28 +211,11 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
num_entries, entries, nullptr);
gpr_free(entries);
}
return CreateErrorFromVector("Method Params", &error_list);
return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
}
ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
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_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.
if (field->type != GRPC_JSON_STRING) return nullptr;
lb_policy_name = field->value;
}
}
return lb_policy_name;
}
int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
int num_names = 0;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
@ -319,8 +287,11 @@ UniquePtr<char> ServiceConfig::ParseJsonMethodName(grpc_json* json,
return UniquePtr<char>(path);
}
const ServiceConfig::ServiceConfigObjectsVector* const*
const ServiceConfig::ServiceConfigObjectsVector*
ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) {
if (parsed_method_service_config_objects_table_.get() == nullptr) {
return nullptr;
}
const auto* value = parsed_method_service_config_objects_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/*").
@ -339,22 +310,22 @@ ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) {
gpr_free(path_str);
if (value == nullptr) return nullptr;
}
return value;
return *value;
}
size_t ServiceConfig::RegisterParser(UniquePtr<ServiceConfigParser> parser) {
registered_parsers->push_back(std::move(parser));
return registered_parsers->size() - 1;
size_t ServiceConfig::RegisterParser(UniquePtr<Parser> parser) {
g_registered_parsers->push_back(std::move(parser));
return g_registered_parsers->size() - 1;
}
void ServiceConfig::Init() {
GPR_ASSERT(registered_parsers == nullptr);
registered_parsers = New<ServiceConfigParserList>();
GPR_ASSERT(g_registered_parsers == nullptr);
g_registered_parsers = New<ServiceConfigParserList>();
}
void ServiceConfig::Shutdown() {
Delete(registered_parsers);
registered_parsers = nullptr;
Delete(g_registered_parsers);
g_registered_parsers = nullptr;
}
} // namespace grpc_core

@ -55,41 +55,73 @@
namespace grpc_core {
/// This is the base class that all service config parsers MUST use to store
/// parsed service config data.
class ServiceConfigParsedObject {
class ServiceConfig : public RefCounted<ServiceConfig> {
public:
virtual ~ServiceConfigParsedObject() = default;
/// This is the base class that all service config parsers MUST use to store
/// parsed service config data.
class ParsedConfig {
public:
virtual ~ParsedConfig() = default;
GRPC_ABSTRACT_BASE_CLASS;
};
/// This is the base class that all service config parsers should derive from.
class Parser {
public:
virtual ~Parser() = default;
virtual UniquePtr<ParsedConfig> ParseGlobalParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
return nullptr;
}
GRPC_ABSTRACT_BASE_CLASS;
};
virtual UniquePtr<ParsedConfig> ParsePerMethodParams(const grpc_json* json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
return nullptr;
}
/// This is the base class that all service config parsers should derive from.
class ServiceConfigParser {
public:
virtual ~ServiceConfigParser() = default;
GRPC_ABSTRACT_BASE_CLASS;
};
virtual UniquePtr<ServiceConfigParsedObject> ParseGlobalParams(
const grpc_json* json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
return nullptr;
}
static constexpr int kNumPreallocatedParsers = 4;
typedef InlinedVector<UniquePtr<ParsedConfig>, kNumPreallocatedParsers>
ServiceConfigObjectsVector;
virtual UniquePtr<ServiceConfigParsedObject> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr);
return nullptr;
}
/// When a service config is applied to a call in the client_channel_filter,
/// we create an instance of this object and store it in the call_data for
/// client_channel. A pointer to this object is also stored in the
/// call_context, so that future filters can easily access method and global
/// parameters for the call.
class CallData {
public:
CallData() = default;
CallData(RefCountedPtr<ServiceConfig> svc_cfg, const grpc_slice& path)
: service_config_(std::move(svc_cfg)) {
if (service_config_ != nullptr) {
method_params_vector_ =
service_config_->GetMethodServiceConfigObjectsVector(path);
}
}
GRPC_ABSTRACT_BASE_CLASS;
};
ServiceConfig* service_config() { return service_config_.get(); }
class ServiceConfig : public RefCounted<ServiceConfig> {
public:
static constexpr int kNumPreallocatedParsers = 4;
typedef InlinedVector<UniquePtr<ServiceConfigParsedObject>,
kNumPreallocatedParsers>
ServiceConfigObjectsVector;
ParsedConfig* GetMethodParsedObject(size_t index) const {
return method_params_vector_ != nullptr
? (*method_params_vector_)[index].get()
: nullptr;
}
ParsedConfig* GetGlobalParsedObject(size_t index) const {
return service_config_->GetParsedGlobalServiceConfigObject(index);
}
private:
RefCountedPtr<ServiceConfig> service_config_;
const ServiceConfigObjectsVector* method_params_vector_ = nullptr;
};
/// Creates a new service config from parsing \a json_string.
/// Returns null on parse error.
@ -100,48 +132,18 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
const char* service_config_json() const { return service_config_json_.get(); }
/// 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) const;
/// 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, const grpc_slice& path);
/// Retrieves the parsed global service config object at index \a index.
ServiceConfigParsedObject* GetParsedGlobalServiceConfigObject(int index) {
GPR_DEBUG_ASSERT(
index < static_cast<int>(parsed_global_service_config_objects_.size()));
/// Retrieves the parsed global service config object at index \a index. The
/// lifetime of the returned object is tied to the lifetime of the
/// ServiceConfig object.
ParsedConfig* GetParsedGlobalServiceConfigObject(size_t index) {
GPR_DEBUG_ASSERT(index < parsed_global_service_config_objects_.size());
return parsed_global_service_config_objects_[index].get();
}
/// Retrieves the vector of method service config objects for a given path \a
/// path.
const ServiceConfigObjectsVector* const* GetMethodServiceConfigObjectsVector(
/// path. The lifetime of the returned vector and contained objects is tied to
/// the lifetime of the ServiceConfig object.
const ServiceConfigObjectsVector* GetMethodServiceConfigObjectsVector(
const grpc_slice& path);
/// Globally register a service config parser. On successful registration, it
@ -150,7 +152,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
/// registered parser. Each parser is responsible for reading the service
/// config json and returning a parsed object. This parsed object can later be
/// retrieved using the same index that was returned at registration time.
static size_t RegisterParser(UniquePtr<ServiceConfigParser> parser);
static size_t RegisterParser(UniquePtr<Parser> parser);
static void Init();
@ -178,14 +180,6 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
static UniquePtr<char> ParseJsonMethodName(grpc_json* json,
grpc_error** error);
// 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);
grpc_error* ParseJsonMethodConfigToServiceConfigObjectsTable(
const grpc_json* json,
SliceHashTable<const ServiceConfigObjectsVector*>::Entry* entries,
@ -195,7 +189,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
UniquePtr<char> json_string_; // Underlying storage for json_tree.
grpc_json* json_tree_;
InlinedVector<UniquePtr<ServiceConfigParsedObject>, kNumPreallocatedParsers>
InlinedVector<UniquePtr<ParsedConfig>, kNumPreallocatedParsers>
parsed_global_service_config_objects_;
// A map from the method name to the service config objects vector. Note that
// we are using a raw pointer and not a unique pointer so that we can use the
@ -208,133 +202,6 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
service_config_objects_vectors_storage_;
};
//
// 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) {
grpc_error* error = GRPC_ERROR_NONE;
UniquePtr<char> path = ParseJsonMethodName(name, &error);
// We are not reporting the error here.
GRPC_ERROR_UNREF(error);
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) const {
// 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) {
int count = CountNamesInMethodConfig(method);
if (count <= 0) return nullptr;
num_entries += static_cast<size_t>(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, const 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);
if (value == nullptr) return nullptr;
}
return RefCountedPtr<T>(*value);
}
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVICE_CONFIG_H */

@ -66,12 +66,13 @@
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
// Conversion between subchannel call and call stack.
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) \
(grpc_call_stack*)((char*)(call) + \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)))
#define CALL_STACK_TO_SUBCHANNEL_CALL(callstack) \
(SubchannelCall*)(((char*)(call_stack)) - \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)))
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) \
(grpc_call_stack*)((char*)(call) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(SubchannelCall)))
#define CALL_STACK_TO_SUBCHANNEL_CALL(callstack) \
(SubchannelCall*)(((char*)(call_stack)) - \
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(SubchannelCall)))
namespace grpc_core {
@ -151,10 +152,10 @@ RefCountedPtr<SubchannelCall> ConnectedSubchannel::CreateCall(
size_t ConnectedSubchannel::GetInitialCallSizeEstimate(
size_t parent_data_size) const {
size_t allocation_size =
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(SubchannelCall));
if (parent_data_size > 0) {
allocation_size +=
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(channel_stack_->call_stack_size) +
parent_data_size;
} else {
allocation_size += channel_stack_->call_stack_size;
@ -178,8 +179,9 @@ void SubchannelCall::StartTransportStreamOpBatch(
void* SubchannelCall::GetParentData() {
grpc_channel_stack* chanstk = connected_subchannel_->channel_stack();
return (char*)this + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(SubchannelCall)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(chanstk->call_stack_size);
return (char*)this +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(SubchannelCall)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(chanstk->call_stack_size);
}
grpc_call_stack* SubchannelCall::GetCallStack() {
@ -529,25 +531,6 @@ BackOff::Options ParseArgsForBackoffValues(
.set_max_backoff(max_backoff_ms);
}
struct HealthCheckParams {
UniquePtr<char> service_name;
static void Parse(const grpc_json* field, HealthCheckParams* params) {
if (strcmp(field->key, "healthCheckConfig") == 0) {
if (field->type != GRPC_JSON_OBJECT) return;
for (grpc_json* sub_field = field->child; sub_field != nullptr;
sub_field = sub_field->next) {
if (sub_field->key == nullptr) return;
if (strcmp(sub_field->key, "serviceName") == 0) {
if (params->service_name != nullptr) return; // Duplicate.
if (sub_field->type != GRPC_JSON_STRING) return;
params->service_name.reset(gpr_strdup(sub_field->value));
}
}
}
}
};
} // namespace
Subchannel::Subchannel(SubchannelKey* key, grpc_connector* connector,
@ -583,21 +566,9 @@ Subchannel::Subchannel(SubchannelKey* key, grpc_connector* connector,
"subchannel");
grpc_connectivity_state_init(&state_and_health_tracker_, GRPC_CHANNEL_IDLE,
"subchannel");
// Check whether we should enable health checking.
const char* service_config_json = grpc_channel_arg_get_string(
grpc_channel_args_find(args_, GRPC_ARG_SERVICE_CONFIG));
if (service_config_json != nullptr) {
grpc_error* service_config_error = GRPC_ERROR_NONE;
RefCountedPtr<ServiceConfig> service_config =
ServiceConfig::Create(service_config_json, &service_config_error);
// service_config_error is currently unused.
GRPC_ERROR_UNREF(service_config_error);
if (service_config != nullptr) {
HealthCheckParams params;
service_config->ParseGlobalParams(HealthCheckParams::Parse, &params);
health_check_service_name_ = std::move(params.service_name);
}
}
health_check_service_name_ =
UniquePtr<char>(gpr_strdup(grpc_channel_arg_get_string(
grpc_channel_args_find(args_, "grpc.temp.health_check"))));
const grpc_arg* arg = grpc_channel_args_find(args_, GRPC_ARG_ENABLE_CHANNELZ);
const bool channelz_enabled =
grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT);

@ -32,75 +32,78 @@
#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/call.h"
#include "src/core/lib/surface/channel_init.h"
typedef struct {
int max_send_size;
int max_recv_size;
} message_size_limits;
static void recv_message_ready(void* user_data, grpc_error* error);
static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
namespace grpc_core {
namespace {
class MessageSizeLimits : public RefCounted<MessageSizeLimits> {
public:
static RefCountedPtr<MessageSizeLimits> CreateFromJson(const grpc_json* json);
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;
}
message_size_limits limits_;
};
namespace {
size_t g_message_size_parser_index;
} // namespace
RefCountedPtr<MessageSizeLimits> MessageSizeLimits::CreateFromJson(
const grpc_json* json) {
UniquePtr<ServiceConfig::ParsedConfig> MessageSizeParser::ParsePerMethodParams(
const grpc_json* json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
int max_request_message_bytes = -1;
int max_response_message_bytes = -1;
InlinedVector<grpc_error*, 4> error_list;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "maxRequestMessageBytes") == 0) {
if (max_request_message_bytes >= 0) return nullptr; // Duplicate.
if (max_request_message_bytes >= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxRequestMessageBytes error:Duplicate entry"));
} // Duplicate, continue parsing.
if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxRequestMessageBytes error:should be of type number"));
} else {
max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_request_message_bytes == -1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxRequestMessageBytes error:should be non-negative"));
}
}
max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_request_message_bytes == -1) return nullptr;
} else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
if (max_response_message_bytes >= 0) return nullptr; // Duplicate.
if (max_response_message_bytes >= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxResponseMessageBytes error:Duplicate entry"));
} // Duplicate, continue parsing
if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) {
return nullptr;
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxResponseMessageBytes error:should be of type number"));
} else {
max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_response_message_bytes == -1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxResponseMessageBytes error:should be non-negative"));
}
}
max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
if (max_response_message_bytes == -1) return nullptr;
}
}
return MakeRefCounted<MessageSizeLimits>(max_request_message_bytes,
max_response_message_bytes);
if (!error_list.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Message size parser", &error_list);
return nullptr;
}
return UniquePtr<ServiceConfig::ParsedConfig>(New<MessageSizeParsedObject>(
max_request_message_bytes, max_response_message_bytes));
}
} // namespace
} // namespace grpc_core
void MessageSizeParser::Register() {
g_message_size_parser_index = ServiceConfig::RegisterParser(
UniquePtr<ServiceConfig::Parser>(New<MessageSizeParser>()));
}
static void recv_message_ready(void* user_data, grpc_error* error);
static void recv_trailing_metadata_ready(void* user_data, grpc_error* error);
size_t MessageSizeParser::ParserIndex() { return g_message_size_parser_index; }
} // namespace grpc_core
namespace {
struct channel_data {
message_size_limits limits;
// Maps path names to refcounted_message_size_limits structs.
grpc_core::RefCountedPtr<grpc_core::SliceHashTable<
grpc_core::RefCountedPtr<grpc_core::MessageSizeLimits>>>
method_limit_table;
grpc_core::MessageSizeParsedObject::message_size_limits limits;
grpc_core::RefCountedPtr<grpc_core::ServiceConfig> svc_cfg;
};
struct call_data {
@ -116,21 +119,34 @@ struct call_data {
// Note: Per-method config is only available on the client, so we
// apply the max request size to the send limit and the max response
// size to the receive limit.
if (chand.method_limit_table != nullptr) {
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 < this->limits.max_send_size ||
this->limits.max_send_size < 0)) {
this->limits.max_send_size = limits->limits().max_send_size;
}
if (limits->limits().max_recv_size >= 0 &&
(limits->limits().max_recv_size < this->limits.max_recv_size ||
this->limits.max_recv_size < 0)) {
this->limits.max_recv_size = limits->limits().max_recv_size;
}
const grpc_core::MessageSizeParsedObject* limits = nullptr;
grpc_core::ServiceConfig::CallData* svc_cfg_call_data = nullptr;
if (args.context != nullptr) {
svc_cfg_call_data = static_cast<grpc_core::ServiceConfig::CallData*>(
args.context[GRPC_SERVICE_CONFIG_CALL_DATA].value);
}
if (svc_cfg_call_data != nullptr) {
limits = static_cast<const grpc_core::MessageSizeParsedObject*>(
svc_cfg_call_data->GetMethodParsedObject(
grpc_core::MessageSizeParser::ParserIndex()));
} else if (chand.svc_cfg != nullptr) {
const auto* objs_vector =
chand.svc_cfg->GetMethodServiceConfigObjectsVector(args.path);
if (objs_vector != nullptr) {
limits = static_cast<const grpc_core::MessageSizeParsedObject*>(
(*objs_vector)[grpc_core::MessageSizeParser::ParserIndex()].get());
}
}
if (limits != nullptr) {
if (limits->limits().max_send_size >= 0 &&
(limits->limits().max_send_size < this->limits.max_send_size ||
this->limits.max_send_size < 0)) {
this->limits.max_send_size = limits->limits().max_send_size;
}
if (limits->limits().max_recv_size >= 0 &&
(limits->limits().max_recv_size < this->limits.max_recv_size ||
this->limits.max_recv_size < 0)) {
this->limits.max_recv_size = limits->limits().max_recv_size;
}
}
}
@ -138,7 +154,7 @@ struct call_data {
~call_data() { GRPC_ERROR_UNREF(error); }
grpc_core::CallCombiner* call_combiner;
message_size_limits limits;
grpc_core::MessageSizeParsedObject::message_size_limits limits;
// Receive closures are chained: we inject this closure as the
// recv_message_ready up-call on transport_stream_op, and remember to
// call our next_recv_message_ready member after handling it.
@ -284,9 +300,9 @@ static int default_size(const grpc_channel_args* args,
return without_minimal_stack;
}
message_size_limits get_message_size_limits(
grpc_core::MessageSizeParsedObject::message_size_limits get_message_size_limits(
const grpc_channel_args* channel_args) {
message_size_limits lim;
grpc_core::MessageSizeParsedObject::message_size_limits lim;
lim.max_send_size =
default_size(channel_args, GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH);
lim.max_recv_size =
@ -313,21 +329,27 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem,
grpc_channel_element_args* args) {
GPR_ASSERT(!args->is_last);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
new (chand) channel_data();
chand->limits = get_message_size_limits(args->channel_args);
// Get method config table from channel args.
// TODO(yashykt): We only need to read GRPC_ARG_SERVICE_CONFIG in the case of
// direct channels. (Service config is otherwise stored in the call_context by
// client_channel filter.) If we ever need a second filter that also needs to
// parse GRPC_ARG_SERVICE_CONFIG, we should refactor this code and add a
// separate filter that reads GRPC_ARG_SERVICE_CONFIG and saves the parsed
// config in the call_context.
const grpc_arg* channel_arg =
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_error* service_config_error = GRPC_ERROR_NONE;
grpc_core::RefCountedPtr<grpc_core::ServiceConfig> service_config =
grpc_core::ServiceConfig::Create(service_config_str,
&service_config_error);
GRPC_ERROR_UNREF(service_config_error);
if (service_config != nullptr) {
chand->method_limit_table = service_config->CreateMethodConfigTable(
grpc_core::MessageSizeLimits::CreateFromJson);
auto svc_cfg = grpc_core::ServiceConfig::Create(service_config_str,
&service_config_error);
if (service_config_error == GRPC_ERROR_NONE) {
chand->svc_cfg = std::move(svc_cfg);
} else {
gpr_log(GPR_ERROR, "%s", grpc_error_string(service_config_error));
}
GRPC_ERROR_UNREF(service_config_error);
}
return GRPC_ERROR_NONE;
}
@ -335,7 +357,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);
chand->method_limit_table.reset();
chand->~channel_data();
}
const grpc_channel_filter grpc_message_size_filter = {
@ -351,18 +373,34 @@ const grpc_channel_filter grpc_message_size_filter = {
grpc_channel_next_get_info,
"message_size"};
// Used for GRPC_CLIENT_SUBCHANNEL
static bool maybe_add_message_size_filter_subchannel(
grpc_channel_stack_builder* builder, void* arg) {
const grpc_channel_args* channel_args =
grpc_channel_stack_builder_get_channel_arguments(builder);
if (grpc_channel_args_want_minimal_stack(channel_args)) {
return true;
}
return grpc_channel_stack_builder_prepend_filter(
builder, &grpc_message_size_filter, nullptr, nullptr);
}
// Used for GRPC_CLIENT_DIRECT_CHANNEL and GRPC_SERVER_CHANNEL. Adds the filter
// only if message size limits or service config is specified.
static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder,
void* arg) {
const grpc_channel_args* channel_args =
grpc_channel_stack_builder_get_channel_arguments(builder);
bool enable = false;
message_size_limits lim = get_message_size_limits(channel_args);
grpc_core::MessageSizeParsedObject::message_size_limits lim =
get_message_size_limits(channel_args);
if (lim.max_send_size != -1 || lim.max_recv_size != -1) {
enable = true;
}
const grpc_arg* a =
grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG);
if (a != nullptr) {
const char* svc_cfg_str = grpc_channel_arg_get_string(a);
if (svc_cfg_str != nullptr) {
enable = true;
}
if (enable) {
@ -374,15 +412,16 @@ static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder,
}
void grpc_message_size_filter_init(void) {
grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
grpc_channel_init_register_stage(
GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter_subchannel, nullptr);
grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
maybe_add_message_size_filter, nullptr);
grpc_core::MessageSizeParser::Register();
}
void grpc_message_size_filter_shutdown(void) {}

@ -19,8 +19,41 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/lib/channel/channel_stack.h"
extern const grpc_channel_filter grpc_message_size_filter;
namespace grpc_core {
class MessageSizeParsedObject : public ServiceConfig::ParsedConfig {
public:
struct message_size_limits {
int max_send_size;
int max_recv_size;
};
MessageSizeParsedObject(int max_send_size, int max_recv_size) {
limits_.max_send_size = max_send_size;
limits_.max_recv_size = max_recv_size;
}
const message_size_limits& limits() const { return limits_; }
private:
message_size_limits limits_;
};
class MessageSizeParser : public ServiceConfig::Parser {
public:
UniquePtr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override;
static void Register();
static size_t ParserIndex();
};
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H */

@ -20,16 +20,15 @@
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/transport/metadata.h"
GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_experimental_disable_flow_control, false,
"Disable flow control");
void grpc_chttp2_plugin_init(void) {
g_flow_control_enabled = true;
char* env_variable = gpr_getenv("GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL");
if (env_variable != nullptr) {
g_flow_control_enabled = false;
gpr_free(env_variable);
}
g_flow_control_enabled =
!GPR_GLOBAL_CONFIG_GET(grpc_experimental_disable_flow_control);
}
void grpc_chttp2_plugin_shutdown(void) {}

@ -633,7 +633,7 @@ struct grpc_chttp2_stream {
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS;
/* Stream decompression method to be used. */
grpc_stream_compression_method stream_decompression_method =
GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS;
GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS;
/** Stream compression decompress context */
grpc_stream_compression_context* stream_decompression_ctx = nullptr;
/** Stream compression compress context */

@ -47,9 +47,9 @@ grpc_core::TraceFlag grpc_trace_channel(false, "channel");
size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
size_t filter_count) {
/* always need the header, and size for the channel elements */
size_t size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
size_t size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(
filter_count * sizeof(grpc_channel_element));
size_t i;
GPR_ASSERT((GPR_MAX_ALIGNMENT & (GPR_MAX_ALIGNMENT - 1)) == 0 &&
@ -57,18 +57,18 @@ size_t grpc_channel_stack_size(const grpc_channel_filter** filters,
/* add the size for each filter */
for (i = 0; i < filter_count; i++) {
size += GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
size += GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
}
return size;
}
#define CHANNEL_ELEMS_FROM_STACK(stk) \
((grpc_channel_element*)((char*)(stk) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE( \
#define CHANNEL_ELEMS_FROM_STACK(stk) \
((grpc_channel_element*)((char*)(stk) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(grpc_channel_stack))))
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element*)((char*)(stk) + GPR_ROUND_UP_TO_ALIGNMENT_SIZE( \
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element*)((char*)(stk) + GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE( \
sizeof(grpc_call_stack))))
grpc_channel_element* grpc_channel_stack_element(
@ -92,8 +92,9 @@ grpc_error* grpc_channel_stack_init(
const grpc_channel_args* channel_args, grpc_transport* optional_transport,
const char* name, grpc_channel_stack* stack) {
size_t call_size =
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_call_element));
grpc_channel_element* elems;
grpc_channel_element_args args;
char* user_data;
@ -104,8 +105,8 @@ grpc_error* grpc_channel_stack_init(
name);
elems = CHANNEL_ELEMS_FROM_STACK(stack);
user_data = (reinterpret_cast<char*>(elems)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filter_count *
sizeof(grpc_channel_element));
/* init per-filter data */
grpc_error* first_error = GRPC_ERROR_NONE;
@ -126,8 +127,9 @@ grpc_error* grpc_channel_stack_init(
}
}
user_data +=
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size += GPR_ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
call_size +=
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
}
GPR_ASSERT(user_data > (char*)stack);
@ -162,8 +164,9 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
GRPC_STREAM_REF_INIT(&elem_args->call_stack->refcount, initial_refs, destroy,
destroy_arg, "CALL_STACK");
call_elems = CALL_ELEMS_FROM_STACK(elem_args->call_stack);
user_data = (reinterpret_cast<char*>(call_elems)) +
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
user_data =
(reinterpret_cast<char*>(call_elems)) +
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */
grpc_error* first_error = GRPC_ERROR_NONE;
@ -171,8 +174,8 @@ grpc_error* grpc_call_stack_init(grpc_channel_stack* channel_stack,
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
user_data +=
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
user_data += GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(
call_elems[i].filter->sizeof_call_data);
}
for (size_t i = 0; i < count; i++) {
grpc_error* error =
@ -242,11 +245,11 @@ grpc_channel_stack* grpc_channel_stack_from_top_element(
grpc_channel_element* elem) {
return reinterpret_cast<grpc_channel_stack*>(
reinterpret_cast<char*>(elem) -
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_channel_stack)));
}
grpc_call_stack* grpc_call_stack_from_top_element(grpc_call_element* elem) {
return reinterpret_cast<grpc_call_stack*>(
reinterpret_cast<char*>(elem) -
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_call_stack)));
}

@ -35,6 +35,9 @@ typedef enum {
/// Reserved for traffic_class_context.
GRPC_CONTEXT_TRAFFIC,
/// Holds a pointer to ServiceConfig::CallData associated with this call.
GRPC_SERVICE_CONFIG_CALL_DATA,
GRPC_CONTEXT_COUNT
} grpc_context_index;

@ -23,6 +23,7 @@
#include <grpc/support/log.h>
#include <stdlib.h>
#include <string.h>
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/profiling/timers.h"
static void* zalloc_with_calloc(size_t sz) { return calloc(sz, 1); }
@ -33,8 +34,56 @@ static void* zalloc_with_gpr_malloc(size_t sz) {
return p;
}
static gpr_allocation_functions g_alloc_functions = {malloc, zalloc_with_calloc,
realloc, free};
#ifndef NDEBUG
static constexpr bool is_power_of_two(size_t value) {
// 2^N = 100000...000
// 2^N - 1 = 011111...111
// (2^N) && ((2^N)-1)) = 0
return (value & (value - 1)) == 0;
}
#endif
static void* platform_malloc_aligned(size_t size, size_t alignment) {
#if defined(GPR_HAS_ALIGNED_ALLOC)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size, alignment);
void* ret = aligned_alloc(alignment, size);
GPR_ASSERT(ret != nullptr);
return ret;
#elif defined(GPR_HAS_ALIGNED_MALLOC)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
void* ret = _aligned_malloc(size, alignment);
GPR_ASSERT(ret != nullptr);
return ret;
#elif defined(GPR_HAS_POSIX_MEMALIGN)
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
GPR_DEBUG_ASSERT(alignment % sizeof(void*) == 0);
void* ret = nullptr;
GPR_ASSERT(posix_memalign(&ret, alignment, size) == 0);
return ret;
#else
GPR_DEBUG_ASSERT(is_power_of_two(alignment));
size_t extra = alignment - 1 + sizeof(void*);
void* p = gpr_malloc(size + extra);
void** ret = (void**)(((uintptr_t)p + extra) & ~(alignment - 1));
ret[-1] = p;
return (void*)ret;
#endif
}
static void platform_free_aligned(void* ptr) {
#if defined(GPR_HAS_ALIGNED_ALLOC) || defined(GPR_HAS_POSIX_MEMALIGN)
free(ptr);
#elif defined(GPR_HAS_ALIGNED_MALLOC)
_aligned_free(ptr);
#else
gpr_free((static_cast<void**>(ptr))[-1]);
#endif
}
static gpr_allocation_functions g_alloc_functions = {
malloc, zalloc_with_calloc, realloc,
free, platform_malloc_aligned, platform_free_aligned};
gpr_allocation_functions gpr_get_allocation_functions() {
return g_alloc_functions;
@ -47,6 +96,12 @@ void gpr_set_allocation_functions(gpr_allocation_functions functions) {
if (functions.zalloc_fn == nullptr) {
functions.zalloc_fn = zalloc_with_gpr_malloc;
}
GPR_ASSERT((functions.aligned_alloc_fn == nullptr) ==
(functions.aligned_free_fn == nullptr));
if (functions.aligned_alloc_fn == nullptr) {
functions.aligned_alloc_fn = platform_malloc_aligned;
functions.aligned_free_fn = platform_free_aligned;
}
g_alloc_functions = functions;
}
@ -88,12 +143,12 @@ void* gpr_realloc(void* p, size_t size) {
}
void* gpr_malloc_aligned(size_t size, size_t alignment) {
GPR_ASSERT(((alignment - 1) & alignment) == 0); // Must be power of 2.
size_t extra = alignment - 1 + sizeof(void*);
void* p = gpr_malloc(size + extra);
void** ret = (void**)(((uintptr_t)p + extra) & ~(alignment - 1));
ret[-1] = p;
return (void*)ret;
GPR_TIMER_SCOPE("gpr_malloc_aligned", 0);
if (size == 0) return nullptr;
return g_alloc_functions.aligned_alloc_fn(size, alignment);
}
void gpr_free_aligned(void* ptr) { gpr_free((static_cast<void**>(ptr))[-1]); }
void gpr_free_aligned(void* ptr) {
GPR_TIMER_SCOPE("gpr_free_aligned", 0);
g_alloc_functions.aligned_free_fn(ptr);
}

@ -22,7 +22,13 @@
#include <grpc/support/port_platform.h>
/// Given a size, round up to the next multiple of sizeof(void*).
#define GPR_ROUND_UP_TO_ALIGNMENT_SIZE(x) \
(((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u))
#define GPR_ROUND_UP_TO_ALIGNMENT_SIZE(x, align) \
(((x) + (align)-1u) & ~((align)-1u))
#define GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(x) \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE((x), GPR_MAX_ALIGNMENT)
#define GPR_ROUND_UP_TO_CACHELINE_SIZE(x) \
GPR_ROUND_UP_TO_ALIGNMENT_SIZE((x), GPR_CACHELINE_SIZE)
#endif /* GRPC_CORE_LIB_GPR_ALLOC_H */

@ -40,4 +40,7 @@ void gpr_setenv(const char* name, const char* value);
level of logging. So DO NOT USE THIS. */
const char* gpr_getenv_silent(const char* name, char** dst);
/* Deletes the variable name from the environment. */
void gpr_unsetenv(const char* name);
#endif /* GRPC_CORE_LIB_GPR_ENV_H */

@ -79,4 +79,9 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res == 0);
}
void gpr_unsetenv(const char* name) {
int res = unsetenv(name);
GPR_ASSERT(res == 0);
}
#endif /* GPR_LINUX_ENV */

@ -44,4 +44,9 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res == 0);
}
void gpr_unsetenv(const char* name) {
int res = unsetenv(name);
GPR_ASSERT(res == 0);
}
#endif /* GPR_POSIX_ENV */

@ -69,4 +69,11 @@ void gpr_setenv(const char* name, const char* value) {
GPR_ASSERT(res);
}
void gpr_unsetenv(const char* name) {
LPTSTR tname = gpr_char_to_tchar(name);
BOOL res = SetEnvironmentVariable(tname, NULL);
gpr_free(tname);
GPR_ASSERT(res);
}
#endif /* GPR_WINDOWS_ENV */

@ -332,16 +332,22 @@ void* gpr_memrchr(const void* s, int c, size_t n) {
return nullptr;
}
bool gpr_is_true(const char* s) {
size_t i;
bool gpr_parse_bool_value(const char* s, bool* dst) {
const char* kTrue[] = {"1", "t", "true", "y", "yes"};
const char* kFalse[] = {"0", "f", "false", "n", "no"};
static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");
if (s == nullptr) {
return false;
}
static const char* truthy[] = {"yes", "true", "1"};
for (i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == gpr_stricmp(s, truthy[i])) {
for (size_t i = 0; i < GPR_ARRAY_SIZE(kTrue); ++i) {
if (gpr_stricmp(s, kTrue[i]) == 0) {
*dst = true;
return true;
} else if (gpr_stricmp(s, kFalse[i]) == 0) {
*dst = false;
return true;
}
}
return false;
return false; // didn't match a legal input
}

@ -113,7 +113,9 @@ int gpr_stricmp(const char* a, const char* b);
void* gpr_memrchr(const void* s, int c, size_t n);
/** Return true if lower(s) equals "true", "yes" or "1", otherwise false. */
bool gpr_is_true(const char* s);
/* Try to parse given string into a boolean value.
When parsed successfully, dst will have the value and returns true.
Otherwise, it returns false. */
bool gpr_parse_bool_value(const char* value, bool* dst);
#endif /* GRPC_CORE_LIB_GPR_STRING_H */

@ -31,11 +31,23 @@
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gprpp/memory.h"
template <size_t alignment>
static void* gpr_arena_malloc(size_t size) {
return gpr_malloc_aligned(size, alignment);
namespace {
void* ArenaStorage(size_t initial_size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(grpc_core::Arena));
initial_size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(initial_size);
size_t alloc_size = base_size + initial_size;
static constexpr size_t alignment =
(GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT &&
GPR_CACHELINE_SIZE % GPR_MAX_ALIGNMENT == 0)
? GPR_CACHELINE_SIZE
: GPR_MAX_ALIGNMENT;
return gpr_malloc_aligned(alloc_size, alignment);
}
} // namespace
namespace grpc_core {
Arena::~Arena() {
@ -49,16 +61,17 @@ Arena::~Arena() {
}
Arena* Arena::Create(size_t initial_size) {
return new (ArenaStorage(initial_size)) Arena(initial_size);
}
Pair<Arena*, void*> Arena::CreateWithAlloc(size_t initial_size,
size_t alloc_size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena));
initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
size_t alloc_size = base_size + initial_size;
static constexpr size_t alignment =
(GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT &&
GPR_CACHELINE_SIZE % GPR_MAX_ALIGNMENT == 0)
? GPR_CACHELINE_SIZE
: GPR_MAX_ALIGNMENT;
return new (gpr_arena_malloc<alignment>(alloc_size)) Arena(initial_size);
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Arena));
auto* new_arena =
new (ArenaStorage(initial_size)) Arena(initial_size, alloc_size);
void* first_alloc = reinterpret_cast<char*>(new_arena) + base_size;
return MakePair(new_arena, first_alloc);
}
size_t Arena::Destroy() {
@ -75,9 +88,9 @@ void* Arena::AllocZone(size_t size) {
// sizing hysteresis (that is, most calls should have a large enough initial
// zone and will not need to grow the arena).
static constexpr size_t zone_base_size =
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Zone));
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Zone));
size_t alloc_size = zone_base_size + size;
Zone* z = new (gpr_arena_malloc<GPR_MAX_ALIGNMENT>(alloc_size)) Zone();
Zone* z = new (gpr_malloc_aligned(alloc_size, GPR_MAX_ALIGNMENT)) Zone();
{
gpr_spinlock_lock(&arena_growth_spinlock_);
z->prev = last_zone_;

@ -36,6 +36,7 @@
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gpr/spinlock.h"
#include "src/core/lib/gprpp/atomic.h"
#include "src/core/lib/gprpp/pair.h"
#include <stddef.h>
@ -45,15 +46,22 @@ class Arena {
public:
// Create an arena, with \a initial_size bytes in the first allocated buffer.
static Arena* Create(size_t initial_size);
// Create an arena, with \a initial_size bytes in the first allocated buffer,
// and return both a void pointer to the returned arena and a void* with the
// first allocation.
static Pair<Arena*, void*> CreateWithAlloc(size_t initial_size,
size_t alloc_size);
// Destroy an arena, returning the total number of bytes allocated.
size_t Destroy();
// Allocate \a size bytes from the arena.
void* Alloc(size_t size) {
static constexpr size_t base_size =
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena));
size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size);
GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(sizeof(Arena));
size = GPR_ROUND_UP_TO_MAX_ALIGNMENT_SIZE(size);
size_t begin = total_used_.FetchAdd(size, MemoryOrder::RELAXED);
if (begin + size <= initial_zone_size_) {
if (GPR_LIKELY(begin + size <= initial_zone_size_)) {
return reinterpret_cast<char*>(this) + base_size + begin;
} else {
return AllocZone(size);
@ -76,7 +84,21 @@ class Arena {
Zone* prev;
};
explicit Arena(size_t initial_size) : initial_zone_size_(initial_size) {}
// Initialize an arena.
// Parameters:
// initial_size: The initial size of the whole arena in bytes. These bytes
// are contained within 'zone 0'. If the arena user ends up requiring more
// memory than the arena contains in zone 0, subsequent zones are allocated
// on demand and maintained in a tail-linked list.
//
// initial_alloc: Optionally, construct the arena as though a call to
// Alloc() had already been made for initial_alloc bytes. This provides a
// quick optimization (avoiding an atomic fetch-add) for the common case
// where we wish to create an arena and then perform an immediate
// allocation.
explicit Arena(size_t initial_size, size_t initial_alloc = 0)
: total_used_(initial_alloc), initial_zone_size_(initial_size) {}
~Arena();
void* AllocZone(size_t size);

@ -0,0 +1,87 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H
#include <grpc/support/port_platform.h>
#include <stdint.h>
// --------------------------------------------------------------------
// How to use global configuration variables:
//
// Defining config variables of a specified type:
// GPR_GLOBAL_CONFIG_DEFINE_*TYPE*(name, default_value, help);
//
// Supported TYPEs: BOOL, INT32, STRING
//
// It's recommended to use lowercase letters for 'name' like
// regular variables. The builtin configuration system uses
// environment variable and the name is converted to uppercase
// when looking up the value. For example,
// GPR_GLOBAL_CONFIG_DEFINE(grpc_latency) looks up the value with the
// name, "GRPC_LATENCY".
//
// The variable initially has the specified 'default_value'
// which must be an expression convertible to 'Type'.
// 'default_value' may be evaluated 0 or more times,
// and at an unspecified time; keep it
// simple and usually free of side-effects.
//
// GPR_GLOBAL_CONFIG_DEFINE_*TYPE* should not be called in a C++ header.
// It should be called at the top-level (outside any namespaces)
// in a .cc file.
//
// Getting the variables:
// GPR_GLOBAL_CONFIG_GET(name)
//
// If error happens during getting variables, error messages will
// be logged and default value will be returned.
//
// Setting the variables with new value:
// GPR_GLOBAL_CONFIG_SET(name, new_value)
//
// Declaring config variables for other modules to access:
// GPR_GLOBAL_CONFIG_DECLARE_*TYPE*(name)
// --------------------------------------------------------------------
// How to customize the global configuration system:
//
// How to read and write configuration value can be customized.
// Builtin system uses environment variables but it can be extended to
// support command-line flag, file, etc.
//
// To customize it, following macros should be redefined.
//
// GPR_GLOBAL_CONFIG_DEFINE_BOOL
// GPR_GLOBAL_CONFIG_DEFINE_INT32
// GPR_GLOBAL_CONFIG_DEFINE_STRING
//
// These macros should define functions for getting and setting variable.
// For example, GPR_GLOBAL_CONFIG_DEFINE_BOOL(test, ...) would define two
// functions.
//
// bool gpr_global_config_get_test();
// void gpr_global_config_set_test(bool value);
#include "src/core/lib/gprpp/global_config_env.h"
#include "src/core/lib/gprpp/global_config_custom.h"
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H */

@ -0,0 +1,29 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H
// This is a placeholder for custom global configuration implementaion.
// To use the custom one, please define following macros here.
//
// GPR_GLOBAL_CONFIG_DEFINE_BOOL
// GPR_GLOBAL_CONFIG_DEFINE_INT32
// GPR_GLOBAL_CONFIG_DEFINE_STRING
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H */

@ -0,0 +1,135 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/global_config_env.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include <ctype.h>
#include <string.h>
namespace grpc_core {
namespace {
void DefaultGlobalConfigEnvErrorFunction(const char* error_message) {
gpr_log(GPR_ERROR, "%s", error_message);
}
GlobalConfigEnvErrorFunctionType g_global_config_env_error_func =
DefaultGlobalConfigEnvErrorFunction;
void LogParsingError(const char* name, const char* value) {
char* error_message;
gpr_asprintf(&error_message,
"Illegal value '%s' specified for environment variable '%s'",
value, name);
(*g_global_config_env_error_func)(error_message);
gpr_free(error_message);
}
} // namespace
void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func) {
g_global_config_env_error_func = func;
}
UniquePtr<char> GlobalConfigEnv::GetValue() {
return UniquePtr<char>(gpr_getenv(GetName()));
}
void GlobalConfigEnv::SetValue(const char* value) {
gpr_setenv(GetName(), value);
}
void GlobalConfigEnv::Unset() { gpr_unsetenv(GetName()); }
char* GlobalConfigEnv::GetName() {
// This makes sure that name_ is in a canonical form having uppercase
// letters. This is okay to be called serveral times.
for (char* c = name_; *c != 0; ++c) {
*c = toupper(*c);
}
return name_;
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvBool>::value,
"GlobalConfigEnvBool needs to be trivially destructible.");
bool GlobalConfigEnvBool::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return default_value_;
}
// parsing given value string.
bool result = false;
if (!gpr_parse_bool_value(str.get(), &result)) {
LogParsingError(GetName(), str.get());
result = default_value_;
}
return result;
}
void GlobalConfigEnvBool::Set(bool value) {
SetValue(value ? "true" : "false");
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvInt32>::value,
"GlobalConfigEnvInt32 needs to be trivially destructible.");
int32_t GlobalConfigEnvInt32::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return default_value_;
}
// parsing given value string.
char* end = str.get();
long result = strtol(str.get(), &end, 10);
if (*end != 0) {
LogParsingError(GetName(), str.get());
result = default_value_;
}
return static_cast<int32_t>(result);
}
void GlobalConfigEnvInt32::Set(int32_t value) {
char buffer[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(value, buffer);
SetValue(buffer);
}
static_assert(std::is_trivially_destructible<GlobalConfigEnvString>::value,
"GlobalConfigEnvString needs to be trivially destructible.");
UniquePtr<char> GlobalConfigEnvString::Get() {
UniquePtr<char> str = GetValue();
if (str == nullptr) {
return UniquePtr<char>(gpr_strdup(default_value_));
}
return str;
}
void GlobalConfigEnvString::Set(const char* value) { SetValue(value); }
} // namespace grpc_core

@ -0,0 +1,131 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/global_config_generic.h"
#include "src/core/lib/gprpp/memory.h"
namespace grpc_core {
typedef void (*GlobalConfigEnvErrorFunctionType)(const char* error_message);
/*
* Set global_config_env_error_function which is called when config system
* encounters errors such as parsing error. What the default function does
* is logging error message.
*/
void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func);
// Base class for all classes to access environment variables.
class GlobalConfigEnv {
protected:
// `name` should be writable and alive after constructor is called.
constexpr explicit GlobalConfigEnv(char* name) : name_(name) {}
public:
// Returns the value of `name` variable.
UniquePtr<char> GetValue();
// Sets the value of `name` variable.
void SetValue(const char* value);
// Unsets `name` variable.
void Unset();
protected:
char* GetName();
private:
char* name_;
};
class GlobalConfigEnvBool : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvBool(char* name, bool default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
bool Get();
void Set(bool value);
private:
bool default_value_;
};
class GlobalConfigEnvInt32 : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvInt32(char* name, int32_t default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
int32_t Get();
void Set(int32_t value);
private:
int32_t default_value_;
};
class GlobalConfigEnvString : public GlobalConfigEnv {
public:
constexpr GlobalConfigEnvString(char* name, const char* default_value)
: GlobalConfigEnv(name), default_value_(default_value) {}
UniquePtr<char> Get();
void Set(const char* value);
private:
const char* default_value_;
};
} // namespace grpc_core
// Macros for defining global config instances using environment variables.
// This defines a GlobalConfig*Type* instance with arguments for
// mutable variable name and default value.
// Mutable name (g_env_str_##name) is here for having an array
// for the canonical name without dynamic allocation.
// `help` argument is ignored for this implementation.
#define GPR_GLOBAL_CONFIG_DEFINE_BOOL(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvBool g_env_##name(g_env_str_##name, \
default_value); \
bool gpr_global_config_get_##name() { return g_env_##name.Get(); } \
void gpr_global_config_set_##name(bool value) { g_env_##name.Set(value); }
#define GPR_GLOBAL_CONFIG_DEFINE_INT32(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvInt32 g_env_##name(g_env_str_##name, \
default_value); \
int32_t gpr_global_config_get_##name() { return g_env_##name.Get(); } \
void gpr_global_config_set_##name(int32_t value) { g_env_##name.Set(value); }
#define GPR_GLOBAL_CONFIG_DEFINE_STRING(name, default_value, help) \
static char g_env_str_##name[] = #name; \
static ::grpc_core::GlobalConfigEnvString g_env_##name(g_env_str_##name, \
default_value); \
::grpc_core::UniquePtr<char> gpr_global_config_get_##name() { \
return g_env_##name.Get(); \
} \
void gpr_global_config_set_##name(const char* value) { \
g_env_##name.Set(value); \
}
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H */

@ -0,0 +1,44 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H
#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/gprpp/memory.h"
#include <stdint.h>
#define GPR_GLOBAL_CONFIG_GET(name) gpr_global_config_get_##name()
#define GPR_GLOBAL_CONFIG_SET(name, value) gpr_global_config_set_##name(value)
#define GPR_GLOBAL_CONFIG_DECLARE_BOOL(name) \
extern bool gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(bool value)
#define GPR_GLOBAL_CONFIG_DECLARE_INT32(name) \
extern int32_t gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(int32_t value)
#define GPR_GLOBAL_CONFIG_DECLARE_STRING(name) \
extern grpc_core::UniquePtr<char> gpr_global_config_get_##name(); \
extern void gpr_global_config_set_##name(const char* value)
#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H */

@ -26,6 +26,7 @@ namespace grpc_core {
template <typename T>
class Optional {
public:
Optional() : value_() {}
void set(const T& val) {
value_ = val;
set_ = true;

@ -31,7 +31,7 @@
// Provides serialized access to some resource.
// Each action queued on a combiner is executed serially in a borrowed thread.
// The actual thread executing actions may change over time (but there will only
// every be one at a time).
// ever be one at a time).
// Initialize the lock, with an optional workqueue to shift load to when
// necessary

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

Loading…
Cancel
Save