Merge remote-tracking branch 'upstream/master' into upb_upgrade

pull/23140/head
Mark D. Roth 5 years ago
commit 08069958fc
  1. 2
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 2
      .github/ISSUE_TEMPLATE/cleanup_request.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 2
      .github/pull_request_template.md
  5. 8
      BUILD
  6. 10
      BUILD.gn
  7. 28
      BUILDING.md
  8. 254
      CMakeLists.txt
  9. 306
      Makefile
  10. 4
      bazel/cc_grpc_library.bzl
  11. 1
      bazel/generate_cc.bzl
  12. 1
      bazel/generate_objc.bzl
  13. 2
      bazel/protobuf.bzl
  14. 1
      bazel/python_rules.bzl
  15. 1
      bazel/test/python_test_repo/BUILD
  16. 76
      build.yaml
  17. 5
      config.m4
  18. 5
      config.w32
  19. 10
      doc/environment_variables.md
  20. 10
      doc/grpc_release_schedule.md
  21. 5
      examples/BUILD
  22. 6
      examples/cpp/helloworld/README.md
  23. 29
      examples/cpp/helloworld/greeter_client.cc
  24. 1
      examples/python/cancellation/BUILD.bazel
  25. 1
      examples/python/multiprocessing/BUILD
  26. 5
      gRPC-C++.podspec
  27. 9
      gRPC-Core.podspec
  28. 7
      grpc.gemspec
  29. 27
      grpc.gyp
  30. 133
      include/grpcpp/generic/generic_stub_impl.h
  31. 7
      package.xml
  32. 6
      src/core/ext/filters/client_channel/client_channel.cc
  33. 44
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  34. 10
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  35. 10
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  36. 110
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  37. 134
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  38. 6
      src/core/ext/filters/client_channel/lb_policy_factory.h
  39. 118
      src/core/ext/filters/client_channel/lb_policy_registry.cc
  40. 2
      src/core/ext/filters/client_channel/lb_policy_registry.h
  41. 125
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  42. 502
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  43. 4
      src/core/ext/filters/client_channel/resolver_result_parsing.h
  44. 240
      src/core/ext/filters/client_channel/service_config.cc
  45. 35
      src/core/ext/filters/client_channel/service_config.h
  46. 361
      src/core/ext/filters/client_channel/xds/xds_api.cc
  47. 355
      src/core/ext/filters/client_channel/xds/xds_api.h
  48. 2
      src/core/ext/filters/client_channel/xds/xds_channel.cc
  49. 136
      src/core/ext/filters/client_channel/xds/xds_client.cc
  50. 9
      src/core/ext/filters/client_channel/xds/xds_client.h
  51. 61
      src/core/ext/filters/message_size/message_size_filter.cc
  52. 2
      src/core/ext/filters/message_size/message_size_filter.h
  53. 6
      src/core/lib/gprpp/inlined_vector.h
  54. 8
      src/core/lib/iomgr/error.h
  55. 103
      src/core/lib/iomgr/logical_thread.cc
  56. 52
      src/core/lib/iomgr/logical_thread.h
  57. 155
      src/core/lib/iomgr/work_serializer.cc
  58. 65
      src/core/lib/iomgr/work_serializer.h
  59. 94
      src/core/lib/json/json.cc
  60. 82
      src/core/lib/json/json.h
  61. 300
      src/core/lib/json/json_reader.cc
  62. 808
      src/core/lib/json/json_reader_new.cc
  63. 212
      src/core/lib/json/json_writer.cc
  64. 336
      src/core/lib/json/json_writer_new.cc
  65. 106
      src/cpp/client/generic_stub.cc
  66. 3
      src/objective-c/grpc_objc_internal_library.bzl
  67. 1
      src/proto/grpc/channelz/BUILD
  68. 2
      src/proto/grpc/gcp/BUILD
  69. 1
      src/proto/grpc/health/v1/BUILD
  70. 1
      src/proto/grpc/lb/v1/BUILD
  71. 1
      src/proto/grpc/reflection/v1alpha/BUILD
  72. 3
      src/proto/grpc/testing/BUILD
  73. 17
      src/proto/grpc/testing/messages.proto
  74. 1
      src/proto/grpc/testing/proto2/BUILD.bazel
  75. 7
      src/proto/grpc/testing/test.proto
  76. 3
      src/python/grpcio/grpc/_cython/_cygrpc/aio/call.pyx.pxi
  77. 17
      src/python/grpcio/grpc/_cython/_cygrpc/aio/callback_common.pyx.pxi
  78. 6
      src/python/grpcio/grpc/_cython/_cygrpc/aio/channel.pyx.pxi
  79. 30
      src/python/grpcio/grpc/_cython/_cygrpc/aio/common.pyx.pxi
  80. 4
      src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pxd.pxi
  81. 89
      src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi
  82. 4
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
  83. 13
      src/python/grpcio/grpc/experimental/aio/__init__.py
  84. 4
      src/python/grpcio/grpc/experimental/aio/_base_call.py
  85. 67
      src/python/grpcio/grpc/experimental/aio/_call.py
  86. 75
      src/python/grpcio/grpc/experimental/aio/_channel.py
  87. 4
      src/python/grpcio/grpc/experimental/aio/_interceptor.py
  88. 54
      src/python/grpcio/grpc/experimental/aio/_server.py
  89. 6
      src/python/grpcio/grpc/experimental/aio/_typing.py
  90. 5
      src/python/grpcio/grpc_core_dependencies.py
  91. 1
      src/python/grpcio_tests/tests/stress/BUILD.bazel
  92. 2
      src/python/grpcio_tests/tests_aio/tests.json
  93. 67
      src/python/grpcio_tests/tests_aio/unit/channel_ready_test.py
  94. 4
      src/python/grpcio_tests/tests_aio/unit/close_channel_test.py
  95. 196
      src/python/grpcio_tests/tests_aio/unit/compression_test.py
  96. 2
      src/python/grpcio_tests/tests_aio/unit/connectivity_test.py
  97. 2
      src/python/grpcio_tests/tests_aio/unit/metadata_test.py
  98. 12
      src/python/grpcio_tests/tests_aio/unit/server_test.py
  99. 136
      test/core/client_channel/service_config_test.cc
  100. 4
      test/core/client_channel/xds_bootstrap_test.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,7 +2,7 @@
name: Report a bug
about: Create a report to help us improve
labels: kind/bug, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -2,7 +2,7 @@
name: Request a cleanup
about: Suggest a cleanup in our repository
labels: kind/internal cleanup, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -2,7 +2,7 @@
name: Request a feature
about: Suggest an idea for this project
labels: kind/enhancement, priority/P2
assignees: donnadionne
assignees: markdroth
---

@ -8,4 +8,4 @@ If you know who should review your pull request, please remove the mentioning be
-->
@donnadionne
@markdroth

@ -134,7 +134,6 @@ GRPCXX_SRCS = [
"src/cpp/client/create_channel_internal.cc",
"src/cpp/client/create_channel_posix.cc",
"src/cpp/client/credentials_cc.cc",
"src/cpp/client/generic_stub.cc",
"src/cpp/common/alarm.cc",
"src/cpp/common/channel_arguments.cc",
"src/cpp/common/channel_filter.cc",
@ -752,7 +751,6 @@ grpc_cc_library(
"src/core/lib/iomgr/is_epollexclusive_available.cc",
"src/core/lib/iomgr/load_file.cc",
"src/core/lib/iomgr/lockfree_event.cc",
"src/core/lib/iomgr/logical_thread.cc",
"src/core/lib/iomgr/polling_entity.cc",
"src/core/lib/iomgr/pollset.cc",
"src/core/lib/iomgr/pollset_custom.cc",
@ -804,11 +802,9 @@ grpc_cc_library(
"src/core/lib/iomgr/wakeup_fd_nospecial.cc",
"src/core/lib/iomgr/wakeup_fd_pipe.cc",
"src/core/lib/iomgr/wakeup_fd_posix.cc",
"src/core/lib/json/json.cc",
"src/core/lib/iomgr/work_serializer.cc",
"src/core/lib/json/json_reader.cc",
"src/core/lib/json/json_reader_new.cc",
"src/core/lib/json/json_writer.cc",
"src/core/lib/json/json_writer_new.cc",
"src/core/lib/slice/b64.cc",
"src/core/lib/slice/percent_encoding.cc",
"src/core/lib/slice/slice.cc",
@ -906,7 +902,6 @@ grpc_cc_library(
"src/core/lib/iomgr/is_epollexclusive_available.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/lockfree_event.h",
"src/core/lib/iomgr/logical_thread.h",
"src/core/lib/iomgr/nameser.h",
"src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h",
@ -949,6 +944,7 @@ grpc_cc_library(
"src/core/lib/iomgr/unix_sockets_posix.h",
"src/core/lib/iomgr/wakeup_fd_pipe.h",
"src/core/lib/iomgr/wakeup_fd_posix.h",
"src/core/lib/iomgr/work_serializer.h",
"src/core/lib/json/json.h",
"src/core/lib/slice/b64.h",
"src/core/lib/slice/percent_encoding.h",

@ -620,8 +620,6 @@ config("grpc_config") {
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/lockfree_event.cc",
"src/core/lib/iomgr/lockfree_event.h",
"src/core/lib/iomgr/logical_thread.cc",
"src/core/lib/iomgr/logical_thread.h",
"src/core/lib/iomgr/nameser.h",
"src/core/lib/iomgr/poller/eventmanager_libuv.cc",
"src/core/lib/iomgr/poller/eventmanager_libuv.h",
@ -715,12 +713,11 @@ config("grpc_config") {
"src/core/lib/iomgr/wakeup_fd_pipe.h",
"src/core/lib/iomgr/wakeup_fd_posix.cc",
"src/core/lib/iomgr/wakeup_fd_posix.h",
"src/core/lib/json/json.cc",
"src/core/lib/iomgr/work_serializer.cc",
"src/core/lib/iomgr/work_serializer.h",
"src/core/lib/json/json.h",
"src/core/lib/json/json_reader.cc",
"src/core/lib/json/json_reader_new.cc",
"src/core/lib/json/json_writer.cc",
"src/core/lib/json/json_writer_new.cc",
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/alts/alts_credentials.cc",
@ -1313,7 +1310,6 @@ config("grpc_config") {
"src/core/lib/iomgr/is_epollexclusive_available.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/lockfree_event.h",
"src/core/lib/iomgr/logical_thread.h",
"src/core/lib/iomgr/nameser.h",
"src/core/lib/iomgr/poller/eventmanager_libuv.h",
"src/core/lib/iomgr/polling_entity.h",
@ -1354,6 +1350,7 @@ config("grpc_config") {
"src/core/lib/iomgr/unix_sockets_posix.h",
"src/core/lib/iomgr/wakeup_fd_pipe.h",
"src/core/lib/iomgr/wakeup_fd_posix.h",
"src/core/lib/iomgr/work_serializer.h",
"src/core/lib/json/json.h",
"src/core/lib/profiling/timers.h",
"src/core/lib/slice/b64.h",
@ -1399,7 +1396,6 @@ config("grpc_config") {
"src/cpp/client/create_channel_internal.h",
"src/cpp/client/create_channel_posix.cc",
"src/cpp/client/credentials_cc.cc",
"src/cpp/client/generic_stub.cc",
"src/cpp/client/insecure_credentials.cc",
"src/cpp/client/secure_credentials.cc",
"src/cpp/client/secure_credentials.h",

@ -161,10 +161,11 @@ Please note that when using Ninja, you will still need Visual C++ (part of Visua
installed to be able to compile the C/C++ sources.
```
> @rem Run from grpc directory after cloning the repo with --recursive or updating submodules.
> md .build
> cd .build
> cd cmake
> md build
> cd build
> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake ..\.. -GNinja -DCMAKE_BUILD_TYPE=Release
> cmake --build .
```
@ -183,7 +184,7 @@ ie `gRPC_CARES_PROVIDER`.
### Install after build
Perform the following steps to install gRPC using CMake.
* Set `gRPC_INSTALL` to `ON`
* Set `-DgRPC_INSTALL=ON`
* Build the `install` target
The install destination is controlled by the
@ -196,16 +197,21 @@ in "module" mode and install them alongside gRPC in a single step.
If you are using an older version of gRPC, you will need to select "package"
mode (rather than "module" mode) for the dependencies.
This means you will need to have external copies of these libraries available
on your system.
on your system. This [example](test/distrib/cpp/run_distrib_test_cmake.sh) shows
how to install dependencies with cmake before proceeding to installing gRPC itself.
```
$ cmake .. -DgRPC_CARES_PROVIDER=package \
-DgRPC_PROTOBUF_PROVIDER=package \
-DgRPC_SSL_PROVIDER=package \
-DgRPC_ZLIB_PROVIDER=package
# NOTE: all of gRPC's dependencies need to be already installed
$ cmake ../.. -DgRPC_INSTALL=ON \
-DCMAKE_BUILD_TYPE=Release \
-DgRPC_ABSL_PROVIDER=package \
-DgRPC_CARES_PROVIDER=package \
-DgRPC_PROTOBUF_PROVIDER=package \
-DgRPC_SSL_PROVIDER=package \
-DgRPC_ZLIB_PROVIDER=package
$ make
$ make install
```
[Example](test/distrib/cpp/run_distrib_test_cmake.sh)
### Cross-compiling
@ -222,7 +228,7 @@ that will be used for this build.
This toolchain file is specified to CMake by setting the `CMAKE_TOOLCHAIN_FILE`
variable.
```
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=path/to/file
$ cmake ../.. -DCMAKE_TOOLCHAIN_FILE=path/to/file
$ make
```

@ -526,7 +526,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c init_test)
add_dependencies(buildtests_c inproc_callback_test)
add_dependencies(buildtests_c invalid_call_argument_test)
add_dependencies(buildtests_c json_test)
add_dependencies(buildtests_c lame_client_test)
add_dependencies(buildtests_c load_file_test)
add_dependencies(buildtests_c message_compress_test)
@ -826,8 +825,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx json_run_localhost)
endif()
add_dependencies(buildtests_cxx json_test_new)
add_dependencies(buildtests_cxx logical_thread_test)
add_dependencies(buildtests_cxx json_test)
add_dependencies(buildtests_cxx message_allocator_end2end_test)
add_dependencies(buildtests_cxx metrics_client)
add_dependencies(buildtests_cxx mock_test)
@ -894,11 +892,18 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx transport_connectivity_state_test)
add_dependencies(buildtests_cxx transport_pid_controller_test)
add_dependencies(buildtests_cxx transport_security_common_api_test)
add_dependencies(buildtests_cxx work_serializer_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx writes_per_rpc_test)
endif()
add_dependencies(buildtests_cxx xds_bootstrap_test)
add_dependencies(buildtests_cxx xds_end2end_test)
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_cxx xds_interop_client)
endif()
if(_gRPC_PLATFORM_LINUX)
add_dependencies(buildtests_cxx xds_interop_server)
endif()
add_dependencies(buildtests_cxx bad_streaming_id_bad_client_test)
add_dependencies(buildtests_cxx badreq_bad_client_test)
add_dependencies(buildtests_cxx connection_prefix_bad_client_test)
@ -1070,7 +1075,6 @@ add_library(alts_test_util
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -1124,11 +1128,9 @@ add_library(alts_test_util
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -1560,7 +1562,6 @@ add_library(grpc
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -1614,11 +1615,9 @@ add_library(grpc
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -2046,7 +2045,6 @@ add_library(grpc_cronet
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -2100,11 +2098,9 @@ add_library(grpc_cronet
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -2477,7 +2473,6 @@ add_library(grpc_test_util
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -2531,11 +2526,9 @@ add_library(grpc_test_util
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -2822,7 +2815,6 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -2876,11 +2868,9 @@ add_library(grpc_test_util_unsecure
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -3143,7 +3133,6 @@ add_library(grpc_unsecure
src/core/lib/iomgr/is_epollexclusive_available.cc
src/core/lib/iomgr/load_file.cc
src/core/lib/iomgr/lockfree_event.cc
src/core/lib/iomgr/logical_thread.cc
src/core/lib/iomgr/poller/eventmanager_libuv.cc
src/core/lib/iomgr/polling_entity.cc
src/core/lib/iomgr/pollset.cc
@ -3197,11 +3186,9 @@ add_library(grpc_unsecure
src/core/lib/iomgr/wakeup_fd_nospecial.cc
src/core/lib/iomgr/wakeup_fd_pipe.cc
src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json.cc
src/core/lib/iomgr/work_serializer.cc
src/core/lib/json/json_reader.cc
src/core/lib/json/json_reader_new.cc
src/core/lib/json/json_writer.cc
src/core/lib/json/json_writer_new.cc
src/core/lib/slice/b64.cc
src/core/lib/slice/percent_encoding.cc
src/core/lib/slice/slice.cc
@ -3696,7 +3683,6 @@ add_library(grpc++
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/credentials_cc.cc
src/cpp/client/generic_stub.cc
src/cpp/common/alarm.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/channel_filter.cc
@ -4830,7 +4816,6 @@ add_library(grpc++_unsecure
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/credentials_cc.cc
src/cpp/client/generic_stub.cc
src/cpp/common/alarm.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/channel_filter.cc
@ -8550,33 +8535,6 @@ target_link_libraries(invalid_call_argument_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(json_test
test/core/json/json_test.cc
)
target_include_directories(json_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
target_link_libraries(json_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
)
endif()
if(gRPC_BUILD_TESTS)
@ -14018,49 +13976,13 @@ endif()
endif()
if(gRPC_BUILD_TESTS)
add_executable(json_test_new
test/core/json/json_test_new.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(json_test_new
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(json_test_new
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(logical_thread_test
test/core/iomgr/logical_thread_test.cc
add_executable(json_test
test/core/json/json_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(logical_thread_test
target_include_directories(json_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
@ -14077,7 +13999,7 @@ target_include_directories(logical_thread_test
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(logical_thread_test
target_link_libraries(json_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
@ -16062,6 +15984,42 @@ target_link_libraries(transport_security_common_api_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(work_serializer_test
test/core/iomgr/work_serializer_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(work_serializer_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(work_serializer_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -16197,6 +16155,110 @@ target_link_libraries(xds_end2end_test
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
add_executable(xds_interop_client
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
test/cpp/interop/xds_interop_client.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(xds_interop_client
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(xds_interop_client
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_config
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX)
add_executable(xds_interop_server
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/empty.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/messages.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
test/cpp/interop/xds_interop_server.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(xds_interop_server
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(xds_interop_server
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc++_test_config
grpc_test_util
grpc++
grpc
gpr
${_gRPC_GFLAGS_LIBRARIES}
)
endif()
endif()
if(gRPC_BUILD_TESTS)

@ -1095,7 +1095,6 @@ init_test: $(BINDIR)/$(CONFIG)/init_test
inproc_callback_test: $(BINDIR)/$(CONFIG)/inproc_callback_test
invalid_call_argument_test: $(BINDIR)/$(CONFIG)/invalid_call_argument_test
json_fuzzer_test: $(BINDIR)/$(CONFIG)/json_fuzzer_test
json_test: $(BINDIR)/$(CONFIG)/json_test
lame_client_test: $(BINDIR)/$(CONFIG)/lame_client_test
load_file_test: $(BINDIR)/$(CONFIG)/load_file_test
low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
@ -1256,8 +1255,7 @@ interop_client: $(BINDIR)/$(CONFIG)/interop_client
interop_server: $(BINDIR)/$(CONFIG)/interop_server
interop_test: $(BINDIR)/$(CONFIG)/interop_test
json_run_localhost: $(BINDIR)/$(CONFIG)/json_run_localhost
json_test_new: $(BINDIR)/$(CONFIG)/json_test_new
logical_thread_test: $(BINDIR)/$(CONFIG)/logical_thread_test
json_test: $(BINDIR)/$(CONFIG)/json_test
message_allocator_end2end_test: $(BINDIR)/$(CONFIG)/message_allocator_end2end_test
metrics_client: $(BINDIR)/$(CONFIG)/metrics_client
mock_test: $(BINDIR)/$(CONFIG)/mock_test
@ -1308,9 +1306,12 @@ timer_test: $(BINDIR)/$(CONFIG)/timer_test
transport_connectivity_state_test: $(BINDIR)/$(CONFIG)/transport_connectivity_state_test
transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
transport_security_common_api_test: $(BINDIR)/$(CONFIG)/transport_security_common_api_test
work_serializer_test: $(BINDIR)/$(CONFIG)/work_serializer_test
writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
xds_bootstrap_test: $(BINDIR)/$(CONFIG)/xds_bootstrap_test
xds_end2end_test: $(BINDIR)/$(CONFIG)/xds_end2end_test
xds_interop_client: $(BINDIR)/$(CONFIG)/xds_interop_client
xds_interop_server: $(BINDIR)/$(CONFIG)/xds_interop_server
public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
boringssl_ssl_test: $(BINDIR)/$(CONFIG)/boringssl_ssl_test
boringssl_crypto_test: $(BINDIR)/$(CONFIG)/boringssl_crypto_test
@ -1527,7 +1528,6 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/init_test \
$(BINDIR)/$(CONFIG)/inproc_callback_test \
$(BINDIR)/$(CONFIG)/invalid_call_argument_test \
$(BINDIR)/$(CONFIG)/json_test \
$(BINDIR)/$(CONFIG)/lame_client_test \
$(BINDIR)/$(CONFIG)/load_file_test \
$(BINDIR)/$(CONFIG)/message_compress_test \
@ -1727,8 +1727,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/json_test_new \
$(BINDIR)/$(CONFIG)/logical_thread_test \
$(BINDIR)/$(CONFIG)/json_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \
$(BINDIR)/$(CONFIG)/mock_test \
@ -1779,9 +1778,12 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/transport_connectivity_state_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/work_serializer_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/xds_bootstrap_test \
$(BINDIR)/$(CONFIG)/xds_end2end_test \
$(BINDIR)/$(CONFIG)/xds_interop_client \
$(BINDIR)/$(CONFIG)/xds_interop_server \
$(BINDIR)/$(CONFIG)/boringssl_ssl_test \
$(BINDIR)/$(CONFIG)/boringssl_crypto_test \
$(BINDIR)/$(CONFIG)/bad_streaming_id_bad_client_test \
@ -1903,8 +1905,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_server \
$(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/json_test_new \
$(BINDIR)/$(CONFIG)/logical_thread_test \
$(BINDIR)/$(CONFIG)/json_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \
$(BINDIR)/$(CONFIG)/mock_test \
@ -1955,9 +1956,12 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/transport_connectivity_state_test \
$(BINDIR)/$(CONFIG)/transport_pid_controller_test \
$(BINDIR)/$(CONFIG)/transport_security_common_api_test \
$(BINDIR)/$(CONFIG)/work_serializer_test \
$(BINDIR)/$(CONFIG)/writes_per_rpc_test \
$(BINDIR)/$(CONFIG)/xds_bootstrap_test \
$(BINDIR)/$(CONFIG)/xds_end2end_test \
$(BINDIR)/$(CONFIG)/xds_interop_client \
$(BINDIR)/$(CONFIG)/xds_interop_server \
$(BINDIR)/$(CONFIG)/bad_streaming_id_bad_client_test \
$(BINDIR)/$(CONFIG)/badreq_bad_client_test \
$(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test \
@ -2139,8 +2143,6 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/inproc_callback_test || ( echo test inproc_callback_test failed ; exit 1 )
$(E) "[RUN] Testing invalid_call_argument_test"
$(Q) $(BINDIR)/$(CONFIG)/invalid_call_argument_test || ( echo test invalid_call_argument_test failed ; exit 1 )
$(E) "[RUN] Testing json_test"
$(Q) $(BINDIR)/$(CONFIG)/json_test || ( echo test json_test failed ; exit 1 )
$(E) "[RUN] Testing lame_client_test"
$(Q) $(BINDIR)/$(CONFIG)/lame_client_test || ( echo test lame_client_test failed ; exit 1 )
$(E) "[RUN] Testing load_file_test"
@ -2417,10 +2419,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/inproc_sync_unary_ping_pong_test || ( echo test inproc_sync_unary_ping_pong_test failed ; exit 1 )
$(E) "[RUN] Testing interop_test"
$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
$(E) "[RUN] Testing json_test_new"
$(Q) $(BINDIR)/$(CONFIG)/json_test_new || ( echo test json_test_new failed ; exit 1 )
$(E) "[RUN] Testing logical_thread_test"
$(Q) $(BINDIR)/$(CONFIG)/logical_thread_test || ( echo test logical_thread_test failed ; exit 1 )
$(E) "[RUN] Testing json_test"
$(Q) $(BINDIR)/$(CONFIG)/json_test || ( echo test json_test failed ; exit 1 )
$(E) "[RUN] Testing message_allocator_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/message_allocator_end2end_test || ( echo test message_allocator_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing mock_test"
@ -2505,6 +2505,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
$(E) "[RUN] Testing transport_security_common_api_test"
$(Q) $(BINDIR)/$(CONFIG)/transport_security_common_api_test || ( echo test transport_security_common_api_test failed ; exit 1 )
$(E) "[RUN] Testing work_serializer_test"
$(Q) $(BINDIR)/$(CONFIG)/work_serializer_test || ( echo test work_serializer_test failed ; exit 1 )
$(E) "[RUN] Testing writes_per_rpc_test"
$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
$(E) "[RUN] Testing xds_bootstrap_test"
@ -3584,7 +3586,6 @@ LIBALTS_TEST_UTIL_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -3638,11 +3639,9 @@ LIBALTS_TEST_UTIL_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -4042,7 +4041,6 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -4096,11 +4094,9 @@ LIBGRPC_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -4520,7 +4516,6 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -4574,11 +4569,9 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -4942,7 +4935,6 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -4996,11 +4988,9 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -5273,7 +5263,6 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -5327,11 +5316,9 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -5567,7 +5554,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -5621,11 +5607,9 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/slice/b64.cc \
src/core/lib/slice/percent_encoding.cc \
src/core/lib/slice/slice.cc \
@ -6084,7 +6068,6 @@ LIBGRPC++_SRC = \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_posix.cc \
src/cpp/client/credentials_cc.cc \
src/cpp/client/generic_stub.cc \
src/cpp/common/alarm.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
@ -7192,7 +7175,6 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/client/create_channel_internal.cc \
src/cpp/client/create_channel_posix.cc \
src/cpp/client/credentials_cc.cc \
src/cpp/client/generic_stub.cc \
src/cpp/common/alarm.cc \
src/cpp/common/channel_arguments.cc \
src/cpp/common/channel_filter.cc \
@ -12021,38 +12003,6 @@ endif
endif
JSON_TEST_SRC = \
test/core/json/json_test.cc \
JSON_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/json_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/json_test: $(JSON_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(JSON_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/json_test
endif
$(OBJDIR)/$(CONFIG)/test/core/json/json_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_json_test: $(JSON_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(JSON_TEST_OBJS:.o=.dep)
endif
endif
LAME_CLIENT_TEST_SRC = \
test/core/surface/lame_client_test.cc \
@ -18367,58 +18317,15 @@ endif
endif
JSON_TEST_NEW_SRC = \
test/core/json/json_test_new.cc \
JSON_TEST_NEW_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_NEW_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/json_test_new: 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)/json_test_new: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/json_test_new: $(PROTOBUF_DEP) $(JSON_TEST_NEW_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(JSON_TEST_NEW_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/json_test_new
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/json/json_test_new.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_json_test_new: $(JSON_TEST_NEW_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(JSON_TEST_NEW_OBJS:.o=.dep)
endif
endif
LOGICAL_THREAD_TEST_SRC = \
test/core/iomgr/logical_thread_test.cc \
JSON_TEST_SRC = \
test/core/json/json_test.cc \
LOGICAL_THREAD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LOGICAL_THREAD_TEST_SRC))))
JSON_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(JSON_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/logical_thread_test: openssl_dep_error
$(BINDIR)/$(CONFIG)/json_test: openssl_dep_error
else
@ -18429,26 +18336,26 @@ 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)/logical_thread_test: protobuf_dep_error
$(BINDIR)/$(CONFIG)/json_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/logical_thread_test: $(PROTOBUF_DEP) $(LOGICAL_THREAD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(BINDIR)/$(CONFIG)/json_test: $(PROTOBUF_DEP) $(JSON_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(LOGICAL_THREAD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/logical_thread_test
$(Q) $(LDXX) $(LDFLAGS) $(JSON_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/json_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/logical_thread_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/core/json/json_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_logical_thread_test: $(LOGICAL_THREAD_TEST_OBJS:.o=.dep)
deps_json_test: $(JSON_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(LOGICAL_THREAD_TEST_OBJS:.o=.dep)
-include $(JSON_TEST_OBJS:.o=.dep)
endif
endif
@ -20677,6 +20584,49 @@ endif
endif
WORK_SERIALIZER_TEST_SRC = \
test/core/iomgr/work_serializer_test.cc \
WORK_SERIALIZER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(WORK_SERIALIZER_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/work_serializer_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)/work_serializer_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/work_serializer_test: $(PROTOBUF_DEP) $(WORK_SERIALIZER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(WORK_SERIALIZER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/work_serializer_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/core/iomgr/work_serializer_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_work_serializer_test: $(WORK_SERIALIZER_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(WORK_SERIALIZER_TEST_OBJS:.o=.dep)
endif
endif
WRITES_PER_RPC_TEST_SRC = \
test/cpp/performance/writes_per_rpc_test.cc \
@ -20822,6 +20772,112 @@ endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/xds_end2end_test.o: $(GENDIR)/src/proto/grpc/testing/xds/ads_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/ads_for_test.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/cds_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/cds_for_test.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/eds_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/eds_for_test.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/lds_rds_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/lds_rds_for_test.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/lrs_for_test.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/lrs_for_test.grpc.pb.cc
XDS_INTEROP_CLIENT_SRC = \
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
test/cpp/interop/xds_interop_client.cc \
XDS_INTEROP_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(XDS_INTEROP_CLIENT_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/xds_interop_client: 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)/xds_interop_client: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/xds_interop_client: $(PROTOBUF_DEP) $(XDS_INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(XDS_INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/xds_interop_client
endif
endif
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/empty.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/cpp/interop/xds_interop_client.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_xds_interop_client: $(XDS_INTEROP_CLIENT_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(XDS_INTEROP_CLIENT_OBJS:.o=.dep)
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/interop/xds_interop_client.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
XDS_INTEROP_SERVER_SRC = \
$(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
$(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
test/cpp/interop/xds_interop_server.cc \
XDS_INTEROP_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(XDS_INTEROP_SERVER_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/xds_interop_server: 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)/xds_interop_server: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/xds_interop_server: $(PROTOBUF_DEP) $(XDS_INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LDXX) $(LDFLAGS) $(XDS_INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/xds_interop_server
endif
endif
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/empty.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/messages.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(OBJDIR)/$(CONFIG)/test/cpp/interop/xds_interop_server.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_xds_interop_server: $(XDS_INTEROP_SERVER_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(XDS_INTEROP_SERVER_OBJS:.o=.dep)
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/interop/xds_interop_server.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
PUBLIC_HEADERS_MUST_BE_C89_SRC = \
test/core/surface/public_headers_must_be_c89.c \

@ -1,5 +1,6 @@
"""Generates and compiles C++ grpc stubs from proto_library rules."""
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:generate_cc.bzl", "generate_cc")
load("//bazel:protobuf.bzl", "well_known_proto_libs")
@ -63,8 +64,7 @@ def cc_grpc_library(
proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1]
if well_known_protos:
proto_deps += well_known_proto_libs()
native.proto_library(
proto_library(
name = proto_target,
srcs = srcs,
deps = proto_deps,

@ -4,6 +4,7 @@ This is an internal rule used by cc_grpc_library, and shouldn't be used
directly.
"""
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
load(
"//bazel:protobuf.bzl",
"get_include_directory",

@ -1,3 +1,4 @@
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
load(
"//bazel:protobuf.bzl",
"get_include_directory",

@ -1,5 +1,7 @@
"""Utility functions for generating protobuf code."""
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
_PROTO_EXTENSION = ".proto"
_VIRTUAL_IMPORTS = "/_virtual_imports/"

@ -1,5 +1,6 @@
"""Generates and compiles Python gRPC stubs from proto_library rules."""
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
load(
"//bazel:protobuf.bzl",
"declare_out_files",

@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_proto//proto:defs.bzl", "proto_library")
load(
"@com_github_grpc_grpc//bazel:python_rules.bzl",
"py2and3_test",

@ -595,7 +595,6 @@ filegroups:
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/credentials_cc.cc
- src/cpp/client/generic_stub.cc
- src/cpp/common/alarm.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/channel_filter.cc
@ -716,7 +715,6 @@ filegroups:
- src/core/lib/iomgr/is_epollexclusive_available.cc
- src/core/lib/iomgr/load_file.cc
- src/core/lib/iomgr/lockfree_event.cc
- src/core/lib/iomgr/logical_thread.cc
- src/core/lib/iomgr/poller/eventmanager_libuv.cc
- src/core/lib/iomgr/polling_entity.cc
- src/core/lib/iomgr/pollset.cc
@ -770,11 +768,9 @@ filegroups:
- src/core/lib/iomgr/wakeup_fd_nospecial.cc
- src/core/lib/iomgr/wakeup_fd_pipe.cc
- src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/json/json.cc
- src/core/lib/iomgr/work_serializer.cc
- src/core/lib/json/json_reader.cc
- src/core/lib/json/json_reader_new.cc
- src/core/lib/json/json_writer.cc
- src/core/lib/json/json_writer_new.cc
- src/core/lib/slice/b64.cc
- src/core/lib/slice/percent_encoding.cc
- src/core/lib/slice/slice.cc
@ -898,7 +894,6 @@ filegroups:
- src/core/lib/iomgr/is_epollexclusive_available.h
- src/core/lib/iomgr/load_file.h
- src/core/lib/iomgr/lockfree_event.h
- src/core/lib/iomgr/logical_thread.h
- src/core/lib/iomgr/nameser.h
- src/core/lib/iomgr/poller/eventmanager_libuv.h
- src/core/lib/iomgr/polling_entity.h
@ -939,6 +934,7 @@ filegroups:
- src/core/lib/iomgr/unix_sockets_posix.h
- src/core/lib/iomgr/wakeup_fd_pipe.h
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/iomgr/work_serializer.h
- src/core/lib/json/json.h
- src/core/lib/slice/b64.h
- src/core/lib/slice/percent_encoding.h
@ -3302,16 +3298,6 @@ targets:
corpus_dirs:
- test/core/json/corpus
maxlen: 512
- name: json_test
build: test
language: c
src:
- test/core/json/json_test.cc
deps:
- grpc_test_util
- grpc
- gpr
uses_polling: false
- name: lame_client_test
build: test
language: c
@ -5396,27 +5382,17 @@ targets:
- mac
- linux
- posix
- name: json_test_new
- name: json_test
gtest: true
build: test
language: c++
src:
- test/core/json/json_test_new.cc
- test/core/json/json_test.cc
deps:
- grpc_test_util
- grpc
- gpr
uses_polling: false
- name: logical_thread_test
cpu_cost: 10
build: test
language: c++
src:
- test/core/iomgr/logical_thread_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- name: message_allocator_end2end_test
gtest: true
cpu_cost: 0.5
@ -6088,6 +6064,16 @@ targets:
- alts_test_util
- gpr
- grpc
- name: work_serializer_test
cpu_cost: 10
build: test
language: c++
src:
- test/core/iomgr/work_serializer_test.cc
deps:
- grpc_test_util
- grpc
- gpr
- name: writes_per_rpc_test
gtest: true
cpu_cost: 0.5
@ -6133,6 +6119,40 @@ targets:
- grpc++
- grpc
- gpr
- name: xds_interop_client
build: test
run: false
language: c++
src:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- test/cpp/interop/xds_interop_client.cc
deps:
- grpc++_test_config
- grpc_test_util
- grpc++
- grpc
- gpr
platforms:
- linux
- name: xds_interop_server
build: test
run: false
language: c++
src:
- src/proto/grpc/testing/empty.proto
- src/proto/grpc/testing/messages.proto
- src/proto/grpc/testing/test.proto
- test/cpp/interop/xds_interop_server.cc
deps:
- grpc++_test_config
- grpc_test_util
- grpc++
- grpc
- gpr
platforms:
- linux
- name: public_headers_must_be_c89
build: test
language: c89

@ -291,7 +291,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/is_epollexclusive_available.cc \
src/core/lib/iomgr/load_file.cc \
src/core/lib/iomgr/lockfree_event.cc \
src/core/lib/iomgr/logical_thread.cc \
src/core/lib/iomgr/poller/eventmanager_libuv.cc \
src/core/lib/iomgr/polling_entity.cc \
src/core/lib/iomgr/pollset.cc \
@ -345,11 +344,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/wakeup_fd_nospecial.cc \
src/core/lib/iomgr/wakeup_fd_pipe.cc \
src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json.cc \
src/core/lib/iomgr/work_serializer.cc \
src/core/lib/json/json_reader.cc \
src/core/lib/json/json_reader_new.cc \
src/core/lib/json/json_writer.cc \
src/core/lib/json/json_writer_new.cc \
src/core/lib/profiling/basic_timers.cc \
src/core/lib/profiling/stap_timers.cc \
src/core/lib/security/context/security_context.cc \

@ -260,7 +260,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\is_epollexclusive_available.cc " +
"src\\core\\lib\\iomgr\\load_file.cc " +
"src\\core\\lib\\iomgr\\lockfree_event.cc " +
"src\\core\\lib\\iomgr\\logical_thread.cc " +
"src\\core\\lib\\iomgr\\poller\\eventmanager_libuv.cc " +
"src\\core\\lib\\iomgr\\polling_entity.cc " +
"src\\core\\lib\\iomgr\\pollset.cc " +
@ -314,11 +313,9 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\iomgr\\wakeup_fd_nospecial.cc " +
"src\\core\\lib\\iomgr\\wakeup_fd_pipe.cc " +
"src\\core\\lib\\iomgr\\wakeup_fd_posix.cc " +
"src\\core\\lib\\json\\json.cc " +
"src\\core\\lib\\iomgr\\work_serializer.cc " +
"src\\core\\lib\\json\\json_reader.cc " +
"src\\core\\lib\\json\\json_reader_new.cc " +
"src\\core\\lib\\json\\json_writer.cc " +
"src\\core\\lib\\json\\json_writer_new.cc " +
"src\\core\\lib\\profiling\\basic_timers.cc " +
"src\\core\\lib\\profiling\\stap_timers.cc " +
"src\\core\\lib\\security\\context\\security_context.cc " +

@ -4,8 +4,14 @@ gRPC environment variables
gRPC C core based implementations (those contained in this repository) expose
some configuration as environment variables that can be set.
* http_proxy
The URI of the proxy to use for HTTP CONNECT support.
* grpc_proxy, https_proxy, http_proxy
The URI of the proxy to use for HTTP CONNECT support. These variables are
checked in order, and the first one that has a value is used.
* no_grpc_proxy, no_proxy
A comma separated list of hostnames to connect to without using a proxy even
if a proxy is set. These variables are checked in order, and the first one
that has a value is used.
* GRPC_ABORT_ON_LEAKS
A debugging aid to cause a call to abort() when gRPC objects are leaked past

@ -20,3 +20,13 @@ v1.23.0 |Jul 30, 2019 |Aug 13, 2019
v1.24.0 |Sept 10, 2019 |Sept 24, 2019
v1.25.0 |Oct 22, 2019 |Nov 5, 2019
v1.26.0 |Dec 3, 2019 |Dec 17, 2019
v1.27.0 |Jan 14, 2020 |Jan 28, 2020
v1.28.0 |Feb 25, 2020 |Mar 10, 2020
v1.29.0 |Apr 7, 2020 |Apr 21, 2020
v1.30.0 |May 19, 2020 |Jun 2, 2020
v1.31.0 |Jun 30, 2020 |Jul 14, 2020
v1.32.0 |Aug 11, 2020 |Aug 25, 2020
v1.33.0 |Sept 22, 2020 |Oct 6, 2020
v1.34.0 |Nov 3, 2020 |Nov 17, 2020
v1.35.0 |Dec 15, 2020 |Dec 29, 2020
v1.36.0 |Jan 26, 2021 |Feb 9, 2021

@ -16,10 +16,11 @@ licenses(["notice"]) # 3-clause BSD
package(default_visibility = ["//visibility:public"])
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
grpc_proto_library(
name = "auth_sample",

@ -255,6 +255,10 @@ main loop in `HandleRpcs` to query the queue.
For a working example, refer to [greeter_async_server.cc](greeter_async_server.cc).
#### Flags for the client
```sh
./greeter_client --target="a target string used to create a GRPC client channel"
```
The Default value for --target is "localhost:50051".

@ -73,11 +73,32 @@ class GreeterClient {
int main(int argc, char** argv) {
// Instantiate the client. It requires a channel, out of which the actual RPCs
// are created. This channel models a connection to an endpoint (in this case,
// localhost at port 50051). We indicate that the channel isn't authenticated
// (use of InsecureChannelCredentials()).
// are created. This channel models a connection to an endpoint specified by
// the argument "--target=" which is the only expected argument.
// We indicate that the channel isn't authenticated (use of
// InsecureChannelCredentials()).
std::string target_str;
std::string arg_str("--target");
if (argc > 1) {
std::string arg_val = argv[1];
size_t start_pos = arg_val.find(arg_str);
if (start_pos != std::string::npos) {
start_pos += arg_str.size();
if (arg_val[start_pos] == '=') {
target_str = arg_val.substr(start_pos + 1);
} else {
std::cout << "The only correct argument syntax is --target=" << std::endl;
return 0;
}
} else {
std::cout << "The only acceptable argument is --target=" << std::endl;
return 0;
}
} else {
target_str = "localhost:50051";
}
GreeterClient greeter(grpc::CreateChannel(
"localhost:50051", grpc::InsecureChannelCredentials()));
target_str, grpc::InsecureChannelCredentials()));
std::string user("world");
std::string reply = greeter.SayHello(user);
std::cout << "Greeter received: " << reply << std::endl;

@ -15,6 +15,7 @@
# limitations under the License.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
package(default_testonly = 1)

@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
proto_library(

@ -443,7 +443,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/is_epollexclusive_available.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/logical_thread.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/poller/eventmanager_libuv.h',
'src/core/lib/iomgr/polling_entity.h',
@ -484,6 +483,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/unix_sockets_posix.h',
'src/core/lib/iomgr/wakeup_fd_pipe.h',
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/context/security_context.h',
@ -591,7 +591,6 @@ Pod::Spec.new do |s|
'src/cpp/client/create_channel_internal.h',
'src/cpp/client/create_channel_posix.cc',
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/client/insecure_credentials.cc',
'src/cpp/client/secure_credentials.cc',
'src/cpp/client/secure_credentials.h',
@ -874,7 +873,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/is_epollexclusive_available.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/logical_thread.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/poller/eventmanager_libuv.h',
'src/core/lib/iomgr/polling_entity.h',
@ -915,6 +913,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/unix_sockets_posix.h',
'src/core/lib/iomgr/wakeup_fd_pipe.h',
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/context/security_context.h',

@ -655,8 +655,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/logical_thread.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.h',
@ -750,12 +748,11 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_pipe.h',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/profiling/timers.h',
@ -1203,7 +1200,6 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/is_epollexclusive_available.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/lockfree_event.h',
'src/core/lib/iomgr/logical_thread.h',
'src/core/lib/iomgr/nameser.h',
'src/core/lib/iomgr/poller/eventmanager_libuv.h',
'src/core/lib/iomgr/polling_entity.h',
@ -1244,6 +1240,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/unix_sockets_posix.h',
'src/core/lib/iomgr/wakeup_fd_pipe.h',
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/iomgr/work_serializer.h',
'src/core/lib/json/json.h',
'src/core/lib/profiling/timers.h',
'src/core/lib/security/context/security_context.h',

@ -577,8 +577,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/load_file.h )
s.files += %w( src/core/lib/iomgr/lockfree_event.cc )
s.files += %w( src/core/lib/iomgr/lockfree_event.h )
s.files += %w( src/core/lib/iomgr/logical_thread.cc )
s.files += %w( src/core/lib/iomgr/logical_thread.h )
s.files += %w( src/core/lib/iomgr/nameser.h )
s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.cc )
s.files += %w( src/core/lib/iomgr/poller/eventmanager_libuv.h )
@ -672,12 +670,11 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/wakeup_fd_pipe.h )
s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.cc )
s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.h )
s.files += %w( src/core/lib/json/json.cc )
s.files += %w( src/core/lib/iomgr/work_serializer.cc )
s.files += %w( src/core/lib/iomgr/work_serializer.h )
s.files += %w( src/core/lib/json/json.h )
s.files += %w( src/core/lib/json/json_reader.cc )
s.files += %w( src/core/lib/json/json_reader_new.cc )
s.files += %w( src/core/lib/json/json_writer.cc )
s.files += %w( src/core/lib/json/json_writer_new.cc )
s.files += %w( src/core/lib/profiling/basic_timers.cc )
s.files += %w( src/core/lib/profiling/stap_timers.cc )
s.files += %w( src/core/lib/profiling/timers.h )

@ -263,7 +263,6 @@
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -317,11 +316,9 @@
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
@ -563,7 +560,6 @@
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -617,11 +613,9 @@
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
@ -988,7 +982,6 @@
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -1042,11 +1035,9 @@
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
@ -1253,7 +1244,6 @@
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -1307,11 +1297,9 @@
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
@ -1494,7 +1482,6 @@
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -1548,11 +1535,9 @@
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/slice/b64.cc',
'src/core/lib/slice/percent_encoding.cc',
'src/core/lib/slice/slice.cc',
@ -1820,7 +1805,6 @@
'src/cpp/client/create_channel_internal.cc',
'src/cpp/client/create_channel_posix.cc',
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/common/alarm.cc',
'src/cpp/common/channel_arguments.cc',
'src/cpp/common/channel_filter.cc',
@ -1992,7 +1976,6 @@
'src/cpp/client/create_channel_internal.cc',
'src/cpp/client/create_channel_posix.cc',
'src/cpp/client/credentials_cc.cc',
'src/cpp/client/generic_stub.cc',
'src/cpp/common/alarm.cc',
'src/cpp/common/channel_arguments.cc',
'src/cpp/common/channel_filter.cc',

@ -22,6 +22,7 @@
#include <functional>
#include <grpcpp/client_context.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/support/async_stream_impl.h>
#include <grpcpp/support/async_unary_call_impl.h>
#include <grpcpp/support/byte_buffer.h>
@ -38,28 +39,39 @@ typedef ::grpc_impl::ClientAsyncResponseReader<ByteBuffer>
namespace grpc_impl {
class CompletionQueue;
/// Generic stubs provide a type-unsafe interface to call gRPC methods
/// by name.
class GenericStub final {
/// Generic stubs provide a type-unaware interface to call gRPC methods
/// by name. In practice, the Request and Response types should be basic
/// types like grpc::ByteBuffer or proto::MessageLite (the base protobuf).
template <class RequestType, class ResponseType>
class TemplatedGenericStub final {
public:
explicit GenericStub(std::shared_ptr<grpc::ChannelInterface> channel)
explicit TemplatedGenericStub(std::shared_ptr<grpc::ChannelInterface> channel)
: channel_(channel) {}
/// Setup a call to a named method \a method using \a context, but don't
/// start it. Let it be started explicitly with StartCall and a tag.
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> PrepareCall(
grpc::ClientContext* context, const grpc::string& method,
CompletionQueue* cq);
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
PrepareCall(ClientContext* context, const grpc::string& method,
CompletionQueue* cq) {
return CallInternal(channel_.get(), context, method, cq, false, nullptr);
}
/// Setup a unary call to a named method \a method using \a context, and don't
/// start it. Let it be started explicitly with StartCall.
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncResponseReader> PrepareUnaryCall(
grpc_impl::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer& request, CompletionQueue* cq);
std::unique_ptr<ClientAsyncResponseReader<ResponseType>> PrepareUnaryCall(
ClientContext* context, const grpc::string& method,
const RequestType& request, CompletionQueue* cq) {
return std::unique_ptr<ClientAsyncResponseReader<ResponseType>>(
internal::ClientAsyncResponseReaderFactory<ResponseType>::Create(
channel_.get(), cq,
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, false));
}
/// DEPRECATED for multi-threaded use
/// Begin a call to a named method \a method using \a context.
@ -67,15 +79,17 @@ class GenericStub final {
/// (i.e, initial metadata has been sent).
/// The return value only indicates whether or not registration of the call
/// succeeded (i.e. the call won't proceed if the return value is nullptr).
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> Call(
grpc_impl::ClientContext* context, const grpc::string& method,
CompletionQueue* cq, void* tag);
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>> Call(
ClientContext* context, const grpc::string& method, CompletionQueue* cq,
void* tag) {
return CallInternal(channel_.get(), context, method, cq, true, tag);
}
#ifdef GRPC_CALLBACK_API_NONEXPERIMENTAL
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(grpc_impl::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
void UnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
UnaryCallInternal(context, method, request, response,
std::move(on_completion));
@ -85,11 +99,9 @@ class GenericStub final {
/// \a context and specifying the \a request and \a response buffers.
/// Like any other reactor-based RPC, it will not be activated until
/// StartCall is invoked on its reactor.
void PrepareUnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
grpc_impl::ClientUnaryReactor* reactor) {
void PrepareUnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
ClientUnaryReactor* reactor) {
PrepareUnaryCallInternal(context, method, request, response, reactor);
}
@ -97,9 +109,8 @@ class GenericStub final {
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
grpc_impl::ClientContext* context, const grpc::string& method,
grpc_impl::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor) {
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
PrepareBidiStreamingCallInternal(context, method, reactor);
}
#endif
@ -109,13 +120,12 @@ class GenericStub final {
/// they are no longer experimental
class experimental_type {
public:
explicit experimental_type(GenericStub* stub) : stub_(stub) {}
explicit experimental_type(TemplatedGenericStub* stub) : stub_(stub) {}
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method, const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
void UnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
stub_->UnaryCallInternal(context, method, request, response,
std::move(on_completion));
@ -125,11 +135,9 @@ class GenericStub final {
/// \a context and specifying the \a request and \a response buffers.
/// Like any other reactor-based RPC, it will not be activated until
/// StartCall is invoked on its reactor.
void PrepareUnaryCall(grpc_impl::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
grpc_impl::ClientUnaryReactor* reactor) {
void PrepareUnaryCall(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
ClientUnaryReactor* reactor) {
stub_->PrepareUnaryCallInternal(context, method, request, response,
reactor);
}
@ -138,14 +146,13 @@ class GenericStub final {
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.
void PrepareBidiStreamingCall(
grpc_impl::ClientContext* context, const grpc::string& method,
grpc_impl::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor) {
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
stub_->PrepareBidiStreamingCallInternal(context, method, reactor);
}
private:
GenericStub* stub_;
TemplatedGenericStub* stub_;
};
/// NOTE: The function experimental() is not stable public API. It is a view
@ -156,24 +163,54 @@ class GenericStub final {
private:
std::shared_ptr<grpc::ChannelInterface> channel_;
void UnaryCallInternal(grpc_impl::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
std::function<void(grpc::Status)> on_completion);
void UnaryCallInternal(ClientContext* context, const grpc::string& method,
const RequestType* request, ResponseType* response,
std::function<void(grpc::Status)> on_completion) {
internal::CallbackUnaryCall(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, std::move(on_completion));
}
void PrepareUnaryCallInternal(grpc_impl::ClientContext* context,
void PrepareUnaryCallInternal(ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
grpc_impl::ClientUnaryReactor* reactor);
const RequestType* request,
ResponseType* response,
ClientUnaryReactor* reactor) {
internal::ClientCallbackUnaryFactory::Create<RequestType, ResponseType>(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, reactor);
}
void PrepareBidiStreamingCallInternal(
grpc_impl::ClientContext* context, const grpc::string& method,
grpc_impl::ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>*
reactor);
ClientContext* context, const grpc::string& method,
ClientBidiReactor<RequestType, ResponseType>* reactor) {
internal::ClientCallbackReaderWriterFactory<RequestType, ResponseType>::
Create(channel_.get(),
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
context, reactor);
}
std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>
CallInternal(grpc::ChannelInterface* channel, ClientContext* context,
const grpc::string& method, CompletionQueue* cq, bool start,
void* tag) {
return std::unique_ptr<ClientAsyncReaderWriter<RequestType, ResponseType>>(
internal::ClientAsyncReaderWriterFactory<RequestType, ResponseType>::
Create(
channel, cq,
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
context, start, tag));
}
};
typedef TemplatedGenericStub<grpc::ByteBuffer, grpc::ByteBuffer> GenericStub;
} // namespace grpc_impl
#endif // GRPCPP_GENERIC_GENERIC_STUB_IMPL_H

@ -560,8 +560,6 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/load_file.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/logical_thread.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/logical_thread.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/nameser.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/poller/eventmanager_libuv.h" role="src" />
@ -655,12 +653,11 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_pipe.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/work_serializer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/work_serializer.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader_new.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_writer_new.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/stap_timers.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />

@ -1729,11 +1729,11 @@ bool ChannelData::ProcessResolverResultLocked(
((service_config == nullptr) !=
(chand->saved_service_config_ == nullptr)) ||
(service_config != nullptr &&
strcmp(service_config->service_config_json(),
chand->saved_service_config_->service_config_json()) != 0);
service_config->json_string() !=
chand->saved_service_config_->json_string());
if (service_config_changed) {
service_config_json.reset(gpr_strdup(
service_config != nullptr ? service_config->service_config_json()
service_config != nullptr ? service_config->json_string().c_str()
: ""));
if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
gpr_log(GPR_INFO,

@ -121,10 +121,9 @@ namespace {
constexpr char kGrpclb[] = "grpclb";
class ParsedGrpcLbConfig : public LoadBalancingPolicy::Config {
class GrpcLbConfig : public LoadBalancingPolicy::Config {
public:
explicit ParsedGrpcLbConfig(
RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
explicit GrpcLbConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy)
: child_policy_(std::move(child_policy)) {}
const char* name() const override { return kGrpclb; }
@ -1447,8 +1446,7 @@ void GrpcLb::ResetBackoffLocked() {
void GrpcLb::UpdateLocked(UpdateArgs args) {
const bool is_initial_update = lb_channel_ == nullptr;
auto* grpclb_config =
static_cast<const ParsedGrpcLbConfig*>(args.config.get());
auto* grpclb_config = static_cast<const GrpcLbConfig*>(args.config.get());
if (grpclb_config != nullptr) {
child_policy_config_ = grpclb_config->child_policy();
} else {
@ -1885,33 +1883,27 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kGrpclb; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
const Json& json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
return RefCountedPtr<LoadBalancingPolicy::Config>(
new ParsedGrpcLbConfig(nullptr));
if (json.type() == Json::Type::JSON_NULL) {
return MakeRefCounted<GrpcLbConfig>(nullptr);
}
InlinedVector<grpc_error*, 2> error_list;
std::vector<grpc_error*> error_list;
RefCountedPtr<LoadBalancingPolicy::Config> 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);
}
auto it = json.object_value().find("childPolicy");
if (it != json.object_value().end()) {
grpc_error* parse_error = GRPC_ERROR_NONE;
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
it->second, &parse_error);
if (parse_error != GRPC_ERROR_NONE) {
std::vector<grpc_error*> child_errors;
child_errors.push_back(parse_error);
error_list.push_back(
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
}
}
if (error_list.empty()) {
return RefCountedPtr<LoadBalancingPolicy::Config>(
new ParsedGrpcLbConfig(std::move(child_policy)));
return MakeRefCounted<GrpcLbConfig>(std::move(child_policy));
} else {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list);
return nullptr;

@ -472,7 +472,7 @@ void PickFirst::PickFirstSubchannelData::
}
}
class ParsedPickFirstConfig : public LoadBalancingPolicy::Config {
class PickFirstConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kPickFirst; }
};
@ -491,12 +491,8 @@ class PickFirstFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kPickFirst; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** /*error*/) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<LoadBalancingPolicy::Config>(
new ParsedPickFirstConfig());
const Json& json, grpc_error** /*error*/) const override {
return MakeRefCounted<PickFirstConfig>();
}
};

@ -467,7 +467,7 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
}
}
class ParsedRoundRobinConfig : public LoadBalancingPolicy::Config {
class RoundRobinConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override { return kRoundRobin; }
};
@ -486,12 +486,8 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kRoundRobin; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** /*error*/) const override {
if (json != nullptr) {
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
}
return RefCountedPtr<LoadBalancingPolicy::Config>(
new ParsedRoundRobinConfig());
const Json& /*json*/, grpc_error** /*error*/) const override {
return MakeRefCounted<RoundRobinConfig>();
}
};

@ -36,12 +36,11 @@ namespace {
constexpr char kCds[] = "cds_experimental";
// Parsed config for this LB policy.
class ParsedCdsConfig : public LoadBalancingPolicy::Config {
// Config for this LB policy.
class CdsConfig : public LoadBalancingPolicy::Config {
public:
explicit ParsedCdsConfig(std::string cluster)
: cluster_(std::move(cluster)) {}
const char* cluster() const { return cluster_.c_str(); }
explicit CdsConfig(std::string cluster) : cluster_(std::move(cluster)) {}
const std::string& cluster() const { return cluster_; }
const char* name() const override { return kCds; }
private:
@ -64,7 +63,7 @@ class CdsLb : public LoadBalancingPolicy {
public:
explicit ClusterWatcher(RefCountedPtr<CdsLb> parent)
: parent_(std::move(parent)) {}
void OnClusterChanged(CdsUpdate cluster_data) override;
void OnClusterChanged(XdsApi::CdsUpdate cluster_data) override;
void OnError(grpc_error* error) override;
private:
@ -90,7 +89,7 @@ class CdsLb : public LoadBalancingPolicy {
void ShutdownLocked() override;
RefCountedPtr<ParsedCdsConfig> config_;
RefCountedPtr<CdsConfig> config_;
// Current channel args from the resolver.
const grpc_channel_args* args_ = nullptr;
@ -112,47 +111,34 @@ class CdsLb : public LoadBalancingPolicy {
// CdsLb::ClusterWatcher
//
void CdsLb::ClusterWatcher::OnClusterChanged(CdsUpdate cluster_data) {
void CdsLb::ClusterWatcher::OnClusterChanged(XdsApi::CdsUpdate cluster_data) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
gpr_log(GPR_INFO, "[cdslb %p] received CDS update from xds client",
parent_.get());
}
// Construct config for child policy.
char* lrs_str = nullptr;
Json::Object child_config = {
{"edsServiceName",
(cluster_data.eds_service_name.empty() ? parent_->config_->cluster()
: cluster_data.eds_service_name)},
};
if (cluster_data.lrs_load_reporting_server_name.has_value()) {
gpr_asprintf(&lrs_str, " \"lrsLoadReportingServerName\": \"%s\",\n",
cluster_data.lrs_load_reporting_server_name.value().c_str());
child_config["lrsLoadReportingServerName"] =
cluster_data.lrs_load_reporting_server_name.value();
}
char* json_str;
gpr_asprintf(&json_str,
"[{\n"
" \"xds_experimental\": {\n"
"%s"
" \"edsServiceName\": \"%s\"\n"
" }\n"
"}]",
(lrs_str == nullptr ? "" : lrs_str),
(cluster_data.eds_service_name.empty()
? parent_->config_->cluster()
: cluster_data.eds_service_name.c_str()));
gpr_free(lrs_str);
grpc_core::UniquePtr<char> json_str_deleter(json_str);
Json json = Json::Array{
Json::Object{
{"xds_experimental", std::move(child_config)},
},
};
if (GRPC_TRACE_FLAG_ENABLED(grpc_cds_lb_trace)) {
std::string json_str = json.Dump();
gpr_log(GPR_INFO, "[cdslb %p] generated config for child policy: %s",
parent_.get(), json_str);
}
grpc_json* json = grpc_json_parse_string(json_str);
if (json == nullptr) {
char* msg;
gpr_asprintf(&msg, "Could not parse LB config: %s", json_str);
OnError(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
return;
parent_.get(), json_str.c_str());
}
grpc_error* error = GRPC_ERROR_NONE;
RefCountedPtr<LoadBalancingPolicy::Config> config =
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
grpc_json_destroy(json);
if (error != GRPC_ERROR_NONE) {
OnError(error);
return;
@ -179,7 +165,8 @@ void CdsLb::ClusterWatcher::OnClusterChanged(CdsUpdate cluster_data) {
void CdsLb::ClusterWatcher::OnError(grpc_error* error) {
gpr_log(GPR_ERROR, "[cdslb %p] xds error obtaining data for cluster %s: %s",
parent_.get(), parent_->config_->cluster(), grpc_error_string(error));
parent_.get(), parent_->config_->cluster().c_str(),
grpc_error_string(error));
// Go into TRANSIENT_FAILURE if we have not yet created the child
// policy (i.e., we have not yet received data from xds). Otherwise,
// we keep running with the data we had previously.
@ -258,8 +245,8 @@ void CdsLb::ShutdownLocked() {
}
if (xds_client_ != nullptr) {
if (cluster_watcher_ != nullptr) {
xds_client_->CancelClusterDataWatch(StringView(config_->cluster()),
cluster_watcher_);
xds_client_->CancelClusterDataWatch(
StringView(config_->cluster().c_str()), cluster_watcher_);
}
xds_client_.reset();
}
@ -281,15 +268,14 @@ void CdsLb::UpdateLocked(UpdateArgs args) {
args_ = args.args;
args.args = nullptr;
// If cluster name changed, cancel watcher and restart.
if (old_config == nullptr ||
strcmp(old_config->cluster(), config_->cluster()) != 0) {
if (old_config == nullptr || old_config->cluster() != config_->cluster()) {
if (old_config != nullptr) {
xds_client_->CancelClusterDataWatch(StringView(old_config->cluster()),
cluster_watcher_);
xds_client_->CancelClusterDataWatch(
StringView(old_config->cluster().c_str()), cluster_watcher_);
}
auto watcher = grpc_core::MakeUnique<ClusterWatcher>(Ref());
cluster_watcher_ = watcher.get();
xds_client_->WatchClusterData(StringView(config_->cluster()),
xds_client_->WatchClusterData(StringView(config_->cluster().c_str()),
std::move(watcher));
}
}
@ -308,9 +294,9 @@ class CdsFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kCds; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
const Json& json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
if (json.type() == Json::Type::JSON_NULL) {
// xds was mentioned as a policy in the deprecated loadBalancingPolicy
// field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@ -318,35 +304,23 @@ class CdsFactory : public LoadBalancingPolicyFactory {
"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* cluster = nullptr;
for (const grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) continue;
if (strcmp(field->key, "cluster") == 0) {
if (cluster != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:cluster error:Duplicate entry"));
}
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:cluster error:type should be string"));
continue;
}
cluster = field->value;
}
}
if (cluster == nullptr) {
std::vector<grpc_error*> error_list;
std::string cluster;
auto it = json.object_value().find("cluster");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"required field 'cluster' not present"));
}
if (error_list.empty()) {
return MakeRefCounted<ParsedCdsConfig>(cluster);
} else if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:cluster error:type should be string"));
} else {
cluster = it->second.string_value();
}
if (!error_list.empty()) {
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Cds Parser", &error_list);
return nullptr;
}
return MakeRefCounted<CdsConfig>(std::move(cluster));
}
};

@ -74,12 +74,12 @@ namespace {
constexpr char kXds[] = "xds_experimental";
class ParsedXdsConfig : public LoadBalancingPolicy::Config {
class XdsConfig : public LoadBalancingPolicy::Config {
public:
ParsedXdsConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy,
std::string eds_service_name,
Optional<std::string> lrs_load_reporting_server_name)
XdsConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy,
std::string eds_service_name,
Optional<std::string> lrs_load_reporting_server_name)
: child_policy_(std::move(child_policy)),
fallback_policy_(std::move(fallback_policy)),
eds_service_name_(std::move(eds_service_name)),
@ -172,7 +172,7 @@ class XdsLb : public LoadBalancingPolicy {
RefCountedPtr<XdsLb> xds_policy_;
PickerList pickers_;
RefCountedPtr<XdsDropConfig> drop_config_;
RefCountedPtr<XdsApi::DropConfig> drop_config_;
};
class FallbackHelper : public ChannelControlHelper {
@ -286,7 +286,7 @@ class XdsLb : public LoadBalancingPolicy {
~LocalityMap() { xds_policy_.reset(DEBUG_LOCATION, "LocalityMap"); }
void UpdateLocked(
const XdsPriorityListUpdate::LocalityMap& locality_map_update);
const XdsApi::PriorityListUpdate::LocalityMap& locality_map_update);
void ResetBackoffLocked();
void UpdateXdsPickerLocked();
OrphanablePtr<Locality> ExtractLocalityLocked(
@ -316,10 +316,10 @@ class XdsLb : public LoadBalancingPolicy {
static void OnDelayedRemovalTimerLocked(void* arg, grpc_error* error);
static void OnFailoverTimerLocked(void* arg, grpc_error* error);
const XdsPriorityListUpdate& priority_list_update() const {
const XdsApi::PriorityListUpdate& priority_list_update() const {
return xds_policy_->priority_list_update_;
}
const XdsPriorityListUpdate::LocalityMap* locality_map_update() const {
const XdsApi::PriorityListUpdate::LocalityMap* locality_map_update() const {
return xds_policy_->priority_list_update_.Find(priority_);
}
@ -387,7 +387,7 @@ class XdsLb : public LoadBalancingPolicy {
// Current channel args and config from the resolver.
const grpc_channel_args* args_ = nullptr;
RefCountedPtr<ParsedXdsConfig> config_;
RefCountedPtr<XdsConfig> config_;
// Internal state.
bool shutting_down_ = false;
@ -431,10 +431,10 @@ class XdsLb : public LoadBalancingPolicy {
// The priority that is being used.
uint32_t current_priority_ = UINT32_MAX;
// The update for priority_list_.
XdsPriorityListUpdate priority_list_update_;
XdsApi::PriorityListUpdate priority_list_update_;
// The config for dropping calls.
RefCountedPtr<XdsDropConfig> drop_config_;
RefCountedPtr<XdsApi::DropConfig> drop_config_;
// The stats for client-side load reporting.
XdsClientStats client_stats_;
@ -594,7 +594,7 @@ class XdsLb::EndpointWatcher : public XdsClient::EndpointWatcherInterface {
~EndpointWatcher() { xds_policy_.reset(DEBUG_LOCATION, "EndpointWatcher"); }
void OnEndpointChanged(EdsUpdate update) override {
void OnEndpointChanged(XdsApi::EdsUpdate update) override {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Received EDS update from xds client",
xds_policy_.get());
@ -1032,6 +1032,8 @@ void XdsLb::UpdatePrioritiesLocked() {
for (uint32_t priority = 0; priority < priorities_.size(); ++priority) {
LocalityMap* locality_map = priorities_[priority].get();
const auto* locality_map_update = priority_list_update_.Find(priority);
// If we have more current priorities than exist in the update, stop here.
if (locality_map_update == nullptr) break;
// Propagate locality_map_update.
// TODO(juanlishen): Find a clean way to skip duplicate update for a
// priority.
@ -1154,7 +1156,7 @@ XdsLb::LocalityMap::LocalityMap(RefCountedPtr<XdsLb> xds_policy,
}
void XdsLb::LocalityMap::UpdateLocked(
const XdsPriorityListUpdate::LocalityMap& locality_map_update) {
const XdsApi::PriorityListUpdate::LocalityMap& locality_map_update) {
if (xds_policy_->shutting_down_) return;
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) {
gpr_log(GPR_INFO, "[xdslb %p] Start Updating priority %" PRIu32,
@ -1777,9 +1779,9 @@ class XdsFactory : public LoadBalancingPolicyFactory {
const char* name() const override { return kXds; }
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const override {
const Json& json, grpc_error** error) const override {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
if (json == nullptr) {
if (json.type() == Json::Type::JSON_NULL) {
// xds was mentioned as a policy in the deprecated loadBalancingPolicy
// field or in the client API.
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
@ -1787,61 +1789,57 @@ class XdsFactory : public LoadBalancingPolicyFactory {
"Please use loadBalancingConfig field of service config instead.");
return nullptr;
}
GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0);
InlinedVector<grpc_error*, 3> error_list;
std::vector<grpc_error*> error_list;
// Child policy.
RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
auto it = json.object_value().find("childPolicy");
if (it != json.object_value().end()) {
grpc_error* parse_error = GRPC_ERROR_NONE;
child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
it->second, &parse_error);
if (child_policy == nullptr) {
GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
std::vector<grpc_error*> child_errors;
child_errors.push_back(parse_error);
error_list.push_back(
GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
}
}
// Fallback policy.
RefCountedPtr<LoadBalancingPolicy::Config> fallback_policy;
it = json.object_value().find("fallbackPolicy");
if (it != json.object_value().end()) {
grpc_error* parse_error = GRPC_ERROR_NONE;
fallback_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
it->second, &parse_error);
if (fallback_policy == nullptr) {
GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
std::vector<grpc_error*> child_errors;
child_errors.push_back(parse_error);
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
"field:fallbackPolicy", &child_errors));
}
}
// EDS service name.
const char* eds_service_name = nullptr;
it = json.object_value().find("edsServiceName");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:edsServiceName error:type should be string"));
} else {
eds_service_name = it->second.string_value().c_str();
}
}
// LRS load reporting server name.
const char* lrs_load_reporting_server_name = nullptr;
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 (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);
}
} else if (strcmp(field->key, "edsServiceName") == 0) {
if (eds_service_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:edsServiceName error:Duplicate entry"));
}
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:edsServiceName error:type should be string"));
continue;
}
eds_service_name = field->value;
} else if (strcmp(field->key, "lrsLoadReportingServerName") == 0) {
if (lrs_load_reporting_server_name != nullptr) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:lrsLoadReportingServerName error:Duplicate entry"));
}
if (field->type != GRPC_JSON_STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:lrsLoadReportingServerName error:type should be string"));
continue;
}
lrs_load_reporting_server_name = field->value;
it = json.object_value().find("lrsLoadReportingServerName");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:lrsLoadReportingServerName error:type should be string"));
} else {
lrs_load_reporting_server_name = it->second.string_value().c_str();
}
}
if (error_list.empty()) {
@ -1850,7 +1848,7 @@ class XdsFactory : public LoadBalancingPolicyFactory {
optional_lrs_load_reporting_server_name.emplace(
std::string(lrs_load_reporting_server_name));
}
return MakeRefCounted<ParsedXdsConfig>(
return MakeRefCounted<XdsConfig>(
std::move(child_policy), std::move(fallback_policy),
eds_service_name == nullptr ? "" : eds_service_name,
std::move(optional_lrs_load_reporting_server_name));

@ -28,6 +28,8 @@ namespace grpc_core {
class LoadBalancingPolicyFactory {
public:
virtual ~LoadBalancingPolicyFactory() {}
/// Returns a new LB policy instance.
virtual OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
LoadBalancingPolicy::Args) const = 0;
@ -37,9 +39,7 @@ class LoadBalancingPolicyFactory {
virtual const char* name() const = 0;
virtual RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error) const = 0;
virtual ~LoadBalancingPolicyFactory() {}
const Json& json, grpc_error** error) const = 0;
};
} // namespace grpc_core

@ -105,106 +105,74 @@ bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
grpc_error* error = GRPC_ERROR_NONE;
// Check if the load balancing policy allows an empty config
*requires_config =
factory->ParseLoadBalancingConfig(nullptr, &error) == nullptr;
factory->ParseLoadBalancingConfig(Json(), &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);
if (lb_config_array == nullptr) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("LB config JSON tree is null");
return nullptr;
grpc_error* ParseLoadBalancingConfigHelper(
const Json& lb_config_array, Json::Object::const_iterator* result) {
if (lb_config_array.type() != Json::Type::ARRAY) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("type should be array");
}
char* error_msg;
if (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;
for (const Json& lb_config : lb_config_array.array_value()) {
if (lb_config.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"child entry should be of type object");
}
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 (lb_config.object_value().empty()) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"no policy found in child entry");
}
if (lb_config.object_value().size() > 1) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("oneOf violation");
}
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;
auto it = lb_config.object_value().begin();
if (it->second.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"child entry should be of type object");
}
// If we support this policy, then select it.
if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key,
nullptr)) {
return policy;
if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(
it->first.c_str(), nullptr)) {
*result = it;
return GRPC_ERROR_NONE;
}
}
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;
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("No known policy");
}
} // namespace
RefCountedPtr<LoadBalancingPolicy::Config>
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json,
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const 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) {
Json::Object::const_iterator policy;
*error = ParseLoadBalancingConfigHelper(json, &policy);
if (*error != GRPC_ERROR_NONE) {
return nullptr;
}
// Find factory.
LoadBalancingPolicyFactory* factory =
g_state->GetLoadBalancingPolicyFactory(policy->first.c_str());
if (factory == nullptr) {
char* msg;
gpr_asprintf(&msg, "Factory not found for policy \"%s\"",
policy->first.c_str());
*error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
gpr_free(msg);
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);
}
// Parse load balancing config via factory.
return factory->ParseLoadBalancingConfig(policy->second, error);
}
} // namespace grpc_core

@ -57,7 +57,7 @@ class LoadBalancingPolicyRegistry {
/// Returns a parsed object of the load balancing policy to be used from a
/// LoadBalancingConfig array \a json.
static RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const grpc_json* json, grpc_error** error);
const Json& json, grpc_error** error);
};
} // namespace grpc_core

@ -223,104 +223,92 @@ void AresDnsResolver::OnNextResolutionLocked(void* arg, grpc_error* error) {
r->Unref(DEBUG_LOCATION, "next_resolution_timer");
}
bool ValueInJsonArray(grpc_json* array, const char* value) {
for (grpc_json* entry = array->child; entry != nullptr; entry = entry->next) {
if (entry->type == GRPC_JSON_STRING && strcmp(entry->value, value) == 0) {
bool ValueInJsonArray(const Json::Array& array, const char* value) {
for (const Json& entry : array) {
if (entry.type() == Json::Type::STRING && entry.string_value() == value) {
return true;
}
}
return false;
}
char* ChooseServiceConfig(char* service_config_choice_json,
grpc_error** error) {
grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json);
if (choices_json == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config JSON Parsing, error: could not parse");
return nullptr;
}
if (choices_json->type != GRPC_JSON_ARRAY) {
std::string ChooseServiceConfig(char* service_config_choice_json,
grpc_error** error) {
Json json = Json::Parse(service_config_choice_json, error);
if (*error != GRPC_ERROR_NONE) return "";
if (json.type() != Json::Type::ARRAY) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config Choices, error: should be of type array");
return nullptr;
return "";
}
char* service_config = nullptr;
const Json* service_config = nullptr;
InlinedVector<grpc_error*, 4> error_list;
bool found_choice = false; // have we found a choice?
for (grpc_json* choice = choices_json->child; choice != nullptr;
choice = choice->next) {
if (choice->type != GRPC_JSON_OBJECT) {
for (const Json& choice : json.array_value()) {
if (choice.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Service Config Choice, error: should be of type object"));
continue;
}
grpc_json* service_config_json = nullptr;
bool selected = true; // has this choice been rejected?
for (grpc_json* field = choice->child; field != nullptr;
field = field->next) {
// Check client language, if specified.
if (strcmp(field->key, "clientLanguage") == 0) {
if (field->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientLanguage error:should be of type array"));
} else if (!ValueInJsonArray(field, "c++")) {
selected = false;
}
// Check client language, if specified.
auto it = choice.object_value().find("clientLanguage");
if (it != choice.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientLanguage error:should be of type array"));
} else if (!ValueInJsonArray(it->second.array_value(), "c++")) {
continue;
}
// Check client hostname, if specified.
if (strcmp(field->key, "clientHostname") == 0) {
if (field->type != GRPC_JSON_ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientHostname error:should be of type array"));
continue;
}
}
// Check client hostname, if specified.
it = choice.object_value().find("clientHostname");
if (it != choice.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:clientHostname error:should be of type array"));
} else {
char* hostname = grpc_gethostname();
if (hostname == nullptr || !ValueInJsonArray(field, hostname)) {
selected = false;
}
}
// Check percentage, if specified.
if (strcmp(field->key, "percentage") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:percentage error:should be of type number"));
if (hostname == nullptr ||
!ValueInJsonArray(it->second.array_value(), hostname)) {
continue;
}
}
}
// Check percentage, if specified.
it = choice.object_value().find("percentage");
if (it != choice.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:percentage error:should be of type number"));
} else {
int random_pct = rand() % 100;
int percentage;
if (sscanf(field->value, "%d", &percentage) != 1) {
if (sscanf(it->second.string_value().c_str(), "%d", &percentage) != 1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:percentage error:should be of type integer"));
} else if (random_pct > percentage || percentage == 0) {
continue;
}
if (random_pct > percentage || percentage == 0) {
selected = false;
}
}
// Save service config.
if (strcmp(field->key, "serviceConfig") == 0) {
if (field->type == GRPC_JSON_OBJECT) {
service_config_json = field;
} else {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceConfig error:should be of type object"));
}
}
}
if (!found_choice && selected && service_config_json != nullptr) {
service_config = grpc_json_dump_to_string(service_config_json, 0);
found_choice = true;
// Found service config.
it = choice.object_value().find("serviceConfig");
if (it == choice.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceConfig error:required field missing"));
} else if (it->second.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceConfig error:should be of type object"));
} else if (service_config == nullptr) {
service_config = &it->second;
}
}
grpc_json_destroy(choices_json);
if (!error_list.empty()) {
gpr_free(service_config);
service_config = nullptr;
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser",
&error_list);
}
return service_config;
if (service_config == nullptr) return "";
return service_config->Dump();
}
void AresDnsResolver::OnResolved(void* arg, grpc_error* error) {
@ -344,17 +332,16 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) {
Result result;
result.addresses = std::move(*r->addresses_);
if (r->service_config_json_ != nullptr) {
char* service_config_string = ChooseServiceConfig(
std::string service_config_string = ChooseServiceConfig(
r->service_config_json_, &result.service_config_error);
gpr_free(r->service_config_json_);
if (result.service_config_error == GRPC_ERROR_NONE &&
service_config_string != nullptr) {
!service_config_string.empty()) {
GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s",
r, service_config_string);
r, service_config_string.c_str());
result.service_config = ServiceConfig::Create(
service_config_string, &result.service_config_error);
}
gpr_free(service_config_string);
}
result.args = grpc_channel_args_copy(r->channel_args_);
r->result_handler()->ReturnResult(std::move(result));

@ -62,11 +62,11 @@ namespace {
// Parses a JSON field of the form generated for a google.proto.Duration
// proto message, as per:
// https://developers.google.com/protocol-buffers/docs/proto3#json
bool ParseDuration(grpc_json* field, grpc_millis* duration) {
if (field->type != GRPC_JSON_STRING) return false;
size_t len = strlen(field->value);
if (field->value[len - 1] != 's') return false;
grpc_core::UniquePtr<char> buf(gpr_strdup(field->value));
bool ParseDuration(const Json& field, grpc_millis* duration) {
if (field.type() != Json::Type::STRING) return false;
size_t len = field.string_value().size();
if (field.string_value()[len - 1] != 's') return false;
grpc_core::UniquePtr<char> buf(gpr_strdup(field.string_value().c_str()));
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
char* decimal_point = strchr(buf.get(), '.');
int nanos = 0;
@ -92,109 +92,92 @@ bool ParseDuration(grpc_json* field, grpc_millis* duration) {
}
std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
grpc_json* field, grpc_error** error) {
const Json& json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
auto retry_policy =
grpc_core::MakeUnique<ClientChannelMethodParsedConfig::RetryPolicy>();
if (field->type != GRPC_JSON_OBJECT) {
if (json.type() != Json::Type::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) continue;
if (strcmp(sub_field->key, "maxAttempts") == 0) {
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);
std::vector<grpc_error*> error_list;
// Parse maxAttempts.
auto it = json.object_value().find("maxAttempts");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxAttempts error:should be of type number"));
} else {
retry_policy->max_attempts =
gpr_parse_nonnegative_int(it->second.string_value().c_str());
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) {
} else if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
gpr_log(GPR_ERROR,
"service config: clamped retryPolicy.maxAttempts at %d",
MAX_MAX_RETRY_ATTEMPTS);
retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS;
}
} else if (strcmp(sub_field->key, "initialBackoff") == 0) {
if (retry_policy->initial_backoff > 0) {
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)) {
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"));
}
} else if (strcmp(sub_field->key, "maxBackoff") == 0) {
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)) {
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"));
}
} else if (strcmp(sub_field->key, "backoffMultiplier") == 0) {
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) {
}
}
// Parse initialBackoff.
it = json.object_value().find("initialBackoff");
if (it != json.object_value().end()) {
if (!ParseDuration(it->second, &retry_policy->initial_backoff)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:Failed to parse"));
} else if (retry_policy->initial_backoff == 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:initialBackoff error:must be greater than 0"));
}
}
// Parse maxBackoff.
it = json.object_value().find("maxBackoff");
if (it != json.object_value().end()) {
if (!ParseDuration(it->second, &retry_policy->max_backoff)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:failed to parse"));
} else if (retry_policy->max_backoff == 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:maxBackoff error:should be greater than 0"));
}
}
// Parse backoffMultiplier.
it = json.object_value().find("backoffMultiplier");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:should be of type number"));
} else {
if (sscanf(it->second.string_value().c_str(), "%f",
&retry_policy->backoff_multiplier) != 1) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:failed to parse"));
continue;
}
if (retry_policy->backoff_multiplier <= 0) {
} else if (retry_policy->backoff_multiplier <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:backoffMultiplier error:should be greater than 0"));
}
} else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) {
if (!retry_policy->retryable_status_codes.Empty()) {
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;
}
for (grpc_json* element = sub_field->child; element != nullptr;
element = element->next) {
if (element->type != GRPC_JSON_STRING) {
}
}
// Parse retryableStatusCodes.
it = json.object_value().find("retryableStatusCodes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:should be of type array"));
} else {
for (const Json& element : it->second.array_value()) {
if (element.type() != Json::Type::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)) {
if (!grpc_status_code_from_string(element.string_value().c_str(),
&status)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryableStatusCodes error:failed to parse status code"));
continue;
@ -222,34 +205,100 @@ std::unique_ptr<ClientChannelMethodParsedConfig::RetryPolicy> ParseRetryPolicy(
return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr;
}
const char* ParseHealthCheckConfig(const grpc_json* field, grpc_error** error) {
grpc_error* ParseRetryThrottling(
const Json& json,
ClientChannelGlobalParsedConfig::RetryThrottling* retry_throttling) {
if (json.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling error:Type should be object");
}
std::vector<grpc_error*> error_list;
// Parse maxTokens.
auto it = json.object_value().find("maxTokens");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:Not found"));
} else if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:Type should be "
"number"));
} else {
retry_throttling->max_milli_tokens =
gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
if (retry_throttling->max_milli_tokens <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:maxTokens error:should be "
"greater than zero"));
}
}
// Parse tokenRatio.
it = json.object_value().find("tokenRatio");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Not found"));
} else if (it->second.type() != Json::Type::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 = it->second.string_value().size();
const char* value = it->second.string_value().c_str();
uint32_t multiplier = 1;
uint32_t decimal_value = 0;
const char* decimal_point = strchr(value, '.');
if (decimal_point != nullptr) {
whole_len = static_cast<size_t>(decimal_point - 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"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
}
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(value, whole_len, &whole_value)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
}
retry_throttling->milli_token_ratio =
static_cast<int>((whole_value * multiplier) + decimal_value);
if (retry_throttling->milli_token_ratio <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:retryThrottling field:tokenRatio error:value should "
"be greater than 0"));
}
}
return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
}
const char* ParseHealthCheckConfig(const 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) {
if (field.type() != Json::Type::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;
std::vector<grpc_error*> error_list;
auto it = field.object_value().find("serviceName");
if (it != field.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:serviceName error:should be of type string"));
} else {
service_name = it->second.string_value().c_str();
}
}
if (!error_list.empty()) {
@ -263,43 +312,35 @@ const char* ParseHealthCheckConfig(const grpc_json* field, grpc_error** error) {
} // namespace
std::unique_ptr<ServiceConfig::ParsedConfig>
ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
ClientChannelServiceConfigParser::ParseGlobalParams(const Json& json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
std::vector<grpc_error*> error_list;
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
grpc_core::UniquePtr<char> lb_policy_name;
Optional<ClientChannelGlobalParsedConfig::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
// Parse LB config.
auto it = json.object_value().find("loadBalancingConfig");
if (it != json.object_value().end()) {
grpc_error* parse_error = GRPC_ERROR_NONE;
parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
it->second, &parse_error);
if (parsed_lb_config == nullptr) {
std::vector<grpc_error*> lb_errors;
lb_errors.push_back(parse_error);
error_list.push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
"field:loadBalancingConfig", &lb_errors));
}
// 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));
}
// Parse deprecated LB policy.
it = json.object_value().find("loadBalancingPolicy");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:loadBalancingPolicy error:type should be string"));
} else {
lb_policy_name.reset(gpr_strdup(it->second.string_value().c_str()));
char* lb_policy = lb_policy_name.get();
if (lb_policy != nullptr) {
for (size_t i = 0; i < strlen(lb_policy); ++i) {
@ -321,118 +362,26 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
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.emplace(
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.emplace(
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"));
}
}
}
}
ClientChannelGlobalParsedConfig::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();
}
}
// Parse retry throttling.
it = json.object_value().find("retryThrottling");
if (it != json.object_value().end()) {
ClientChannelGlobalParsedConfig::RetryThrottling data;
grpc_error* parsing_error = ParseRetryThrottling(it->second, &data);
if (parsing_error != GRPC_ERROR_NONE) {
error_list.push_back(parsing_error);
} else {
retry_throttling.emplace(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);
}
}
// Parse health check config.
it = json.object_value().find("healthCheckConfig");
if (it != json.object_value().end()) {
grpc_error* parsing_error = GRPC_ERROR_NONE;
health_check_service_name =
ParseHealthCheckConfig(it->second, &parsing_error);
if (parsing_error != GRPC_ERROR_NONE) {
error_list.push_back(parsing_error);
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel global parser",
@ -446,47 +395,40 @@ ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json,
}
std::unique_ptr<ServiceConfig::ParsedConfig>
ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json,
ClientChannelServiceConfigParser::ParsePerMethodParams(const Json& json,
grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
InlinedVector<grpc_error*, 4> error_list;
std::vector<grpc_error*> error_list;
Optional<bool> wait_for_ready;
grpc_millis timeout = 0;
std::unique_ptr<ClientChannelMethodParsedConfig::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 (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.emplace(true);
} else if (field->type == GRPC_JSON_FALSE) {
wait_for_ready.emplace(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 (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 (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);
}
// Parse waitForReady.
auto it = json.object_value().find("waitForReady");
if (it != json.object_value().end()) {
if (it->second.type() == Json::Type::JSON_TRUE) {
wait_for_ready.emplace(true);
} else if (it->second.type() == Json::Type::JSON_FALSE) {
wait_for_ready.emplace(false);
} else {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:waitForReady error:Type should be true/false"));
}
}
// Parse timeout.
it = json.object_value().find("timeout");
if (it != json.object_value().end()) {
if (!ParseDuration(it->second, &timeout)) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:timeout error:Failed parsing"));
};
}
// Parse retry policy.
it = json.object_value().find("retryPolicy");
if (it != json.object_value().end()) {
grpc_error* error = GRPC_ERROR_NONE;
retry_policy = ParseRetryPolicy(it->second, &error);
if (retry_policy == nullptr) {
error_list.push_back(error);
}
}
*error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);

@ -109,10 +109,10 @@ class ClientChannelMethodParsedConfig : public ServiceConfig::ParsedConfig {
class ClientChannelServiceConfigParser : public ServiceConfig::Parser {
public:
std::unique_ptr<ServiceConfig::ParsedConfig> ParseGlobalParams(
const grpc_json* json, grpc_error** error) override;
const Json& json, grpc_error** error) override;
std::unique_ptr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override;
const Json& json, grpc_error** error) override;
static size_t ParserIndex();
static void Register();

@ -40,37 +40,29 @@ typedef InlinedVector<std::unique_ptr<ServiceConfig::Parser>,
ServiceConfigParserList* g_registered_parsers;
} // namespace
RefCountedPtr<ServiceConfig> ServiceConfig::Create(const char* json,
RefCountedPtr<ServiceConfig> ServiceConfig::Create(StringView json_string,
grpc_error** error) {
grpc_core::UniquePtr<char> service_config_json(gpr_strdup(json));
grpc_core::UniquePtr<char> json_string(gpr_strdup(json));
GPR_DEBUG_ASSERT(error != nullptr);
grpc_json* json_tree = grpc_json_parse_string(json_string.get());
if (json_tree == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"failed to parse JSON for service config");
return nullptr;
}
Json json = Json::Parse(json_string, error);
if (*error != GRPC_ERROR_NONE) return nullptr;
return MakeRefCounted<ServiceConfig>(
std::move(service_config_json), std::move(json_string), json_tree, error);
std::string(json_string.data(), json_string.size()), std::move(json),
error);
}
ServiceConfig::ServiceConfig(grpc_core::UniquePtr<char> service_config_json,
grpc_core::UniquePtr<char> json_string,
grpc_json* json_tree, grpc_error** error)
: service_config_json_(std::move(service_config_json)),
json_string_(std::move(json_string)),
json_tree_(json_tree) {
ServiceConfig::ServiceConfig(std::string json_string, Json json,
grpc_error** error)
: json_string_(std::move(json_string)), json_(std::move(json)) {
GPR_DEBUG_ASSERT(error != nullptr);
if (json_tree->type != GRPC_JSON_OBJECT || json_tree->key != nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Malformed service Config JSON object");
if (json_.type() != Json::Type::OBJECT) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON value is not an object");
return;
}
grpc_error* error_list[2];
int error_count = 0;
grpc_error* global_error = ParseGlobalParams(json_tree);
grpc_error* local_error = ParsePerMethodParams(json_tree);
grpc_error* global_error = ParseGlobalParams();
grpc_error* local_error = ParsePerMethodParams();
if (global_error != GRPC_ERROR_NONE) {
error_list[error_count++] = global_error;
}
@ -85,14 +77,12 @@ ServiceConfig::ServiceConfig(grpc_core::UniquePtr<char> service_config_json,
}
}
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;
grpc_error* ServiceConfig::ParseGlobalParams() {
std::vector<grpc_error*> error_list;
for (size_t i = 0; i < g_registered_parsers->size(); i++) {
grpc_error* parser_error = GRPC_ERROR_NONE;
auto parsed_obj =
(*g_registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error);
(*g_registered_parsers)[i]->ParseGlobalParams(json_, &parser_error);
if (parser_error != GRPC_ERROR_NONE) {
error_list.push_back(parser_error);
}
@ -102,8 +92,9 @@ grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) {
}
grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
const grpc_json* json,
SliceHashTable<const ParsedConfigVector*>::Entry* entries, size_t* idx) {
const Json& json,
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10>*
entries) {
auto objs_vector = grpc_core::MakeUnique<ParsedConfigVector>();
InlinedVector<grpc_error*, 4> error_list;
for (size_t i = 0; i < g_registered_parsers->size(); i++) {
@ -116,30 +107,25 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
objs_vector->push_back(std::move(parsed_obj));
}
parsed_method_config_vectors_storage_.push_back(std::move(objs_vector));
const auto* vector_ptr =
parsed_method_config_vectors_storage_
[parsed_method_config_vectors_storage_.size() - 1]
.get();
const auto* vector_ptr = parsed_method_config_vectors_storage_.back().get();
// Construct list of paths.
InlinedVector<grpc_core::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) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:not of type Array"));
goto wrap_error;
}
for (grpc_json* name = child->child; name != nullptr; name = name->next) {
grpc_error* parse_error = GRPC_ERROR_NONE;
grpc_core::UniquePtr<char> path =
ParseJsonMethodName(name, &parse_error);
if (path == nullptr) {
error_list.push_back(parse_error);
} else {
GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE);
paths.push_back(std::move(path));
}
InlinedVector<UniquePtr<char>, 10> paths;
auto it = json.object_value().find("name");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:not of type Array"));
return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
}
const Json::Array& name_array = it->second.array_value();
for (const Json& name : name_array) {
grpc_error* parse_error = GRPC_ERROR_NONE;
UniquePtr<char> path = ParseJsonMethodName(name, &parse_error);
if (path == nullptr) {
error_list.push_back(parse_error);
} else {
GPR_DEBUG_ASSERT(parse_error == GRPC_ERROR_NONE);
paths.push_back(std::move(path));
}
}
}
@ -149,136 +135,82 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable(
}
// 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 = vector_ptr;
++*idx;
entries->push_back(
{grpc_slice_from_copied_string(paths[i].get()), vector_ptr});
}
wrap_error:
return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list);
}
grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) {
GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT);
GPR_DEBUG_ASSERT(json_tree_->key == nullptr);
SliceHashTable<const ParsedConfigVector*>::Entry* entries = nullptr;
size_t num_entries = 0;
InlinedVector<grpc_error*, 4> error_list;
for (grpc_json* field = json_tree->child; field != nullptr;
field = field->next) {
if (field->key == nullptr) {
grpc_error* ServiceConfig::ParsePerMethodParams() {
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10> entries;
std::vector<grpc_error*> error_list;
auto it = json_.object_value().find("methodConfig");
if (it != json_.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"error:Illegal key value - NULL"));
continue;
"field:methodConfig error:not of type Array"));
}
if (strcmp(field->key, "methodConfig") == 0) {
if (entries != nullptr) {
GPR_ASSERT(false);
}
if (field->type != GRPC_JSON_ARRAY) {
for (const Json& method_config : it->second.array_value()) {
if (method_config.type() != Json::Type::OBJECT) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:methodConfig error:not of type Array"));
}
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
int count = CountNamesInMethodConfig(method);
if (count <= 0) {
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:methodConfig error:No names found"));
}
num_entries += static_cast<size_t>(count);
"field:methodConfig error:not of type Object"));
continue;
}
entries = static_cast<SliceHashTable<const ParsedConfigVector*>::Entry*>(
gpr_zalloc(num_entries *
sizeof(SliceHashTable<const ParsedConfigVector*>::Entry)));
size_t idx = 0;
for (grpc_json* method = field->child; method != nullptr;
method = method->next) {
grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable(
method, entries, &idx);
if (error != GRPC_ERROR_NONE) {
error_list.push_back(error);
}
grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable(
method_config, &entries);
if (error != GRPC_ERROR_NONE) {
error_list.push_back(error);
}
// idx might not be equal to num_entries due to parsing errors
num_entries = idx;
break;
}
}
if (entries != nullptr) {
if (!entries.empty()) {
parsed_method_configs_table_ =
SliceHashTable<const ParsedConfigVector*>::Create(num_entries, entries,
nullptr);
gpr_free(entries);
SliceHashTable<const ParsedConfigVector*>::Create(
entries.size(), entries.data(), nullptr);
}
return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list);
}
ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); }
int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) {
int num_names = 0;
for (grpc_json* field = json->child; field != nullptr; field = field->next) {
if (field->key != nullptr && strcmp(field->key, "name") == 0) {
if (field->type != GRPC_JSON_ARRAY) return -1;
for (grpc_json* name = field->child; name != nullptr; name = name->next) {
if (name->type != GRPC_JSON_OBJECT) return -1;
++num_names;
}
}
}
return num_names;
}
grpc_core::UniquePtr<char> ServiceConfig::ParseJsonMethodName(
grpc_json* json, grpc_error** error) {
if (json->type != GRPC_JSON_OBJECT) {
UniquePtr<char> ServiceConfig::ParseJsonMethodName(const Json& json,
grpc_error** error) {
if (json.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:type is not object");
return nullptr;
}
const char* service_name = nullptr;
// Find service name.
auto it = json.object_value().find("service");
if (it == json.object_value().end()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:not found");
return nullptr; // Required field.
}
if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:not of type string");
return nullptr;
}
if (it->second.string_value().empty()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:empty value");
return nullptr;
}
const char* service_name = it->second.string_value().c_str();
const char* method_name = nullptr;
for (grpc_json* child = json->child; child != nullptr; child = child->next) {
if (child->key == nullptr) {
// Find method name.
it = json.object_value().find("method");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:Child entry with no key");
"field:name error: field:method error:not of type string");
return nullptr;
}
if (child->type != GRPC_JSON_STRING) {
if (it->second.string_value().empty()) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error:Child entry not of type string");
"field:name error: field:method error:empty value");
return nullptr;
}
if (strcmp(child->key, "service") == 0) {
if (service_name != nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:Multiple entries");
return nullptr; // Duplicate.
}
if (child->value == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:empty value");
return nullptr;
}
service_name = child->value;
} else if (strcmp(child->key, "method") == 0) {
if (method_name != nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:method error:multiple entries");
return nullptr; // Duplicate.
}
if (child->value == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:method error:empty value");
return nullptr;
}
method_name = child->value;
}
}
if (service_name == nullptr) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"field:name error: field:service error:not found");
return nullptr; // Required field.
method_name = it->second.string_value().c_str();
}
char* path;
gpr_asprintf(&path, "/%s/%s", service_name,

@ -70,7 +70,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
virtual ~Parser() = default;
virtual std::unique_ptr<ParsedConfig> ParseGlobalParams(
const grpc_json* /* json */, grpc_error** error) {
const Json& /* json */, grpc_error** error) {
// Avoid unused parameter warning on debug-only parameter
(void)error;
GPR_DEBUG_ASSERT(error != nullptr);
@ -78,7 +78,7 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
}
virtual std::unique_ptr<ParsedConfig> ParsePerMethodParams(
const grpc_json* /* json */, grpc_error** error) {
const Json& /* json */, grpc_error** error) {
// Avoid unused parameter warning on debug-only parameter
(void)error;
GPR_DEBUG_ASSERT(error != nullptr);
@ -125,16 +125,12 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
/// Creates a new service config from parsing \a json_string.
/// Returns null on parse error.
static RefCountedPtr<ServiceConfig> Create(const char* json,
static RefCountedPtr<ServiceConfig> Create(StringView json_string,
grpc_error** error);
// Takes ownership of \a json_tree.
ServiceConfig(grpc_core::UniquePtr<char> service_config_json,
grpc_core::UniquePtr<char> json_string, grpc_json* json_tree,
grpc_error** error);
~ServiceConfig();
ServiceConfig(std::string json_string, Json json, grpc_error** error);
const char* service_config_json() const { return service_config_json_.get(); }
const std::string& json_string() const { return json_string_; }
/// Retrieves the global parsed config at index \a index. The
/// lifetime of the returned object is tied to the lifetime of the
@ -163,24 +159,21 @@ class ServiceConfig : public RefCounted<ServiceConfig> {
private:
// Helper functions to parse the service config
grpc_error* ParseGlobalParams(const grpc_json* json_tree);
grpc_error* ParsePerMethodParams(const grpc_json* json_tree);
// Returns the number of names specified in the method config \a json.
static int CountNamesInMethodConfig(grpc_json* json);
grpc_error* ParseGlobalParams();
grpc_error* ParsePerMethodParams();
// Returns a path string for the JSON name object specified by \a json.
// Returns null on error, and stores error in \a error.
static grpc_core::UniquePtr<char> ParseJsonMethodName(grpc_json* json,
grpc_error** error);
static UniquePtr<char> ParseJsonMethodName(const Json& json,
grpc_error** error);
grpc_error* ParseJsonMethodConfigToServiceConfigVectorTable(
const grpc_json* json,
SliceHashTable<const ParsedConfigVector*>::Entry* entries, size_t* idx);
const Json& json,
InlinedVector<SliceHashTable<const ParsedConfigVector*>::Entry, 10>*
entries);
grpc_core::UniquePtr<char> service_config_json_;
grpc_core::UniquePtr<char> json_string_; // Underlying storage for json_tree.
grpc_json* json_tree_;
std::string json_string_;
Json json_;
InlinedVector<std::unique_ptr<ParsedConfig>, kNumPreallocatedParsers>
parsed_global_configs_;

@ -56,8 +56,12 @@
namespace grpc_core {
bool XdsPriorityListUpdate::operator==(
const XdsPriorityListUpdate& other) const {
//
// XdsApi::PriorityListUpdate
//
bool XdsApi::PriorityListUpdate::operator==(
const XdsApi::PriorityListUpdate& other) const {
if (priorities_.size() != other.priorities_.size()) return false;
for (size_t i = 0; i < priorities_.size(); ++i) {
if (priorities_[i].localities != other.priorities_[i].localities) {
@ -67,8 +71,8 @@ bool XdsPriorityListUpdate::operator==(
return true;
}
void XdsPriorityListUpdate::Add(
XdsPriorityListUpdate::LocalityMap::Locality locality) {
void XdsApi::PriorityListUpdate::Add(
XdsApi::PriorityListUpdate::LocalityMap::Locality locality) {
// Pad the missing priorities in case the localities are not ordered by
// priority.
if (!Contains(locality.priority)) priorities_.resize(locality.priority + 1);
@ -76,13 +80,13 @@ void XdsPriorityListUpdate::Add(
locality_map.localities.emplace(locality.name, std::move(locality));
}
const XdsPriorityListUpdate::LocalityMap* XdsPriorityListUpdate::Find(
const XdsApi::PriorityListUpdate::LocalityMap* XdsApi::PriorityListUpdate::Find(
uint32_t priority) const {
if (!Contains(priority)) return nullptr;
return &priorities_[priority];
}
bool XdsPriorityListUpdate::Contains(
bool XdsApi::PriorityListUpdate::Contains(
const RefCountedPtr<XdsLocalityName>& name) {
for (size_t i = 0; i < priorities_.size(); ++i) {
const LocalityMap& locality_map = priorities_[i];
@ -91,7 +95,11 @@ bool XdsPriorityListUpdate::Contains(
return false;
}
bool XdsDropConfig::ShouldDrop(const std::string** category_name) const {
//
// XdsApi::DropConfig
//
bool XdsApi::DropConfig::ShouldDrop(const std::string** category_name) const {
for (size_t i = 0; i < drop_category_list_.size(); ++i) {
const auto& drop_category = drop_category_list_[i];
// Generate a random number in [0, 1000000).
@ -104,6 +112,17 @@ bool XdsDropConfig::ShouldDrop(const std::string** category_name) const {
return false;
}
//
// XdsApi
//
const char* XdsApi::kLdsTypeUrl = "type.googleapis.com/envoy.api.v2.Listener";
const char* XdsApi::kRdsTypeUrl =
"type.googleapis.com/envoy.api.v2.RouteConfiguration";
const char* XdsApi::kCdsTypeUrl = "type.googleapis.com/envoy.api.v2.Cluster";
const char* XdsApi::kEdsTypeUrl =
"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
namespace {
void PopulateMetadataValue(upb_arena* arena, google_protobuf_Value* value_pb,
@ -200,67 +219,21 @@ void PopulateNode(upb_arena* arena, const XdsBootstrap::Node* node,
upb_strview_makez(build_version));
}
} // namespace
grpc_slice XdsUnsupportedTypeNackRequestCreateAndEncode(
const std::string& type_url, const std::string& nonce, grpc_error* error) {
upb::Arena arena;
envoy_api_v2_DiscoveryRequest* CreateDiscoveryRequest(
upb_arena* arena, const char* type_url, const std::string& version,
const std::string& nonce, grpc_error* error, const XdsBootstrap::Node* node,
const char* build_version) {
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
envoy_api_v2_DiscoveryRequest_new(arena);
// Set type_url.
envoy_api_v2_DiscoveryRequest_set_type_url(
request, upb_strview_makez(type_url.c_str()));
// Set nonce.
envoy_api_v2_DiscoveryRequest_set_response_nonce(
request, upb_strview_makez(nonce.c_str()));
// Set error_detail.
grpc_slice error_description_slice;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&error_description_slice));
upb_strview error_description_strview =
upb_strview_make(reinterpret_cast<const char*>(
GPR_SLICE_START_PTR(error_description_slice)),
GPR_SLICE_LENGTH(error_description_slice));
google_rpc_Status* error_detail =
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request, arena.ptr());
google_rpc_Status_set_message(error_detail, error_description_strview);
GRPC_ERROR_UNREF(error);
// Encode the request.
size_t output_length;
char* output = envoy_api_v2_DiscoveryRequest_serialize(request, arena.ptr(),
&output_length);
return grpc_slice_from_copied_buffer(output, output_length);
}
grpc_slice XdsLdsRequestCreateAndEncode(const std::string& server_name,
const XdsBootstrap::Node* node,
const char* build_version,
const std::string& version,
const std::string& nonce,
grpc_error* error) {
upb::Arena arena;
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
envoy_api_v2_DiscoveryRequest_set_type_url(request,
upb_strview_makez(type_url));
// Set version_info.
if (!version.empty()) {
envoy_api_v2_DiscoveryRequest_set_version_info(
request, upb_strview_makez(version.c_str()));
}
// Populate node.
if (build_version != nullptr) {
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
}
// Add resource_name.
envoy_api_v2_DiscoveryRequest_add_resource_names(
request, upb_strview_make(server_name.data(), server_name.size()),
arena.ptr());
// Set type_url.
envoy_api_v2_DiscoveryRequest_set_type_url(request,
upb_strview_makez(kLdsTypeUrl));
// Set nonce.
if (!nonce.empty()) {
envoy_api_v2_DiscoveryRequest_set_response_nonce(
@ -276,148 +249,98 @@ grpc_slice XdsLdsRequestCreateAndEncode(const std::string& server_name,
GPR_SLICE_START_PTR(error_description_slice)),
GPR_SLICE_LENGTH(error_description_slice));
google_rpc_Status* error_detail =
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request,
arena.ptr());
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request, arena);
google_rpc_Status_set_message(error_detail, error_description_strview);
GRPC_ERROR_UNREF(error);
}
// Encode the request.
// Populate node.
if (build_version != nullptr) {
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena);
PopulateNode(arena, node, build_version, node_msg);
}
return request;
}
grpc_slice SerializeDiscoveryRequest(upb_arena* arena,
envoy_api_v2_DiscoveryRequest* request) {
size_t output_length;
char* output = envoy_api_v2_DiscoveryRequest_serialize(request, arena.ptr(),
&output_length);
char* output =
envoy_api_v2_DiscoveryRequest_serialize(request, arena, &output_length);
return grpc_slice_from_copied_buffer(output, output_length);
}
grpc_slice XdsRdsRequestCreateAndEncode(const std::string& route_config_name,
const XdsBootstrap::Node* node,
const char* build_version,
const std::string& version,
const std::string& nonce,
grpc_error* error) {
} // namespace
grpc_slice XdsApi::CreateUnsupportedTypeNackRequest(const std::string& type_url,
const std::string& nonce,
grpc_error* error) {
upb::Arena arena;
envoy_api_v2_DiscoveryRequest* request = CreateDiscoveryRequest(
arena.ptr(), type_url.c_str(), /*version=*/"", nonce, error,
/*node=*/nullptr, /*build_version=*/nullptr);
return SerializeDiscoveryRequest(arena.ptr(), request);
}
grpc_slice XdsApi::CreateLdsRequest(const std::string& server_name,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node) {
upb::Arena arena;
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
// Set version_info.
if (!version.empty()) {
envoy_api_v2_DiscoveryRequest_set_version_info(
request, upb_strview_makez(version.c_str()));
}
// Populate node.
if (build_version != nullptr) {
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
}
CreateDiscoveryRequest(arena.ptr(), kLdsTypeUrl, version, nonce, error,
populate_node ? node_ : nullptr,
populate_node ? build_version_ : nullptr);
// Add resource_name.
envoy_api_v2_DiscoveryRequest_add_resource_names(
request, upb_strview_make(server_name.data(), server_name.size()),
arena.ptr());
return SerializeDiscoveryRequest(arena.ptr(), request);
}
grpc_slice XdsApi::CreateRdsRequest(const std::string& route_config_name,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node) {
upb::Arena arena;
envoy_api_v2_DiscoveryRequest* request =
CreateDiscoveryRequest(arena.ptr(), kRdsTypeUrl, version, nonce, error,
populate_node ? node_ : nullptr,
populate_node ? build_version_ : nullptr);
// Add resource_name.
envoy_api_v2_DiscoveryRequest_add_resource_names(
request,
upb_strview_make(route_config_name.data(), route_config_name.size()),
arena.ptr());
// Set type_url.
envoy_api_v2_DiscoveryRequest_set_type_url(request,
upb_strview_makez(kRdsTypeUrl));
// Set nonce.
if (!nonce.empty()) {
envoy_api_v2_DiscoveryRequest_set_response_nonce(
request, upb_strview_makez(nonce.c_str()));
}
// Set error_detail if it's a NACK.
if (error != GRPC_ERROR_NONE) {
grpc_slice error_description_slice;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&error_description_slice));
upb_strview error_description_strview =
upb_strview_make(reinterpret_cast<const char*>(
GPR_SLICE_START_PTR(error_description_slice)),
GPR_SLICE_LENGTH(error_description_slice));
google_rpc_Status* error_detail =
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request,
arena.ptr());
google_rpc_Status_set_message(error_detail, error_description_strview);
GRPC_ERROR_UNREF(error);
}
// Encode the request.
size_t output_length;
char* output = envoy_api_v2_DiscoveryRequest_serialize(request, arena.ptr(),
&output_length);
return grpc_slice_from_copied_buffer(output, output_length);
return SerializeDiscoveryRequest(arena.ptr(), request);
}
grpc_slice XdsCdsRequestCreateAndEncode(
const std::set<StringView>& cluster_names, const XdsBootstrap::Node* node,
const char* build_version, const std::string& version,
const std::string& nonce, grpc_error* error) {
grpc_slice XdsApi::CreateCdsRequest(const std::set<StringView>& cluster_names,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node) {
upb::Arena arena;
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
// Set version_info.
if (!version.empty()) {
envoy_api_v2_DiscoveryRequest_set_version_info(
request, upb_strview_makez(version.c_str()));
}
// Populate node.
if (build_version != nullptr) {
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
}
CreateDiscoveryRequest(arena.ptr(), kCdsTypeUrl, version, nonce, error,
populate_node ? node_ : nullptr,
populate_node ? build_version_ : nullptr);
// Add resource_names.
for (const auto& cluster_name : cluster_names) {
envoy_api_v2_DiscoveryRequest_add_resource_names(
request, upb_strview_make(cluster_name.data(), cluster_name.size()),
arena.ptr());
}
// Set type_url.
envoy_api_v2_DiscoveryRequest_set_type_url(request,
upb_strview_makez(kCdsTypeUrl));
// Set nonce.
if (!nonce.empty()) {
envoy_api_v2_DiscoveryRequest_set_response_nonce(
request, upb_strview_makez(nonce.c_str()));
}
// Set error_detail if it's a NACK.
if (error != GRPC_ERROR_NONE) {
grpc_slice error_description_slice;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&error_description_slice));
upb_strview error_description_strview =
upb_strview_make(reinterpret_cast<const char*>(
GPR_SLICE_START_PTR(error_description_slice)),
GPR_SLICE_LENGTH(error_description_slice));
google_rpc_Status* error_detail =
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request,
arena.ptr());
google_rpc_Status_set_message(error_detail, error_description_strview);
GRPC_ERROR_UNREF(error);
}
// Encode the request.
size_t output_length;
char* output = envoy_api_v2_DiscoveryRequest_serialize(request, arena.ptr(),
&output_length);
return grpc_slice_from_copied_buffer(output, output_length);
return SerializeDiscoveryRequest(arena.ptr(), request);
}
grpc_slice XdsEdsRequestCreateAndEncode(
const std::set<StringView>& eds_service_names,
const XdsBootstrap::Node* node, const char* build_version,
const std::string& version, const std::string& nonce, grpc_error* error) {
grpc_slice XdsApi::CreateEdsRequest(
const std::set<StringView>& eds_service_names, const std::string& version,
const std::string& nonce, grpc_error* error, bool populate_node) {
upb::Arena arena;
// Create a request.
envoy_api_v2_DiscoveryRequest* request =
envoy_api_v2_DiscoveryRequest_new(arena.ptr());
// Set version_info.
if (!version.empty()) {
envoy_api_v2_DiscoveryRequest_set_version_info(
request, upb_strview_makez(version.c_str()));
}
// Populate node.
if (build_version != nullptr) {
envoy_api_v2_core_Node* node_msg =
envoy_api_v2_DiscoveryRequest_mutable_node(request, arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
}
CreateDiscoveryRequest(arena.ptr(), kEdsTypeUrl, version, nonce, error,
populate_node ? node_ : nullptr,
populate_node ? build_version_ : nullptr);
// Add resource_names.
for (const auto& eds_service_name : eds_service_names) {
envoy_api_v2_DiscoveryRequest_add_resource_names(
@ -425,34 +348,7 @@ grpc_slice XdsEdsRequestCreateAndEncode(
upb_strview_make(eds_service_name.data(), eds_service_name.size()),
arena.ptr());
}
// Set type_url.
envoy_api_v2_DiscoveryRequest_set_type_url(request,
upb_strview_makez(kEdsTypeUrl));
// Set nonce.
if (!nonce.empty()) {
envoy_api_v2_DiscoveryRequest_set_response_nonce(
request, upb_strview_makez(nonce.c_str()));
}
// Set error_detail if it's a NACK.
if (error != GRPC_ERROR_NONE) {
grpc_slice error_description_slice;
GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
&error_description_slice));
upb_strview error_description_strview =
upb_strview_make(reinterpret_cast<const char*>(
GPR_SLICE_START_PTR(error_description_slice)),
GPR_SLICE_LENGTH(error_description_slice));
google_rpc_Status* error_detail =
envoy_api_v2_DiscoveryRequest_mutable_error_detail(request,
arena.ptr());
google_rpc_Status_set_message(error_detail, error_description_strview);
GRPC_ERROR_UNREF(error);
}
// Encode the request.
size_t output_length;
char* output = envoy_api_v2_DiscoveryRequest_serialize(request, arena.ptr(),
&output_length);
return grpc_slice_from_copied_buffer(output, output_length);
return SerializeDiscoveryRequest(arena.ptr(), request);
}
namespace {
@ -508,7 +404,7 @@ MatchType DomainPatternMatchType(const std::string& domain_pattern) {
grpc_error* RouteConfigParse(
const envoy_api_v2_RouteConfiguration* route_config,
const std::string& expected_server_name, RdsUpdate* rds_update) {
const std::string& expected_server_name, XdsApi::RdsUpdate* rds_update) {
// Strip off port from server name, if any.
size_t pos = expected_server_name.find(':');
std::string expected_host_name = expected_server_name.substr(0, pos);
@ -601,11 +497,9 @@ grpc_error* RouteConfigParse(
return GRPC_ERROR_NONE;
}
} // namespace
grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
const std::string& expected_server_name,
LdsUpdate* lds_update, upb_arena* arena) {
XdsApi::LdsUpdate* lds_update, upb_arena* arena) {
// Get the resources from the response.
size_t size;
const google_protobuf_Any* const* resources =
@ -617,7 +511,7 @@ grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
for (size_t i = 0; i < size; ++i) {
// Check the type_url of the resource.
const upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
if (!upb_strview_eql(type_url, upb_strview_makez(kLdsTypeUrl))) {
if (!upb_strview_eql(type_url, upb_strview_makez(XdsApi::kLdsTypeUrl))) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not LDS.");
}
// Decode the listener.
@ -652,7 +546,7 @@ grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
const envoy_api_v2_RouteConfiguration* route_config =
envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_route_config(
http_connection_manager);
RdsUpdate rds_update;
XdsApi::RdsUpdate rds_update;
grpc_error* error =
RouteConfigParse(route_config, expected_server_name, &rds_update);
if (error != GRPC_ERROR_NONE) return error;
@ -687,7 +581,7 @@ grpc_error* LdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
const std::string& expected_server_name,
const std::string& expected_route_config_name,
RdsUpdate* rds_update, upb_arena* arena) {
XdsApi::RdsUpdate* rds_update, upb_arena* arena) {
// Get the resources from the response.
size_t size;
const google_protobuf_Any* const* resources =
@ -699,7 +593,7 @@ grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
for (size_t i = 0; i < size; ++i) {
// Check the type_url of the resource.
const upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
if (!upb_strview_eql(type_url, upb_strview_makez(kRdsTypeUrl))) {
if (!upb_strview_eql(type_url, upb_strview_makez(XdsApi::kRdsTypeUrl))) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not RDS.");
}
// Decode the route_config.
@ -717,7 +611,7 @@ grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
upb_strview_makez(expected_route_config_name.c_str());
if (!upb_strview_eql(name, expected_name)) continue;
// Parse the route_config.
RdsUpdate local_rds_update;
XdsApi::RdsUpdate local_rds_update;
grpc_error* error =
RouteConfigParse(route_config, expected_server_name, &local_rds_update);
if (error != GRPC_ERROR_NONE) return error;
@ -729,7 +623,8 @@ grpc_error* RdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
}
grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
CdsUpdateMap* cds_update_map, upb_arena* arena) {
XdsApi::CdsUpdateMap* cds_update_map,
upb_arena* arena) {
// Get the resources from the response.
size_t size;
const google_protobuf_Any* const* resources =
@ -740,10 +635,10 @@ grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
}
// Parse all the resources in the CDS response.
for (size_t i = 0; i < size; ++i) {
CdsUpdate cds_update;
XdsApi::CdsUpdate cds_update;
// Check the type_url of the resource.
const upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
if (!upb_strview_eql(type_url, upb_strview_makez(kCdsTypeUrl))) {
if (!upb_strview_eql(type_url, upb_strview_makez(XdsApi::kCdsTypeUrl))) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not CDS.");
}
// Decode the cluster.
@ -798,8 +693,6 @@ grpc_error* CdsResponseParse(const envoy_api_v2_DiscoveryResponse* response,
return GRPC_ERROR_NONE;
}
namespace {
grpc_error* ServerAddressParseAndAppend(
const envoy_api_v2_endpoint_LbEndpoint* lb_endpoint,
ServerAddressList* list) {
@ -837,7 +730,7 @@ grpc_error* ServerAddressParseAndAppend(
grpc_error* LocalityParse(
const envoy_api_v2_endpoint_LocalityLbEndpoints* locality_lb_endpoints,
XdsPriorityListUpdate::LocalityMap::Locality* output_locality) {
XdsApi::PriorityListUpdate::LocalityMap::Locality* output_locality) {
// Parse LB weight.
const google_protobuf_UInt32Value* lb_weight =
envoy_api_v2_endpoint_LocalityLbEndpoints_load_balancing_weight(
@ -875,7 +768,7 @@ grpc_error* LocalityParse(
grpc_error* DropParseAndAppend(
const envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload* drop_overload,
XdsDropConfig* drop_config, bool* drop_all) {
XdsApi::DropConfig* drop_config, bool* drop_all) {
// Get the category.
upb_strview category =
envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload_category(
@ -915,7 +808,7 @@ grpc_error* DropParseAndAppend(
grpc_error* EdsResponsedParse(
const envoy_api_v2_DiscoveryResponse* response,
const std::set<StringView>& expected_eds_service_names,
EdsUpdateMap* eds_update_map, upb_arena* arena) {
XdsApi::EdsUpdateMap* eds_update_map, upb_arena* arena) {
// Get the resources from the response.
size_t size;
const google_protobuf_Any* const* resources =
@ -925,10 +818,10 @@ grpc_error* EdsResponsedParse(
"EDS response contains 0 resource.");
}
for (size_t i = 0; i < size; ++i) {
EdsUpdate eds_update;
XdsApi::EdsUpdate eds_update;
// Check the type_url of the resource.
upb_strview type_url = google_protobuf_Any_type_url(resources[i]);
if (!upb_strview_eql(type_url, upb_strview_makez(kEdsTypeUrl))) {
if (!upb_strview_eql(type_url, upb_strview_makez(XdsApi::kEdsTypeUrl))) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("Resource is not EDS.");
}
// Get the cluster_load_assignment.
@ -957,7 +850,7 @@ grpc_error* EdsResponsedParse(
envoy_api_v2_ClusterLoadAssignment_endpoints(cluster_load_assignment,
&locality_size);
for (size_t j = 0; j < locality_size; ++j) {
XdsPriorityListUpdate::LocalityMap::Locality locality;
XdsApi::PriorityListUpdate::LocalityMap::Locality locality;
grpc_error* error = LocalityParse(endpoints[j], &locality);
if (error != GRPC_ERROR_NONE) return error;
// Filter out locality with weight 0.
@ -965,7 +858,7 @@ grpc_error* EdsResponsedParse(
eds_update.priority_list_update.Add(locality);
}
// Get the drop config.
eds_update.drop_config = MakeRefCounted<XdsDropConfig>();
eds_update.drop_config = MakeRefCounted<XdsApi::DropConfig>();
const envoy_api_v2_ClusterLoadAssignment_Policy* policy =
envoy_api_v2_ClusterLoadAssignment_policy(cluster_load_assignment);
if (policy != nullptr) {
@ -995,7 +888,7 @@ grpc_error* EdsResponsedParse(
} // namespace
grpc_error* XdsAdsResponseDecodeAndParse(
grpc_error* XdsApi::ParseAdsResponse(
const grpc_slice& encoded_response, const std::string& expected_server_name,
const std::string& expected_route_config_name,
const std::set<StringView>& expected_eds_service_names,
@ -1044,7 +937,7 @@ grpc_error* XdsAdsResponseDecodeAndParse(
namespace {
grpc_slice LrsRequestEncode(
grpc_slice SerializeLrsRequest(
const envoy_service_load_stats_v2_LoadStatsRequest* request,
upb_arena* arena) {
size_t output_length;
@ -1055,9 +948,7 @@ grpc_slice LrsRequestEncode(
} // namespace
grpc_slice XdsLrsRequestCreateAndEncode(const std::string& server_name,
const XdsBootstrap::Node* node,
const char* build_version) {
grpc_slice XdsApi::CreateLrsInitialRequest(const std::string& server_name) {
upb::Arena arena;
// Create a request.
envoy_service_load_stats_v2_LoadStatsRequest* request =
@ -1066,7 +957,7 @@ grpc_slice XdsLrsRequestCreateAndEncode(const std::string& server_name,
envoy_api_v2_core_Node* node_msg =
envoy_service_load_stats_v2_LoadStatsRequest_mutable_node(request,
arena.ptr());
PopulateNode(arena.ptr(), node, build_version, node_msg);
PopulateNode(arena.ptr(), node_, build_version_, node_msg);
// Add cluster stats. There is only one because we only use one server name in
// one channel.
envoy_api_v2_endpoint_ClusterStats* cluster_stats =
@ -1075,7 +966,7 @@ grpc_slice XdsLrsRequestCreateAndEncode(const std::string& server_name,
// Set the cluster name.
envoy_api_v2_endpoint_ClusterStats_set_cluster_name(
cluster_stats, upb_strview_makez(server_name.c_str()));
return LrsRequestEncode(request, arena.ptr());
return SerializeLrsRequest(request, arena.ptr());
}
namespace {
@ -1120,7 +1011,7 @@ void LocalityStatsPopulate(
} // namespace
grpc_slice XdsLrsRequestCreateAndEncode(
grpc_slice XdsApi::CreateLrsRequest(
std::map<StringView, std::set<XdsClientStats*>, StringLess>
client_stats_map) {
upb::Arena arena;
@ -1190,12 +1081,12 @@ grpc_slice XdsLrsRequestCreateAndEncode(
timespec.tv_nsec);
}
}
return LrsRequestEncode(request, arena.ptr());
return SerializeLrsRequest(request, arena.ptr());
}
grpc_error* XdsLrsResponseDecodeAndParse(const grpc_slice& encoded_response,
std::set<std::string>* cluster_names,
grpc_millis* load_reporting_interval) {
grpc_error* XdsApi::ParseLrsResponse(const grpc_slice& encoded_response,
std::set<std::string>* cluster_names,
grpc_millis* load_reporting_interval) {
upb::Arena arena;
// Decode the response.
const envoy_service_load_stats_v2_LoadStatsResponse* decoded_response =

@ -34,215 +34,218 @@
namespace grpc_core {
constexpr char kLdsTypeUrl[] = "type.googleapis.com/envoy.api.v2.Listener";
constexpr char kRdsTypeUrl[] =
"type.googleapis.com/envoy.api.v2.RouteConfiguration";
constexpr char kCdsTypeUrl[] = "type.googleapis.com/envoy.api.v2.Cluster";
constexpr char kEdsTypeUrl[] =
"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment";
struct RdsUpdate {
// The name to use in the CDS request.
std::string cluster_name;
};
struct LdsUpdate {
// The name to use in the RDS request.
std::string route_config_name;
// The name to use in the CDS request. Present if the LDS response has it
// inlined.
Optional<RdsUpdate> rds_update;
};
class XdsApi {
public:
static const char* kLdsTypeUrl;
static const char* kRdsTypeUrl;
static const char* kCdsTypeUrl;
static const char* kEdsTypeUrl;
struct RdsUpdate {
// The name to use in the CDS request.
std::string cluster_name;
};
using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>;
struct LdsUpdate {
// The name to use in the RDS request.
std::string route_config_name;
// The name to use in the CDS request. Present if the LDS response has it
// inlined.
Optional<RdsUpdate> rds_update;
};
using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>;
using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>;
struct CdsUpdate {
// The name to use in the EDS request.
// If empty, the cluster name will be used.
std::string eds_service_name;
// The LRS server to use for load reporting.
// If not set, load reporting will be disabled.
// If set to the empty string, will use the same server we obtained the CDS
// data from.
Optional<std::string> lrs_load_reporting_server_name;
};
using RdsUpdateMap = std::map<std::string /*route_config_name*/, RdsUpdate>;
using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
struct CdsUpdate {
// The name to use in the EDS request.
// If empty, the cluster name will be used.
std::string eds_service_name;
// The LRS server to use for load reporting.
// If not set, load reporting will be disabled.
// If set to the empty string, will use the same server we obtained the CDS
// data from.
Optional<std::string> lrs_load_reporting_server_name;
};
class XdsPriorityListUpdate {
public:
struct LocalityMap {
struct Locality {
bool operator==(const Locality& other) const {
return *name == *other.name && serverlist == other.serverlist &&
lb_weight == other.lb_weight && priority == other.priority;
}
using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
// This comparator only compares the locality names.
struct Less {
bool operator()(const Locality& lhs, const Locality& rhs) const {
return XdsLocalityName::Less()(lhs.name, rhs.name);
class PriorityListUpdate {
public:
struct LocalityMap {
struct Locality {
bool operator==(const Locality& other) const {
return *name == *other.name && serverlist == other.serverlist &&
lb_weight == other.lb_weight && priority == other.priority;
}
// This comparator only compares the locality names.
struct Less {
bool operator()(const Locality& lhs, const Locality& rhs) const {
return XdsLocalityName::Less()(lhs.name, rhs.name);
}
};
RefCountedPtr<XdsLocalityName> name;
ServerAddressList serverlist;
uint32_t lb_weight;
uint32_t priority;
};
RefCountedPtr<XdsLocalityName> name;
ServerAddressList serverlist;
uint32_t lb_weight;
uint32_t priority;
bool Contains(const RefCountedPtr<XdsLocalityName>& name) const {
return localities.find(name) != localities.end();
}
size_t size() const { return localities.size(); }
std::map<RefCountedPtr<XdsLocalityName>, Locality, XdsLocalityName::Less>
localities;
};
bool Contains(const RefCountedPtr<XdsLocalityName>& name) const {
return localities.find(name) != localities.end();
bool operator==(const PriorityListUpdate& other) const;
bool operator!=(const PriorityListUpdate& other) const {
return !(*this == other);
}
size_t size() const { return localities.size(); }
void Add(LocalityMap::Locality locality);
std::map<RefCountedPtr<XdsLocalityName>, Locality, XdsLocalityName::Less>
localities;
};
const LocalityMap* Find(uint32_t priority) const;
bool operator==(const XdsPriorityListUpdate& other) const;
bool operator!=(const XdsPriorityListUpdate& other) const {
return !(*this == other);
}
bool Contains(uint32_t priority) const {
return priority < priorities_.size();
}
bool Contains(const RefCountedPtr<XdsLocalityName>& name);
void Add(LocalityMap::Locality locality);
bool empty() const { return priorities_.empty(); }
size_t size() const { return priorities_.size(); }
const LocalityMap* Find(uint32_t priority) const;
// Callers should make sure the priority list is non-empty.
uint32_t LowestPriority() const {
return static_cast<uint32_t>(priorities_.size()) - 1;
}
bool Contains(uint32_t priority) const {
return priority < priorities_.size();
}
bool Contains(const RefCountedPtr<XdsLocalityName>& name);
private:
InlinedVector<LocalityMap, 2> priorities_;
};
bool empty() const { return priorities_.empty(); }
size_t size() const { return priorities_.size(); }
// There are two phases of accessing this class's content:
// 1. to initialize in the control plane combiner;
// 2. to use in the data plane combiner.
// So no additional synchronization is needed.
class DropConfig : public RefCounted<DropConfig> {
public:
struct DropCategory {
bool operator==(const DropCategory& other) const {
return name == other.name &&
parts_per_million == other.parts_per_million;
}
// Callers should make sure the priority list is non-empty.
uint32_t LowestPriority() const {
return static_cast<uint32_t>(priorities_.size()) - 1;
}
std::string name;
const uint32_t parts_per_million;
};
private:
InlinedVector<LocalityMap, 2> priorities_;
};
using DropCategoryList = InlinedVector<DropCategory, 2>;
// There are two phases of accessing this class's content:
// 1. to initialize in the control plane combiner;
// 2. to use in the data plane combiner.
// So no additional synchronization is needed.
class XdsDropConfig : public RefCounted<XdsDropConfig> {
public:
struct DropCategory {
bool operator==(const DropCategory& other) const {
return name == other.name && parts_per_million == other.parts_per_million;
void AddCategory(std::string name, uint32_t parts_per_million) {
drop_category_list_.emplace_back(
DropCategory{std::move(name), parts_per_million});
}
std::string name;
const uint32_t parts_per_million;
};
// The only method invoked from the data plane combiner.
bool ShouldDrop(const std::string** category_name) const;
using DropCategoryList = InlinedVector<DropCategory, 2>;
const DropCategoryList& drop_category_list() const {
return drop_category_list_;
}
void AddCategory(std::string name, uint32_t parts_per_million) {
drop_category_list_.emplace_back(
DropCategory{std::move(name), parts_per_million});
}
bool operator==(const DropConfig& other) const {
return drop_category_list_ == other.drop_category_list_;
}
bool operator!=(const DropConfig& other) const { return !(*this == other); }
// The only method invoked from the data plane combiner.
bool ShouldDrop(const std::string** category_name) const;
private:
DropCategoryList drop_category_list_;
};
const DropCategoryList& drop_category_list() const {
return drop_category_list_;
}
struct EdsUpdate {
PriorityListUpdate priority_list_update;
RefCountedPtr<DropConfig> drop_config;
bool drop_all = false;
};
bool operator==(const XdsDropConfig& other) const {
return drop_category_list_ == other.drop_category_list_;
}
bool operator!=(const XdsDropConfig& other) const {
return !(*this == other);
}
using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
XdsApi(const XdsBootstrap::Node* node, const char* build_version)
: node_(node), build_version_(build_version) {}
// Creates a request to nack an unsupported resource type.
// Takes ownership of \a error.
grpc_slice CreateUnsupportedTypeNackRequest(const std::string& type_url,
const std::string& nonce,
grpc_error* error);
// Creates an LDS request querying \a server_name.
// Takes ownership of \a error.
grpc_slice CreateLdsRequest(const std::string& server_name,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node);
// Creates an RDS request querying \a route_config_name.
// Takes ownership of \a error.
grpc_slice CreateRdsRequest(const std::string& route_config_name,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node);
// Creates a CDS request querying \a cluster_names.
// Takes ownership of \a error.
grpc_slice CreateCdsRequest(const std::set<StringView>& cluster_names,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node);
// Creates an EDS request querying \a eds_service_names.
// Takes ownership of \a error.
grpc_slice CreateEdsRequest(const std::set<StringView>& eds_service_names,
const std::string& version,
const std::string& nonce, grpc_error* error,
bool populate_node);
// Parses the ADS response and outputs the validated update for either CDS or
// EDS. If the response can't be parsed at the top level, \a type_url will
// point to an empty string; otherwise, it will point to the received data.
grpc_error* ParseAdsResponse(
const grpc_slice& encoded_response,
const std::string& expected_server_name,
const std::string& expected_route_config_name,
const std::set<StringView>& expected_eds_service_names,
LdsUpdate* lds_update, RdsUpdate* rds_update,
CdsUpdateMap* cds_update_map, EdsUpdateMap* eds_update_map,
std::string* version, std::string* nonce, std::string* type_url);
// Creates an LRS request querying \a server_name.
grpc_slice CreateLrsInitialRequest(const std::string& server_name);
// Creates an LRS request sending client-side load reports. If all the
// counters are zero, returns empty slice.
grpc_slice CreateLrsRequest(std::map<StringView /*cluster_name*/,
std::set<XdsClientStats*>, StringLess>
client_stats_map);
// Parses the LRS response and returns \a
// load_reporting_interval for client-side load reporting. If there is any
// error, the output config is invalid.
grpc_error* ParseLrsResponse(const grpc_slice& encoded_response,
std::set<std::string>* cluster_names,
grpc_millis* load_reporting_interval);
private:
DropCategoryList drop_category_list_;
const XdsBootstrap::Node* node_;
const char* build_version_;
};
struct EdsUpdate {
XdsPriorityListUpdate priority_list_update;
RefCountedPtr<XdsDropConfig> drop_config;
bool drop_all = false;
};
using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
// Creates a request to nack an unsupported resource type.
// Takes ownership of \a error.
grpc_slice XdsUnsupportedTypeNackRequestCreateAndEncode(
const std::string& type_url, const std::string& nonce, grpc_error* error);
// Creates an LDS request querying \a server_name.
// Takes ownership of \a error.
grpc_slice XdsLdsRequestCreateAndEncode(const std::string& server_name,
const XdsBootstrap::Node* node,
const char* build_version,
const std::string& version,
const std::string& nonce,
grpc_error* error);
// Creates an RDS request querying \a route_config_name.
// Takes ownership of \a error.
grpc_slice XdsRdsRequestCreateAndEncode(const std::string& route_config_name,
const XdsBootstrap::Node* node,
const char* build_version,
const std::string& version,
const std::string& nonce,
grpc_error* error);
// Creates a CDS request querying \a cluster_names.
// Takes ownership of \a error.
grpc_slice XdsCdsRequestCreateAndEncode(
const std::set<StringView>& cluster_names, const XdsBootstrap::Node* node,
const char* build_version, const std::string& version,
const std::string& nonce, grpc_error* error);
// Creates an EDS request querying \a eds_service_names.
// Takes ownership of \a error.
grpc_slice XdsEdsRequestCreateAndEncode(
const std::set<StringView>& eds_service_names,
const XdsBootstrap::Node* node, const char* build_version,
const std::string& version, const std::string& nonce, grpc_error* error);
// Parses the ADS response and outputs the validated update for either CDS or
// EDS. If the response can't be parsed at the top level, \a type_url will point
// to an empty string; otherwise, it will point to the received data.
grpc_error* XdsAdsResponseDecodeAndParse(
const grpc_slice& encoded_response, const std::string& expected_server_name,
const std::string& expected_route_config_name,
const std::set<StringView>& expected_eds_service_names,
LdsUpdate* lds_update, RdsUpdate* rds_update, CdsUpdateMap* cds_update_map,
EdsUpdateMap* eds_update_map, std::string* version, std::string* nonce,
std::string* type_url);
// Creates an LRS request querying \a server_name.
grpc_slice XdsLrsRequestCreateAndEncode(const std::string& server_name,
const XdsBootstrap::Node* node,
const char* build_version);
// Creates an LRS request sending client-side load reports. If all the counters
// are zero, returns empty slice.
grpc_slice XdsLrsRequestCreateAndEncode(
std::map<StringView /*cluster_name*/, std::set<XdsClientStats*>, StringLess>
client_stats_map);
// Parses the LRS response and returns \a
// load_reporting_interval for client-side load reporting. If there is any
// error, the output config is invalid.
grpc_error* XdsLrsResponseDecodeAndParse(const grpc_slice& encoded_response,
std::set<std::string>* cluster_names,
grpc_millis* load_reporting_interval);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_XDS_XDS_API_H */

@ -30,7 +30,7 @@ grpc_channel_args* ModifyXdsChannelArgs(grpc_channel_args* args) {
grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
const grpc_channel_args& args,
grpc_error** error) {
grpc_error** /*error*/) {
if (!bootstrap.server().channel_creds.empty()) return nullptr;
return grpc_insecure_channel_create(bootstrap.server().server_uri.c_str(),
&args, nullptr);

@ -187,17 +187,18 @@ class XdsClient::ChannelState::AdsCallState
gpr_log(GPR_INFO, "[xds_client %p] %s",
self->ads_calld_->xds_client(), grpc_error_string(error));
}
if (self->type_url_ == kLdsTypeUrl || self->type_url_ == kRdsTypeUrl) {
if (self->type_url_ == XdsApi::kLdsTypeUrl ||
self->type_url_ == XdsApi::kRdsTypeUrl) {
self->ads_calld_->xds_client()->service_config_watcher_->OnError(
error);
} else if (self->type_url_ == kCdsTypeUrl) {
} else if (self->type_url_ == XdsApi::kCdsTypeUrl) {
ClusterState& state =
self->ads_calld_->xds_client()->cluster_map_[self->name_];
for (const auto& p : state.watchers) {
p.first->OnError(GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
} else if (self->type_url_ == kEdsTypeUrl) {
} else if (self->type_url_ == XdsApi::kEdsTypeUrl) {
EndpointState& state =
self->ads_calld_->xds_client()->endpoint_map_[self->name_];
for (const auto& p : state.watchers) {
@ -237,10 +238,10 @@ class XdsClient::ChannelState::AdsCallState
void SendMessageLocked(const std::string& type_url);
void AcceptLdsUpdate(LdsUpdate lds_update);
void AcceptRdsUpdate(RdsUpdate rds_update);
void AcceptCdsUpdate(CdsUpdateMap cds_update_map);
void AcceptEdsUpdate(EdsUpdateMap eds_update_map);
void AcceptLdsUpdate(XdsApi::LdsUpdate lds_update);
void AcceptRdsUpdate(XdsApi::RdsUpdate rds_update);
void AcceptCdsUpdate(XdsApi::CdsUpdateMap cds_update_map);
void AcceptEdsUpdate(XdsApi::EdsUpdateMap eds_update_map);
static void OnRequestSent(void* arg, grpc_error* error);
static void OnRequestSentLocked(void* arg, grpc_error* error);
@ -710,13 +711,13 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
GRPC_CLOSURE_INIT(&on_request_sent_, OnRequestSent, this,
grpc_schedule_on_exec_ctx);
if (xds_client()->service_config_watcher_ != nullptr) {
Subscribe(kLdsTypeUrl, xds_client()->server_name_);
Subscribe(XdsApi::kLdsTypeUrl, xds_client()->server_name_);
}
for (const auto& p : xds_client()->cluster_map_) {
Subscribe(kCdsTypeUrl, std::string(p.first));
Subscribe(XdsApi::kCdsTypeUrl, std::string(p.first));
}
for (const auto& p : xds_client()->endpoint_map_) {
Subscribe(kEdsTypeUrl, std::string(p.first));
Subscribe(XdsApi::kEdsTypeUrl, std::string(p.first));
}
// Op: recv initial metadata.
op = ops;
@ -789,35 +790,31 @@ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
auto& state = state_map_[type_url];
grpc_error* error = state.error;
state.error = GRPC_ERROR_NONE;
const XdsBootstrap::Node* node =
sent_initial_message_ ? nullptr : xds_client()->bootstrap_->node();
const char* build_version =
sent_initial_message_ ? nullptr : xds_client()->build_version_.get();
sent_initial_message_ = true;
grpc_slice request_payload_slice;
if (type_url == kLdsTypeUrl) {
request_payload_slice = XdsLdsRequestCreateAndEncode(
xds_client()->server_name_, node, build_version, state.version,
state.nonce, error);
if (type_url == XdsApi::kLdsTypeUrl) {
request_payload_slice = xds_client()->api_.CreateLdsRequest(
xds_client()->server_name_, state.version, state.nonce, error,
!sent_initial_message_);
state.subscribed_resources[xds_client()->server_name_]->Start(Ref());
} else if (type_url == kRdsTypeUrl) {
request_payload_slice = XdsRdsRequestCreateAndEncode(
xds_client()->route_config_name_, node, build_version, state.version,
state.nonce, error);
} else if (type_url == XdsApi::kRdsTypeUrl) {
request_payload_slice = xds_client()->api_.CreateRdsRequest(
xds_client()->route_config_name_, state.version, state.nonce, error,
!sent_initial_message_);
state.subscribed_resources[xds_client()->route_config_name_]->Start(Ref());
} else if (type_url == kCdsTypeUrl) {
request_payload_slice = XdsCdsRequestCreateAndEncode(
ClusterNamesForRequest(), node, build_version, state.version,
state.nonce, error);
} else if (type_url == kEdsTypeUrl) {
request_payload_slice = XdsEdsRequestCreateAndEncode(
EdsServiceNamesForRequest(), node, build_version, state.version,
state.nonce, error);
} else if (type_url == XdsApi::kCdsTypeUrl) {
request_payload_slice = xds_client()->api_.CreateCdsRequest(
ClusterNamesForRequest(), state.version, state.nonce, error,
!sent_initial_message_);
} else if (type_url == XdsApi::kEdsTypeUrl) {
request_payload_slice = xds_client()->api_.CreateEdsRequest(
EdsServiceNamesForRequest(), state.version, state.nonce, error,
!sent_initial_message_);
} else {
request_payload_slice = XdsUnsupportedTypeNackRequestCreateAndEncode(
request_payload_slice = xds_client()->api_.CreateUnsupportedTypeNackRequest(
type_url, state.nonce, state.error);
state_map_.erase(type_url);
}
sent_initial_message_ = true;
// Create message payload.
send_message_payload_ =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
@ -863,7 +860,7 @@ bool XdsClient::ChannelState::AdsCallState::HasSubscribedResources() const {
}
void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
LdsUpdate lds_update) {
XdsApi::LdsUpdate lds_update) {
const std::string& cluster_name =
lds_update.rds_update.has_value()
? lds_update.rds_update.value().cluster_name
@ -876,7 +873,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
xds_client(), lds_update.route_config_name.c_str(),
cluster_name.c_str());
}
auto& lds_state = state_map_[kLdsTypeUrl];
auto& lds_state = state_map_[XdsApi::kLdsTypeUrl];
auto& state = lds_state.subscribed_resources[xds_client()->server_name_];
if (state != nullptr) state->Finish();
// Ignore identical update.
@ -906,19 +903,19 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
}
} else {
// Send RDS request for dynamic resolution.
Subscribe(kRdsTypeUrl, xds_client()->route_config_name_);
Subscribe(XdsApi::kRdsTypeUrl, xds_client()->route_config_name_);
}
}
void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
RdsUpdate rds_update) {
XdsApi::RdsUpdate rds_update) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
gpr_log(GPR_INFO,
"[xds_client %p] RDS update received: "
"cluster_name=%s",
xds_client(), rds_update.cluster_name.c_str());
}
auto& rds_state = state_map_[kRdsTypeUrl];
auto& rds_state = state_map_[XdsApi::kRdsTypeUrl];
auto& state =
rds_state.subscribed_resources[xds_client()->route_config_name_];
if (state != nullptr) state->Finish();
@ -945,11 +942,11 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
}
void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
CdsUpdateMap cds_update_map) {
auto& cds_state = state_map_[kCdsTypeUrl];
XdsApi::CdsUpdateMap cds_update_map) {
auto& cds_state = state_map_[XdsApi::kCdsTypeUrl];
for (auto& p : cds_update_map) {
const char* cluster_name = p.first.c_str();
CdsUpdate& cds_update = p.second;
XdsApi::CdsUpdate& cds_update = p.second;
auto& state = cds_state.subscribed_resources[cluster_name];
if (state != nullptr) state->Finish();
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@ -987,11 +984,11 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
}
void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
EdsUpdateMap eds_update_map) {
auto& eds_state = state_map_[kEdsTypeUrl];
XdsApi::EdsUpdateMap eds_update_map) {
auto& eds_state = state_map_[XdsApi::kEdsTypeUrl];
for (auto& p : eds_update_map) {
const char* eds_service_name = p.first.c_str();
EdsUpdate& eds_update = p.second;
XdsApi::EdsUpdate& eds_update = p.second;
auto& state = eds_state.subscribed_resources[eds_service_name];
if (state != nullptr) state->Finish();
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
@ -1015,9 +1012,9 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
const auto& locality = p.second;
gpr_log(GPR_INFO,
"[xds_client %p] Priority %" PRIuPTR ", locality %" PRIuPTR
" %s contains %" PRIuPTR " server addresses",
" %s has weight %d, contains %" PRIuPTR " server addresses",
xds_client(), priority, locality_count,
locality.name->AsHumanReadableString(),
locality.name->AsHumanReadableString(), locality.lb_weight,
locality.serverlist.size());
for (size_t i = 0; i < locality.serverlist.size(); ++i) {
char* ipport;
@ -1035,7 +1032,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
}
for (size_t i = 0;
i < eds_update.drop_config->drop_category_list().size(); ++i) {
const XdsDropConfig::DropCategory& drop_category =
const XdsApi::DropConfig::DropCategory& drop_category =
eds_update.drop_config->drop_category_list()[i];
gpr_log(GPR_INFO,
"[xds_client %p] Drop category %s has drop rate %d per million",
@ -1046,7 +1043,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
EndpointState& endpoint_state =
xds_client()->endpoint_map_[eds_service_name];
// Ignore identical update.
const EdsUpdate& prev_update = endpoint_state.update;
const XdsApi::EdsUpdate& prev_update = endpoint_state.update;
const bool priority_list_changed =
prev_update.priority_list_update != eds_update.priority_list_update;
const bool drop_config_changed =
@ -1138,15 +1135,15 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
// mode. We will also need to cancel the timer when we receive a serverlist
// from the balancer.
// Parse the response.
LdsUpdate lds_update;
RdsUpdate rds_update;
CdsUpdateMap cds_update_map;
EdsUpdateMap eds_update_map;
XdsApi::LdsUpdate lds_update;
XdsApi::RdsUpdate rds_update;
XdsApi::CdsUpdateMap cds_update_map;
XdsApi::EdsUpdateMap eds_update_map;
std::string version;
std::string nonce;
std::string type_url;
// Note that XdsAdsResponseDecodeAndParse() also validate the response.
grpc_error* parse_error = XdsAdsResponseDecodeAndParse(
// Note that ParseAdsResponse() also validates the response.
grpc_error* parse_error = xds_client->api_.ParseAdsResponse(
response_slice, xds_client->server_name_, xds_client->route_config_name_,
ads_calld->EdsServiceNamesForRequest(), &lds_update, &rds_update,
&cds_update_map, &eds_update_map, &version, &nonce, &type_url);
@ -1173,13 +1170,13 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
} else {
ads_calld->seen_response_ = true;
// Accept the ADS response according to the type_url.
if (type_url == kLdsTypeUrl) {
if (type_url == XdsApi::kLdsTypeUrl) {
ads_calld->AcceptLdsUpdate(std::move(lds_update));
} else if (type_url == kRdsTypeUrl) {
} else if (type_url == XdsApi::kRdsTypeUrl) {
ads_calld->AcceptRdsUpdate(std::move(rds_update));
} else if (type_url == kCdsTypeUrl) {
} else if (type_url == XdsApi::kCdsTypeUrl) {
ads_calld->AcceptCdsUpdate(std::move(cds_update_map));
} else if (type_url == kEdsTypeUrl) {
} else if (type_url == XdsApi::kEdsTypeUrl) {
ads_calld->AcceptEdsUpdate(std::move(eds_update_map));
}
state.version = std::move(version);
@ -1258,7 +1255,7 @@ bool XdsClient::ChannelState::AdsCallState::IsCurrentCallOnChannel() const {
std::set<StringView>
XdsClient::ChannelState::AdsCallState::ClusterNamesForRequest() {
std::set<StringView> cluster_names;
for (auto& p : state_map_[kCdsTypeUrl].subscribed_resources) {
for (auto& p : state_map_[XdsApi::kCdsTypeUrl].subscribed_resources) {
cluster_names.insert(p.first);
OrphanablePtr<ResourceState>& state = p.second;
state->Start(Ref());
@ -1269,7 +1266,7 @@ XdsClient::ChannelState::AdsCallState::ClusterNamesForRequest() {
std::set<StringView>
XdsClient::ChannelState::AdsCallState::EdsServiceNamesForRequest() {
std::set<StringView> eds_names;
for (auto& p : state_map_[kEdsTypeUrl].subscribed_resources) {
for (auto& p : state_map_[XdsApi::kEdsTypeUrl].subscribed_resources) {
eds_names.insert(p.first);
OrphanablePtr<ResourceState>& state = p.second;
state->Start(Ref());
@ -1320,7 +1317,7 @@ void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
void XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
// Create a request that contains the load report.
grpc_slice request_payload_slice =
XdsLrsRequestCreateAndEncode(xds_client()->ClientStatsMap());
xds_client()->api_.CreateLrsRequest(xds_client()->ClientStatsMap());
// Skip client load report if the counters were all zero in the last
// report and they are still zero in this one.
const bool old_val = last_report_counters_were_zero_;
@ -1396,9 +1393,8 @@ XdsClient::ChannelState::LrsCallState::LrsCallState(
nullptr, GRPC_MILLIS_INF_FUTURE, nullptr);
GPR_ASSERT(call_ != nullptr);
// Init the request payload.
grpc_slice request_payload_slice = XdsLrsRequestCreateAndEncode(
xds_client()->server_name_, xds_client()->bootstrap_->node(),
xds_client()->build_version_.get());
grpc_slice request_payload_slice =
xds_client()->api_.CreateLrsInitialRequest(xds_client()->server_name_);
send_message_payload_ =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_slice_unref_internal(request_payload_slice);
@ -1577,7 +1573,7 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked(
// Parse the response.
std::set<std::string> new_cluster_names;
grpc_millis new_load_reporting_interval;
grpc_error* parse_error = XdsLrsResponseDecodeAndParse(
grpc_error* parse_error = xds_client->api_.ParseLrsResponse(
response_slice, &new_cluster_names, &new_load_reporting_interval);
if (parse_error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR,
@ -1722,6 +1718,8 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
combiner_(GRPC_COMBINER_REF(combiner, "xds_client")),
interested_parties_(interested_parties),
bootstrap_(XdsBootstrap::ReadFromFile(error)),
api_(bootstrap_ == nullptr ? nullptr : bootstrap_->node(),
build_version_.get()),
server_name_(server_name),
service_config_watcher_(std::move(watcher)) {
if (*error != GRPC_ERROR_NONE) {
@ -1744,7 +1742,7 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
chand_ = MakeOrphanable<ChannelState>(
Ref(DEBUG_LOCATION, "XdsClient+ChannelState"), channel);
if (service_config_watcher_ != nullptr) {
chand_->Subscribe(kLdsTypeUrl, std::string(server_name));
chand_->Subscribe(XdsApi::kLdsTypeUrl, std::string(server_name));
}
}
@ -1769,7 +1767,7 @@ void XdsClient::WatchClusterData(
if (cluster_state.update.has_value()) {
w->OnClusterChanged(cluster_state.update.value());
}
chand_->Subscribe(kCdsTypeUrl, cluster_name_str);
chand_->Subscribe(XdsApi::kCdsTypeUrl, cluster_name_str);
}
void XdsClient::CancelClusterDataWatch(StringView cluster_name,
@ -1782,7 +1780,7 @@ void XdsClient::CancelClusterDataWatch(StringView cluster_name,
cluster_state.watchers.erase(it);
if (cluster_state.watchers.empty()) {
cluster_map_.erase(cluster_name_str);
chand_->Unsubscribe(kCdsTypeUrl, cluster_name_str);
chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str);
}
}
}
@ -1799,7 +1797,7 @@ void XdsClient::WatchEndpointData(
if (!endpoint_state.update.priority_list_update.empty()) {
w->OnEndpointChanged(endpoint_state.update);
}
chand_->Subscribe(kEdsTypeUrl, eds_service_name_str);
chand_->Subscribe(XdsApi::kEdsTypeUrl, eds_service_name_str);
}
void XdsClient::CancelEndpointDataWatch(StringView eds_service_name,
@ -1812,7 +1810,7 @@ void XdsClient::CancelEndpointDataWatch(StringView eds_service_name,
endpoint_state.watchers.erase(it);
if (endpoint_state.watchers.empty()) {
endpoint_map_.erase(eds_service_name_str);
chand_->Unsubscribe(kEdsTypeUrl, eds_service_name_str);
chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str);
}
}
}

@ -56,7 +56,7 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
public:
virtual ~ClusterWatcherInterface() = default;
virtual void OnClusterChanged(CdsUpdate cluster_data) = 0;
virtual void OnClusterChanged(XdsApi::CdsUpdate cluster_data) = 0;
virtual void OnError(grpc_error* error) = 0;
};
@ -66,7 +66,7 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
public:
virtual ~EndpointWatcherInterface() = default;
virtual void OnEndpointChanged(EdsUpdate update) = 0;
virtual void OnEndpointChanged(XdsApi::EdsUpdate update) = 0;
virtual void OnError(grpc_error* error) = 0;
};
@ -175,7 +175,7 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
std::map<ClusterWatcherInterface*, std::unique_ptr<ClusterWatcherInterface>>
watchers;
// The latest data seen from CDS.
Optional<CdsUpdate> update;
Optional<XdsApi::CdsUpdate> update;
};
struct EndpointState {
@ -184,7 +184,7 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
watchers;
std::set<XdsClientStats*> client_stats;
// The latest data seen from EDS.
EdsUpdate update;
XdsApi::EdsUpdate update;
};
// Sends an error notification to all watchers.
@ -212,6 +212,7 @@ class XdsClient : public InternallyRefCounted<XdsClient> {
grpc_pollset_set* interested_parties_;
std::unique_ptr<XdsBootstrap> bootstrap_;
XdsApi api_;
const std::string server_name_;

@ -45,43 +45,40 @@ size_t g_message_size_parser_index;
} // namespace
std::unique_ptr<ServiceConfig::ParsedConfig>
MessageSizeParser::ParsePerMethodParams(const grpc_json* json,
grpc_error** error) {
MessageSizeParser::ParsePerMethodParams(const Json& json, grpc_error** error) {
GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
std::vector<grpc_error*> error_list;
// Max request size.
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) {
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) {
auto it = json.object_value().find("maxRequestMessageBytes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING &&
it->second.type() != Json::Type::NUMBER) {
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(it->second.string_value().c_str());
if (max_request_message_bytes == -1) {
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"));
}
"field:maxRequestMessageBytes error:should be non-negative"));
}
} else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
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) {
}
}
// Max response size.
int max_response_message_bytes = -1;
it = json.object_value().find("maxResponseMessageBytes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING &&
it->second.type() != Json::Type::NUMBER) {
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(it->second.string_value().c_str());
if (max_response_message_bytes == -1) {
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"));
}
"field:maxResponseMessageBytes error:should be non-negative"));
}
}
}

@ -47,7 +47,7 @@ class MessageSizeParsedConfig : public ServiceConfig::ParsedConfig {
class MessageSizeParser : public ServiceConfig::Parser {
public:
std::unique_ptr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override;
const Json& json, grpc_error** error) override;
static void Register();

@ -162,6 +162,12 @@ class InlinedVector {
size_--;
}
T& front() { return data()[0]; }
const T& front() const { return data()[0]; }
T& back() { return data()[size_ - 1]; }
const T& back() const { return data()[size_ - 1]; }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }

@ -201,10 +201,10 @@ inline void grpc_error_unref(grpc_error* err) {
// 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>
static grpc_error* grpc_error_create_from_vector(
const char* file, int line, const char* desc,
grpc_core::InlinedVector<grpc_error*, N>* error_list) {
template <typename VectorType>
static grpc_error* grpc_error_create_from_vector(const char* file, int line,
const char* desc,
VectorType* error_list) {
grpc_error* error = GRPC_ERROR_NONE;
if (error_list->size() != 0) {
error = grpc_error_create(file, line, grpc_slice_from_static_string(desc),

@ -1,103 +0,0 @@
/*
*
* 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/logical_thread.h"
namespace grpc_core {
DebugOnlyTraceFlag grpc_logical_thread_trace(false, "logical_thread");
struct CallbackWrapper {
CallbackWrapper(std::function<void()> cb, const grpc_core::DebugLocation& loc)
: callback(std::move(cb)), location(loc) {}
MultiProducerSingleConsumerQueue::Node mpscq_node;
const std::function<void()> callback;
const DebugLocation location;
};
void LogicalThread::Run(std::function<void()> callback,
const grpc_core::DebugLocation& location) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, "LogicalThread::Run() %p Scheduling callback [%s:%d]",
this, location.file(), location.line());
}
const size_t prev_size = size_.FetchAdd(1);
if (prev_size == 0) {
// There is no other closure executing right now on this logical thread.
// Execute this closure immediately.
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, " Executing immediately");
}
callback();
// Loan this thread to the logical thread and drain the queue.
DrainQueue();
} else {
CallbackWrapper* cb_wrapper =
new CallbackWrapper(std::move(callback), location);
// There already are closures executing on this logical thread. Simply add
// this closure to the queue.
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, " Scheduling on queue : item %p", cb_wrapper);
}
queue_.Push(&cb_wrapper->mpscq_node);
}
}
// The thread that calls this loans itself to the logical thread so as to
// execute all the scheduled callback. This is called from within
// LogicalThread::Run() after executing a callback immediately, and hence size_
// is atleast 1.
void LogicalThread::DrainQueue() {
while (true) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, "LogicalThread::DrainQueue() %p", this);
}
size_t prev_size = size_.FetchSub(1);
// prev_size should be atleast 1 since
GPR_DEBUG_ASSERT(prev_size >= 1);
if (prev_size == 1) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, " Queue Drained");
}
break;
}
// There is atleast one callback on the queue. Pop the callback from the
// queue and execute it.
CallbackWrapper* cb_wrapper = nullptr;
bool empty_unused;
while ((cb_wrapper = reinterpret_cast<CallbackWrapper*>(
queue_.PopAndCheckEnd(&empty_unused))) == nullptr) {
// This can happen either due to a race condition within the mpscq
// implementation or because of a race with Run()
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, " Queue returned nullptr, trying again");
}
}
if (GRPC_TRACE_FLAG_ENABLED(grpc_logical_thread_trace)) {
gpr_log(GPR_INFO, " Running item %p : callback scheduled at [%s:%d]",
cb_wrapper, cb_wrapper->location.file(),
cb_wrapper->location.line());
}
cb_wrapper->callback();
delete cb_wrapper;
}
}
} // namespace grpc_core

@ -1,52 +0,0 @@
/*
*
* 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 <functional>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/atomic.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/mpscq.h"
#include "src/core/lib/gprpp/ref_counted.h"
#ifndef GRPC_CORE_LIB_IOMGR_LOGICAL_THREAD_H
#define GRPC_CORE_LIB_IOMGR_LOGICAL_THREAD_H
namespace grpc_core {
extern DebugOnlyTraceFlag grpc_logical_thread_trace;
// LogicalThread is a mechanism to schedule callbacks in a synchronized manner.
// All callbacks scheduled on a LogicalThread instance will be executed serially
// in a borrowed thread. The API provides a FIFO guarantee to the execution of
// callbacks scheduled on the thread.
class LogicalThread : public RefCounted<LogicalThread> {
public:
void Run(std::function<void()> callback,
const grpc_core::DebugLocation& location);
private:
void DrainQueue();
Atomic<size_t> size_{0};
MultiProducerSingleConsumerQueue queue_;
};
} /* namespace grpc_core */
#endif /* GRPC_CORE_LIB_IOMGR_LOGICAL_THREAD_H */

@ -0,0 +1,155 @@
/*
*
* 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/work_serializer.h"
namespace grpc_core {
DebugOnlyTraceFlag grpc_work_serializer_trace(false, "work_serializer");
struct CallbackWrapper {
CallbackWrapper(std::function<void()> cb, const grpc_core::DebugLocation& loc)
: callback(std::move(cb)), location(loc) {}
MultiProducerSingleConsumerQueue::Node mpscq_node;
const std::function<void()> callback;
const DebugLocation location;
};
class WorkSerializer::WorkSerializerImpl : public Orphanable {
public:
void Run(std::function<void()> callback,
const grpc_core::DebugLocation& location);
void Orphan() override;
private:
void DrainQueue();
// An initial size of 1 keeps track of whether the work serializer has been
// orphaned.
Atomic<size_t> size_{1};
MultiProducerSingleConsumerQueue queue_;
};
void WorkSerializer::WorkSerializerImpl::Run(
std::function<void()> callback, const grpc_core::DebugLocation& location) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, "WorkSerializer::Run() %p Scheduling callback [%s:%d]",
this, location.file(), location.line());
}
const size_t prev_size = size_.FetchAdd(1);
// The work serializer should not have been orphaned.
GPR_DEBUG_ASSERT(prev_size > 0);
if (prev_size == 1) {
// There is no other closure executing right now on this work serializer.
// Execute this closure immediately.
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Executing immediately");
}
callback();
// Loan this thread to the work serializer thread and drain the queue.
DrainQueue();
} else {
CallbackWrapper* cb_wrapper =
new CallbackWrapper(std::move(callback), location);
// There already are closures executing on this work serializer. Simply add
// this closure to the queue.
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Scheduling on queue : item %p", cb_wrapper);
}
queue_.Push(&cb_wrapper->mpscq_node);
}
}
void WorkSerializer::WorkSerializerImpl::Orphan() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, "WorkSerializer::Orphan() %p", this);
}
size_t prev_size = size_.FetchSub(1);
if (prev_size == 1) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Destroying");
}
delete this;
}
}
// The thread that calls this loans itself to the work serializer so as to
// execute all the scheduled callback. This is called from within
// WorkSerializer::Run() after executing a callback immediately, and hence size_
// is at least 1.
void WorkSerializer::WorkSerializerImpl::DrainQueue() {
while (true) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, "WorkSerializer::DrainQueue() %p", this);
}
size_t prev_size = size_.FetchSub(1);
GPR_DEBUG_ASSERT(prev_size >= 1);
// It is possible that while draining the queue, one of the callbacks ended
// up orphaning the work serializer. In that case, delete the object.
if (prev_size == 1) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Queue Drained. Destroying");
}
delete this;
return;
}
if (prev_size == 2) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Queue Drained");
}
return;
}
// There is at least one callback on the queue. Pop the callback from the
// queue and execute it.
CallbackWrapper* cb_wrapper = nullptr;
bool empty_unused;
while ((cb_wrapper = reinterpret_cast<CallbackWrapper*>(
queue_.PopAndCheckEnd(&empty_unused))) == nullptr) {
// This can happen either due to a race condition within the mpscq
// implementation or because of a race with Run()
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Queue returned nullptr, trying again");
}
}
if (GRPC_TRACE_FLAG_ENABLED(grpc_work_serializer_trace)) {
gpr_log(GPR_INFO, " Running item %p : callback scheduled at [%s:%d]",
cb_wrapper, cb_wrapper->location.file(),
cb_wrapper->location.line());
}
cb_wrapper->callback();
delete cb_wrapper;
}
}
// WorkSerializer
WorkSerializer::WorkSerializer()
: impl_(MakeOrphanable<WorkSerializerImpl>()) {}
WorkSerializer::~WorkSerializer() {}
void WorkSerializer::Run(std::function<void()> callback,
const grpc_core::DebugLocation& location) {
impl_->Run(std::move(callback), location);
}
} // namespace grpc_core

@ -0,0 +1,65 @@
/*
*
* 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 <functional>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/atomic.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/mpscq.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#ifndef GRPC_CORE_LIB_IOMGR_WORK_SERIALIZER_H
#define GRPC_CORE_LIB_IOMGR_WORK_SERIALIZER_H
namespace grpc_core {
// WorkSerializer is a mechanism to schedule callbacks in a synchronized manner.
// All callbacks scheduled on a WorkSerializer instance will be executed
// serially in a borrowed thread. The API provides a FIFO guarantee to the
// execution of callbacks scheduled on the thread.
// When a thread calls Run() with a callback, the thread is considered borrowed.
// The callback might run inline, or it might run asynchronously in a different
// thread that is already inside of Run(). If the callback runs directly inline,
// other callbacks from other threads might also be executed before Run()
// returns. Since an arbitrary set of callbacks might be executed when Run() is
// called, generally no locks should be held while calling Run().
class WorkSerializer {
public:
WorkSerializer();
~WorkSerializer();
// TODO(yashkt): Replace grpc_core::DebugLocation with absl::SourceLocation
// once we can start using it directly.
void Run(std::function<void()> callback,
const grpc_core::DebugLocation& location);
private:
class WorkSerializerImpl;
OrphanablePtr<WorkSerializerImpl> impl_;
};
} /* namespace grpc_core */
#endif /* GRPC_CORE_LIB_IOMGR_WORK_SERIALIZER_H */

@ -1,94 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <inttypes.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/json/json.h"
grpc_json* grpc_json_create(grpc_json_type type) {
grpc_json* json = static_cast<grpc_json*>(gpr_zalloc(sizeof(*json)));
json->type = type;
return json;
}
void grpc_json_destroy(grpc_json* json) {
if (json == nullptr) return;
while (json->child) {
grpc_json_destroy(json->child);
}
if (json->next) {
json->next->prev = json->prev;
}
if (json->prev) {
json->prev->next = json->next;
} else if (json->parent) {
json->parent->child = json->next;
}
if (json->owns_value) {
gpr_free((void*)json->value);
}
gpr_free(json);
}
grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child,
grpc_json* sibling) {
// link child up to parent
child->parent = parent;
// first child case.
if (parent->child == nullptr) {
GPR_ASSERT(sibling == nullptr);
parent->child = child;
return child;
}
if (sibling == nullptr) {
sibling = parent->child;
}
// always find the right most sibling.
while (sibling->next != nullptr) {
sibling = sibling->next;
}
sibling->next = child;
return child;
}
grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent,
const char* key, const char* value,
grpc_json_type type, bool owns_value) {
grpc_json* child = grpc_json_create(type);
grpc_json_link_child(parent, child, sibling);
child->owns_value = owns_value;
child->value = value;
child->key = key;
return child;
}
grpc_json* grpc_json_add_number_string_child(grpc_json* parent, grpc_json* it,
const char* name, int64_t num) {
char* num_str;
gpr_asprintf(&num_str, "%" PRId64, num);
return grpc_json_create_child(it, parent, name, num_str, GRPC_JSON_STRING,
true);
}

@ -236,86 +236,4 @@ class Json {
} // namespace grpc_core
/* The various json types. */
typedef enum {
GRPC_JSON_OBJECT,
GRPC_JSON_ARRAY,
GRPC_JSON_STRING,
GRPC_JSON_NUMBER,
GRPC_JSON_TRUE,
GRPC_JSON_FALSE,
GRPC_JSON_NULL,
GRPC_JSON_TOP_LEVEL
} grpc_json_type;
/* A tree-like structure to hold json values. The key and value pointers
* are not owned by it.
*/
typedef struct grpc_json {
struct grpc_json* next;
struct grpc_json* prev;
struct grpc_json* child;
struct grpc_json* parent;
grpc_json_type type;
const char* key;
const char* value;
/* if set, destructor will free value */
bool owns_value;
} grpc_json;
/* The next two functions are going to parse the input string, and
* modify it in the process, in order to use its space to store
* all of the keys and values for the returned object tree.
*
* They assume UTF-8 input stream, and will output UTF-8 encoded
* strings in the tree. The input stream's UTF-8 isn't validated,
* as in, what you input is what you get as an output.
*
* All the keys and values in the grpc_json objects will be strings
* pointing at your input buffer.
*
* Delete the allocated tree afterward using grpc_json_destroy().
*/
grpc_json* grpc_json_parse_string_with_len(char* input, size_t size);
grpc_json* grpc_json_parse_string(char* input);
/* This function will create a new string using gpr_realloc, and will
* deserialize the grpc_json tree into it. It'll be zero-terminated,
* but will be allocated in chunks of 256 bytes.
*
* The indent parameter controls the way the output is formatted.
* If indent is 0, then newlines will be suppressed as well, and the
* output will be condensed at its maximum.
*/
char* grpc_json_dump_to_string(const grpc_json* json, int indent);
/* Use these to create or delete a grpc_json object.
* Deletion is recursive. We will not attempt to free any of the strings
* in any of the objects of that tree, unless the boolean, owns_value,
* is true.
*/
grpc_json* grpc_json_create(grpc_json_type type);
void grpc_json_destroy(grpc_json* json);
/* Links the child json object into the parent's json tree. If the parent
* already has children, then passing in the most recently added child as the
* sibling parameter is an optimization. For if sibling is NULL, this function
* will manually traverse the tree in order to find the right most sibling.
*/
grpc_json* grpc_json_link_child(grpc_json* parent, grpc_json* child,
grpc_json* sibling);
/* Creates a child json object into the parent's json tree then links it in
* as described above. */
grpc_json* grpc_json_create_child(grpc_json* sibling, grpc_json* parent,
const char* key, const char* value,
grpc_json_type type, bool owns_value);
/* Creates a child json string object from the integer num, then links the
json object into the parent's json tree */
grpc_json* grpc_json_add_number_string_child(grpc_json* parent, grpc_json* it,
const char* name, int64_t num);
#endif /* GRPC_CORE_LIB_JSON_JSON_H */

@ -21,6 +21,7 @@
#include <string.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/json/json.h"
@ -30,7 +31,7 @@ namespace {
class JsonReader {
public:
static grpc_json* Parse(char* input, size_t size);
static grpc_error* Parse(StringView input, Json* output);
private:
enum class Status {
@ -76,61 +77,50 @@ class JsonReader {
*/
static constexpr uint32_t GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0;
JsonReader(char* input, size_t size)
: input_(reinterpret_cast<uint8_t*>(input)),
remaining_input_(size),
string_ptr_(input_) {
StringClear();
}
explicit JsonReader(StringView input)
: original_input_(reinterpret_cast<const uint8_t*>(input.data())),
input_(original_input_),
remaining_input_(input.size()) {}
Status Run();
uint32_t ReadChar();
bool IsComplete();
size_t CurrentIndex() const { return input_ - original_input_ - 1; }
void StringClear();
void StringAddChar(uint32_t c);
void StringAddUtf32(uint32_t c);
uint32_t ReadChar();
grpc_json* CreateAndLink(grpc_json_type type);
void ContainerBegins(grpc_json_type type);
grpc_json_type ContainerEnds();
Json* CreateAndLinkValue();
void StartContainer(Json::Type type);
void EndContainer();
void SetKey();
void SetString();
bool SetNumber();
void SetTrue();
void SetFalse();
void SetNull();
bool IsComplete();
Status Run();
State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
const uint8_t* original_input_;
const uint8_t* input_;
size_t remaining_input_;
int depth_ = 0;
int in_object_ = 0;
int in_array_ = 0;
int escaped_string_was_key_ = 0;
int container_just_begun_ = 0;
State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
bool escaped_string_was_key_ = false;
bool container_just_begun_ = false;
uint16_t unicode_char_ = 0;
uint16_t unicode_high_surrogate_ = 0;
std::vector<grpc_error*> errors_;
grpc_json* top_ = nullptr;
grpc_json* current_container_ = nullptr;
grpc_json* current_value_ = nullptr;
uint8_t* input_;
size_t remaining_input_;
uint8_t* string_ptr_;
uint8_t* key_ = nullptr;
uint8_t* string_ = nullptr;
};
Json root_value_;
std::vector<Json*> stack_;
void JsonReader::StringClear() {
if (string_ != nullptr) {
GPR_ASSERT(string_ptr_ < input_);
*string_ptr_++ = 0;
}
string_ = string_ptr_;
}
std::string key_;
std::string string_;
};
void JsonReader::StringAddChar(uint32_t c) {
GPR_ASSERT(string_ptr_ < input_);
GPR_ASSERT(c <= 0xff);
*string_ptr_++ = static_cast<uint8_t>(c);
string_.push_back(static_cast<uint8_t>(c));
}
void JsonReader::StringAddUtf32(uint32_t c) {
@ -162,8 +152,8 @@ void JsonReader::StringAddUtf32(uint32_t c) {
uint32_t JsonReader::ReadChar() {
if (remaining_input_ == 0) return GRPC_JSON_READ_CHAR_EOF;
uint32_t r = *input_++;
remaining_input_--;
const uint32_t r = *input_++;
--remaining_input_;
if (r == 0) {
remaining_input_ = 0;
return GRPC_JSON_READ_CHAR_EOF;
@ -171,71 +161,81 @@ uint32_t JsonReader::ReadChar() {
return r;
}
/* Helper function to create a new grpc_json object and link it into
* our tree-in-progress inside our opaque structure.
*/
grpc_json* JsonReader::CreateAndLink(grpc_json_type type) {
grpc_json* json = grpc_json_create(type);
json->parent = current_container_;
json->prev = current_value_;
current_value_ = json;
if (json->prev) {
json->prev->next = json;
}
if (json->parent) {
if (!json->parent->child) {
json->parent->child = json;
Json* JsonReader::CreateAndLinkValue() {
Json* value;
if (stack_.empty()) {
value = &root_value_;
} else {
Json* parent = stack_.back();
if (parent->type() == Json::Type::OBJECT) {
if (parent->object_value().find(key_) != parent->object_value().end()) {
char* msg;
gpr_asprintf(&msg, "duplicate key \"%s\" at index %" PRIuPTR,
key_.c_str(), CurrentIndex());
errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
}
value = &(*parent->mutable_object())[std::move(key_)];
} else {
GPR_ASSERT(parent->type() == Json::Type::ARRAY);
parent->mutable_array()->emplace_back();
value = &parent->mutable_array()->back();
}
if (json->parent->type == GRPC_JSON_OBJECT) {
json->key = reinterpret_cast<char*>(key_);
}
}
if (top_ == nullptr) {
top_ = json;
}
return json;
return value;
}
void JsonReader::ContainerBegins(grpc_json_type type) {
GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
grpc_json* container = CreateAndLink(type);
current_container_ = container;
current_value_ = nullptr;
void JsonReader::StartContainer(Json::Type type) {
Json* value = CreateAndLinkValue();
if (type == Json::Type::OBJECT) {
*value = Json::Object();
} else {
GPR_ASSERT(type == Json::Type::ARRAY);
*value = Json::Array();
}
stack_.push_back(value);
}
grpc_json_type JsonReader::ContainerEnds() {
grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
GPR_ASSERT(current_container_);
current_value_ = current_container_;
current_container_ = current_container_->parent;
if (current_container_ != nullptr) {
container_type = current_container_->type;
}
return container_type;
void JsonReader::EndContainer() {
GPR_ASSERT(!stack_.empty());
stack_.pop_back();
}
void JsonReader::SetKey() { key_ = string_; }
void JsonReader::SetKey() {
key_ = std::move(string_);
string_.clear();
}
void JsonReader::SetString() {
grpc_json* json = CreateAndLink(GRPC_JSON_STRING);
json->value = reinterpret_cast<char*>(string_);
Json* value = CreateAndLinkValue();
*value = std::move(string_);
string_.clear();
}
bool JsonReader::SetNumber() {
grpc_json* json = CreateAndLink(GRPC_JSON_NUMBER);
json->value = reinterpret_cast<char*>(string_);
Json* value = CreateAndLinkValue();
*value = Json(std::move(string_), /*is_number=*/true);
string_.clear();
return true;
}
void JsonReader::SetTrue() { CreateAndLink(GRPC_JSON_TRUE); }
void JsonReader::SetTrue() {
Json* value = CreateAndLinkValue();
*value = true;
string_.clear();
}
void JsonReader::SetFalse() { CreateAndLink(GRPC_JSON_FALSE); }
void JsonReader::SetFalse() {
Json* value = CreateAndLinkValue();
*value = false;
string_.clear();
}
void JsonReader::SetNull() { CreateAndLink(GRPC_JSON_NULL); }
void JsonReader::SetNull() { CreateAndLinkValue(); }
bool JsonReader::IsComplete() {
return (depth_ == 0 && (state_ == State::GRPC_JSON_STATE_END ||
state_ == State::GRPC_JSON_STATE_VALUE_END));
return (stack_.empty() && (state_ == State::GRPC_JSON_STATE_END ||
state_ == State::GRPC_JSON_STATE_VALUE_END));
}
/* Call this function to start parsing the input. It will return the following:
@ -246,7 +246,7 @@ bool JsonReader::IsComplete() {
* internal state.
*/
JsonReader::Status JsonReader::Run() {
uint32_t c, success;
uint32_t c;
/* This state-machine is a strict implementation of ECMA-404 */
while (true) {
@ -277,8 +277,9 @@ JsonReader::Status JsonReader::Run() {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
case State::GRPC_JSON_STATE_VALUE_STRING:
if (c != ' ') return Status::GRPC_JSON_PARSE_ERROR;
if (unicode_high_surrogate_ != 0)
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
StringAddChar(c);
break;
@ -286,9 +287,7 @@ JsonReader::Status JsonReader::Run() {
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
success = static_cast<uint32_t>(SetNumber());
if (!success) return Status::GRPC_JSON_PARSE_ERROR;
StringClear();
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
@ -314,16 +313,16 @@ JsonReader::Status JsonReader::Run() {
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
if (depth_ == 0) {
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
} else if ((c == '}') && !in_object_) {
} else if (c == '}' &&
stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
} else if ((c == ']') && !in_array_) {
return Status::GRPC_JSON_PARSE_ERROR;
} else if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
}
success = static_cast<uint32_t>(SetNumber());
if (!success) return Status::GRPC_JSON_PARSE_ERROR;
StringClear();
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
/* The missing break here is intentional. */
/* fallthrough */
@ -335,48 +334,38 @@ JsonReader::Status JsonReader::Run() {
if (state_ != State::GRPC_JSON_STATE_VALUE_END) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (in_object_) {
if (!stack_.empty() &&
stack_.back()->type() == Json::Type::OBJECT) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
} else if (in_array_) {
} else if (!stack_.empty() &&
stack_.back()->type() == Json::Type::ARRAY) {
state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
} else {
if (depth_-- == 0) return Status::GRPC_JSON_PARSE_ERROR;
if ((c == '}') && !in_object_) {
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '}' && stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if ((c == '}') &&
(state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN) &&
if (c == '}' &&
state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if ((c == ']') && !in_array_)
if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
if ((c == ']') &&
(state_ == State::GRPC_JSON_STATE_VALUE_BEGIN) &&
}
if (c == ']' && state_ == State::GRPC_JSON_STATE_VALUE_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
state_ = State::GRPC_JSON_STATE_VALUE_END;
switch (ContainerEnds()) {
case GRPC_JSON_OBJECT:
in_object_ = 1;
in_array_ = 0;
break;
case GRPC_JSON_ARRAY:
in_object_ = 0;
in_array_ = 1;
break;
case GRPC_JSON_TOP_LEVEL:
GPR_ASSERT(depth_ == 0);
in_object_ = 0;
in_array_ = 0;
state_ = State::GRPC_JSON_STATE_END;
break;
default:
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
EndContainer();
if (stack_.empty()) {
state_ = State::GRPC_JSON_STATE_END;
}
}
break;
@ -390,12 +379,12 @@ JsonReader::Status JsonReader::Run() {
case '\\':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
escaped_string_was_key_ = 1;
escaped_string_was_key_ = true;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
case State::GRPC_JSON_STATE_VALUE_STRING:
escaped_string_was_key_ = 0;
escaped_string_was_key_ = false;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
@ -417,7 +406,7 @@ JsonReader::Status JsonReader::Run() {
break;
default:
container_just_begun_ = 0;
container_just_begun_ = false;
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
if (c != '"') return Status::GRPC_JSON_PARSE_ERROR;
@ -431,7 +420,6 @@ JsonReader::Status JsonReader::Run() {
if (c == '"') {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_END;
SetKey();
StringClear();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
@ -445,7 +433,6 @@ JsonReader::Status JsonReader::Run() {
if (c == '"') {
state_ = State::GRPC_JSON_STATE_VALUE_END;
SetString();
StringClear();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
@ -495,20 +482,14 @@ JsonReader::Status JsonReader::Run() {
break;
case '{':
container_just_begun_ = 1;
ContainerBegins(GRPC_JSON_OBJECT);
depth_++;
container_just_begun_ = true;
StartContainer(Json::Type::OBJECT);
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
in_object_ = 1;
in_array_ = 0;
break;
case '[':
container_just_begun_ = 1;
ContainerBegins(GRPC_JSON_ARRAY);
depth_++;
in_object_ = 0;
in_array_ = 1;
container_just_begun_ = true;
StartContainer(Json::Type::ARRAY);
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
@ -809,29 +790,36 @@ JsonReader::Status JsonReader::Run() {
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
}
grpc_json* JsonReader::Parse(char* input, size_t size) {
JsonReader reader(input, size);
grpc_error* JsonReader::Parse(StringView input, Json* output) {
JsonReader reader(input);
Status status = reader.Run();
grpc_json* json = reader.top_;
if ((status != Status::GRPC_JSON_DONE) && json != nullptr) {
grpc_json_destroy(json);
json = nullptr;
if (status == Status::GRPC_JSON_INTERNAL_ERROR) {
char* msg;
gpr_asprintf(&msg, "internal error in JSON parser at index %" PRIuPTR,
reader.CurrentIndex());
reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
} else if (status == Status::GRPC_JSON_PARSE_ERROR) {
char* msg;
gpr_asprintf(&msg, "JSON parse error at index %" PRIuPTR,
reader.CurrentIndex());
reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg));
gpr_free(msg);
}
if (!reader.errors_.empty()) {
return GRPC_ERROR_CREATE_FROM_VECTOR("JSON parsing failed",
&reader.errors_);
}
return json;
*output = std::move(reader.root_value_);
return GRPC_ERROR_NONE;
}
} // namespace
} // namespace grpc_core
/* And finally, let's define our public API. */
grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
if (input == nullptr) return nullptr;
return grpc_core::JsonReader::Parse(input, size);
Json Json::Parse(StringView json_str, grpc_error** error) {
Json value;
*error = JsonReader::Parse(json_str, &value);
return value;
}
#define UNBOUND_JSON_STRING_LENGTH 0x7fffffff
grpc_json* grpc_json_parse_string(char* input) {
return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
}
} // namespace grpc_core

@ -1,808 +0,0 @@
/*
*
* Copyright 2015-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 <string.h>
#include <grpc/support/log.h>
#include "src/core/lib/json/json.h"
namespace grpc_core {
namespace {
class JsonReader {
public:
enum class Status {
GRPC_JSON_DONE, /* The parser finished successfully. */
GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */
GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
};
static Status Parse(StringView input, Json* output);
private:
enum class State {
GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
GRPC_JSON_STATE_OBJECT_KEY_STRING,
GRPC_JSON_STATE_OBJECT_KEY_END,
GRPC_JSON_STATE_VALUE_BEGIN,
GRPC_JSON_STATE_VALUE_STRING,
GRPC_JSON_STATE_STRING_ESCAPE,
GRPC_JSON_STATE_STRING_ESCAPE_U1,
GRPC_JSON_STATE_STRING_ESCAPE_U2,
GRPC_JSON_STATE_STRING_ESCAPE_U3,
GRPC_JSON_STATE_STRING_ESCAPE_U4,
GRPC_JSON_STATE_VALUE_NUMBER,
GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL,
GRPC_JSON_STATE_VALUE_NUMBER_ZERO,
GRPC_JSON_STATE_VALUE_NUMBER_DOT,
GRPC_JSON_STATE_VALUE_NUMBER_E,
GRPC_JSON_STATE_VALUE_NUMBER_EPM,
GRPC_JSON_STATE_VALUE_TRUE_R,
GRPC_JSON_STATE_VALUE_TRUE_U,
GRPC_JSON_STATE_VALUE_TRUE_E,
GRPC_JSON_STATE_VALUE_FALSE_A,
GRPC_JSON_STATE_VALUE_FALSE_L,
GRPC_JSON_STATE_VALUE_FALSE_S,
GRPC_JSON_STATE_VALUE_FALSE_E,
GRPC_JSON_STATE_VALUE_NULL_U,
GRPC_JSON_STATE_VALUE_NULL_L1,
GRPC_JSON_STATE_VALUE_NULL_L2,
GRPC_JSON_STATE_VALUE_END,
GRPC_JSON_STATE_END
};
/* The first non-unicode value is 0x110000. But let's pick
* a value high enough to start our error codes from. These
* values are safe to return from the read_char function.
*/
static constexpr uint32_t GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0;
explicit JsonReader(StringView input)
: input_(reinterpret_cast<const uint8_t*>(input.data())),
remaining_input_(input.size()) {}
Status Run();
uint32_t ReadChar();
bool IsComplete();
void StringAddChar(uint32_t c);
void StringAddUtf32(uint32_t c);
Json* CreateAndLinkValue();
void StartContainer(Json::Type type);
void EndContainer();
void SetKey();
void SetString();
bool SetNumber();
void SetTrue();
void SetFalse();
void SetNull();
const uint8_t* input_;
size_t remaining_input_;
State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
bool escaped_string_was_key_ = false;
bool container_just_begun_ = false;
uint16_t unicode_char_ = 0;
uint16_t unicode_high_surrogate_ = 0;
bool duplicate_key_found_ = false;
Json root_value_;
std::vector<Json*> stack_;
std::string key_;
std::string string_;
};
void JsonReader::StringAddChar(uint32_t c) {
string_.push_back(static_cast<uint8_t>(c));
}
void JsonReader::StringAddUtf32(uint32_t c) {
if (c <= 0x7f) {
StringAddChar(c);
} else if (c <= 0x7ff) {
uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f);
uint32_t b2 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
} else if (c <= 0xffff) {
uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f);
uint32_t b2 = 0x80 | ((c >> 6) & 0x3f);
uint32_t b3 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
StringAddChar(b3);
} else if (c <= 0x1fffff) {
uint32_t b1 = 0xf0 | ((c >> 18) & 0x07);
uint32_t b2 = 0x80 | ((c >> 12) & 0x3f);
uint32_t b3 = 0x80 | ((c >> 6) & 0x3f);
uint32_t b4 = 0x80 | (c & 0x3f);
StringAddChar(b1);
StringAddChar(b2);
StringAddChar(b3);
StringAddChar(b4);
}
}
uint32_t JsonReader::ReadChar() {
if (remaining_input_ == 0) return GRPC_JSON_READ_CHAR_EOF;
const uint32_t r = *input_++;
--remaining_input_;
if (r == 0) {
remaining_input_ = 0;
return GRPC_JSON_READ_CHAR_EOF;
}
return r;
}
Json* JsonReader::CreateAndLinkValue() {
Json* value;
if (stack_.empty()) {
value = &root_value_;
} else {
Json* parent = stack_.back();
if (parent->type() == Json::Type::OBJECT) {
if (parent->object_value().find(key_) != parent->object_value().end()) {
duplicate_key_found_ = true;
}
value = &(*parent->mutable_object())[std::move(key_)];
} else {
GPR_ASSERT(parent->type() == Json::Type::ARRAY);
parent->mutable_array()->emplace_back();
value = &parent->mutable_array()->back();
}
}
return value;
}
void JsonReader::StartContainer(Json::Type type) {
Json* value = CreateAndLinkValue();
if (type == Json::Type::OBJECT) {
*value = Json::Object();
} else {
GPR_ASSERT(type == Json::Type::ARRAY);
*value = Json::Array();
}
stack_.push_back(value);
}
void JsonReader::EndContainer() {
GPR_ASSERT(!stack_.empty());
stack_.pop_back();
}
void JsonReader::SetKey() {
key_ = std::move(string_);
string_.clear();
}
void JsonReader::SetString() {
Json* value = CreateAndLinkValue();
*value = std::move(string_);
string_.clear();
}
bool JsonReader::SetNumber() {
Json* value = CreateAndLinkValue();
*value = Json(std::move(string_), /*is_number=*/true);
string_.clear();
return true;
}
void JsonReader::SetTrue() {
Json* value = CreateAndLinkValue();
*value = true;
string_.clear();
}
void JsonReader::SetFalse() {
Json* value = CreateAndLinkValue();
*value = false;
string_.clear();
}
void JsonReader::SetNull() { CreateAndLinkValue(); }
bool JsonReader::IsComplete() {
return (stack_.empty() && (state_ == State::GRPC_JSON_STATE_END ||
state_ == State::GRPC_JSON_STATE_VALUE_END));
}
/* Call this function to start parsing the input. It will return the following:
* . GRPC_JSON_DONE if the input got eof, and the parsing finished
* successfully.
* . GRPC_JSON_PARSE_ERROR if the input was somehow invalid.
* . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
* internal state.
*/
JsonReader::Status JsonReader::Run() {
uint32_t c;
/* This state-machine is a strict implementation of ECMA-404 */
while (true) {
c = ReadChar();
switch (c) {
/* Let's process the error case first. */
case GRPC_JSON_READ_CHAR_EOF:
if (IsComplete()) {
return Status::GRPC_JSON_DONE;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* Processing whitespaces. */
case ' ':
case '\t':
case '\n':
case '\r':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
case State::GRPC_JSON_STATE_OBJECT_KEY_END:
case State::GRPC_JSON_STATE_VALUE_BEGIN:
case State::GRPC_JSON_STATE_VALUE_END:
case State::GRPC_JSON_STATE_END:
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
case State::GRPC_JSON_STATE_VALUE_STRING:
if (c != ' ') return Status::GRPC_JSON_PARSE_ERROR;
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
StringAddChar(c);
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* Value, object or array terminations. */
case ',':
case '}':
case ']':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
case State::GRPC_JSON_STATE_VALUE_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
StringAddChar(c);
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
} else if (c == '}' &&
stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
return Status::GRPC_JSON_PARSE_ERROR;
} else if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_END;
/* The missing break here is intentional. */
/* fallthrough */
case State::GRPC_JSON_STATE_VALUE_END:
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
case State::GRPC_JSON_STATE_VALUE_BEGIN:
if (c == ',') {
if (state_ != State::GRPC_JSON_STATE_VALUE_END) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (!stack_.empty() &&
stack_.back()->type() == Json::Type::OBJECT) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
} else if (!stack_.empty() &&
stack_.back()->type() == Json::Type::ARRAY) {
state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
} else {
if (stack_.empty()) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '}' && stack_.back()->type() != Json::Type::OBJECT) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '}' &&
state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == ']' && state_ == State::GRPC_JSON_STATE_VALUE_BEGIN &&
!container_just_begun_) {
return Status::GRPC_JSON_PARSE_ERROR;
}
state_ = State::GRPC_JSON_STATE_VALUE_END;
EndContainer();
if (stack_.empty()) {
state_ = State::GRPC_JSON_STATE_END;
}
}
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
/* In-string escaping. */
case '\\':
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
escaped_string_was_key_ = true;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
case State::GRPC_JSON_STATE_VALUE_STRING:
escaped_string_was_key_ = false;
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE;
break;
/* This is the \\ case. */
case State::GRPC_JSON_STATE_STRING_ESCAPE:
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar('\\');
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
default:
container_just_begun_ = false;
switch (state_) {
case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN:
if (c != '"') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '"') {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_END;
SetKey();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
}
break;
case State::GRPC_JSON_STATE_VALUE_STRING:
if (unicode_high_surrogate_ != 0) {
return Status::GRPC_JSON_PARSE_ERROR;
}
if (c == '"') {
state_ = State::GRPC_JSON_STATE_VALUE_END;
SetString();
} else {
if (c < 32) return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
}
break;
case State::GRPC_JSON_STATE_OBJECT_KEY_END:
if (c != ':') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_BEGIN;
break;
case State::GRPC_JSON_STATE_VALUE_BEGIN:
switch (c) {
case 't':
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_R;
break;
case 'f':
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_A;
break;
case 'n':
state_ = State::GRPC_JSON_STATE_VALUE_NULL_U;
break;
case '"':
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
break;
case '0':
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER;
break;
case '{':
container_just_begun_ = true;
StartContainer(Json::Type::OBJECT);
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
break;
case '[':
container_just_begun_ = true;
StartContainer(Json::Type::ARRAY);
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE:
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
if (unicode_high_surrogate_ && c != 'u') {
return Status::GRPC_JSON_PARSE_ERROR;
}
switch (c) {
case '"':
case '/':
StringAddChar(c);
break;
case 'b':
StringAddChar('\b');
break;
case 'f':
StringAddChar('\f');
break;
case 'n':
StringAddChar('\n');
break;
case 'r':
StringAddChar('\r');
break;
case 't':
StringAddChar('\t');
break;
case 'u':
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U1;
unicode_char_ = 0;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U1:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U2:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U3:
case State::GRPC_JSON_STATE_STRING_ESCAPE_U4:
if ((c >= '0') && (c <= '9')) {
c -= '0';
} else if ((c >= 'A') && (c <= 'F')) {
c -= 'A' - 10;
} else if ((c >= 'a') && (c <= 'f')) {
c -= 'a' - 10;
} else {
return Status::GRPC_JSON_PARSE_ERROR;
}
unicode_char_ = static_cast<uint16_t>(unicode_char_ << 4);
unicode_char_ = static_cast<uint16_t>(unicode_char_ | c);
switch (state_) {
case State::GRPC_JSON_STATE_STRING_ESCAPE_U1:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U2;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U2:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U3;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U3:
state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U4;
break;
case State::GRPC_JSON_STATE_STRING_ESCAPE_U4:
/* See grpc_json_writer_escape_string to have a description
* of what's going on here.
*/
if ((unicode_char_ & 0xfc00) == 0xd800) {
/* high surrogate utf-16 */
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
unicode_high_surrogate_ = unicode_char_;
} else if ((unicode_char_ & 0xfc00) == 0xdc00) {
/* low surrogate utf-16 */
uint32_t utf32;
if (unicode_high_surrogate_ == 0)
return Status::GRPC_JSON_PARSE_ERROR;
utf32 = 0x10000;
utf32 += static_cast<uint32_t>(
(unicode_high_surrogate_ - 0xd800) * 0x400);
utf32 += static_cast<uint32_t>(unicode_char_ - 0xdc00);
StringAddUtf32(utf32);
unicode_high_surrogate_ = 0;
} else {
/* anything else */
if (unicode_high_surrogate_ != 0)
return Status::GRPC_JSON_PARSE_ERROR;
StringAddUtf32(unicode_char_);
}
if (escaped_string_was_key_) {
state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING;
} else {
state_ = State::GRPC_JSON_STATE_VALUE_STRING;
}
break;
default:
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case 'e':
case 'E':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E;
break;
case '.':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
case 'e':
case 'E':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
if (c != '.') return Status::GRPC_JSON_PARSE_ERROR;
StringAddChar(c);
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT;
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_DOT:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_E:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
case '-':
state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_EPM;
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM:
StringAddChar(c);
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_R:
if (c != 'r') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_U;
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_U:
if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_TRUE_E;
break;
case State::GRPC_JSON_STATE_VALUE_TRUE_E:
if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR;
SetTrue();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_A:
if (c != 'a') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_L;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_L:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_S;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_S:
if (c != 's') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_FALSE_E;
break;
case State::GRPC_JSON_STATE_VALUE_FALSE_E:
if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR;
SetFalse();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_U:
if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_NULL_L1;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_L1:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
state_ = State::GRPC_JSON_STATE_VALUE_NULL_L2;
break;
case State::GRPC_JSON_STATE_VALUE_NULL_L2:
if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR;
SetNull();
state_ = State::GRPC_JSON_STATE_VALUE_END;
break;
/* All of the VALUE_END cases are handled in the specialized case
* above. */
case State::GRPC_JSON_STATE_VALUE_END:
switch (c) {
case ',':
case '}':
case ']':
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
break;
default:
return Status::GRPC_JSON_PARSE_ERROR;
}
break;
case State::GRPC_JSON_STATE_END:
return Status::GRPC_JSON_PARSE_ERROR;
}
}
}
GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR);
}
JsonReader::Status JsonReader::Parse(StringView input, Json* output) {
JsonReader reader(input);
Status status = reader.Run();
if (reader.duplicate_key_found_) status = Status::GRPC_JSON_PARSE_ERROR;
if (status == Status::GRPC_JSON_DONE) {
*output = std::move(reader.root_value_);
}
return status;
}
} // namespace
Json Json::Parse(StringView json_str, grpc_error** error) {
Json value;
JsonReader::Status status = JsonReader::Parse(json_str, &value);
if (status == JsonReader::Status::GRPC_JSON_PARSE_ERROR) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON parse error");
} else if (status == JsonReader::Status::GRPC_JSON_INTERNAL_ERROR) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("internal error in JSON parser");
}
return value;
}
} // namespace grpc_core

@ -26,6 +26,8 @@
#include "src/core/lib/json/json.h"
#include "src/core/lib/gprpp/string_view.h"
namespace grpc_core {
namespace {
@ -43,35 +45,33 @@ namespace {
*/
class JsonWriter {
public:
static char* Dump(const grpc_json* json, int indent);
static std::string Dump(const Json& value, int indent);
private:
explicit JsonWriter(int indent) : indent_(indent) {}
void OutputCheck(size_t needed);
void OutputChar(char c);
void OutputStringWithLen(const char* str, size_t len);
void OutputString(const char* str);
void OutputString(const StringView str);
void OutputIndent();
void ValueEnd();
void EscapeUtf16(uint16_t utf16);
void EscapeString(const char* string);
void ContainerBegins(grpc_json_type type);
void ContainerEnds(grpc_json_type type);
void ObjectKey(const char* string);
void ValueRaw(const char* string);
void ValueRawWithLen(const char* string, size_t len);
void ValueString(const char* string);
void DumpRecursive(const grpc_json* json, int in_object);
void EscapeString(const std::string& string);
void ContainerBegins(Json::Type type);
void ContainerEnds(Json::Type type);
void ObjectKey(const std::string& string);
void ValueRaw(const std::string& string);
void ValueString(const std::string& string);
void DumpObject(const Json::Object& object);
void DumpArray(const Json::Array& array);
void DumpValue(const Json& value);
int indent_;
int depth_ = 0;
int container_empty_ = 1;
int got_key_ = 0;
char* output_ = nullptr;
size_t free_space_ = 0;
size_t string_len_ = 0;
size_t allocated_ = 0;
bool container_empty_ = true;
bool got_key_ = false;
std::string output_;
};
/* This function checks if there's enough space left in the output buffer,
@ -79,31 +79,22 @@ class JsonWriter {
* bytes at a time (or multiples thereof).
*/
void JsonWriter::OutputCheck(size_t needed) {
if (free_space_ >= needed) return;
needed -= free_space_;
size_t free_space = output_.capacity() - output_.size();
if (free_space >= needed) return;
needed -= free_space;
/* Round up by 256 bytes. */
needed = (needed + 0xff) & ~0xffU;
output_ = static_cast<char*>(gpr_realloc(output_, allocated_ + needed));
free_space_ += needed;
allocated_ += needed;
output_.reserve(output_.capacity() + needed);
}
void JsonWriter::OutputChar(char c) {
OutputCheck(1);
output_[string_len_++] = c;
free_space_--;
output_.push_back(c);
}
void JsonWriter::OutputStringWithLen(const char* str, size_t len) {
OutputCheck(len);
memcpy(output_ + string_len_, str, len);
string_len_ += len;
free_space_ -= len;
}
void JsonWriter::OutputString(const char* str) {
size_t len = strlen(str);
OutputStringWithLen(str, len);
void JsonWriter::OutputString(const StringView str) {
OutputCheck(str.size());
output_.append(str.data(), str.size());
}
void JsonWriter::OutputIndent() {
@ -119,16 +110,16 @@ void JsonWriter::OutputIndent() {
return;
}
while (spaces >= (sizeof(spacesstr) - 1)) {
OutputStringWithLen(spacesstr, sizeof(spacesstr) - 1);
OutputString(StringView(spacesstr, sizeof(spacesstr) - 1));
spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
}
if (spaces == 0) return;
OutputStringWithLen(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
OutputString(StringView(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces));
}
void JsonWriter::ValueEnd() {
if (container_empty_) {
container_empty_ = 0;
container_empty_ = false;
if (indent_ == 0 || depth_ == 0) return;
OutputChar('\n');
} else {
@ -140,17 +131,17 @@ void JsonWriter::ValueEnd() {
void JsonWriter::EscapeUtf16(uint16_t utf16) {
static const char hex[] = "0123456789abcdef";
OutputStringWithLen("\\u", 2);
OutputString(StringView("\\u", 2));
OutputChar(hex[(utf16 >> 12) & 0x0f]);
OutputChar(hex[(utf16 >> 8) & 0x0f]);
OutputChar(hex[(utf16 >> 4) & 0x0f]);
OutputChar(hex[(utf16)&0x0f]);
}
void JsonWriter::EscapeString(const char* string) {
void JsonWriter::EscapeString(const std::string& string) {
OutputChar('"');
while (true) {
uint8_t c = static_cast<uint8_t>(*string++);
for (size_t idx = 0; idx < string.size(); ++idx) {
uint8_t c = static_cast<uint8_t>(string[idx]);
if (c == 0) {
break;
} else if (c >= 32 && c <= 126) {
@ -159,19 +150,19 @@ void JsonWriter::EscapeString(const char* string) {
} else if (c < 32 || c == 127) {
switch (c) {
case '\b':
OutputStringWithLen("\\b", 2);
OutputString(StringView("\\b", 2));
break;
case '\f':
OutputStringWithLen("\\f", 2);
OutputString(StringView("\\f", 2));
break;
case '\n':
OutputStringWithLen("\\n", 2);
OutputString(StringView("\\n", 2));
break;
case '\r':
OutputStringWithLen("\\r", 2);
OutputString(StringView("\\r", 2));
break;
case '\t':
OutputStringWithLen("\\t", 2);
OutputString(StringView("\\t", 2));
break;
default:
EscapeUtf16(c);
@ -196,7 +187,13 @@ void JsonWriter::EscapeString(const char* string) {
}
for (i = 0; i < extra; i++) {
utf32 <<= 6;
c = static_cast<uint8_t>(*string++);
++idx;
/* Breaks out and bail if we hit the end of the string. */
if (idx == string.size()) {
valid = 0;
break;
}
c = static_cast<uint8_t>(string[idx]);
/* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
if ((c & 0xc0) != 0x80) {
valid = 0;
@ -239,98 +236,101 @@ void JsonWriter::EscapeString(const char* string) {
OutputChar('"');
}
void JsonWriter::ContainerBegins(grpc_json_type type) {
void JsonWriter::ContainerBegins(Json::Type type) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputChar(type == GRPC_JSON_OBJECT ? '{' : '[');
container_empty_ = 1;
got_key_ = 0;
OutputChar(type == Json::Type::OBJECT ? '{' : '[');
container_empty_ = true;
got_key_ = false;
depth_++;
}
void JsonWriter::ContainerEnds(grpc_json_type type) {
void JsonWriter::ContainerEnds(Json::Type type) {
if (indent_ && !container_empty_) OutputChar('\n');
depth_--;
if (!container_empty_) OutputIndent();
OutputChar(type == GRPC_JSON_OBJECT ? '}' : ']');
container_empty_ = 0;
got_key_ = 0;
OutputChar(type == Json::Type::OBJECT ? '}' : ']');
container_empty_ = false;
got_key_ = false;
}
void JsonWriter::ObjectKey(const char* string) {
void JsonWriter::ObjectKey(const std::string& string) {
ValueEnd();
OutputIndent();
EscapeString(string);
OutputChar(':');
got_key_ = 1;
got_key_ = true;
}
void JsonWriter::ValueRaw(const char* string) {
void JsonWriter::ValueRaw(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputString(string);
got_key_ = 0;
got_key_ = false;
}
void JsonWriter::ValueRawWithLen(const char* string, size_t len) {
void JsonWriter::ValueString(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputStringWithLen(string, len);
got_key_ = 0;
EscapeString(string);
got_key_ = false;
}
void JsonWriter::ValueString(const char* string) {
if (!got_key_) ValueEnd();
OutputIndent();
EscapeString(string);
got_key_ = 0;
void JsonWriter::DumpObject(const Json::Object& object) {
ContainerBegins(Json::Type::OBJECT);
for (const auto& p : object) {
ObjectKey(p.first.data());
DumpValue(p.second);
}
ContainerEnds(Json::Type::OBJECT);
}
void JsonWriter::DumpRecursive(const grpc_json* json, int in_object) {
while (json != nullptr) {
if (in_object) ObjectKey(json->key);
switch (json->type) {
case GRPC_JSON_OBJECT:
case GRPC_JSON_ARRAY:
ContainerBegins(json->type);
if (json->child != nullptr) {
DumpRecursive(json->child, json->type == GRPC_JSON_OBJECT);
}
ContainerEnds(json->type);
break;
case GRPC_JSON_STRING:
ValueString(json->value);
break;
case GRPC_JSON_NUMBER:
ValueRaw(json->value);
break;
case GRPC_JSON_TRUE:
ValueRawWithLen("true", 4);
break;
case GRPC_JSON_FALSE:
ValueRawWithLen("false", 5);
break;
case GRPC_JSON_NULL:
ValueRawWithLen("null", 4);
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
json = json->next;
void JsonWriter::DumpArray(const Json::Array& array) {
ContainerBegins(Json::Type::ARRAY);
for (const auto& v : array) {
DumpValue(v);
}
ContainerEnds(Json::Type::ARRAY);
}
char* JsonWriter::Dump(const grpc_json* json, int indent) {
void JsonWriter::DumpValue(const Json& value) {
switch (value.type()) {
case Json::Type::OBJECT:
DumpObject(value.object_value());
break;
case Json::Type::ARRAY:
DumpArray(value.array_value());
break;
case Json::Type::STRING:
ValueString(value.string_value());
break;
case Json::Type::NUMBER:
ValueRaw(value.string_value());
break;
case Json::Type::JSON_TRUE:
ValueRaw(std::string("true", 4));
break;
case Json::Type::JSON_FALSE:
ValueRaw(std::string("false", 5));
break;
case Json::Type::JSON_NULL:
ValueRaw(std::string("null", 4));
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
}
std::string JsonWriter::Dump(const Json& value, int indent) {
JsonWriter writer(indent);
writer.DumpRecursive(json, 0);
writer.OutputChar(0);
return writer.output_;
writer.DumpValue(value);
return std::move(writer.output_);
}
} // namespace
} // namespace grpc_core
char* grpc_json_dump_to_string(const grpc_json* json, int indent) {
return grpc_core::JsonWriter::Dump(json, indent);
std::string Json::Dump(int indent) const {
return JsonWriter::Dump(*this, indent);
}
} // namespace grpc_core

@ -1,336 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/json/json.h"
#include "src/core/lib/gprpp/string_view.h"
namespace grpc_core {
namespace {
/* The idea of the writer is basically symmetrical of the reader. While the
* reader emits various calls to your code, the writer takes basically the
* same calls and emit json out of it. It doesn't try to make any check on
* the order of the calls you do on it. Meaning you can theorically force
* it to generate invalid json.
*
* Also, unlike the reader, the writer expects UTF-8 encoded input strings.
* These strings will be UTF-8 validated, and any invalid character will
* cut the conversion short, before any invalid UTF-8 sequence, thus forming
* a valid UTF-8 string overall.
*/
class JsonWriter {
public:
static std::string Dump(const Json& value, int indent);
private:
explicit JsonWriter(int indent) : indent_(indent) {}
void OutputCheck(size_t needed);
void OutputChar(char c);
void OutputString(const StringView str);
void OutputIndent();
void ValueEnd();
void EscapeUtf16(uint16_t utf16);
void EscapeString(const std::string& string);
void ContainerBegins(Json::Type type);
void ContainerEnds(Json::Type type);
void ObjectKey(const std::string& string);
void ValueRaw(const std::string& string);
void ValueString(const std::string& string);
void DumpObject(const Json::Object& object);
void DumpArray(const Json::Array& array);
void DumpValue(const Json& value);
int indent_;
int depth_ = 0;
bool container_empty_ = true;
bool got_key_ = false;
std::string output_;
};
/* This function checks if there's enough space left in the output buffer,
* and will enlarge it if necessary. We're only allocating chunks of 256
* bytes at a time (or multiples thereof).
*/
void JsonWriter::OutputCheck(size_t needed) {
size_t free_space = output_.capacity() - output_.size();
if (free_space >= needed) return;
needed -= free_space;
/* Round up by 256 bytes. */
needed = (needed + 0xff) & ~0xffU;
output_.reserve(output_.capacity() + needed);
}
void JsonWriter::OutputChar(char c) {
OutputCheck(1);
output_.push_back(c);
}
void JsonWriter::OutputString(const StringView str) {
OutputCheck(str.size());
output_.append(str.data(), str.size());
}
void JsonWriter::OutputIndent() {
static const char spacesstr[] =
" "
" "
" "
" ";
unsigned spaces = static_cast<unsigned>(depth_ * indent_);
if (indent_ == 0) return;
if (got_key_) {
OutputChar(' ');
return;
}
while (spaces >= (sizeof(spacesstr) - 1)) {
OutputString(StringView(spacesstr, sizeof(spacesstr) - 1));
spaces -= static_cast<unsigned>(sizeof(spacesstr) - 1);
}
if (spaces == 0) return;
OutputString(StringView(spacesstr + sizeof(spacesstr) - 1 - spaces, spaces));
}
void JsonWriter::ValueEnd() {
if (container_empty_) {
container_empty_ = false;
if (indent_ == 0 || depth_ == 0) return;
OutputChar('\n');
} else {
OutputChar(',');
if (indent_ == 0) return;
OutputChar('\n');
}
}
void JsonWriter::EscapeUtf16(uint16_t utf16) {
static const char hex[] = "0123456789abcdef";
OutputString(StringView("\\u", 2));
OutputChar(hex[(utf16 >> 12) & 0x0f]);
OutputChar(hex[(utf16 >> 8) & 0x0f]);
OutputChar(hex[(utf16 >> 4) & 0x0f]);
OutputChar(hex[(utf16)&0x0f]);
}
void JsonWriter::EscapeString(const std::string& string) {
OutputChar('"');
for (size_t idx = 0; idx < string.size(); ++idx) {
uint8_t c = static_cast<uint8_t>(string[idx]);
if (c == 0) {
break;
} else if (c >= 32 && c <= 126) {
if (c == '\\' || c == '"') OutputChar('\\');
OutputChar(static_cast<char>(c));
} else if (c < 32 || c == 127) {
switch (c) {
case '\b':
OutputString(StringView("\\b", 2));
break;
case '\f':
OutputString(StringView("\\f", 2));
break;
case '\n':
OutputString(StringView("\\n", 2));
break;
case '\r':
OutputString(StringView("\\r", 2));
break;
case '\t':
OutputString(StringView("\\t", 2));
break;
default:
EscapeUtf16(c);
break;
}
} else {
uint32_t utf32 = 0;
int extra = 0;
int i;
int valid = 1;
if ((c & 0xe0) == 0xc0) {
utf32 = c & 0x1f;
extra = 1;
} else if ((c & 0xf0) == 0xe0) {
utf32 = c & 0x0f;
extra = 2;
} else if ((c & 0xf8) == 0xf0) {
utf32 = c & 0x07;
extra = 3;
} else {
break;
}
for (i = 0; i < extra; i++) {
utf32 <<= 6;
++idx;
/* Breaks out and bail if we hit the end of the string. */
if (idx == string.size()) {
valid = 0;
break;
}
c = static_cast<uint8_t>(string[idx]);
/* Breaks out and bail on any invalid UTF-8 sequence, including \0. */
if ((c & 0xc0) != 0x80) {
valid = 0;
break;
}
utf32 |= c & 0x3f;
}
if (!valid) break;
/* The range 0xd800 - 0xdfff is reserved by the surrogates ad vitam.
* Any other range is technically reserved for future usage, so if we
* don't want the software to break in the future, we have to allow
* anything else. The first non-unicode character is 0x110000. */
if (((utf32 >= 0xd800) && (utf32 <= 0xdfff)) || (utf32 >= 0x110000))
break;
if (utf32 >= 0x10000) {
/* If utf32 contains a character that is above 0xffff, it needs to be
* broken down into a utf-16 surrogate pair. A surrogate pair is first
* a high surrogate, followed by a low surrogate. Each surrogate holds
* 10 bits of usable data, thus allowing a total of 20 bits of data.
* The high surrogate marker is 0xd800, while the low surrogate marker
* is 0xdc00. The low 10 bits of each will be the usable data.
*
* After re-combining the 20 bits of data, one has to add 0x10000 to
* the resulting value, in order to obtain the original character.
* This is obviously because the range 0x0000 - 0xffff can be written
* without any special trick.
*
* Since 0x10ffff is the highest allowed character, we're working in
* the range 0x00000 - 0xfffff after we decrement it by 0x10000.
* That range is exactly 20 bits.
*/
utf32 -= 0x10000;
EscapeUtf16(static_cast<uint16_t>(0xd800 | (utf32 >> 10)));
EscapeUtf16(static_cast<uint16_t>(0xdc00 | (utf32 & 0x3ff)));
} else {
EscapeUtf16(static_cast<uint16_t>(utf32));
}
}
}
OutputChar('"');
}
void JsonWriter::ContainerBegins(Json::Type type) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputChar(type == Json::Type::OBJECT ? '{' : '[');
container_empty_ = true;
got_key_ = false;
depth_++;
}
void JsonWriter::ContainerEnds(Json::Type type) {
if (indent_ && !container_empty_) OutputChar('\n');
depth_--;
if (!container_empty_) OutputIndent();
OutputChar(type == Json::Type::OBJECT ? '}' : ']');
container_empty_ = false;
got_key_ = false;
}
void JsonWriter::ObjectKey(const std::string& string) {
ValueEnd();
OutputIndent();
EscapeString(string);
OutputChar(':');
got_key_ = true;
}
void JsonWriter::ValueRaw(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
OutputString(string);
got_key_ = false;
}
void JsonWriter::ValueString(const std::string& string) {
if (!got_key_) ValueEnd();
OutputIndent();
EscapeString(string);
got_key_ = false;
}
void JsonWriter::DumpObject(const Json::Object& object) {
ContainerBegins(Json::Type::OBJECT);
for (const auto& p : object) {
ObjectKey(p.first.data());
DumpValue(p.second);
}
ContainerEnds(Json::Type::OBJECT);
}
void JsonWriter::DumpArray(const Json::Array& array) {
ContainerBegins(Json::Type::ARRAY);
for (const auto& v : array) {
DumpValue(v);
}
ContainerEnds(Json::Type::ARRAY);
}
void JsonWriter::DumpValue(const Json& value) {
switch (value.type()) {
case Json::Type::OBJECT:
DumpObject(value.object_value());
break;
case Json::Type::ARRAY:
DumpArray(value.array_value());
break;
case Json::Type::STRING:
ValueString(value.string_value());
break;
case Json::Type::NUMBER:
ValueRaw(value.string_value());
break;
case Json::Type::JSON_TRUE:
ValueRaw(std::string("true", 4));
break;
case Json::Type::JSON_FALSE:
ValueRaw(std::string("false", 5));
break;
case Json::Type::JSON_NULL:
ValueRaw(std::string("null", 4));
break;
default:
GPR_UNREACHABLE_CODE(abort());
}
}
std::string JsonWriter::Dump(const Json& value, int indent) {
JsonWriter writer(indent);
writer.DumpValue(value);
return std::move(writer.output_);
}
} // namespace
std::string Json::Dump(int indent) const {
return JsonWriter::Dump(*this, indent);
}
} // namespace grpc_core

@ -1,106 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <functional>
#include <grpcpp/generic/generic_stub.h>
#include <grpcpp/impl/rpc_method.h>
#include <grpcpp/support/client_callback.h>
namespace grpc_impl {
namespace {
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> CallInternal(
grpc::ChannelInterface* channel, grpc::ClientContext* context,
const grpc::string& method, CompletionQueue* cq, bool start, void* tag) {
return std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
internal::ClientAsyncReaderWriterFactory<grpc::ByteBuffer,
grpc::ByteBuffer>::
Create(channel, cq,
grpc::internal::RpcMethod(
method.c_str(), grpc::internal::RpcMethod::BIDI_STREAMING),
context, start, tag));
}
} // namespace
// begin a call to a named method
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> GenericStub::Call(
grpc::ClientContext* context, const grpc::string& method,
CompletionQueue* cq, void* tag) {
return CallInternal(channel_.get(), context, method, cq, true, tag);
}
// setup a call to a named method
std::unique_ptr<grpc::GenericClientAsyncReaderWriter> GenericStub::PrepareCall(
grpc::ClientContext* context, const grpc::string& method,
CompletionQueue* cq) {
return CallInternal(channel_.get(), context, method, cq, false, nullptr);
}
// setup a unary call to a named method
std::unique_ptr<grpc::GenericClientAsyncResponseReader>
GenericStub::PrepareUnaryCall(grpc::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer& request,
CompletionQueue* cq) {
return std::unique_ptr<grpc::GenericClientAsyncResponseReader>(
internal::ClientAsyncResponseReaderFactory<grpc::ByteBuffer>::Create(
channel_.get(), cq,
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, false));
}
void GenericStub::UnaryCallInternal(
grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
std::function<void(grpc::Status)> on_completion) {
internal::CallbackUnaryCall(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, std::move(on_completion));
}
void GenericStub::PrepareBidiStreamingCallInternal(
grpc::ClientContext* context, const grpc::string& method,
ClientBidiReactor<grpc::ByteBuffer, grpc::ByteBuffer>* reactor) {
internal::ClientCallbackReaderWriterFactory<
grpc::ByteBuffer,
grpc::ByteBuffer>::Create(channel_.get(),
grpc::internal::RpcMethod(
method.c_str(),
grpc::internal::RpcMethod::BIDI_STREAMING),
context, reactor);
}
void GenericStub::PrepareUnaryCallInternal(grpc::ClientContext* context,
const grpc::string& method,
const grpc::ByteBuffer* request,
grpc::ByteBuffer* response,
ClientUnaryReactor* reactor) {
internal::ClientCallbackUnaryFactory::Create<grpc::ByteBuffer,
grpc::ByteBuffer>(
channel_.get(),
grpc::internal::RpcMethod(method.c_str(),
grpc::internal::RpcMethod::NORMAL_RPC),
context, request, response, reactor);
}
} // namespace grpc_impl

@ -23,6 +23,7 @@
# each change must be ported from one to the other.
#
load("@rules_proto//proto:defs.bzl", "proto_library")
load(
"//bazel:generate_objc.bzl",
"generate_objc",
@ -39,7 +40,7 @@ def proto_library_objc_wrapper(
"""proto_library for adding dependencies to google/protobuf protos
use_well_known_protos - ignored in open source version
"""
native.proto_library(
proto_library(
name = name,
srcs = srcs,
deps = deps,

@ -14,6 +14,7 @@
licenses(["notice"]) # Apache v2
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
grpc_package(

@ -14,6 +14,8 @@
licenses(["notice"]) # Apache v2
load("@rules_proto//proto:defs.bzl", "proto_library")
proto_library(
name = "alts_handshaker_proto",
srcs = [

@ -14,6 +14,7 @@
licenses(["notice"]) # Apache v2
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
grpc_package(

@ -14,6 +14,7 @@
licenses(["notice"]) # Apache v2
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
grpc_package(

@ -14,6 +14,7 @@
licenses(["notice"]) # Apache v2
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
grpc_package(

@ -14,8 +14,9 @@
licenses(["notice"]) # Apache v2
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("//bazel:grpc_build_system.bzl", "grpc_package", "grpc_proto_library")
load("//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
grpc_package(

@ -115,6 +115,9 @@ message SimpleResponse {
string server_id = 4;
// gRPCLB Path.
GrpclbRouteType grpclb_route_type = 5;
// Server hostname.
string hostname = 6;
}
// Client-streaming request.
@ -190,3 +193,17 @@ message ReconnectInfo {
bool passed = 1;
repeated int32 backoff_ms = 2;
}
message LoadBalancerStatsRequest {
// Request stats for the next num_rpcs sent by client.
int32 num_rpcs = 1;
// If num_rpcs have not completed within timeout_sec, return partial results.
int32 timeout_sec = 2;
}
message LoadBalancerStatsResponse {
// The number of completed RPCs for each peer.
map<string, int32> rpcs_by_peer = 1;
// The number of RPCs that failed to record a remote peer.
int32 num_failures = 2;
}

@ -1,3 +1,4 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
package(default_visibility = ["//visibility:public"])

@ -77,3 +77,10 @@ service ReconnectService {
rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty);
rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo);
}
// A service used to obtain stats for verifying LB behavior.
service LoadBalancerStatsService {
// Gets the backend distribution for RPCs sent by a test client.
rpc GetClientStats(LoadBalancerStatsRequest)
returns (LoadBalancerStatsResponse) {}
}

@ -367,7 +367,8 @@ cdef class _AioCall(GrpcCallWrapper):
"""Sends one single raw message in bytes."""
await _send_message(self,
message,
True,
None,
False,
self._loop)
async def send_receive_close(self):

@ -66,7 +66,7 @@ cdef class CallbackWrapper:
cdef CallbackFailureHandler CQ_SHUTDOWN_FAILURE_HANDLER = CallbackFailureHandler(
'grpc_completion_queue_shutdown',
'Unknown',
RuntimeError)
InternalError)
cdef class CallbackCompletionQueue:
@ -153,12 +153,13 @@ async def _receive_message(GrpcCallWrapper grpc_call_wrapper,
async def _send_message(GrpcCallWrapper grpc_call_wrapper,
bytes message,
bint metadata_sent,
Operation send_initial_metadata_op,
int write_flag,
object loop):
cdef SendMessageOperation op = SendMessageOperation(message, _EMPTY_FLAG)
cdef SendMessageOperation op = SendMessageOperation(message, write_flag)
cdef tuple ops = (op,)
if not metadata_sent:
ops = prepend_send_initial_metadata_op(ops, None)
if send_initial_metadata_op is not None:
ops = (send_initial_metadata_op,) + ops
await execute_batch(grpc_call_wrapper, ops, loop)
@ -184,7 +185,7 @@ async def _send_error_status_from_server(GrpcCallWrapper grpc_call_wrapper,
grpc_status_code code,
str details,
tuple trailing_metadata,
bint metadata_sent,
Operation send_initial_metadata_op,
object loop):
assert code != StatusCode.ok, 'Expecting non-ok status code.'
cdef SendStatusFromServerOperation op = SendStatusFromServerOperation(
@ -194,6 +195,6 @@ async def _send_error_status_from_server(GrpcCallWrapper grpc_call_wrapper,
_EMPTY_FLAGS,
)
cdef tuple ops = (op,)
if not metadata_sent:
ops = prepend_send_initial_metadata_op(ops, None)
if send_initial_metadata_op is not None:
ops = (send_initial_metadata_op,) + ops
await execute_batch(grpc_call_wrapper, ops, loop)

@ -71,8 +71,7 @@ cdef class AioChannel:
other design of API if necessary.
"""
if self._status in (AIO_CHANNEL_STATUS_DESTROYED, AIO_CHANNEL_STATUS_CLOSING):
# TODO(lidiz) switch to UsageError
raise RuntimeError('Channel is closed.')
raise UsageError('Channel is closed.')
cdef gpr_timespec c_deadline = _timespec_from_time(deadline)
@ -115,8 +114,7 @@ cdef class AioChannel:
The _AioCall object.
"""
if self.closed():
# TODO(lidiz) switch to UsageError
raise RuntimeError('Channel is closed.')
raise UsageError('Channel is closed.')
cdef CallCredentials cython_call_credentials
if python_call_credentials is not None:

@ -67,3 +67,33 @@ class _EOF:
EOF = _EOF()
_COMPRESSION_METADATA_STRING_MAPPING = {
CompressionAlgorithm.none: 'identity',
CompressionAlgorithm.deflate: 'deflate',
CompressionAlgorithm.gzip: 'gzip',
}
class BaseError(Exception):
"""The base class for exceptions generated by gRPC AsyncIO stack."""
class UsageError(BaseError):
"""Raised when the usage of API by applications is inappropriate.
For example, trying to invoke RPC on a closed channel, mixing two styles
of streaming API on the client side. This exception should not be
suppressed.
"""
class AbortError(BaseError):
"""Raised when calling abort in servicer methods.
This exception should not be suppressed. Applications may catch it to
perform certain clean-up logic, and then re-raise it.
"""
class InternalError(BaseError):
"""Raised upon unexpected errors in native code."""

@ -31,10 +31,14 @@ cdef class RPCState(GrpcCallWrapper):
cdef grpc_status_code status_code
cdef str status_details
cdef tuple trailing_metadata
cdef object compression_algorithm
cdef bint disable_next_compression
cdef bytes method(self)
cdef tuple invocation_metadata(self)
cdef void raise_for_termination(self) except *
cdef int get_write_flag(self)
cdef Operation create_send_initial_metadata_op_if_not_sent(self)
cdef enum AioServerStatus:

@ -21,13 +21,23 @@ cdef int _EMPTY_FLAG = 0
cdef str _RPC_FINISHED_DETAILS = 'RPC already finished.'
cdef str _SERVER_STOPPED_DETAILS = 'Server already stopped.'
cdef _augment_metadata(tuple metadata, object compression):
if compression is None:
return metadata
else:
return ((
GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY,
_COMPRESSION_METADATA_STRING_MAPPING[compression]
),) + metadata
cdef class _HandlerCallDetails:
def __cinit__(self, str method, tuple invocation_metadata):
self.method = method
self.invocation_metadata = invocation_metadata
class _ServerStoppedError(RuntimeError):
class _ServerStoppedError(BaseError):
"""Raised if the server is stopped."""
@ -45,6 +55,8 @@ cdef class RPCState:
self.status_code = StatusCode.ok
self.status_details = ''
self.trailing_metadata = _IMMUTABLE_EMPTY_METADATA
self.compression_algorithm = None
self.disable_next_compression = False
cdef bytes method(self):
return _slice_bytes(self.details.method)
@ -65,10 +77,28 @@ cdef class RPCState:
if self.abort_exception is not None:
raise self.abort_exception
if self.status_sent:
raise RuntimeError(_RPC_FINISHED_DETAILS)
raise UsageError(_RPC_FINISHED_DETAILS)
if self.server._status == AIO_SERVER_STATUS_STOPPED:
raise _ServerStoppedError(_SERVER_STOPPED_DETAILS)
cdef int get_write_flag(self):
if self.disable_next_compression:
self.disable_next_compression = False
return WriteFlag.no_compress
else:
return _EMPTY_FLAG
cdef Operation create_send_initial_metadata_op_if_not_sent(self):
cdef SendInitialMetadataOperation op
if self.metadata_sent:
return None
else:
op = SendInitialMetadataOperation(
_augment_metadata(_IMMUTABLE_EMPTY_METADATA, self.compression_algorithm),
_EMPTY_FLAG
)
return op
def __dealloc__(self):
"""Cleans the Core objects."""
grpc_call_details_destroy(&self.details)
@ -77,11 +107,6 @@ cdef class RPCState:
grpc_call_unref(self.call)
# TODO(lidiz) inherit this from Python level `AioRpcStatus`, we need to improve
# current code structure to make it happen.
class AbortError(Exception): pass
cdef class _ServicerContext:
cdef RPCState _rpc_state
cdef object _loop
@ -116,18 +141,23 @@ cdef class _ServicerContext:
await _send_message(self._rpc_state,
serialize(self._response_serializer, message),
self._rpc_state.metadata_sent,
self._rpc_state.create_send_initial_metadata_op_if_not_sent(),
self._rpc_state.get_write_flag(),
self._loop)
if not self._rpc_state.metadata_sent:
self._rpc_state.metadata_sent = True
self._rpc_state.metadata_sent = True
async def send_initial_metadata(self, tuple metadata):
self._rpc_state.raise_for_termination()
if self._rpc_state.metadata_sent:
raise RuntimeError('Send initial metadata failed: already sent')
raise UsageError('Send initial metadata failed: already sent')
else:
await _send_initial_metadata(self._rpc_state, metadata, _EMPTY_FLAG, self._loop)
await _send_initial_metadata(
self._rpc_state,
_augment_metadata(metadata, self._rpc_state.compression_algorithm),
_EMPTY_FLAG,
self._loop
)
self._rpc_state.metadata_sent = True
async def abort(self,
@ -135,7 +165,7 @@ cdef class _ServicerContext:
str details='',
tuple trailing_metadata=_IMMUTABLE_EMPTY_METADATA):
if self._rpc_state.abort_exception is not None:
raise RuntimeError('Abort already called!')
raise UsageError('Abort already called!')
else:
# Keeps track of the exception object. After abort happen, the RPC
# should stop execution. However, if users decided to suppress it, it
@ -156,7 +186,7 @@ cdef class _ServicerContext:
actual_code,
details,
trailing_metadata,
self._rpc_state.metadata_sent,
self._rpc_state.create_send_initial_metadata_op_if_not_sent(),
self._loop
)
@ -174,6 +204,15 @@ cdef class _ServicerContext:
def set_details(self, str details):
self._rpc_state.status_details = details
def set_compression(self, object compression):
if self._rpc_state.metadata_sent:
raise RuntimeError('Compression setting must be specified before sending initial metadata')
else:
self._rpc_state.compression_algorithm = compression
def disable_next_message_compression(self):
self._rpc_state.disable_next_compression = True
cdef _find_method_handler(str method, tuple metadata, list generic_handlers):
cdef _HandlerCallDetails handler_call_details = _HandlerCallDetails(method,
@ -217,7 +256,7 @@ async def _finish_handler_with_unary_response(RPCState rpc_state,
# Assembles the batch operations
cdef tuple finish_ops
finish_ops = (
SendMessageOperation(response_raw, _EMPTY_FLAGS),
SendMessageOperation(response_raw, rpc_state.get_write_flag()),
SendStatusFromServerOperation(
rpc_state.trailing_metadata,
rpc_state.status_code,
@ -446,7 +485,7 @@ async def _handle_exceptions(RPCState rpc_state, object rpc_coro, object loop):
status_code,
'Unexpected %s: %s' % (type(e), e),
rpc_state.trailing_metadata,
rpc_state.metadata_sent,
rpc_state.create_send_initial_metadata_op_if_not_sent(),
loop
)
@ -492,7 +531,7 @@ async def _handle_rpc(list generic_handlers, RPCState rpc_state, object loop):
StatusCode.unimplemented,
'Method not found!',
_IMMUTABLE_EMPTY_METADATA,
rpc_state.metadata_sent,
rpc_state.create_send_initial_metadata_op_if_not_sent(),
loop
)
return
@ -535,13 +574,13 @@ cdef CallbackFailureHandler REQUEST_CALL_FAILURE_HANDLER = CallbackFailureHandle
cdef CallbackFailureHandler SERVER_SHUTDOWN_FAILURE_HANDLER = CallbackFailureHandler(
'grpc_server_shutdown_and_notify',
None,
RuntimeError)
InternalError)
cdef class AioServer:
def __init__(self, loop, thread_pool, generic_handlers, interceptors,
options, maximum_concurrent_rpcs, compression):
options, maximum_concurrent_rpcs):
# NOTE(lidiz) Core objects won't be deallocated automatically.
# If AioServer.shutdown is not called, those objects will leak.
self._server = Server(options)
@ -570,8 +609,6 @@ cdef class AioServer:
raise NotImplementedError()
if maximum_concurrent_rpcs:
raise NotImplementedError()
if compression:
raise NotImplementedError()
if thread_pool:
raise NotImplementedError()
@ -600,7 +637,7 @@ cdef class AioServer:
wrapper.c_functor()
)
if error != GRPC_CALL_OK:
raise RuntimeError("Error in grpc_server_request_call: %s" % error)
raise InternalError("Error in grpc_server_request_call: %s" % error)
await future
return rpc_state
@ -650,7 +687,7 @@ cdef class AioServer:
if self._status == AIO_SERVER_STATUS_RUNNING:
return
elif self._status != AIO_SERVER_STATUS_READY:
raise RuntimeError('Server not in ready state')
raise UsageError('Server not in ready state')
self._status = AIO_SERVER_STATUS_RUNNING
cdef object server_started = self._loop.create_future()
@ -746,11 +783,7 @@ cdef class AioServer:
return True
def __dealloc__(self):
"""Deallocation of Core objects are ensured by Python grpc.aio.Server.
If the Cython representation is deallocated without underlying objects
freed, raise an RuntimeError.
"""
"""Deallocation of Core objects are ensured by Python layer."""
# TODO(lidiz) if users create server, and then dealloc it immediately.
# There is a potential memory leak of created Core server.
if self._status != AIO_SERVER_STATUS_STOPPED:

@ -118,7 +118,7 @@ cdef class Server:
def cancel_all_calls(self):
if not self.is_shutting_down:
raise RuntimeError("the server must be shutting down to cancel all calls")
raise UsageError("the server must be shutting down to cancel all calls")
elif self.is_shutdown:
return
else:
@ -136,7 +136,7 @@ cdef class Server:
pass
elif not self.is_shutting_down:
if self.backup_shutdown_queue is None:
raise RuntimeError('Server shutdown failed: no completion queue.')
raise InternalError('Server shutdown failed: no completion queue.')
else:
# the user didn't call shutdown - use our backup queue
self._c_shutdown(self.backup_shutdown_queue, None)

@ -17,12 +17,11 @@ gRPC Async API objects may only be used on the thread on which they were
created. AsyncIO doesn't provide thread safety for most of its APIs.
"""
import abc
from typing import Any, Optional, Sequence, Text, Tuple
import six
from typing import Any, Optional, Sequence, Tuple
import grpc
from grpc._cython.cygrpc import EOF, AbortError, init_grpc_aio
from grpc._cython.cygrpc import (EOF, AbortError, BaseError, UsageError,
init_grpc_aio)
from ._base_call import Call, RpcContext, UnaryStreamCall, UnaryUnaryCall
from ._call import AioRpcError
@ -34,7 +33,7 @@ from ._typing import ChannelArgumentType
def insecure_channel(
target: Text,
target: str,
options: Optional[ChannelArgumentType] = None,
compression: Optional[grpc.Compression] = None,
interceptors: Optional[Sequence[UnaryUnaryClientInterceptor]] = None):
@ -57,7 +56,7 @@ def insecure_channel(
def secure_channel(
target: Text,
target: str,
credentials: grpc.ChannelCredentials,
options: Optional[ChannelArgumentType] = None,
compression: Optional[grpc.Compression] = None,
@ -88,4 +87,4 @@ __all__ = ('AioRpcError', 'RpcContext', 'Call', 'UnaryUnaryCall',
'UnaryUnaryMultiCallable', 'ClientCallDetails',
'UnaryUnaryClientInterceptor', 'InterceptedUnaryUnaryCall',
'insecure_channel', 'server', 'Server', 'EOF', 'secure_channel',
'AbortError')
'AbortError', 'BaseError', 'UsageError')

@ -19,7 +19,7 @@ RPC, e.g. cancellation.
"""
from abc import ABCMeta, abstractmethod
from typing import AsyncIterable, Awaitable, Generic, Optional, Text, Union
from typing import AsyncIterable, Awaitable, Generic, Optional, Union
import grpc
@ -110,7 +110,7 @@ class Call(RpcContext, metaclass=ABCMeta):
"""
@abstractmethod
async def details(self) -> Text:
async def details(self) -> str:
"""Accesses the details sent by the server.
Returns:

@ -16,6 +16,7 @@
import asyncio
from functools import partial
import logging
import enum
from typing import AsyncIterable, Awaitable, Dict, Optional
import grpc
@ -143,9 +144,13 @@ class AioRpcError(grpc.RpcError):
def _create_rpc_error(initial_metadata: Optional[MetadataType],
status: cygrpc.AioRpcStatus) -> AioRpcError:
return AioRpcError(_common.CYGRPC_STATUS_CODE_TO_STATUS_CODE[status.code()],
status.details(), initial_metadata,
status.trailing_metadata())
return AioRpcError(
_common.CYGRPC_STATUS_CODE_TO_STATUS_CODE[status.code()],
status.details(),
initial_metadata,
status.trailing_metadata(),
status.debug_error_string(),
)
class Call:
@ -234,6 +239,12 @@ class Call:
return self._repr()
class _APIStyle(enum.IntEnum):
UNKNOWN = 0
ASYNC_GENERATOR = 1
READER_WRITER = 2
class _UnaryResponseMixin(Call):
_call_response: asyncio.Task
@ -279,10 +290,19 @@ class _UnaryResponseMixin(Call):
class _StreamResponseMixin(Call):
_message_aiter: AsyncIterable[ResponseType]
_preparation: asyncio.Task
_response_style: _APIStyle
def _init_stream_response_mixin(self, preparation: asyncio.Task):
self._message_aiter = None
self._preparation = preparation
self._response_style = _APIStyle.UNKNOWN
def _update_response_style(self, style: _APIStyle):
if self._response_style is _APIStyle.UNKNOWN:
self._response_style = style
elif self._response_style is not style:
raise cygrpc.UsageError(
'Please don\'t mix two styles of API for streaming responses')
def cancel(self) -> bool:
if super().cancel():
@ -298,6 +318,7 @@ class _StreamResponseMixin(Call):
message = await self._read()
def __aiter__(self) -> AsyncIterable[ResponseType]:
self._update_response_style(_APIStyle.ASYNC_GENERATOR)
if self._message_aiter is None:
self._message_aiter = self._fetch_stream_responses()
return self._message_aiter
@ -324,6 +345,7 @@ class _StreamResponseMixin(Call):
if self.done():
await self._raise_for_status()
return cygrpc.EOF
self._update_response_style(_APIStyle.READER_WRITER)
response_message = await self._read()
@ -335,20 +357,28 @@ class _StreamResponseMixin(Call):
class _StreamRequestMixin(Call):
_metadata_sent: asyncio.Event
_done_writing: bool
_done_writing_flag: bool
_async_request_poller: Optional[asyncio.Task]
_request_style: _APIStyle
def _init_stream_request_mixin(
self, request_async_iterator: Optional[AsyncIterable[RequestType]]):
self._metadata_sent = asyncio.Event(loop=self._loop)
self._done_writing = False
self._done_writing_flag = False
# If user passes in an async iterator, create a consumer Task.
if request_async_iterator is not None:
self._async_request_poller = self._loop.create_task(
self._consume_request_iterator(request_async_iterator))
self._request_style = _APIStyle.ASYNC_GENERATOR
else:
self._async_request_poller = None
self._request_style = _APIStyle.READER_WRITER
def _raise_for_different_style(self, style: _APIStyle):
if self._request_style is not style:
raise cygrpc.UsageError(
'Please don\'t mix two styles of API for streaming requests')
def cancel(self) -> bool:
if super().cancel():
@ -365,8 +395,8 @@ class _StreamRequestMixin(Call):
self, request_async_iterator: AsyncIterable[RequestType]) -> None:
try:
async for request in request_async_iterator:
await self.write(request)
await self.done_writing()
await self._write(request)
await self._done_writing()
except AioRpcError as rpc_error:
# Rpc status should be exposed through other API. Exceptions raised
# within this Task won't be retrieved by another coroutine. It's
@ -374,10 +404,10 @@ class _StreamRequestMixin(Call):
_LOGGER.debug('Exception while consuming the request_iterator: %s',
rpc_error)
async def write(self, request: RequestType) -> None:
async def _write(self, request: RequestType) -> None:
if self.done():
raise asyncio.InvalidStateError(_RPC_ALREADY_FINISHED_DETAILS)
if self._done_writing:
if self._done_writing_flag:
raise asyncio.InvalidStateError(_RPC_HALF_CLOSED_DETAILS)
if not self._metadata_sent.is_set():
await self._metadata_sent.wait()
@ -394,14 +424,13 @@ class _StreamRequestMixin(Call):
self.cancel()
await self._raise_for_status()
async def done_writing(self) -> None:
"""Implementation of done_writing is idempotent."""
async def _done_writing(self) -> None:
if self.done():
# If the RPC is finished, do nothing.
return
if not self._done_writing:
if not self._done_writing_flag:
# If the done writing is not sent before, try to send it.
self._done_writing = True
self._done_writing_flag = True
try:
await self._cython_call.send_receive_close()
except asyncio.CancelledError:
@ -409,6 +438,18 @@ class _StreamRequestMixin(Call):
self.cancel()
await self._raise_for_status()
async def write(self, request: RequestType) -> None:
self._raise_for_different_style(_APIStyle.READER_WRITER)
await self._write(request)
async def done_writing(self) -> None:
"""Signal peer that client is done writing.
This method is idempotent.
"""
self._raise_for_different_style(_APIStyle.READER_WRITER)
await self._done_writing()
class UnaryUnaryCall(_UnaryResponseMixin, Call, _base_call.UnaryUnaryCall):
"""Object for managing unary-unary RPC calls.

@ -13,13 +13,15 @@
# limitations under the License.
"""Invocation-side implementation of gRPC Asyncio Python."""
import asyncio
from typing import Any, AsyncIterable, Optional, Sequence, AbstractSet, Text
from typing import Any, AsyncIterable, Optional, Sequence, AbstractSet
from weakref import WeakSet
import logging
import grpc
from grpc import _common
from grpc._cython import cygrpc
from grpc import _compression
from grpc import _grpcio_metadata
from . import _base_call
from ._call import (StreamStreamCall, StreamUnaryCall, UnaryStreamCall,
@ -31,6 +33,20 @@ from ._typing import (ChannelArgumentType, DeserializingFunction, MetadataType,
from ._utils import _timeout_to_deadline
_IMMUTABLE_EMPTY_TUPLE = tuple()
_USER_AGENT = 'grpc-python-asyncio/{}'.format(_grpcio_metadata.__version__)
def _augment_channel_arguments(base_options: ChannelArgumentType,
compression: Optional[grpc.Compression]):
compression_channel_argument = _compression.create_channel_option(
compression)
user_agent_channel_argument = ((
cygrpc.ChannelArgKey.primary_user_agent_string,
_USER_AGENT,
),)
return tuple(base_options
) + compression_channel_argument + user_agent_channel_argument
_LOGGER = logging.getLogger(__name__)
@ -44,7 +60,10 @@ class _OngoingCalls:
self._calls = WeakSet()
def _remove_call(self, call: _base_call.RpcContext):
self._calls.remove(call)
try:
self._calls.remove(call)
except KeyError:
pass
@property
def calls(self) -> AbstractSet[_base_call.RpcContext]:
@ -107,7 +126,7 @@ class UnaryUnaryMultiCallable(_BaseMultiCallable):
request: Any,
*,
timeout: Optional[float] = None,
metadata: Optional[MetadataType] = None,
metadata: Optional[MetadataType] = _IMMUTABLE_EMPTY_TUPLE,
credentials: Optional[grpc.CallCredentials] = None,
wait_for_ready: Optional[bool] = None,
compression: Optional[grpc.Compression] = None
@ -136,10 +155,7 @@ class UnaryUnaryMultiCallable(_BaseMultiCallable):
metadata, status code, and details.
"""
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
if metadata is None:
metadata = _IMMUTABLE_EMPTY_TUPLE
metadata = _compression.augment_metadata(metadata, compression)
if not self._interceptors:
call = UnaryUnaryCall(request, _timeout_to_deadline(timeout),
@ -165,7 +181,7 @@ class UnaryStreamMultiCallable(_BaseMultiCallable):
request: Any,
*,
timeout: Optional[float] = None,
metadata: Optional[MetadataType] = None,
metadata: Optional[MetadataType] = _IMMUTABLE_EMPTY_TUPLE,
credentials: Optional[grpc.CallCredentials] = None,
wait_for_ready: Optional[bool] = None,
compression: Optional[grpc.Compression] = None
@ -189,11 +205,9 @@ class UnaryStreamMultiCallable(_BaseMultiCallable):
A Call object instance which is an awaitable object.
"""
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
metadata = _compression.augment_metadata(metadata, compression)
deadline = _timeout_to_deadline(timeout)
if metadata is None:
metadata = _IMMUTABLE_EMPTY_TUPLE
call = UnaryStreamCall(request, deadline, metadata, credentials,
wait_for_ready, self._channel, self._method,
@ -209,7 +223,7 @@ class StreamUnaryMultiCallable(_BaseMultiCallable):
def __call__(self,
request_async_iterator: Optional[AsyncIterable[Any]] = None,
timeout: Optional[float] = None,
metadata: Optional[MetadataType] = None,
metadata: Optional[MetadataType] = _IMMUTABLE_EMPTY_TUPLE,
credentials: Optional[grpc.CallCredentials] = None,
wait_for_ready: Optional[bool] = None,
compression: Optional[grpc.Compression] = None
@ -238,11 +252,9 @@ class StreamUnaryMultiCallable(_BaseMultiCallable):
metadata, status code, and details.
"""
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
metadata = _compression.augment_metadata(metadata, compression)
deadline = _timeout_to_deadline(timeout)
if metadata is None:
metadata = _IMMUTABLE_EMPTY_TUPLE
call = StreamUnaryCall(request_async_iterator, deadline, metadata,
credentials, wait_for_ready, self._channel,
@ -258,7 +270,7 @@ class StreamStreamMultiCallable(_BaseMultiCallable):
def __call__(self,
request_async_iterator: Optional[AsyncIterable[Any]] = None,
timeout: Optional[float] = None,
metadata: Optional[MetadataType] = None,
metadata: Optional[MetadataType] = _IMMUTABLE_EMPTY_TUPLE,
credentials: Optional[grpc.CallCredentials] = None,
wait_for_ready: Optional[bool] = None,
compression: Optional[grpc.Compression] = None
@ -287,11 +299,9 @@ class StreamStreamMultiCallable(_BaseMultiCallable):
metadata, status code, and details.
"""
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
metadata = _compression.augment_metadata(metadata, compression)
deadline = _timeout_to_deadline(timeout)
if metadata is None:
metadata = _IMMUTABLE_EMPTY_TUPLE
call = StreamStreamCall(request_async_iterator, deadline, metadata,
credentials, wait_for_ready, self._channel,
@ -311,7 +321,7 @@ class Channel:
_unary_unary_interceptors: Optional[Sequence[UnaryUnaryClientInterceptor]]
_ongoing_calls: _OngoingCalls
def __init__(self, target: Text, options: Optional[ChannelArgumentType],
def __init__(self, target: str, options: ChannelArgumentType,
credentials: Optional[grpc.ChannelCredentials],
compression: Optional[grpc.Compression],
interceptors: Optional[Sequence[UnaryUnaryClientInterceptor]]):
@ -326,10 +336,6 @@ class Channel:
interceptors: An optional list of interceptors that would be used for
intercepting any RPC executed with that channel.
"""
if compression:
raise NotImplementedError("TODO: compression not implemented yet")
if interceptors is None:
self._unary_unary_interceptors = None
else:
@ -349,8 +355,10 @@ class Channel:
.format(invalid_interceptors))
self._loop = asyncio.get_event_loop()
self._channel = cygrpc.AioChannel(_common.encode(target), options,
credentials, self._loop)
self._channel = cygrpc.AioChannel(
_common.encode(target),
_augment_channel_arguments(options, compression), credentials,
self._loop)
self._ongoing_calls = _OngoingCalls()
async def __aenter__(self):
@ -453,9 +461,16 @@ class Channel:
assert await self._channel.watch_connectivity_state(
last_observed_state.value[0], None)
async def channel_ready(self) -> None:
"""Creates a coroutine that ends when a Channel is ready."""
state = self.get_state(try_to_connect=True)
while state != grpc.ChannelConnectivity.READY:
await self.wait_for_state_change(state)
state = self.get_state(try_to_connect=True)
def unary_unary(
self,
method: Text,
method: str,
request_serializer: Optional[SerializingFunction] = None,
response_deserializer: Optional[DeserializingFunction] = None
) -> UnaryUnaryMultiCallable:
@ -481,7 +496,7 @@ class Channel:
def unary_stream(
self,
method: Text,
method: str,
request_serializer: Optional[SerializingFunction] = None,
response_deserializer: Optional[DeserializingFunction] = None
) -> UnaryStreamMultiCallable:
@ -492,7 +507,7 @@ class Channel:
def stream_unary(
self,
method: Text,
method: str,
request_serializer: Optional[SerializingFunction] = None,
response_deserializer: Optional[DeserializingFunction] = None
) -> StreamUnaryMultiCallable:
@ -503,7 +518,7 @@ class Channel:
def stream_stream(
self,
method: Text,
method: str,
request_serializer: Optional[SerializingFunction] = None,
response_deserializer: Optional[DeserializingFunction] = None
) -> StreamStreamMultiCallable:

@ -16,7 +16,7 @@ import asyncio
import collections
import functools
from abc import ABCMeta, abstractmethod
from typing import Callable, Optional, Iterator, Sequence, Text, Union
from typing import Callable, Optional, Iterator, Sequence, Union
import grpc
from grpc._cython import cygrpc
@ -36,7 +36,7 @@ class ClientCallDetails(
('method', 'timeout', 'metadata', 'credentials', 'wait_for_ready')),
grpc.ClientCallDetails):
method: Text
method: str
timeout: Optional[float]
metadata: Optional[MetadataType]
credentials: Optional[grpc.CallCredentials]

@ -13,39 +13,52 @@
# limitations under the License.
"""Server-side implementation of gRPC Asyncio Python."""
from typing import Text, Optional
import asyncio
from concurrent.futures import Executor
from typing import Any, Optional, Sequence
import grpc
from grpc import _common
from grpc import _common, _compression
from grpc._cython import cygrpc
from ._typing import ChannelArgumentType
def _augment_channel_arguments(base_options: ChannelArgumentType,
compression: Optional[grpc.Compression]):
compression_option = _compression.create_channel_option(compression)
return tuple(base_options) + compression_option
class Server:
"""Serves RPCs."""
def __init__(self, thread_pool, generic_handlers, interceptors, options,
maximum_concurrent_rpcs, compression):
def __init__(self, thread_pool: Optional[Executor],
generic_handlers: Optional[Sequence[grpc.GenericRpcHandler]],
interceptors: Optional[Sequence[Any]],
options: ChannelArgumentType,
maximum_concurrent_rpcs: Optional[int],
compression: Optional[grpc.Compression]):
self._loop = asyncio.get_event_loop()
self._server = cygrpc.AioServer(self._loop, thread_pool,
generic_handlers, interceptors, options,
maximum_concurrent_rpcs, compression)
self._server = cygrpc.AioServer(
self._loop, thread_pool, generic_handlers, interceptors,
_augment_channel_arguments(options, compression),
maximum_concurrent_rpcs)
def add_generic_rpc_handlers(
self,
generic_rpc_handlers,
# generic_rpc_handlers: Iterable[grpc.GenericRpcHandlers]
) -> None:
generic_rpc_handlers: Sequence[grpc.GenericRpcHandler]) -> None:
"""Registers GenericRpcHandlers with this Server.
This method is only safe to call before the server is started.
Args:
generic_rpc_handlers: An iterable of GenericRpcHandlers that will be
generic_rpc_handlers: A sequence of GenericRpcHandlers that will be
used to service RPCs.
"""
self._server.add_generic_rpc_handlers(generic_rpc_handlers)
def add_insecure_port(self, address: Text) -> int:
def add_insecure_port(self, address: str) -> int:
"""Opens an insecure port for accepting RPCs.
This method may only be called before starting the server.
@ -59,7 +72,7 @@ class Server:
"""
return self._server.add_insecure_port(_common.encode(address))
def add_secure_port(self, address: Text,
def add_secure_port(self, address: str,
server_credentials: grpc.ServerCredentials) -> int:
"""Opens a secure port for accepting RPCs.
@ -141,12 +154,12 @@ class Server:
self._loop.create_task(self._server.shutdown(None))
def server(migration_thread_pool=None,
handlers=None,
interceptors=None,
options=None,
maximum_concurrent_rpcs=None,
compression=None):
def server(migration_thread_pool: Optional[Executor] = None,
handlers: Optional[Sequence[grpc.GenericRpcHandler]] = None,
interceptors: Optional[Sequence[Any]] = None,
options: Optional[ChannelArgumentType] = None,
maximum_concurrent_rpcs: Optional[int] = None,
compression: Optional[grpc.Compression] = None):
"""Creates a Server with which RPCs can be serviced.
Args:
@ -166,7 +179,8 @@ def server(migration_thread_pool=None,
indicate no limit.
compression: An element of grpc.compression, e.g.
grpc.compression.Gzip. This compression algorithm will be used for the
lifetime of the server unless overridden. This is an EXPERIMENTAL option.
lifetime of the server unless overridden by set_compression. This is an
EXPERIMENTAL option.
Returns:
A Server object.

@ -13,15 +13,15 @@
# limitations under the License.
"""Common types for gRPC Async API"""
from typing import Any, AnyStr, Callable, Sequence, Text, Tuple, TypeVar
from typing import Any, AnyStr, Callable, Sequence, Tuple, TypeVar
from grpc._cython.cygrpc import EOF
RequestType = TypeVar('RequestType')
ResponseType = TypeVar('ResponseType')
SerializingFunction = Callable[[Any], bytes]
DeserializingFunction = Callable[[bytes], Any]
MetadatumType = Tuple[Text, AnyStr]
MetadatumType = Tuple[str, AnyStr]
MetadataType = Sequence[MetadatumType]
ChannelArgumentType = Sequence[Tuple[Text, Any]]
ChannelArgumentType = Sequence[Tuple[str, Any]]
EOFType = type(EOF)
DoneCallbackType = Callable[[Any], None]

@ -269,7 +269,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/is_epollexclusive_available.cc',
'src/core/lib/iomgr/load_file.cc',
'src/core/lib/iomgr/lockfree_event.cc',
'src/core/lib/iomgr/logical_thread.cc',
'src/core/lib/iomgr/poller/eventmanager_libuv.cc',
'src/core/lib/iomgr/polling_entity.cc',
'src/core/lib/iomgr/pollset.cc',
@ -323,11 +322,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/wakeup_fd_nospecial.cc',
'src/core/lib/iomgr/wakeup_fd_pipe.cc',
'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json.cc',
'src/core/lib/iomgr/work_serializer.cc',
'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_reader_new.cc',
'src/core/lib/json/json_writer.cc',
'src/core/lib/json/json_writer_new.cc',
'src/core/lib/profiling/basic_timers.cc',
'src/core/lib/profiling/stap_timers.cc',
'src/core/lib/security/context/security_context.cc',

@ -1,3 +1,4 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@com_github_grpc_grpc//bazel:python_rules.bzl", "py_grpc_library", "py_proto_library")
proto_library(

@ -9,9 +9,11 @@
"unit.call_test.TestUnaryStreamCall",
"unit.call_test.TestUnaryUnaryCall",
"unit.channel_argument_test.TestChannelArgument",
"unit.channel_ready_test.TestChannelReady",
"unit.channel_test.TestChannel",
"unit.close_channel_test.TestCloseChannel",
"unit.close_channel_test.TestOngoingCalls",
"unit.compression_test.TestCompression",
"unit.connectivity_test.TestConnectivityState",
"unit.done_callback_test.TestDoneCallback",
"unit.init_test.TestInsecureChannel",

@ -0,0 +1,67 @@
# Copyright 2020 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Testing the channel_ready function."""
import asyncio
import gc
import logging
import time
import unittest
import grpc
from grpc.experimental import aio
from tests.unit.framework.common import get_socket, test_constants
from tests_aio.unit import _common
from tests_aio.unit._test_base import AioTestBase
from tests_aio.unit._test_server import start_test_server
class TestChannelReady(AioTestBase):
async def setUp(self):
address, self._port, self._socket = get_socket(listen=False)
self._channel = aio.insecure_channel(f"{address}:{self._port}")
self._socket.close()
async def tearDown(self):
await self._channel.close()
async def test_channel_ready_success(self):
# Start `channel_ready` as another Task
channel_ready_task = self.loop.create_task(
self._channel.channel_ready())
# Wait for TRANSIENT_FAILURE
await _common.block_until_certain_state(
self._channel, grpc.ChannelConnectivity.TRANSIENT_FAILURE)
try:
# Start the server
_, server = await start_test_server(port=self._port)
# The RPC should recover itself
await channel_ready_task
finally:
await server.stop(None)
async def test_channel_ready_blocked(self):
with self.assertRaises(asyncio.TimeoutError):
await asyncio.wait_for(self._channel.channel_ready(),
test_constants.SHORT_TIMEOUT)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
unittest.main(verbosity=2)

@ -24,11 +24,11 @@ from grpc.experimental.aio import _base_call
from grpc.experimental.aio._channel import _OngoingCalls
from src.proto.grpc.testing import messages_pb2, test_pb2_grpc
from tests_aio.unit._constants import UNARY_CALL_WITH_SLEEP_VALUE
from tests_aio.unit._test_base import AioTestBase
from tests_aio.unit._test_server import start_test_server
_UNARY_CALL_METHOD_WITH_SLEEP = '/grpc.testing.TestService/UnaryCallWithSleep'
_LONG_TIMEOUT_THAT_SHOULD_NOT_EXPIRE = 60
class TestOngoingCalls(unittest.TestCase):
@ -90,7 +90,7 @@ class TestCloseChannel(AioTestBase):
call = UnaryCallWithSleep(messages_pb2.SimpleRequest())
await channel.close(grace=UNARY_CALL_WITH_SLEEP_VALUE * 4)
await channel.close(grace=_LONG_TIMEOUT_THAT_SHOULD_NOT_EXPIRE)
self.assertEqual(grpc.StatusCode.OK, await call.code())

@ -0,0 +1,196 @@
# Copyright 2020 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests behavior around the compression mechanism."""
import asyncio
import logging
import platform
import random
import unittest
import grpc
from grpc.experimental import aio
from tests_aio.unit._test_base import AioTestBase
from tests_aio.unit import _common
_GZIP_CHANNEL_ARGUMENT = ('grpc.default_compression_algorithm', 2)
_GZIP_DISABLED_CHANNEL_ARGUMENT = ('grpc.compression_enabled_algorithms_bitset',
3)
_DEFLATE_DISABLED_CHANNEL_ARGUMENT = (
'grpc.compression_enabled_algorithms_bitset', 5)
_TEST_UNARY_UNARY = '/test/TestUnaryUnary'
_TEST_SET_COMPRESSION = '/test/TestSetCompression'
_TEST_DISABLE_COMPRESSION_UNARY = '/test/TestDisableCompressionUnary'
_TEST_DISABLE_COMPRESSION_STREAM = '/test/TestDisableCompressionStream'
_REQUEST = b'\x01' * 100
_RESPONSE = b'\x02' * 100
async def _test_unary_unary(unused_request, unused_context):
return _RESPONSE
async def _test_set_compression(unused_request_iterator, context):
assert _REQUEST == await context.read()
context.set_compression(grpc.Compression.Deflate)
await context.write(_RESPONSE)
try:
context.set_compression(grpc.Compression.Deflate)
except RuntimeError:
# NOTE(lidiz) Testing if the servicer context raises exception when
# the set_compression method is called after initial_metadata sent.
# After the initial_metadata sent, the server-side has no control over
# which compression algorithm it should use.
pass
else:
raise ValueError(
'Expecting exceptions if set_compression is not effective')
async def _test_disable_compression_unary(request, context):
assert _REQUEST == request
context.set_compression(grpc.Compression.Deflate)
context.disable_next_message_compression()
return _RESPONSE
async def _test_disable_compression_stream(unused_request_iterator, context):
assert _REQUEST == await context.read()
context.set_compression(grpc.Compression.Deflate)
await context.write(_RESPONSE)
context.disable_next_message_compression()
await context.write(_RESPONSE)
await context.write(_RESPONSE)
_ROUTING_TABLE = {
_TEST_UNARY_UNARY:
grpc.unary_unary_rpc_method_handler(_test_unary_unary),
_TEST_SET_COMPRESSION:
grpc.stream_stream_rpc_method_handler(_test_set_compression),
_TEST_DISABLE_COMPRESSION_UNARY:
grpc.unary_unary_rpc_method_handler(_test_disable_compression_unary),
_TEST_DISABLE_COMPRESSION_STREAM:
grpc.stream_stream_rpc_method_handler(_test_disable_compression_stream),
}
class _GenericHandler(grpc.GenericRpcHandler):
def service(self, handler_call_details):
return _ROUTING_TABLE.get(handler_call_details.method)
async def _start_test_server(options=None):
server = aio.server(options=options)
port = server.add_insecure_port('[::]:0')
server.add_generic_rpc_handlers((_GenericHandler(),))
await server.start()
return f'localhost:{port}', server
class TestCompression(AioTestBase):
async def setUp(self):
server_options = (_GZIP_DISABLED_CHANNEL_ARGUMENT,)
self._address, self._server = await _start_test_server(server_options)
self._channel = aio.insecure_channel(self._address)
async def tearDown(self):
await self._channel.close()
await self._server.stop(None)
async def test_channel_level_compression_baned_compression(self):
# GZIP is disabled, this call should fail
async with aio.insecure_channel(
self._address, compression=grpc.Compression.Gzip) as channel:
multicallable = channel.unary_unary(_TEST_UNARY_UNARY)
call = multicallable(_REQUEST)
with self.assertRaises(aio.AioRpcError) as exception_context:
await call
rpc_error = exception_context.exception
self.assertEqual(grpc.StatusCode.UNIMPLEMENTED, rpc_error.code())
async def test_channel_level_compression_allowed_compression(self):
# Deflate is allowed, this call should succeed
async with aio.insecure_channel(
self._address, compression=grpc.Compression.Deflate) as channel:
multicallable = channel.unary_unary(_TEST_UNARY_UNARY)
call = multicallable(_REQUEST)
self.assertEqual(grpc.StatusCode.OK, await call.code())
async def test_client_call_level_compression_baned_compression(self):
multicallable = self._channel.unary_unary(_TEST_UNARY_UNARY)
# GZIP is disabled, this call should fail
call = multicallable(_REQUEST, compression=grpc.Compression.Gzip)
with self.assertRaises(aio.AioRpcError) as exception_context:
await call
rpc_error = exception_context.exception
self.assertEqual(grpc.StatusCode.UNIMPLEMENTED, rpc_error.code())
async def test_client_call_level_compression_allowed_compression(self):
multicallable = self._channel.unary_unary(_TEST_UNARY_UNARY)
# Deflate is allowed, this call should succeed
call = multicallable(_REQUEST, compression=grpc.Compression.Deflate)
self.assertEqual(grpc.StatusCode.OK, await call.code())
async def test_server_call_level_compression(self):
multicallable = self._channel.stream_stream(_TEST_SET_COMPRESSION)
call = multicallable()
await call.write(_REQUEST)
await call.done_writing()
self.assertEqual(_RESPONSE, await call.read())
self.assertEqual(grpc.StatusCode.OK, await call.code())
async def test_server_disable_compression_unary(self):
multicallable = self._channel.unary_unary(
_TEST_DISABLE_COMPRESSION_UNARY)
call = multicallable(_REQUEST)
self.assertEqual(_RESPONSE, await call)
self.assertEqual(grpc.StatusCode.OK, await call.code())
async def test_server_disable_compression_stream(self):
multicallable = self._channel.stream_stream(
_TEST_DISABLE_COMPRESSION_STREAM)
call = multicallable()
await call.write(_REQUEST)
await call.done_writing()
self.assertEqual(_RESPONSE, await call.read())
self.assertEqual(_RESPONSE, await call.read())
self.assertEqual(_RESPONSE, await call.read())
self.assertEqual(grpc.StatusCode.OK, await call.code())
async def test_server_default_compression_algorithm(self):
server = aio.server(compression=grpc.Compression.Deflate)
port = server.add_insecure_port('[::]:0')
server.add_generic_rpc_handlers((_GenericHandler(),))
await server.start()
async with aio.insecure_channel(f'localhost:{port}') as channel:
multicallable = channel.unary_unary(_TEST_UNARY_UNARY)
call = multicallable(_REQUEST)
self.assertEqual(_RESPONSE, await call)
self.assertEqual(grpc.StatusCode.OK, await call.code())
await server.stop(None)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
unittest.main(verbosity=2)

@ -102,7 +102,7 @@ class TestConnectivityState(AioTestBase):
# It can raise exceptions since it is an usage error, but it should not
# segfault or abort.
with self.assertRaises(RuntimeError):
with self.assertRaises(aio.UsageError):
await channel.wait_for_state_change(
grpc.ChannelConnectivity.SHUTDOWN)

@ -210,6 +210,8 @@ class TestMetadata(AioTestBase):
self.assertEqual(_RESPONSE, await call)
self.assertEqual(grpc.StatusCode.OK, await call.code())
@unittest.skipIf(platform.system() == 'Windows',
'https://github.com/grpc/grpc/issues/21943')
async def test_invalid_metadata(self):
multicallable = self._client.unary_unary(_TEST_CLIENT_TO_SERVER)
for exception_type, metadata in _INVALID_METADATA_TEST_CASES:

@ -231,14 +231,10 @@ class TestServer(AioTestBase):
# Uses reader API
self.assertEqual(_RESPONSE, await call.read())
# Uses async generator API
response_cnt = 0
async for response in call:
response_cnt += 1
self.assertEqual(_RESPONSE, response)
self.assertEqual(_NUM_STREAM_RESPONSES - 1, response_cnt)
self.assertEqual(await call.code(), grpc.StatusCode.OK)
# Uses async generator API, mixed!
with self.assertRaises(aio.UsageError):
async for response in call:
self.assertEqual(_RESPONSE, response)
async def test_stream_unary_async_generator(self):
stream_unary_call = self._channel.stream_unary(_STREAM_UNARY_ASYNC_GEN)

@ -44,24 +44,22 @@ class TestParsedConfig1 : public ServiceConfig::ParsedConfig {
class TestParser1 : public ServiceConfig::Parser {
public:
std::unique_ptr<ServiceConfig::ParsedConfig> ParseGlobalParams(
const grpc_json* json, grpc_error** error) override {
const Json& json, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
for (grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (strcmp(field->key, "global_param") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage());
return nullptr;
}
int value = gpr_parse_nonnegative_int(field->value);
if (value == -1) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage());
return nullptr;
}
return grpc_core::MakeUnique<TestParsedConfig1>(value);
auto it = json.object_value().find("global_param");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage());
return nullptr;
}
int value = gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (value == -1) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage());
return nullptr;
}
return grpc_core::MakeUnique<TestParsedConfig1>(value);
}
return nullptr;
}
@ -78,27 +76,22 @@ class TestParser1 : public ServiceConfig::Parser {
class TestParser2 : public ServiceConfig::Parser {
public:
std::unique_ptr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* json, grpc_error** error) override {
const Json& json, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
for (grpc_json* field = json->child; field != nullptr;
field = field->next) {
if (field->key == nullptr || strcmp(field->key, "name") == 0) {
continue;
auto it = json.object_value().find("method_param");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::NUMBER) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage());
return nullptr;
}
if (strcmp(field->key, "method_param") == 0) {
if (field->type != GRPC_JSON_NUMBER) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage());
return nullptr;
}
int value = gpr_parse_nonnegative_int(field->value);
if (value == -1) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage());
return nullptr;
}
return grpc_core::MakeUnique<TestParsedConfig1>(value);
int value = gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (value == -1) {
*error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage());
return nullptr;
}
return grpc_core::MakeUnique<TestParsedConfig1>(value);
}
return nullptr;
}
@ -116,14 +109,14 @@ class TestParser2 : public ServiceConfig::Parser {
class ErrorParser : public ServiceConfig::Parser {
public:
std::unique_ptr<ServiceConfig::ParsedConfig> ParsePerMethodParams(
const grpc_json* /*json*/, grpc_error** error) override {
const Json& /*json*/, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(MethodError());
return nullptr;
}
std::unique_ptr<ServiceConfig::ParsedConfig> ParseGlobalParams(
const grpc_json* /*json*/, grpc_error** error) override {
const Json& /*json*/, grpc_error** error) override {
GPR_DEBUG_ASSERT(error != nullptr);
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(GlobalError());
return nullptr;
@ -159,7 +152,7 @@ TEST_F(ServiceConfigTest, ErrorCheck1) {
auto svc_cfg = ServiceConfig::Create(test_json, &error);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(std::string("failed to parse JSON for service config"));
std::regex e(std::string("JSON parse error"));
VerifyRegexMatch(error, e);
}
@ -177,11 +170,10 @@ TEST_F(ServiceConfigTest, ErrorNoNames) {
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors)(.*)(Method "
"Params)(.*)(referenced_errors)(.*)(No names "
"found)(.*)(methodConfig)(.*)(referenced_errors)(.*)(No "
"names specified)"));
std::string("(Service config parsing error)(.*)(referenced_errors)"
"(.*)(Method Params)(.*)(referenced_errors)"
"(.*)(methodConfig)(.*)(referenced_errors)"
"(.*)(No names specified)"));
VerifyRegexMatch(error, e);
}
@ -193,11 +185,10 @@ TEST_F(ServiceConfigTest, ErrorNoNamesWithMultipleMethodConfigs) {
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors)(.*)(Method "
"Params)(.*)(referenced_errors)(.*)(No names "
"found)(.*)(methodConfig)(.*)(referenced_errors)(.*)(No "
"names specified)"));
std::string("(Service config parsing error)(.*)(referenced_errors)"
"(.*)(Method Params)(.*)(referenced_errors)"
"(.*)(methodConfig)(.*)(referenced_errors)"
"(.*)(No names specified)"));
VerifyRegexMatch(error, e);
}
@ -337,18 +328,16 @@ TEST_F(ErroredParsersScopingTest, MethodParams) {
auto svc_cfg = ServiceConfig::Create(test_json, &error);
ASSERT_TRUE(error != GRPC_ERROR_NONE);
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors\":\\[)(.*)(Global "
"Params)(.*)(referenced_errors)()(.*)") +
ErrorParser::GlobalError() + std::string("(.*)") +
ErrorParser::GlobalError() +
std::string("(.*)(Method "
"Params)(.*)(referenced_errors)(.*)(field:methodConfig "
"error:No names "
"found)(.*)(methodConfig)(.*)(referenced_errors)(.*)") +
ErrorParser::MethodError() + std::string("(.*)") +
ErrorParser::MethodError() + std::string("(.*)(No names specified)"));
std::regex e(std::string("(Service config parsing "
"error)(.*)(referenced_errors\":\\[)(.*)(Global "
"Params)(.*)(referenced_errors)()(.*)") +
ErrorParser::GlobalError() + std::string("(.*)") +
ErrorParser::GlobalError() +
std::string("(.*)(Method Params)(.*)(referenced_errors)"
"(.*)(methodConfig)(.*)(referenced_errors)(.*)") +
ErrorParser::MethodError() + std::string("(.*)") +
ErrorParser::MethodError() +
std::string("(.*)(No names specified)"));
VerifyRegexMatch(error, e);
}
@ -428,11 +417,11 @@ TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors)(.*)(Global "
"Params)(.*)(referenced_errors)(.*)(Client channel global "
"parser)(.*)(referenced_errors)(.*)(field:"
"loadBalancingConfig error:No known policy)"));
std::string("(Service config parsing error)(.*)(referenced_errors)"
"(.*)(Global Params)(.*)(referenced_errors)"
"(.*)(Client channel global parser)(.*)(referenced_errors)"
"(.*)(field:loadBalancingConfig)(.*)(referenced_errors)"
"(.*)(No known policy)"));
VerifyRegexMatch(error, e);
}
@ -445,12 +434,13 @@ TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors)(.*)(Global "
"Params)(.*)(referenced_errors)(.*)(Client channel global "
"parser)(.*)(referenced_errors)(.*)(GrpcLb "
"Parser)(.*)(referenced_errors)(.*)(field:childPolicy "
"error:No known policy)"));
std::string("(Service config parsing error)(.*)(referenced_errors)"
"(.*)(Global Params)(.*)(referenced_errors)"
"(.*)(Client channel global parser)(.*)(referenced_errors)"
"(.*)(field:loadBalancingConfig)(.*)(referenced_errors)"
"(.*)(GrpcLb Parser)(.*)(referenced_errors)"
"(.*)(field:childPolicy)(.*)(referenced_errors)"
"(.*)(No known policy)"));
VerifyRegexMatch(error, e);
}
@ -914,10 +904,8 @@ TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
gpr_log(GPR_ERROR, "%s", grpc_error_string(error));
ASSERT_TRUE(error != GRPC_ERROR_NONE);
std::regex e(
std::string("(Service config parsing "
"error)(.*)(referenced_errors)(.*)(Global "
"Params)(.*)(referenced_errors)(.*)(field:healthCheckConfig "
"error:Duplicate entry)"));
std::string("(JSON parsing failed)(.*)(referenced_errors)"
"(.*)(duplicate key \"healthCheckConfig\" at index 104)"));
VerifyRegexMatch(error, e);
}

@ -83,7 +83,7 @@ TEST(XdsBootstrapTest, Basic) {
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
ASSERT_EQ(bootstrap.server().channel_creds.size(), 1);
ASSERT_EQ(bootstrap.server().channel_creds.size(), 1UL);
EXPECT_EQ(bootstrap.server().channel_creds[0].type, "fake");
EXPECT_EQ(bootstrap.server().channel_creds[0].config.type(),
Json::Type::JSON_NULL);
@ -123,7 +123,7 @@ TEST(XdsBootstrapTest, ValidWithoutChannelCredsAndNode) {
grpc_core::XdsBootstrap bootstrap(std::move(json), &error);
EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
EXPECT_EQ(bootstrap.server().channel_creds.size(), 0);
EXPECT_EQ(bootstrap.server().channel_creds.size(), 0UL);
EXPECT_EQ(bootstrap.node(), nullptr);
}

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

Loading…
Cancel
Save