Merge branch 'master' into fixes

pull/6888/head
yang-g 9 years ago
commit 4bcd135824
  1. 17
      .travis.yml
  2. 132
      BUILD
  3. 706
      Makefile
  4. 5
      binding.gyp
  5. 152
      build.yaml
  6. 1
      composer.json
  7. 5
      config.m4
  8. 2
      doc/c-style-guide.md
  9. 91
      doc/cpp-style-guide.md
  10. 2
      doc/statuscodes.md
  11. 2
      examples/python/route_guide/route_guide_server.py
  12. 15
      gRPC.podspec
  13. 2
      grpc.def
  14. 10
      grpc.gemspec
  15. 69
      include/grpc++/ext/proto_server_reflection_plugin.h
  16. 184
      include/grpc++/ext/reflection.grpc.pb.h
  17. 2035
      include/grpc++/ext/reflection.pb.h
  18. 2
      include/grpc++/impl/codegen/call.h
  19. 17
      include/grpc++/impl/codegen/config.h
  20. 22
      include/grpc++/impl/codegen/config_protobuf.h
  21. 46
      include/grpc++/impl/codegen/core_codegen.h
  22. 8
      include/grpc++/impl/codegen/server_interface.h
  23. 3
      include/grpc++/impl/server_builder_option.h
  24. 19
      include/grpc++/server_builder.h
  25. 3
      include/grpc/impl/codegen/log.h
  26. 13
      include/grpc/impl/codegen/port_platform.h
  27. 5
      include/grpc/support/avl.h
  28. 3
      include/grpc/support/string_util.h
  29. 25
      package.xml
  30. 1
      setup.py
  31. 18
      src/compiler/config.h
  32. 7
      src/compiler/cpp_generator.cc
  33. 3
      src/compiler/generator_helpers.h
  34. 14
      src/compiler/node_generator.cc
  35. 146
      src/compiler/python_generator.cc
  36. 1
      src/compiler/python_generator.h
  37. 1
      src/compiler/python_plugin.cc
  38. 6
      src/core/ext/census/grpc_filter.c
  39. 34
      src/core/ext/client_config/channel_connectivity.c
  40. 89
      src/core/ext/client_config/client_channel.c
  41. 2
      src/core/ext/client_config/connector.h
  42. 11
      src/core/ext/client_config/lb_policy.c
  43. 8
      src/core/ext/client_config/lb_policy.h
  44. 65
      src/core/ext/client_config/subchannel.c
  45. 2
      src/core/ext/client_config/subchannel.h
  46. 47
      src/core/ext/client_config/subchannel_call_holder.c
  47. 76
      src/core/ext/lb_policy/pick_first/pick_first.c
  48. 61
      src/core/ext/lb_policy/round_robin/round_robin.c
  49. 30
      src/core/ext/resolver/dns/native/dns_resolver.c
  50. 4
      src/core/ext/resolver/sockaddr/sockaddr_resolver.c
  51. 513
      src/core/ext/resolver/zookeeper/zookeeper_resolver.c
  52. 8
      src/core/ext/transport/chttp2/client/insecure/channel_create.c
  53. 24
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
  54. 62
      src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
  55. 80
      src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
  56. 232
      src/core/ext/transport/chttp2/transport/bin_decoder.c
  57. 66
      src/core/ext/transport/chttp2/transport/bin_decoder.h
  58. 394
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  59. 8
      src/core/ext/transport/chttp2/transport/frame.h
  60. 71
      src/core/ext/transport/chttp2/transport/frame_data.c
  61. 11
      src/core/ext/transport/chttp2/transport/frame_data.h
  62. 37
      src/core/ext/transport/chttp2/transport/frame_goaway.c
  63. 4
      src/core/ext/transport/chttp2/transport/frame_goaway.h
  64. 19
      src/core/ext/transport/chttp2/transport/frame_ping.c
  65. 6
      src/core/ext/transport/chttp2/transport/frame_ping.h
  66. 24
      src/core/ext/transport/chttp2/transport/frame_rst_stream.c
  67. 4
      src/core/ext/transport/chttp2/transport/frame_rst_stream.h
  68. 42
      src/core/ext/transport/chttp2/transport/frame_settings.c
  69. 4
      src/core/ext/transport/chttp2/transport/frame_settings.h
  70. 24
      src/core/ext/transport/chttp2/transport/frame_window_update.c
  71. 4
      src/core/ext/transport/chttp2/transport/frame_window_update.h
  72. 560
      src/core/ext/transport/chttp2/transport/hpack_parser.c
  73. 14
      src/core/ext/transport/chttp2/transport/hpack_parser.h
  74. 32
      src/core/ext/transport/chttp2/transport/hpack_table.c
  75. 5
      src/core/ext/transport/chttp2/transport/hpack_table.h
  76. 35
      src/core/ext/transport/chttp2/transport/internal.h
  77. 313
      src/core/ext/transport/chttp2/transport/parsing.c
  78. 17
      src/core/ext/transport/chttp2/transport/writing.c
  79. 4
      src/core/ext/transport/cronet/transport/cronet_transport.c
  80. 3
      src/core/lib/channel/channel_args.c
  81. 16
      src/core/lib/channel/compress_filter.c
  82. 5
      src/core/lib/channel/http_client_filter.c
  83. 27
      src/core/lib/channel/http_server_filter.c
  84. 123
      src/core/lib/http/httpcli.c
  85. 21
      src/core/lib/http/httpcli.h
  86. 6
      src/core/lib/http/httpcli_security_connector.c
  87. 238
      src/core/lib/http/parser.c
  88. 357
      src/core/lib/http/parser.c.orig
  89. 17
      src/core/lib/http/parser.h
  90. 36
      src/core/lib/iomgr/closure.c
  91. 34
      src/core/lib/iomgr/closure.h
  92. 2
      src/core/lib/iomgr/endpoint.h
  93. 4
      src/core/lib/iomgr/endpoint_pair_posix.c
  94. 535
      src/core/lib/iomgr/error.c
  95. 192
      src/core/lib/iomgr/error.h
  96. 185
      src/core/lib/iomgr/ev_poll_and_epoll_posix.c
  97. 133
      src/core/lib/iomgr/ev_poll_posix.c
  98. 14
      src/core/lib/iomgr/ev_posix.c
  99. 12
      src/core/lib/iomgr/ev_posix.h
  100. 13
      src/core/lib/iomgr/exec_ctx.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,20 +1,23 @@
language: objective-c language: objective-c
osx_image: xcode7.2 osx_image: xcode7.3
env: env:
global: global:
- CONFIG=opt - CONFIG=opt
- TEST=objc - TEST=objc
- JOBS=1 - JOBS=1
before_install: before_install:
- pod --version
- gem uninstall cocoapods -a
- gem install cocoapods -v '1.0.0'
- pod --version
- brew install gflags - brew install gflags
# Pod install does this too, but we don't want the output. - pushd third_party/protobuf
- pod repo update --silent - git checkout v3.0.0-beta-3
- popd
install: install:
- make grpc_objective_c_plugin - make grpc_objective_c_plugin
- pushd src/objective-c/tests - pushd src/objective-c/tests
# Needs to be verbose, or otherwise OpenSSL's prepare_command makes Travis - pod install
# time out:
- pod install --verbose
- popd - popd
before_script: before_script:
- make interop_server - make interop_server
@ -27,6 +30,6 @@ xcode_scheme:
- InteropTestsLocalCleartext - InteropTestsLocalCleartext
# TODO(jcanizales): Investigate why they time out: # TODO(jcanizales): Investigate why they time out:
# - InteropTestsRemote # - InteropTestsRemote
xcode_sdk: iphonesimulator9.2 xcode_sdk: iphonesimulator9.3
notifications: notifications:
email: false email: false

132
BUILD

@ -49,7 +49,6 @@ cc_library(
"src/core/lib/support/backoff.h", "src/core/lib/support/backoff.h",
"src/core/lib/support/block_annotate.h", "src/core/lib/support/block_annotate.h",
"src/core/lib/support/env.h", "src/core/lib/support/env.h",
"src/core/lib/support/load_file.h",
"src/core/lib/support/murmur_hash.h", "src/core/lib/support/murmur_hash.h",
"src/core/lib/support/stack_lockfree.h", "src/core/lib/support/stack_lockfree.h",
"src/core/lib/support/string.h", "src/core/lib/support/string.h",
@ -72,7 +71,6 @@ cc_library(
"src/core/lib/support/env_windows.c", "src/core/lib/support/env_windows.c",
"src/core/lib/support/histogram.c", "src/core/lib/support/histogram.c",
"src/core/lib/support/host_port.c", "src/core/lib/support/host_port.c",
"src/core/lib/support/load_file.c",
"src/core/lib/support/log.c", "src/core/lib/support/log.c",
"src/core/lib/support/log_android.c", "src/core/lib/support/log_android.c",
"src/core/lib/support/log_linux.c", "src/core/lib/support/log_linux.c",
@ -178,6 +176,7 @@ cc_library(
"src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
"src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/ev_posix.h",
@ -187,6 +186,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr.h",
"src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_internal.h",
"src/core/lib/iomgr/iomgr_posix.h", "src/core/lib/iomgr/iomgr_posix.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset.h",
"src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set.h",
@ -236,6 +236,7 @@ cc_library(
"src/core/lib/transport/static_metadata.h", "src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/transport.h", "src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h", "src/core/lib/transport/transport_impl.h",
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
@ -273,6 +274,7 @@ cc_library(
"src/core/lib/security/transport/handshake.h", "src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h", "src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h", "src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
"src/core/lib/tsi/fake_transport_security.h", "src/core/lib/tsi/fake_transport_security.h",
@ -325,6 +327,7 @@ cc_library(
"src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint.c",
"src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_posix.c",
"src/core/lib/iomgr/endpoint_pair_windows.c", "src/core/lib/iomgr/endpoint_pair_windows.c",
"src/core/lib/iomgr/error.c",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
"src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_poll_posix.c",
"src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/ev_posix.c",
@ -334,6 +337,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr.c",
"src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_posix.c",
"src/core/lib/iomgr/iomgr_windows.c", "src/core/lib/iomgr/iomgr_windows.c",
"src/core/lib/iomgr/load_file.c",
"src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/polling_entity.c",
"src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_set_windows.c",
"src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/pollset_windows.c",
@ -392,6 +396,7 @@ cc_library(
"src/core/lib/transport/transport.c", "src/core/lib/transport/transport.c",
"src/core/lib/transport/transport_op_string.c", "src/core/lib/transport/transport_op_string.c",
"src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c", "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
"src/core/ext/transport/chttp2/transport/bin_decoder.c",
"src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
"src/core/ext/transport/chttp2/transport/chttp2_transport.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
@ -435,6 +440,7 @@ cc_library(
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.c", "src/core/lib/security/util/b64.c",
"src/core/lib/security/util/json_util.c", "src/core/lib/security/util/json_util.c",
"src/core/lib/surface/init_secure.c", "src/core/lib/surface/init_secure.c",
@ -554,6 +560,7 @@ cc_library(
"src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
"src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/ev_posix.h",
@ -563,6 +570,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr.h",
"src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_internal.h",
"src/core/lib/iomgr/iomgr_posix.h", "src/core/lib/iomgr/iomgr_posix.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset.h",
"src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set.h",
@ -613,6 +621,7 @@ cc_library(
"src/core/lib/transport/transport.h", "src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h", "src/core/lib/transport/transport_impl.h",
"third_party/objective_c/Cronet/cronet_c_for_grpc.h", "third_party/objective_c/Cronet/cronet_c_for_grpc.h",
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
@ -666,6 +675,7 @@ cc_library(
"src/core/lib/security/transport/handshake.h", "src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h", "src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h", "src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
"src/core/lib/tsi/fake_transport_security.h", "src/core/lib/tsi/fake_transport_security.h",
@ -691,6 +701,7 @@ cc_library(
"src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint.c",
"src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_posix.c",
"src/core/lib/iomgr/endpoint_pair_windows.c", "src/core/lib/iomgr/endpoint_pair_windows.c",
"src/core/lib/iomgr/error.c",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
"src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_poll_posix.c",
"src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/ev_posix.c",
@ -700,6 +711,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr.c",
"src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_posix.c",
"src/core/lib/iomgr/iomgr_windows.c", "src/core/lib/iomgr/iomgr_windows.c",
"src/core/lib/iomgr/load_file.c",
"src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/polling_entity.c",
"src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_set_windows.c",
"src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/pollset_windows.c",
@ -761,6 +773,7 @@ cc_library(
"src/core/ext/transport/cronet/transport/cronet_api_dummy.c", "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
"src/core/ext/transport/cronet/transport/cronet_transport.c", "src/core/ext/transport/cronet/transport/cronet_transport.c",
"src/core/ext/transport/chttp2/client/secure/secure_channel_create.c", "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
"src/core/ext/transport/chttp2/transport/bin_decoder.c",
"src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
"src/core/ext/transport/chttp2/transport/chttp2_transport.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
@ -823,6 +836,7 @@ cc_library(
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.c", "src/core/lib/security/util/b64.c",
"src/core/lib/security/util/json_util.c", "src/core/lib/security/util/json_util.c",
"src/core/lib/surface/init_secure.c", "src/core/lib/surface/init_secure.c",
@ -895,6 +909,7 @@ cc_library(
"src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
"src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/ev_posix.h",
@ -904,6 +919,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr.h",
"src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_internal.h",
"src/core/lib/iomgr/iomgr_posix.h", "src/core/lib/iomgr/iomgr_posix.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset.h",
"src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set.h",
@ -953,6 +969,7 @@ cc_library(
"src/core/lib/transport/static_metadata.h", "src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/transport.h", "src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h", "src/core/lib/transport/transport_impl.h",
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
@ -1020,6 +1037,7 @@ cc_library(
"src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint.c",
"src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_posix.c",
"src/core/lib/iomgr/endpoint_pair_windows.c", "src/core/lib/iomgr/endpoint_pair_windows.c",
"src/core/lib/iomgr/error.c",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
"src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_poll_posix.c",
"src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/ev_posix.c",
@ -1029,6 +1047,7 @@ cc_library(
"src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr.c",
"src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_posix.c",
"src/core/lib/iomgr/iomgr_windows.c", "src/core/lib/iomgr/iomgr_windows.c",
"src/core/lib/iomgr/load_file.c",
"src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/polling_entity.c",
"src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_set_windows.c",
"src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/pollset_windows.c",
@ -1088,6 +1107,7 @@ cc_library(
"src/core/lib/transport/transport_op_string.c", "src/core/lib/transport/transport_op_string.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/transport/bin_decoder.c",
"src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
"src/core/ext/transport/chttp2/transport/chttp2_transport.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
@ -1196,26 +1216,6 @@ cc_library(
cc_library(
name = "grpc_zookeeper",
srcs = [
"src/core/ext/resolver/zookeeper/zookeeper_resolver.c",
],
hdrs = [
"include/grpc/grpc_zookeeper.h",
],
includes = [
"include",
".",
],
deps = [
":gpr",
":grpc",
],
)
cc_library( cc_library(
name = "grpc++", name = "grpc++",
srcs = [ srcs = [
@ -1373,6 +1373,84 @@ cc_library(
cc_library(
name = "grpc++_reflection",
srcs = [
"src/cpp/ext/proto_server_reflection.h",
"src/cpp/ext/proto_server_reflection.cc",
"src/cpp/ext/proto_server_reflection_plugin.cc",
"src/cpp/ext/reflection.grpc.pb.cc",
"src/cpp/ext/reflection.pb.cc",
],
hdrs = [
"include/grpc++/ext/proto_server_reflection_plugin.h",
"include/grpc++/ext/reflection.grpc.pb.h",
"include/grpc++/ext/reflection.pb.h",
"include/grpc++/impl/codegen/proto_utils.h",
"include/grpc++/impl/codegen/async_stream.h",
"include/grpc++/impl/codegen/async_unary_call.h",
"include/grpc++/impl/codegen/call.h",
"include/grpc++/impl/codegen/call_hook.h",
"include/grpc++/impl/codegen/channel_interface.h",
"include/grpc++/impl/codegen/client_context.h",
"include/grpc++/impl/codegen/client_unary_call.h",
"include/grpc++/impl/codegen/completion_queue.h",
"include/grpc++/impl/codegen/completion_queue_tag.h",
"include/grpc++/impl/codegen/config.h",
"include/grpc++/impl/codegen/core_codegen_interface.h",
"include/grpc++/impl/codegen/create_auth_context.h",
"include/grpc++/impl/codegen/grpc_library.h",
"include/grpc++/impl/codegen/method_handler_impl.h",
"include/grpc++/impl/codegen/rpc_method.h",
"include/grpc++/impl/codegen/rpc_service_method.h",
"include/grpc++/impl/codegen/security/auth_context.h",
"include/grpc++/impl/codegen/serialization_traits.h",
"include/grpc++/impl/codegen/server_context.h",
"include/grpc++/impl/codegen/server_interface.h",
"include/grpc++/impl/codegen/service_type.h",
"include/grpc++/impl/codegen/status.h",
"include/grpc++/impl/codegen/status_code_enum.h",
"include/grpc++/impl/codegen/string_ref.h",
"include/grpc++/impl/codegen/stub_options.h",
"include/grpc++/impl/codegen/sync.h",
"include/grpc++/impl/codegen/sync_cxx11.h",
"include/grpc++/impl/codegen/sync_no_cxx11.h",
"include/grpc++/impl/codegen/sync_stream.h",
"include/grpc++/impl/codegen/time.h",
"include/grpc/impl/codegen/byte_buffer.h",
"include/grpc/impl/codegen/byte_buffer_reader.h",
"include/grpc/impl/codegen/compression_types.h",
"include/grpc/impl/codegen/connectivity_state.h",
"include/grpc/impl/codegen/grpc_types.h",
"include/grpc/impl/codegen/propagation_bits.h",
"include/grpc/impl/codegen/status.h",
"include/grpc/impl/codegen/alloc.h",
"include/grpc/impl/codegen/atm.h",
"include/grpc/impl/codegen/atm_gcc_atomic.h",
"include/grpc/impl/codegen/atm_gcc_sync.h",
"include/grpc/impl/codegen/atm_windows.h",
"include/grpc/impl/codegen/log.h",
"include/grpc/impl/codegen/port_platform.h",
"include/grpc/impl/codegen/slice.h",
"include/grpc/impl/codegen/slice_buffer.h",
"include/grpc/impl/codegen/sync.h",
"include/grpc/impl/codegen/sync_generic.h",
"include/grpc/impl/codegen/sync_posix.h",
"include/grpc/impl/codegen/sync_windows.h",
"include/grpc/impl/codegen/time.h",
"include/grpc++/impl/codegen/config_protobuf.h",
],
includes = [
"include",
".",
],
deps = [
":grpc++",
],
)
cc_library( cc_library(
name = "grpc++_unsecure", name = "grpc++_unsecure",
srcs = [ srcs = [
@ -1599,7 +1677,6 @@ objc_library(
"src/core/lib/support/env_windows.c", "src/core/lib/support/env_windows.c",
"src/core/lib/support/histogram.c", "src/core/lib/support/histogram.c",
"src/core/lib/support/host_port.c", "src/core/lib/support/host_port.c",
"src/core/lib/support/load_file.c",
"src/core/lib/support/log.c", "src/core/lib/support/log.c",
"src/core/lib/support/log_android.c", "src/core/lib/support/log_android.c",
"src/core/lib/support/log_linux.c", "src/core/lib/support/log_linux.c",
@ -1678,7 +1755,6 @@ objc_library(
"src/core/lib/support/backoff.h", "src/core/lib/support/backoff.h",
"src/core/lib/support/block_annotate.h", "src/core/lib/support/block_annotate.h",
"src/core/lib/support/env.h", "src/core/lib/support/env.h",
"src/core/lib/support/load_file.h",
"src/core/lib/support/murmur_hash.h", "src/core/lib/support/murmur_hash.h",
"src/core/lib/support/stack_lockfree.h", "src/core/lib/support/stack_lockfree.h",
"src/core/lib/support/string.h", "src/core/lib/support/string.h",
@ -1718,6 +1794,7 @@ objc_library(
"src/core/lib/iomgr/endpoint.c", "src/core/lib/iomgr/endpoint.c",
"src/core/lib/iomgr/endpoint_pair_posix.c", "src/core/lib/iomgr/endpoint_pair_posix.c",
"src/core/lib/iomgr/endpoint_pair_windows.c", "src/core/lib/iomgr/endpoint_pair_windows.c",
"src/core/lib/iomgr/error.c",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.c", "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
"src/core/lib/iomgr/ev_poll_posix.c", "src/core/lib/iomgr/ev_poll_posix.c",
"src/core/lib/iomgr/ev_posix.c", "src/core/lib/iomgr/ev_posix.c",
@ -1727,6 +1804,7 @@ objc_library(
"src/core/lib/iomgr/iomgr.c", "src/core/lib/iomgr/iomgr.c",
"src/core/lib/iomgr/iomgr_posix.c", "src/core/lib/iomgr/iomgr_posix.c",
"src/core/lib/iomgr/iomgr_windows.c", "src/core/lib/iomgr/iomgr_windows.c",
"src/core/lib/iomgr/load_file.c",
"src/core/lib/iomgr/polling_entity.c", "src/core/lib/iomgr/polling_entity.c",
"src/core/lib/iomgr/pollset_set_windows.c", "src/core/lib/iomgr/pollset_set_windows.c",
"src/core/lib/iomgr/pollset_windows.c", "src/core/lib/iomgr/pollset_windows.c",
@ -1785,6 +1863,7 @@ objc_library(
"src/core/lib/transport/transport.c", "src/core/lib/transport/transport.c",
"src/core/lib/transport/transport_op_string.c", "src/core/lib/transport/transport_op_string.c",
"src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c", "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
"src/core/ext/transport/chttp2/transport/bin_decoder.c",
"src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
"src/core/ext/transport/chttp2/transport/chttp2_transport.c", "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
@ -1828,6 +1907,7 @@ objc_library(
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.c", "src/core/lib/security/util/b64.c",
"src/core/lib/security/util/json_util.c", "src/core/lib/security/util/json_util.c",
"src/core/lib/surface/init_secure.c", "src/core/lib/surface/init_secure.c",
@ -1926,6 +2006,7 @@ objc_library(
"src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/closure.h",
"src/core/lib/iomgr/endpoint.h", "src/core/lib/iomgr/endpoint.h",
"src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/endpoint_pair.h",
"src/core/lib/iomgr/error.h",
"src/core/lib/iomgr/ev_poll_and_epoll_posix.h", "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
"src/core/lib/iomgr/ev_poll_posix.h", "src/core/lib/iomgr/ev_poll_posix.h",
"src/core/lib/iomgr/ev_posix.h", "src/core/lib/iomgr/ev_posix.h",
@ -1935,6 +2016,7 @@ objc_library(
"src/core/lib/iomgr/iomgr.h", "src/core/lib/iomgr/iomgr.h",
"src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_internal.h",
"src/core/lib/iomgr/iomgr_posix.h", "src/core/lib/iomgr/iomgr_posix.h",
"src/core/lib/iomgr/load_file.h",
"src/core/lib/iomgr/polling_entity.h", "src/core/lib/iomgr/polling_entity.h",
"src/core/lib/iomgr/pollset.h", "src/core/lib/iomgr/pollset.h",
"src/core/lib/iomgr/pollset_set.h", "src/core/lib/iomgr/pollset_set.h",
@ -1984,6 +2066,7 @@ objc_library(
"src/core/lib/transport/static_metadata.h", "src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/transport.h", "src/core/lib/transport/transport.h",
"src/core/lib/transport/transport_impl.h", "src/core/lib/transport/transport_impl.h",
"src/core/ext/transport/chttp2/transport/bin_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
"src/core/ext/transport/chttp2/transport/frame.h", "src/core/ext/transport/chttp2/transport/frame.h",
@ -2021,6 +2104,7 @@ objc_library(
"src/core/lib/security/transport/handshake.h", "src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h", "src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h", "src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
"src/core/lib/tsi/fake_transport_security.h", "src/core/lib/tsi/fake_transport_security.h",

File diff suppressed because it is too large Load Diff

@ -510,7 +510,6 @@
'src/core/lib/support/env_windows.c', 'src/core/lib/support/env_windows.c',
'src/core/lib/support/histogram.c', 'src/core/lib/support/histogram.c',
'src/core/lib/support/host_port.c', 'src/core/lib/support/host_port.c',
'src/core/lib/support/load_file.c',
'src/core/lib/support/log.c', 'src/core/lib/support/log.c',
'src/core/lib/support/log_android.c', 'src/core/lib/support/log_android.c',
'src/core/lib/support/log_linux.c', 'src/core/lib/support/log_linux.c',
@ -581,6 +580,7 @@
'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint.c',
'src/core/lib/iomgr/endpoint_pair_posix.c', 'src/core/lib/iomgr/endpoint_pair_posix.c',
'src/core/lib/iomgr/endpoint_pair_windows.c', 'src/core/lib/iomgr/endpoint_pair_windows.c',
'src/core/lib/iomgr/error.c',
'src/core/lib/iomgr/ev_poll_and_epoll_posix.c', 'src/core/lib/iomgr/ev_poll_and_epoll_posix.c',
'src/core/lib/iomgr/ev_poll_posix.c', 'src/core/lib/iomgr/ev_poll_posix.c',
'src/core/lib/iomgr/ev_posix.c', 'src/core/lib/iomgr/ev_posix.c',
@ -590,6 +590,7 @@
'src/core/lib/iomgr/iomgr.c', 'src/core/lib/iomgr/iomgr.c',
'src/core/lib/iomgr/iomgr_posix.c', 'src/core/lib/iomgr/iomgr_posix.c',
'src/core/lib/iomgr/iomgr_windows.c', 'src/core/lib/iomgr/iomgr_windows.c',
'src/core/lib/iomgr/load_file.c',
'src/core/lib/iomgr/polling_entity.c', 'src/core/lib/iomgr/polling_entity.c',
'src/core/lib/iomgr/pollset_set_windows.c', 'src/core/lib/iomgr/pollset_set_windows.c',
'src/core/lib/iomgr/pollset_windows.c', 'src/core/lib/iomgr/pollset_windows.c',
@ -648,6 +649,7 @@
'src/core/lib/transport/transport.c', 'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c', 'src/core/lib/transport/transport_op_string.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c', 'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c', 'src/core/ext/transport/chttp2/transport/bin_encoder.c',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.c', 'src/core/ext/transport/chttp2/transport/chttp2_plugin.c',
'src/core/ext/transport/chttp2/transport/chttp2_transport.c', 'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
@ -691,6 +693,7 @@
'src/core/lib/security/transport/secure_endpoint.c', 'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c', 'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/server_auth_filter.c', 'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c', 'src/core/lib/security/util/b64.c',
'src/core/lib/security/util/json_util.c', 'src/core/lib/security/util/json_util.c',
'src/core/lib/surface/init_secure.c', 'src/core/lib/surface/init_secure.c',

@ -70,7 +70,6 @@ filegroups:
- src/core/lib/support/backoff.h - src/core/lib/support/backoff.h
- src/core/lib/support/block_annotate.h - src/core/lib/support/block_annotate.h
- src/core/lib/support/env.h - src/core/lib/support/env.h
- src/core/lib/support/load_file.h
- src/core/lib/support/murmur_hash.h - src/core/lib/support/murmur_hash.h
- src/core/lib/support/stack_lockfree.h - src/core/lib/support/stack_lockfree.h
- src/core/lib/support/string.h - src/core/lib/support/string.h
@ -94,7 +93,6 @@ filegroups:
- src/core/lib/support/env_windows.c - src/core/lib/support/env_windows.c
- src/core/lib/support/histogram.c - src/core/lib/support/histogram.c
- src/core/lib/support/host_port.c - src/core/lib/support/host_port.c
- src/core/lib/support/load_file.c
- src/core/lib/support/log.c - src/core/lib/support/log.c
- src/core/lib/support/log_android.c - src/core/lib/support/log_android.c
- src/core/lib/support/log_linux.c - src/core/lib/support/log_linux.c
@ -174,6 +172,7 @@ filegroups:
- src/core/lib/iomgr/closure.h - src/core/lib/iomgr/closure.h
- src/core/lib/iomgr/endpoint.h - src/core/lib/iomgr/endpoint.h
- src/core/lib/iomgr/endpoint_pair.h - src/core/lib/iomgr/endpoint_pair.h
- src/core/lib/iomgr/error.h
- src/core/lib/iomgr/ev_poll_and_epoll_posix.h - src/core/lib/iomgr/ev_poll_and_epoll_posix.h
- src/core/lib/iomgr/ev_poll_posix.h - src/core/lib/iomgr/ev_poll_posix.h
- src/core/lib/iomgr/ev_posix.h - src/core/lib/iomgr/ev_posix.h
@ -183,6 +182,7 @@ filegroups:
- src/core/lib/iomgr/iomgr.h - src/core/lib/iomgr/iomgr.h
- src/core/lib/iomgr/iomgr_internal.h - src/core/lib/iomgr/iomgr_internal.h
- src/core/lib/iomgr/iomgr_posix.h - src/core/lib/iomgr/iomgr_posix.h
- src/core/lib/iomgr/load_file.h
- src/core/lib/iomgr/polling_entity.h - src/core/lib/iomgr/polling_entity.h
- src/core/lib/iomgr/pollset.h - src/core/lib/iomgr/pollset.h
- src/core/lib/iomgr/pollset_set.h - src/core/lib/iomgr/pollset_set.h
@ -250,6 +250,7 @@ filegroups:
- src/core/lib/iomgr/endpoint.c - src/core/lib/iomgr/endpoint.c
- src/core/lib/iomgr/endpoint_pair_posix.c - src/core/lib/iomgr/endpoint_pair_posix.c
- src/core/lib/iomgr/endpoint_pair_windows.c - src/core/lib/iomgr/endpoint_pair_windows.c
- src/core/lib/iomgr/error.c
- src/core/lib/iomgr/ev_poll_and_epoll_posix.c - src/core/lib/iomgr/ev_poll_and_epoll_posix.c
- src/core/lib/iomgr/ev_poll_posix.c - src/core/lib/iomgr/ev_poll_posix.c
- src/core/lib/iomgr/ev_posix.c - src/core/lib/iomgr/ev_posix.c
@ -259,6 +260,7 @@ filegroups:
- src/core/lib/iomgr/iomgr.c - src/core/lib/iomgr/iomgr.c
- src/core/lib/iomgr/iomgr_posix.c - src/core/lib/iomgr/iomgr_posix.c
- src/core/lib/iomgr/iomgr_windows.c - src/core/lib/iomgr/iomgr_windows.c
- src/core/lib/iomgr/load_file.c
- src/core/lib/iomgr/polling_entity.c - src/core/lib/iomgr/polling_entity.c
- src/core/lib/iomgr/pollset_set_windows.c - src/core/lib/iomgr/pollset_set_windows.c
- src/core/lib/iomgr/pollset_windows.c - src/core/lib/iomgr/pollset_windows.c
@ -442,6 +444,7 @@ filegroups:
- src/core/lib/security/transport/handshake.h - src/core/lib/security/transport/handshake.h
- src/core/lib/security/transport/secure_endpoint.h - src/core/lib/security/transport/secure_endpoint.h
- src/core/lib/security/transport/security_connector.h - src/core/lib/security/transport/security_connector.h
- src/core/lib/security/transport/tsi_error.h
- src/core/lib/security/util/b64.h - src/core/lib/security/util/b64.h
- src/core/lib/security/util/json_util.h - src/core/lib/security/util/json_util.h
src: src:
@ -466,6 +469,7 @@ filegroups:
- src/core/lib/security/transport/secure_endpoint.c - src/core/lib/security/transport/secure_endpoint.c
- src/core/lib/security/transport/security_connector.c - src/core/lib/security/transport/security_connector.c
- src/core/lib/security/transport/server_auth_filter.c - src/core/lib/security/transport/server_auth_filter.c
- src/core/lib/security/transport/tsi_error.c
- src/core/lib/security/util/b64.c - src/core/lib/security/util/b64.c
- src/core/lib/security/util/json_util.c - src/core/lib/security/util/json_util.c
- src/core/lib/surface/init_secure.c - src/core/lib/surface/init_secure.c
@ -506,6 +510,7 @@ filegroups:
- gpr_test_util - gpr_test_util
- name: grpc_transport_chttp2 - name: grpc_transport_chttp2
headers: headers:
- src/core/ext/transport/chttp2/transport/bin_decoder.h
- src/core/ext/transport/chttp2/transport/bin_encoder.h - src/core/ext/transport/chttp2/transport/bin_encoder.h
- src/core/ext/transport/chttp2/transport/chttp2_transport.h - src/core/ext/transport/chttp2/transport/chttp2_transport.h
- src/core/ext/transport/chttp2/transport/frame.h - src/core/ext/transport/chttp2/transport/frame.h
@ -527,6 +532,7 @@ filegroups:
- src/core/ext/transport/chttp2/transport/timeout_encoding.h - src/core/ext/transport/chttp2/transport/timeout_encoding.h
- src/core/ext/transport/chttp2/transport/varint.h - src/core/ext/transport/chttp2/transport/varint.h
src: src:
- src/core/ext/transport/chttp2/transport/bin_decoder.c
- src/core/ext/transport/chttp2/transport/bin_encoder.c - src/core/ext/transport/chttp2/transport/bin_encoder.c
- src/core/ext/transport/chttp2/transport/chttp2_plugin.c - src/core/ext/transport/chttp2/transport/chttp2_plugin.c
- src/core/ext/transport/chttp2/transport/chttp2_transport.c - src/core/ext/transport/chttp2/transport/chttp2_transport.c
@ -895,21 +901,6 @@ libs:
generate_plugin_registry: true generate_plugin_registry: true
secure: false secure: false
vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}' vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
- name: grpc_zookeeper
build: all
language: c
public_headers:
- include/grpc/grpc_zookeeper.h
src:
- src/core/ext/resolver/zookeeper/zookeeper_resolver.c
deps:
- gpr
- grpc
external_deps:
- zookeeper
platforms:
- linux
secure: false
- name: reconnect_server - name: reconnect_server
build: private build: private
language: c language: c
@ -960,6 +951,24 @@ libs:
- grpc++_codegen_base_src - grpc++_codegen_base_src
secure: check secure: check
vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}' vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}'
- name: grpc++_reflection
build: all
language: c++
public_headers:
- include/grpc++/ext/proto_server_reflection_plugin.h
- include/grpc++/ext/reflection.grpc.pb.h
- include/grpc++/ext/reflection.pb.h
headers:
- src/cpp/ext/proto_server_reflection.h
src:
- src/cpp/ext/proto_server_reflection.cc
- src/cpp/ext/proto_server_reflection_plugin.cc
- src/cpp/ext/reflection.grpc.pb.cc
- src/cpp/ext/reflection.pb.cc
deps:
- grpc++
filegroups:
- grpc++_codegen_proto
- name: grpc++_test_config - name: grpc++_test_config
build: private build: private
language: c++ language: c++
@ -1229,6 +1238,14 @@ targets:
- test/core/end2end/fuzzers/api_fuzzer_corpus - test/core/end2end/fuzzers/api_fuzzer_corpus
dict: test/core/end2end/fuzzers/api_fuzzer.dictionary dict: test/core/end2end/fuzzers/api_fuzzer.dictionary
maxlen: 2048 maxlen: 2048
- name: bin_decoder_test
build: test
language: c
src:
- test/core/transport/chttp2/bin_decoder_test.c
deps:
- grpc_test_util
- grpc
- name: bin_encoder_test - name: bin_encoder_test
build: test build: test
language: c language: c
@ -1428,7 +1445,7 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: fling_stream_test - name: fling_stream_test
cpu_cost: 2 cpu_cost: 1.5
build: test build: test
language: c language: c
src: src:
@ -1443,7 +1460,7 @@ targets:
- linux - linux
- posix - posix
- name: fling_test - name: fling_test
cpu_cost: 2 cpu_cost: 1.5
build: test build: test
language: c language: c
src: src:
@ -1542,14 +1559,6 @@ targets:
deps: deps:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: gpr_load_file_test
build: test
language: c
src:
- test/core/support/load_file_test.c
deps:
- gpr_test_util
- gpr
- name: gpr_log_test - name: gpr_log_test
build: test build: test
language: c language: c
@ -1575,7 +1584,7 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: gpr_stack_lockfree_test - name: gpr_stack_lockfree_test
cpu_cost: 10 cpu_cost: 7
build: test build: test
language: c language: c
src: src:
@ -1592,7 +1601,7 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: gpr_sync_test - name: gpr_sync_test
cpu_cost: 10 cpu_cost: 3
build: test build: test
language: c language: c
src: src:
@ -1601,7 +1610,7 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: gpr_thd_test - name: gpr_thd_test
cpu_cost: 10 cpu_cost: 1
build: test build: test
language: c language: c
src: src:
@ -1821,11 +1830,21 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: http_fuzzer_test - name: http_parser_test
build: test
language: c
src:
- test/core/http/parser_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: http_request_fuzzer_test
build: fuzzer build: fuzzer
language: c language: c
src: src:
- test/core/http/fuzzer.c - test/core/http/request_fuzzer.c
deps: deps:
- grpc_test_util - grpc_test_util
- grpc - grpc
@ -1834,16 +1853,19 @@ targets:
corpus_dirs: corpus_dirs:
- test/core/http/corpus - test/core/http/corpus
maxlen: 2048 maxlen: 2048
- name: http_parser_test - name: http_response_fuzzer_test
build: test build: fuzzer
language: c language: c
src: src:
- test/core/http/parser_test.c - test/core/http/response_fuzzer.c
deps: deps:
- grpc_test_util - grpc_test_util
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
corpus_dirs:
- test/core/http/corpus
maxlen: 2048
- name: httpcli_format_request_test - name: httpcli_format_request_test
build: test build: test
language: c language: c
@ -1926,6 +1948,7 @@ targets:
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: invalid_call_argument_test - name: invalid_call_argument_test
cpu_cost: 0.1
build: test build: test
language: c language: c
src: src:
@ -2009,6 +2032,16 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: load_file_test
build: test
language: c
src:
- test/core/iomgr/load_file_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: low_level_ping_pong_benchmark - name: low_level_ping_pong_benchmark
build: benchmark build: benchmark
language: c language: c
@ -2129,6 +2162,16 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: sequential_connectivity_test
build: test
language: c
src:
- test/core/surface/sequential_connectivity_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
- name: server_chttp2_test - name: server_chttp2_test
build: test build: test
language: c language: c
@ -2225,7 +2268,7 @@ targets:
- linux - linux
- posix - posix
- name: tcp_posix_test - name: tcp_posix_test
cpu_cost: 0.5 cpu_cost: 0.2
build: test build: test
language: c language: c
src: src:
@ -2798,6 +2841,23 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: proto_server_reflection_test
gtest: true
build: test
language: c++
headers:
- test/cpp/util/proto_reflection_descriptor_database.h
src:
- test/cpp/end2end/proto_server_reflection_test.cc
- test/cpp/util/proto_reflection_descriptor_database.cc
deps:
- grpc++_reflection
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr_test_util
- gpr
- name: qps_interarrival_test - name: qps_interarrival_test
build: test build: test
run: false run: false
@ -3059,26 +3119,6 @@ targets:
- grpc - grpc
- gpr_test_util - gpr_test_util
- gpr - gpr
- name: zookeeper_test
gtest: true
build: test
run: false
language: c++
src:
- src/proto/grpc/testing/echo.proto
- test/cpp/end2end/zookeeper_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc_zookeeper
- grpc
- gpr_test_util
- gpr
external_deps:
- zookeeper
platforms:
- linux
- name: public_headers_must_be_c89 - name: public_headers_must_be_c89
build: test build: test
language: c89 language: c89

@ -2,7 +2,6 @@
"name": "grpc/grpc", "name": "grpc/grpc",
"type": "library", "type": "library",
"description": "gRPC library for PHP", "description": "gRPC library for PHP",
"version": "0.15.0",
"keywords": ["rpc"], "keywords": ["rpc"],
"homepage": "http://grpc.io", "homepage": "http://grpc.io",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",

@ -51,7 +51,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/support/env_windows.c \ src/core/lib/support/env_windows.c \
src/core/lib/support/histogram.c \ src/core/lib/support/histogram.c \
src/core/lib/support/host_port.c \ src/core/lib/support/host_port.c \
src/core/lib/support/load_file.c \
src/core/lib/support/log.c \ src/core/lib/support/log.c \
src/core/lib/support/log_android.c \ src/core/lib/support/log_android.c \
src/core/lib/support/log_linux.c \ src/core/lib/support/log_linux.c \
@ -100,6 +99,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/endpoint.c \ src/core/lib/iomgr/endpoint.c \
src/core/lib/iomgr/endpoint_pair_posix.c \ src/core/lib/iomgr/endpoint_pair_posix.c \
src/core/lib/iomgr/endpoint_pair_windows.c \ src/core/lib/iomgr/endpoint_pair_windows.c \
src/core/lib/iomgr/error.c \
src/core/lib/iomgr/ev_poll_and_epoll_posix.c \ src/core/lib/iomgr/ev_poll_and_epoll_posix.c \
src/core/lib/iomgr/ev_poll_posix.c \ src/core/lib/iomgr/ev_poll_posix.c \
src/core/lib/iomgr/ev_posix.c \ src/core/lib/iomgr/ev_posix.c \
@ -109,6 +109,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/iomgr/iomgr.c \ src/core/lib/iomgr/iomgr.c \
src/core/lib/iomgr/iomgr_posix.c \ src/core/lib/iomgr/iomgr_posix.c \
src/core/lib/iomgr/iomgr_windows.c \ src/core/lib/iomgr/iomgr_windows.c \
src/core/lib/iomgr/load_file.c \
src/core/lib/iomgr/polling_entity.c \ src/core/lib/iomgr/polling_entity.c \
src/core/lib/iomgr/pollset_set_windows.c \ src/core/lib/iomgr/pollset_set_windows.c \
src/core/lib/iomgr/pollset_windows.c \ src/core/lib/iomgr/pollset_windows.c \
@ -167,6 +168,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/transport.c \ src/core/lib/transport/transport.c \
src/core/lib/transport/transport_op_string.c \ src/core/lib/transport/transport_op_string.c \
src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \ src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
src/core/ext/transport/chttp2/transport/bin_decoder.c \
src/core/ext/transport/chttp2/transport/bin_encoder.c \ src/core/ext/transport/chttp2/transport/bin_encoder.c \
src/core/ext/transport/chttp2/transport/chttp2_plugin.c \ src/core/ext/transport/chttp2/transport/chttp2_plugin.c \
src/core/ext/transport/chttp2/transport/chttp2_transport.c \ src/core/ext/transport/chttp2/transport/chttp2_transport.c \
@ -210,6 +212,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/transport/secure_endpoint.c \ src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \ src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/server_auth_filter.c \ src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.c \ src/core/lib/security/util/b64.c \
src/core/lib/security/util/json_util.c \ src/core/lib/security/util/json_util.c \
src/core/lib/surface/init_secure.c \ src/core/lib/surface/init_secure.c \

@ -11,7 +11,7 @@ General
- Layout rules are defined by clang-format, and all code should be passed through - Layout rules are defined by clang-format, and all code should be passed through
clang-format. A (docker-based) script to do so is included in clang-format. A (docker-based) script to do so is included in
tools/distrib/clang_format_code.sh. [tools/distrib/clang\_format\_code.sh] (../tools/distrib/clang_format_code.sh).
Header Files Header Files
------------ ------------

@ -0,0 +1,91 @@
GRPC C++ STYLE GUIDE
=====================
Background
----------
Here we document style rules for C++ usage in the gRPC C++ bindings
and tests.
General
-------
- The majority of gRPC's C++ requirements are drawn from the [Google C++ style
guide] (https://google.github.io/styleguide/cppguide.html)
- However, gRPC has some additional requirements to maintain
[portability] (#portability)
- As in C, layout rules are defined by clang-format, and all code
should be passed through clang-format. A (docker-based) script to do
so is included in [tools/distrib/clang\_format\_code.sh]
(../tools/distrib/clang_format_code.sh).
<a name="portability"></a>
Portability Restrictions
-------------------
gRPC supports a large number of compilers, ranging from those that are
missing many key C++11 features to those that have quite detailed
analysis. As a result, gRPC compiles with a high level of warnings and
treat all warnings as errors. gRPC also forbids the use of some common
C++11 constructs. Here are some guidelines, to be extended as needed:
- Do not use range-based for. Expressions of the form
```c
for (auto& i: vec) {
// code
}
```
are not allowed and should be replaced with code such as
```c
for (auto it = vec.begin; it != vec.end(); it++) {
auto& i = *it;
// code
}
```
- Do not use lambda of any kind (no capture, explicit capture, or
default capture). Other C++ functional features such as
`std::function` or `std::bind` are allowed
- Do not use brace-list initializers.
- Do not compare a pointer to `nullptr` . This is because gcc 4.4
does not support `nullptr` directly and gRPC implements a subset of
its features in [include/grpc++/impl/codegen/config.h]
(../include/grpc++/impl/codegen/config.h). Instead, pointers should
be checked for validity using their implicit conversion to `bool`.
In other words, use `if (p)` rather than `if (p != nullptr)`
- Do not initialize global/static pointer variables to `nullptr`. Just let
the compiler implicitly initialize them to `nullptr` (which it will
definitely do). The reason is that `nullptr` is an actual object in
our implementation rather than just a constant pointer value, so
static/global constructors will be called in a potentially
undesirable sequence.
- Do not use `final` or `override` as these are not supported by some
compilers. Instead use `GRPC_FINAL` and `GRPC_OVERRIDE` . These
compile down to the traditional C++ forms for compilers that support
them but are just elided if the compiler does not support those features.
- In the [include] (../../../tree/master/include/grpc++) and [src]
(../../../tree/master/src/cpp) directory trees, you should also not
use certain STL objects like `std::mutex`, `std::lock_guard`,
`std::unique_lock`, `std::nullptr`, `std::thread` . Instead, use
`grpc::mutex`, `grpc::lock_guard`, etc., which are gRPC
implementations of the prominent features of these objects that are
not always available. You can use the `std` versions of those in [test]
(../../../tree/master/test/cpp)
- Similarly, in the same directories, do not use `std::chrono` unless
it is guarded by `#ifndef GRPC_CXX0X_NO_CHRONO` . For platforms that
lack`std::chrono,` there is a C-language timer called gpr_timespec that can
be used instead.
- `std::unique_ptr` must be used with extreme care in any kind of
collection. For example `vector<std::unique_ptr>` does not work in
gcc 4.4 if the vector is constructed to its full size at
initialization but does work if elements are added to the vector
using functions like `push_back`. `map` and other pair-based
collections do not work with `unique_ptr` under gcc 4.4. The issue
is that many of these collection implementations assume a copy
constructor
to be available.
- Don't use `std::this_thread` . Use `gpr_sleep_until` for sleeping a thread.
- [Some adjacent character combinations cause problems]
(https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C). If declaring a
template against some class relative to the global namespace,
`<::name` will be non-portable. Separate the `<` from the `:` and use `< ::name`.

@ -21,6 +21,8 @@ Only a subset of the pre-defined status codes are generated by the gRPC librarie
| Flow-control protocol violation | INTERNAL | Both | | Flow-control protocol violation | INTERNAL | Both |
| Error parsing returned status | UNKNOWN | Client | | Error parsing returned status | UNKNOWN | Client |
| Incorrect Auth metadata ( Credentials failed to get metadata, Incompatible credentials set on channel and call, Invalid host set in `:authority` metadata, etc.) | UNAUTHENTICATED | Both | | Incorrect Auth metadata ( Credentials failed to get metadata, Incompatible credentials set on channel and call, Invalid host set in `:authority` metadata, etc.) | UNAUTHENTICATED | Both |
| Request cardinality violation (method requires exactly one request but client sent some other number of requests) | UNIMPLEMENTED | Server|
| Response cardinality violation (method requires exactly one response but server sent some other number of responses) | UNIMPLEMENTED | Client|
| Error parsing response proto | INTERNAL | Client| | Error parsing response proto | INTERNAL | Client|
| Error parsing request proto | INTERNAL | Server| | Error parsing request proto | INTERNAL | Server|

@ -51,7 +51,7 @@ def get_distance(start, end):
coord_factor = 10000000.0 coord_factor = 10000000.0
lat_1 = start.latitude / coord_factor lat_1 = start.latitude / coord_factor
lat_2 = end.latitude / coord_factor lat_2 = end.latitude / coord_factor
lon_1 = start.latitude / coord_factor lon_1 = start.longitude / coord_factor
lon_2 = end.longitude / coord_factor lon_2 = end.longitude / coord_factor
lat_rad_1 = math.radians(lat_1) lat_rad_1 = math.radians(lat_1)
lat_rad_2 = math.radians(lat_2) lat_rad_2 = math.radians(lat_2)

@ -68,7 +68,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/backoff.h', 'src/core/lib/support/backoff.h',
'src/core/lib/support/block_annotate.h', 'src/core/lib/support/block_annotate.h',
'src/core/lib/support/env.h', 'src/core/lib/support/env.h',
'src/core/lib/support/load_file.h',
'src/core/lib/support/murmur_hash.h', 'src/core/lib/support/murmur_hash.h',
'src/core/lib/support/stack_lockfree.h', 'src/core/lib/support/stack_lockfree.h',
'src/core/lib/support/string.h', 'src/core/lib/support/string.h',
@ -133,7 +132,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/env_windows.c', 'src/core/lib/support/env_windows.c',
'src/core/lib/support/histogram.c', 'src/core/lib/support/histogram.c',
'src/core/lib/support/host_port.c', 'src/core/lib/support/host_port.c',
'src/core/lib/support/load_file.c',
'src/core/lib/support/log.c', 'src/core/lib/support/log.c',
'src/core/lib/support/log_android.c', 'src/core/lib/support/log_android.c',
'src/core/lib/support/log_linux.c', 'src/core/lib/support/log_linux.c',
@ -181,6 +179,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
'src/core/lib/iomgr/ev_poll_and_epoll_posix.h', 'src/core/lib/iomgr/ev_poll_and_epoll_posix.h',
'src/core/lib/iomgr/ev_poll_posix.h', 'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h', 'src/core/lib/iomgr/ev_posix.h',
@ -190,6 +189,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/iomgr.h', 'src/core/lib/iomgr/iomgr.h',
'src/core/lib/iomgr/iomgr_internal.h', 'src/core/lib/iomgr/iomgr_internal.h',
'src/core/lib/iomgr/iomgr_posix.h', 'src/core/lib/iomgr/iomgr_posix.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/polling_entity.h', 'src/core/lib/iomgr/polling_entity.h',
'src/core/lib/iomgr/pollset.h', 'src/core/lib/iomgr/pollset.h',
'src/core/lib/iomgr/pollset_set.h', 'src/core/lib/iomgr/pollset_set.h',
@ -239,6 +239,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/static_metadata.h', 'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h', 'src/core/lib/transport/transport_impl.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/frame.h', 'src/core/ext/transport/chttp2/transport/frame.h',
@ -276,6 +277,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/transport/handshake.h', 'src/core/lib/security/transport/handshake.h',
'src/core/lib/security/transport/secure_endpoint.h', 'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h', 'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/b64.h', 'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h', 'src/core/lib/security/util/json_util.h',
'src/core/lib/tsi/fake_transport_security.h', 'src/core/lib/tsi/fake_transport_security.h',
@ -362,6 +364,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/endpoint.c', 'src/core/lib/iomgr/endpoint.c',
'src/core/lib/iomgr/endpoint_pair_posix.c', 'src/core/lib/iomgr/endpoint_pair_posix.c',
'src/core/lib/iomgr/endpoint_pair_windows.c', 'src/core/lib/iomgr/endpoint_pair_windows.c',
'src/core/lib/iomgr/error.c',
'src/core/lib/iomgr/ev_poll_and_epoll_posix.c', 'src/core/lib/iomgr/ev_poll_and_epoll_posix.c',
'src/core/lib/iomgr/ev_poll_posix.c', 'src/core/lib/iomgr/ev_poll_posix.c',
'src/core/lib/iomgr/ev_posix.c', 'src/core/lib/iomgr/ev_posix.c',
@ -371,6 +374,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/iomgr.c', 'src/core/lib/iomgr/iomgr.c',
'src/core/lib/iomgr/iomgr_posix.c', 'src/core/lib/iomgr/iomgr_posix.c',
'src/core/lib/iomgr/iomgr_windows.c', 'src/core/lib/iomgr/iomgr_windows.c',
'src/core/lib/iomgr/load_file.c',
'src/core/lib/iomgr/polling_entity.c', 'src/core/lib/iomgr/polling_entity.c',
'src/core/lib/iomgr/pollset_set_windows.c', 'src/core/lib/iomgr/pollset_set_windows.c',
'src/core/lib/iomgr/pollset_windows.c', 'src/core/lib/iomgr/pollset_windows.c',
@ -429,6 +433,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/transport.c', 'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c', 'src/core/lib/transport/transport_op_string.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c', 'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c', 'src/core/ext/transport/chttp2/transport/bin_encoder.c',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.c', 'src/core/ext/transport/chttp2/transport/chttp2_plugin.c',
'src/core/ext/transport/chttp2/transport/chttp2_transport.c', 'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
@ -472,6 +477,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/transport/secure_endpoint.c', 'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c', 'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/server_auth_filter.c', 'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c', 'src/core/lib/security/util/b64.c',
'src/core/lib/security/util/json_util.c', 'src/core/lib/security/util/json_util.c',
'src/core/lib/surface/init_secure.c', 'src/core/lib/surface/init_secure.c',
@ -529,7 +535,6 @@ Pod::Spec.new do |s|
'src/core/lib/support/backoff.h', 'src/core/lib/support/backoff.h',
'src/core/lib/support/block_annotate.h', 'src/core/lib/support/block_annotate.h',
'src/core/lib/support/env.h', 'src/core/lib/support/env.h',
'src/core/lib/support/load_file.h',
'src/core/lib/support/murmur_hash.h', 'src/core/lib/support/murmur_hash.h',
'src/core/lib/support/stack_lockfree.h', 'src/core/lib/support/stack_lockfree.h',
'src/core/lib/support/string.h', 'src/core/lib/support/string.h',
@ -554,6 +559,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/closure.h',
'src/core/lib/iomgr/endpoint.h', 'src/core/lib/iomgr/endpoint.h',
'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/endpoint_pair.h',
'src/core/lib/iomgr/error.h',
'src/core/lib/iomgr/ev_poll_and_epoll_posix.h', 'src/core/lib/iomgr/ev_poll_and_epoll_posix.h',
'src/core/lib/iomgr/ev_poll_posix.h', 'src/core/lib/iomgr/ev_poll_posix.h',
'src/core/lib/iomgr/ev_posix.h', 'src/core/lib/iomgr/ev_posix.h',
@ -563,6 +569,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/iomgr.h', 'src/core/lib/iomgr/iomgr.h',
'src/core/lib/iomgr/iomgr_internal.h', 'src/core/lib/iomgr/iomgr_internal.h',
'src/core/lib/iomgr/iomgr_posix.h', 'src/core/lib/iomgr/iomgr_posix.h',
'src/core/lib/iomgr/load_file.h',
'src/core/lib/iomgr/polling_entity.h', 'src/core/lib/iomgr/polling_entity.h',
'src/core/lib/iomgr/pollset.h', 'src/core/lib/iomgr/pollset.h',
'src/core/lib/iomgr/pollset_set.h', 'src/core/lib/iomgr/pollset_set.h',
@ -612,6 +619,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/static_metadata.h', 'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/transport.h', 'src/core/lib/transport/transport.h',
'src/core/lib/transport/transport_impl.h', 'src/core/lib/transport/transport_impl.h',
'src/core/ext/transport/chttp2/transport/bin_decoder.h',
'src/core/ext/transport/chttp2/transport/bin_encoder.h', 'src/core/ext/transport/chttp2/transport/bin_encoder.h',
'src/core/ext/transport/chttp2/transport/chttp2_transport.h', 'src/core/ext/transport/chttp2/transport/chttp2_transport.h',
'src/core/ext/transport/chttp2/transport/frame.h', 'src/core/ext/transport/chttp2/transport/frame.h',
@ -649,6 +657,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/transport/handshake.h', 'src/core/lib/security/transport/handshake.h',
'src/core/lib/security/transport/secure_endpoint.h', 'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h', 'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/b64.h', 'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h', 'src/core/lib/security/util/json_util.h',
'src/core/lib/tsi/fake_transport_security.h', 'src/core/lib/tsi/fake_transport_security.h',

@ -222,6 +222,8 @@ EXPORTS
gpr_avl_add gpr_avl_add
gpr_avl_remove gpr_avl_remove
gpr_avl_get gpr_avl_get
gpr_avl_maybe_get
gpr_avl_is_empty
gpr_cmdline_create gpr_cmdline_create
gpr_cmdline_add_int gpr_cmdline_add_int
gpr_cmdline_add_flag gpr_cmdline_add_flag

@ -89,7 +89,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/backoff.h ) s.files += %w( src/core/lib/support/backoff.h )
s.files += %w( src/core/lib/support/block_annotate.h ) s.files += %w( src/core/lib/support/block_annotate.h )
s.files += %w( src/core/lib/support/env.h ) s.files += %w( src/core/lib/support/env.h )
s.files += %w( src/core/lib/support/load_file.h )
s.files += %w( src/core/lib/support/murmur_hash.h ) s.files += %w( src/core/lib/support/murmur_hash.h )
s.files += %w( src/core/lib/support/stack_lockfree.h ) s.files += %w( src/core/lib/support/stack_lockfree.h )
s.files += %w( src/core/lib/support/string.h ) s.files += %w( src/core/lib/support/string.h )
@ -112,7 +111,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/support/env_windows.c ) s.files += %w( src/core/lib/support/env_windows.c )
s.files += %w( src/core/lib/support/histogram.c ) s.files += %w( src/core/lib/support/histogram.c )
s.files += %w( src/core/lib/support/host_port.c ) s.files += %w( src/core/lib/support/host_port.c )
s.files += %w( src/core/lib/support/load_file.c )
s.files += %w( src/core/lib/support/log.c ) s.files += %w( src/core/lib/support/log.c )
s.files += %w( src/core/lib/support/log_android.c ) s.files += %w( src/core/lib/support/log_android.c )
s.files += %w( src/core/lib/support/log_linux.c ) s.files += %w( src/core/lib/support/log_linux.c )
@ -190,6 +188,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/closure.h ) s.files += %w( src/core/lib/iomgr/closure.h )
s.files += %w( src/core/lib/iomgr/endpoint.h ) s.files += %w( src/core/lib/iomgr/endpoint.h )
s.files += %w( src/core/lib/iomgr/endpoint_pair.h ) s.files += %w( src/core/lib/iomgr/endpoint_pair.h )
s.files += %w( src/core/lib/iomgr/error.h )
s.files += %w( src/core/lib/iomgr/ev_poll_and_epoll_posix.h ) s.files += %w( src/core/lib/iomgr/ev_poll_and_epoll_posix.h )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.h ) s.files += %w( src/core/lib/iomgr/ev_poll_posix.h )
s.files += %w( src/core/lib/iomgr/ev_posix.h ) s.files += %w( src/core/lib/iomgr/ev_posix.h )
@ -199,6 +198,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/iomgr.h ) s.files += %w( src/core/lib/iomgr/iomgr.h )
s.files += %w( src/core/lib/iomgr/iomgr_internal.h ) s.files += %w( src/core/lib/iomgr/iomgr_internal.h )
s.files += %w( src/core/lib/iomgr/iomgr_posix.h ) s.files += %w( src/core/lib/iomgr/iomgr_posix.h )
s.files += %w( src/core/lib/iomgr/load_file.h )
s.files += %w( src/core/lib/iomgr/polling_entity.h ) s.files += %w( src/core/lib/iomgr/polling_entity.h )
s.files += %w( src/core/lib/iomgr/pollset.h ) s.files += %w( src/core/lib/iomgr/pollset.h )
s.files += %w( src/core/lib/iomgr/pollset_set.h ) s.files += %w( src/core/lib/iomgr/pollset_set.h )
@ -248,6 +248,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/static_metadata.h ) s.files += %w( src/core/lib/transport/static_metadata.h )
s.files += %w( src/core/lib/transport/transport.h ) s.files += %w( src/core/lib/transport/transport.h )
s.files += %w( src/core/lib/transport/transport_impl.h ) s.files += %w( src/core/lib/transport/transport_impl.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.h )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h ) s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.h )
s.files += %w( src/core/ext/transport/chttp2/transport/frame.h ) s.files += %w( src/core/ext/transport/chttp2/transport/frame.h )
@ -285,6 +286,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/transport/handshake.h ) s.files += %w( src/core/lib/security/transport/handshake.h )
s.files += %w( src/core/lib/security/transport/secure_endpoint.h ) s.files += %w( src/core/lib/security/transport/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_connector.h ) s.files += %w( src/core/lib/security/transport/security_connector.h )
s.files += %w( src/core/lib/security/transport/tsi_error.h )
s.files += %w( src/core/lib/security/util/b64.h ) s.files += %w( src/core/lib/security/util/b64.h )
s.files += %w( src/core/lib/security/util/json_util.h ) s.files += %w( src/core/lib/security/util/json_util.h )
s.files += %w( src/core/lib/tsi/fake_transport_security.h ) s.files += %w( src/core/lib/tsi/fake_transport_security.h )
@ -341,6 +343,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/endpoint.c ) s.files += %w( src/core/lib/iomgr/endpoint.c )
s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c ) s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c )
s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c ) s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c )
s.files += %w( src/core/lib/iomgr/error.c )
s.files += %w( src/core/lib/iomgr/ev_poll_and_epoll_posix.c ) s.files += %w( src/core/lib/iomgr/ev_poll_and_epoll_posix.c )
s.files += %w( src/core/lib/iomgr/ev_poll_posix.c ) s.files += %w( src/core/lib/iomgr/ev_poll_posix.c )
s.files += %w( src/core/lib/iomgr/ev_posix.c ) s.files += %w( src/core/lib/iomgr/ev_posix.c )
@ -350,6 +353,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/iomgr.c ) s.files += %w( src/core/lib/iomgr/iomgr.c )
s.files += %w( src/core/lib/iomgr/iomgr_posix.c ) s.files += %w( src/core/lib/iomgr/iomgr_posix.c )
s.files += %w( src/core/lib/iomgr/iomgr_windows.c ) s.files += %w( src/core/lib/iomgr/iomgr_windows.c )
s.files += %w( src/core/lib/iomgr/load_file.c )
s.files += %w( src/core/lib/iomgr/polling_entity.c ) s.files += %w( src/core/lib/iomgr/polling_entity.c )
s.files += %w( src/core/lib/iomgr/pollset_set_windows.c ) s.files += %w( src/core/lib/iomgr/pollset_set_windows.c )
s.files += %w( src/core/lib/iomgr/pollset_windows.c ) s.files += %w( src/core/lib/iomgr/pollset_windows.c )
@ -408,6 +412,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/transport.c ) s.files += %w( src/core/lib/transport/transport.c )
s.files += %w( src/core/lib/transport/transport_op_string.c ) s.files += %w( src/core/lib/transport/transport_op_string.c )
s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c ) s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.c )
s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.c ) s.files += %w( src/core/ext/transport/chttp2/transport/bin_encoder.c )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_plugin.c ) s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_plugin.c )
s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.c ) s.files += %w( src/core/ext/transport/chttp2/transport/chttp2_transport.c )
@ -451,6 +456,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/transport/secure_endpoint.c ) s.files += %w( src/core/lib/security/transport/secure_endpoint.c )
s.files += %w( src/core/lib/security/transport/security_connector.c ) s.files += %w( src/core/lib/security/transport/security_connector.c )
s.files += %w( src/core/lib/security/transport/server_auth_filter.c ) s.files += %w( src/core/lib/security/transport/server_auth_filter.c )
s.files += %w( src/core/lib/security/transport/tsi_error.c )
s.files += %w( src/core/lib/security/util/b64.c ) s.files += %w( src/core/lib/security/util/b64.c )
s.files += %w( src/core/lib/security/util/json_util.c ) s.files += %w( src/core/lib/security/util/json_util.c )
s.files += %w( src/core/lib/surface/init_secure.c ) s.files += %w( src/core/lib/surface/init_secure.c )

@ -0,0 +1,69 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
#define GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H
#include <grpc++/impl/server_builder_plugin.h>
#include <grpc++/support/config.h>
namespace grpc {
class ServerInitializer;
class ProtoServerReflection;
} // namespace grpc
namespace grpc {
namespace reflection {
class ProtoServerReflectionPlugin : public ::grpc::ServerBuilderPlugin {
public:
ProtoServerReflectionPlugin();
::grpc::string name() GRPC_OVERRIDE;
void InitServer(::grpc::ServerInitializer* si) GRPC_OVERRIDE;
void Finish(::grpc::ServerInitializer* si) GRPC_OVERRIDE;
void ChangeArguments(const ::grpc::string& name, void* value) GRPC_OVERRIDE;
bool has_async_methods() const GRPC_OVERRIDE;
bool has_sync_methods() const GRPC_OVERRIDE;
private:
std::shared_ptr<grpc::ProtoServerReflection> reflection_service_;
};
// Add proto reflection plugin to ServerBuilder. This function should be called
// at the static initialization time.
void InitProtoReflectionServerBuilderPlugin();
} // namespace reflection
} // namespace grpc
#endif // GRPCXX_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H

@ -0,0 +1,184 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// Generated by the gRPC protobuf plugin.
// If you make any local change, they will be lost.
// source: reflection.proto
// Original file comments:
// Copyright 2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Service exported by server reflection
//
#ifndef GRPC_reflection_2eproto__INCLUDED
#define GRPC_reflection_2eproto__INCLUDED
#include <grpc++/ext/reflection.pb.h>
#include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/async_unary_call.h>
#include <grpc++/impl/codegen/proto_utils.h>
#include <grpc++/impl/codegen/rpc_method.h>
#include <grpc++/impl/codegen/service_type.h>
#include <grpc++/impl/codegen/status.h>
#include <grpc++/impl/codegen/stub_options.h>
#include <grpc++/impl/codegen/sync_stream.h>
namespace grpc {
class CompletionQueue;
class Channel;
class RpcService;
class ServerCompletionQueue;
class ServerContext;
} // namespace grpc
namespace grpc {
namespace reflection {
namespace v1alpha {
class ServerReflection GRPC_FINAL {
public:
class StubInterface {
public:
virtual ~StubInterface() {}
// The reflection service is structured as a bidirectional stream, ensuring
// all related requests go to a single server.
std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>> ServerReflectionInfo(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>>(ServerReflectionInfoRaw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>> AsyncServerReflectionInfo(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>>(AsyncServerReflectionInfoRaw(context, cq, tag));
}
private:
virtual ::grpc::ClientReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* ServerReflectionInfoRaw(::grpc::ClientContext* context) = 0;
virtual ::grpc::ClientAsyncReaderWriterInterface< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* AsyncServerReflectionInfoRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) = 0;
};
class Stub GRPC_FINAL : public StubInterface {
public:
Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>> ServerReflectionInfo(::grpc::ClientContext* context) {
return std::unique_ptr< ::grpc::ClientReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>>(ServerReflectionInfoRaw(context));
}
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>> AsyncServerReflectionInfo(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>>(AsyncServerReflectionInfoRaw(context, cq, tag));
}
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
::grpc::ClientReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* ServerReflectionInfoRaw(::grpc::ClientContext* context) GRPC_OVERRIDE;
::grpc::ClientAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* AsyncServerReflectionInfoRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;
const ::grpc::RpcMethod rpcmethod_ServerReflectionInfo_;
};
static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
class Service : public ::grpc::Service {
public:
Service();
virtual ~Service();
// The reflection service is structured as a bidirectional stream, ensuring
// all related requests go to a single server.
virtual ::grpc::Status ServerReflectionInfo(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionResponse, ::grpc::reflection::v1alpha::ServerReflectionRequest>* stream);
};
template <class BaseClass>
class WithAsyncMethod_ServerReflectionInfo : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_ServerReflectionInfo() {
::grpc::Service::MarkMethodAsync(0);
}
~WithAsyncMethod_ServerReflectionInfo() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ServerReflectionInfo(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionResponse, ::grpc::reflection::v1alpha::ServerReflectionRequest>* stream) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestServerReflectionInfo(::grpc::ServerContext* context, ::grpc::ServerAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionResponse, ::grpc::reflection::v1alpha::ServerReflectionRequest>* stream, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncBidiStreaming(0, context, stream, new_call_cq, notification_cq, tag);
}
};
typedef WithAsyncMethod_ServerReflectionInfo<Service > AsyncService;
template <class BaseClass>
class WithGenericMethod_ServerReflectionInfo : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_ServerReflectionInfo() {
::grpc::Service::MarkMethodGeneric(0);
}
~WithGenericMethod_ServerReflectionInfo() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status ServerReflectionInfo(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionResponse, ::grpc::reflection::v1alpha::ServerReflectionRequest>* stream) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
};
} // namespace v1alpha
} // namespace reflection
} // namespace grpc
#endif // GRPC_reflection_2eproto__INCLUDED

File diff suppressed because it is too large Load Diff

@ -337,7 +337,7 @@ class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
return SerializationTraits<R>::Deserialize(buf, message_, max_message_size); return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
} }
~DeserializeFuncType() override {} ~DeserializeFuncType() GRPC_OVERRIDE {}
private: private:
R* message_; // Not a managed pointer because management is external to this R* message_; // Not a managed pointer because management is external to this

@ -54,6 +54,7 @@
// nullptr was added in gcc 4.6 // nullptr was added in gcc 4.6
#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406) #if (__GNUC__ * 100 + __GNUC_MINOR__ < 406)
#define GRPC_CXX0X_NO_NULLPTR 1 #define GRPC_CXX0X_NO_NULLPTR 1
#define GRPC_CXX0X_LIMITED_TOSTRING 1
#endif #endif
// final and override were added in gcc 4.7 // final and override were added in gcc 4.7
#if (__GNUC__ * 100 + __GNUC_MINOR__ < 407) #if (__GNUC__ * 100 + __GNUC_MINOR__ < 407)
@ -78,6 +79,7 @@
#endif #endif
#ifdef GRPC_CXX0X_NO_NULLPTR #ifdef GRPC_CXX0X_NO_NULLPTR
#include <functional>
#include <memory> #include <memory>
namespace grpc { namespace grpc {
const class { const class {
@ -95,6 +97,10 @@ const class {
return std::shared_ptr<T>(static_cast<T *>(0)); return std::shared_ptr<T>(static_cast<T *>(0));
} }
operator bool() const { return false; } operator bool() const { return false; }
template <class F>
operator std::function<F>() const {
return std::function<F>();
}
private: private:
void operator&() const = delete; void operator&() const = delete;
@ -111,6 +117,17 @@ namespace grpc {
typedef GRPC_CUSTOM_STRING string; typedef GRPC_CUSTOM_STRING string;
#ifdef GRPC_CXX0X_LIMITED_TOSTRING
inline grpc::string to_string(const int x) {
return std::to_string(static_cast<const long long int>(x));
}
inline grpc::string to_string(const unsigned int x) {
return std::to_string(static_cast<const long long unsigned int>(x));
}
#else
using std::to_string;
#endif
} // namespace grpc } // namespace grpc
#endif // GRPCXX_IMPL_CODEGEN_CONFIG_H #endif // GRPCXX_IMPL_CODEGEN_CONFIG_H

@ -44,6 +44,19 @@
#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message #define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
#endif #endif
#ifndef GRPC_CUSTOM_DESCRIPTOR
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool
#define GPRC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
#endif
#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM #ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
#include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream.h>
@ -60,6 +73,15 @@ namespace protobuf {
typedef GRPC_CUSTOM_MESSAGE Message; typedef GRPC_CUSTOM_MESSAGE Message;
typedef GRPC_CUSTOM_PROTOBUF_INT64 int64; typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool;
typedef GPRC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
namespace io { namespace io {
typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream; typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream; typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;

@ -42,42 +42,44 @@ namespace grpc {
/// Implementation of the core codegen interface. /// Implementation of the core codegen interface.
class CoreCodegen : public CoreCodegenInterface { class CoreCodegen : public CoreCodegenInterface {
private: private:
grpc_completion_queue* grpc_completion_queue_create(void* reserved) override; grpc_completion_queue* grpc_completion_queue_create(void* reserved)
void grpc_completion_queue_destroy(grpc_completion_queue* cq) override; GRPC_OVERRIDE;
void grpc_completion_queue_destroy(grpc_completion_queue* cq) GRPC_OVERRIDE;
grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag, grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
gpr_timespec deadline, gpr_timespec deadline,
void* reserved) override; void* reserved) GRPC_OVERRIDE;
void* gpr_malloc(size_t size) override; void* gpr_malloc(size_t size) GRPC_OVERRIDE;
void gpr_free(void* p) override; void gpr_free(void* p) GRPC_OVERRIDE;
void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override; void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) GRPC_OVERRIDE;
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader, void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
grpc_byte_buffer* buffer) override; grpc_byte_buffer* buffer) GRPC_OVERRIDE;
void grpc_byte_buffer_reader_destroy( void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader* reader)
grpc_byte_buffer_reader* reader) override; GRPC_OVERRIDE;
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader, int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
gpr_slice* slice) override; gpr_slice* slice) GRPC_OVERRIDE;
grpc_byte_buffer* grpc_raw_byte_buffer_create(gpr_slice* slice, grpc_byte_buffer* grpc_raw_byte_buffer_create(gpr_slice* slice,
size_t nslices) override; size_t nslices) GRPC_OVERRIDE;
gpr_slice gpr_slice_malloc(size_t length) override; gpr_slice gpr_slice_malloc(size_t length) GRPC_OVERRIDE;
void gpr_slice_unref(gpr_slice slice) override; void gpr_slice_unref(gpr_slice slice) GRPC_OVERRIDE;
gpr_slice gpr_slice_split_tail(gpr_slice* s, size_t split) override; gpr_slice gpr_slice_split_tail(gpr_slice* s, size_t split) GRPC_OVERRIDE;
void gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) override; void gpr_slice_buffer_add(gpr_slice_buffer* sb,
void gpr_slice_buffer_pop(gpr_slice_buffer* sb) override; gpr_slice slice) GRPC_OVERRIDE;
void gpr_slice_buffer_pop(gpr_slice_buffer* sb) GRPC_OVERRIDE;
void grpc_metadata_array_init(grpc_metadata_array* array) override; void grpc_metadata_array_init(grpc_metadata_array* array) GRPC_OVERRIDE;
void grpc_metadata_array_destroy(grpc_metadata_array* array) override; void grpc_metadata_array_destroy(grpc_metadata_array* array) GRPC_OVERRIDE;
gpr_timespec gpr_inf_future(gpr_clock_type type) override; gpr_timespec gpr_inf_future(gpr_clock_type type) GRPC_OVERRIDE;
virtual const Status& ok() override; virtual const Status& ok() GRPC_OVERRIDE;
virtual const Status& cancelled() override; virtual const Status& cancelled() GRPC_OVERRIDE;
void assert_fail(const char* failed_assertion) override; void assert_fail(const char* failed_assertion) GRPC_OVERRIDE;
}; };
} // namespace grpc } // namespace grpc

@ -62,6 +62,10 @@ class ServerInterface : public CallHook {
/// Shutdown the server, blocking until all rpc processing finishes. /// Shutdown the server, blocking until all rpc processing finishes.
/// Forcefully terminate pending calls after \a deadline expires. /// Forcefully terminate pending calls after \a deadline expires.
/// ///
/// All completion queue associated with the server (for example, for async
/// serving) must be shutdown *after* this method has returned:
/// See \a ServerBuilder::AddCompletionQueue for details.
///
/// \param deadline How long to wait until pending rpcs are forcefully /// \param deadline How long to wait until pending rpcs are forcefully
/// terminated. /// terminated.
template <class T> template <class T>
@ -70,6 +74,10 @@ class ServerInterface : public CallHook {
} }
/// Shutdown the server, waiting for all rpc processing to finish. /// Shutdown the server, waiting for all rpc processing to finish.
///
/// All completion queue associated with the server (for example, for async
/// serving) must be shutdown *after* this method has returned:
/// See \a ServerBuilder::AddCompletionQueue for details.
void Shutdown() { ShutdownInternal(gpr_inf_future(GPR_CLOCK_MONOTONIC)); } void Shutdown() { ShutdownInternal(gpr_inf_future(GPR_CLOCK_MONOTONIC)); }
/// Block waiting for all work to complete. /// Block waiting for all work to complete.

@ -50,8 +50,7 @@ class ServerBuilderOption {
virtual void UpdateArguments(ChannelArguments* args) = 0; virtual void UpdateArguments(ChannelArguments* args) = 0;
/// Alter the ServerBuilderPlugin map that will be added into ServerBuilder. /// Alter the ServerBuilderPlugin map that will be added into ServerBuilder.
virtual void UpdatePlugins( virtual void UpdatePlugins(
std::map<grpc::string, std::unique_ptr<ServerBuilderPlugin> >* std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins) = 0;
plugins) = 0;
}; };
} // namespace grpc } // namespace grpc

@ -119,9 +119,20 @@ class ServerBuilder {
std::shared_ptr<ServerCredentials> creds, std::shared_ptr<ServerCredentials> creds,
int* selected_port = nullptr); int* selected_port = nullptr);
/// Add a completion queue for handling asynchronous services /// Add a completion queue for handling asynchronous services.
/// Caller is required to keep this completion queue live until ///
/// the server is destroyed. /// Caller is required to shutdown the server prior to shutting down the
/// returned completion queue. A typical usage scenario:
///
/// // While building the server:
/// ServerBuilder builder;
/// ...
/// cq_ = builder.AddCompletionQueue();
/// server_ = builder.BuildAndStart();
///
/// // While shutting down the server;
/// server_->Shutdown();
/// cq_->Shutdown(); // Always *after* the associated server's Shutdown()!
/// ///
/// \param is_frequently_polled This is an optional parameter to inform GRPC /// \param is_frequently_polled This is an optional parameter to inform GRPC
/// library about whether this completion queue would be frequently polled /// library about whether this completion queue would be frequently polled
@ -163,7 +174,7 @@ class ServerBuilder {
std::vector<Port> ports_; std::vector<Port> ports_;
std::vector<ServerCompletionQueue*> cqs_; std::vector<ServerCompletionQueue*> cqs_;
std::shared_ptr<ServerCredentials> creds_; std::shared_ptr<ServerCredentials> creds_;
std::map<grpc::string, std::unique_ptr<ServerBuilderPlugin>> plugins_; std::vector<std::unique_ptr<ServerBuilderPlugin>> plugins_;
AsyncGenericService* generic_service_; AsyncGenericService* generic_service_;
struct { struct {
bool is_set; bool is_set;

@ -34,6 +34,7 @@
#ifndef GRPC_IMPL_CODEGEN_LOG_H #ifndef GRPC_IMPL_CODEGEN_LOG_H
#define GRPC_IMPL_CODEGEN_LOG_H #define GRPC_IMPL_CODEGEN_LOG_H
#include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> /* for abort() */ #include <stdlib.h> /* for abort() */
@ -74,7 +75,7 @@ const char *gpr_log_severity_string(gpr_log_severity severity);
/* Log a message. It's advised to use GPR_xxx above to generate the context /* Log a message. It's advised to use GPR_xxx above to generate the context
* for each message */ * for each message */
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity,
const char *format, ...); const char *format, ...) GPRC_PRINT_FORMAT_CHECK(4, 5);
GPRAPI void gpr_log_message(const char *file, int line, GPRAPI void gpr_log_message(const char *file, int line,
gpr_log_severity severity, const char *message); gpr_log_severity severity, const char *message);

@ -150,7 +150,11 @@
#elif defined(ANDROID) || defined(__ANDROID__) #elif defined(ANDROID) || defined(__ANDROID__)
#define GPR_PLATFORM_STRING "android" #define GPR_PLATFORM_STRING "android"
#define GPR_ANDROID 1 #define GPR_ANDROID 1
#ifdef _LP64
#define GPR_ARCH_64 1
#else /* _LP64 */
#define GPR_ARCH_32 1 #define GPR_ARCH_32 1
#endif /* _LP64 */
#define GPR_CPU_LINUX 1 #define GPR_CPU_LINUX 1
#define GPR_GCC_SYNC 1 #define GPR_GCC_SYNC 1
#define GPR_GCC_TLS 1 #define GPR_GCC_TLS 1
@ -434,6 +438,15 @@ typedef unsigned __int64 uint64_t;
#endif #endif
#endif #endif
#ifndef GPRC_PRINT_FORMAT_CHECK
#ifdef __GNUC__
#define GPRC_PRINT_FORMAT_CHECK(FORMAT_STR, ARGS) \
__attribute__((format(printf, FORMAT_STR, ARGS)))
#else
#define GPRC_PRINT_FORMAT_CHECK(FORMAT_STR, ARGS)
#endif
#endif /* GPRC_PRINT_FORMAT_CHECK */
#if GPR_FORBID_UNREACHABLE_CODE #if GPR_FORBID_UNREACHABLE_CODE
#define GPR_UNREACHABLE_CODE(STATEMENT) #define GPR_UNREACHABLE_CODE(STATEMENT)
#else #else

@ -88,5 +88,10 @@ GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key);
does not mutate avl. does not mutate avl.
returns NULL if key is not found. */ returns NULL if key is not found. */
GPRAPI void *gpr_avl_get(gpr_avl avl, void *key); GPRAPI void *gpr_avl_get(gpr_avl avl, void *key);
/** Return 1 if avl contains key, 0 otherwise; if it has the key, sets *value to
its value*/
GPRAPI int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value);
/** Return 1 if avl is empty, 0 otherwise */
GPRAPI int gpr_avl_is_empty(gpr_avl avl);
#endif /* GRPC_SUPPORT_AVL_H */ #endif /* GRPC_SUPPORT_AVL_H */

@ -54,7 +54,8 @@ GPRAPI char *gpr_strdup(const char *src);
On error, returns -1 and sets *strp to NULL. If the format string is bad, On error, returns -1 and sets *strp to NULL. If the format string is bad,
the result is undefined. */ the result is undefined. */
GPRAPI int gpr_asprintf(char **strp, const char *format, ...); GPRAPI int gpr_asprintf(char **strp, const char *format, ...)
GPRC_PRINT_FORMAT_CHECK(2, 3);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -96,7 +96,6 @@
<file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/load_file.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" />
@ -119,7 +118,6 @@
<file baseinstalldir="/" name="src/core/lib/support/env_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/env_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/histogram.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/histogram.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/host_port.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/host_port.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/load_file.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/log.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/log.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/log_android.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/log_android.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/support/log_linux.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/support/log_linux.c" role="src" />
@ -197,6 +195,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_and_epoll_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_and_epoll_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.h" role="src" />
@ -206,6 +205,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/load_file.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set.h" role="src" />
@ -255,6 +255,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/frame.h" role="src" />
@ -292,6 +293,7 @@
<file baseinstalldir="/" name="src/core/lib/security/transport/handshake.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/handshake.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/b64.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.h" role="src" />
@ -348,6 +350,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/error.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_and_epoll_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_and_epoll_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.c" role="src" />
@ -357,6 +360,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/load_file.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_windows.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_windows.c" role="src" />
@ -415,6 +419,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_encoder.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_plugin.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_plugin.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/chttp2_transport.c" role="src" />
@ -458,6 +463,7 @@
<file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/secure_endpoint.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/server_auth_filter.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/server_auth_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/tsi_error.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/json_util.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/surface/init_secure.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/surface/init_secure.c" role="src" />
@ -1072,20 +1078,5 @@ Update to wrap gRPC C Core version 0.10.0
- Updated functions with TSRM macros for ZTS support #6607 - Updated functions with TSRM macros for ZTS support #6607
</notes> </notes>
</release> </release>
<release>
<version>
<release>0.15.0</release>
<api>0.15.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2016-05-19</date>
<license>BSD</license>
<notes>
- TBD
</notes>
</release>
</changelog> </changelog>
</package> </package>

@ -246,7 +246,6 @@ setuptools.setup(
ext_modules=CYTHON_EXTENSION_MODULES, ext_modules=CYTHON_EXTENSION_MODULES,
packages=list(PACKAGES), packages=list(PACKAGES),
package_dir=PACKAGE_DIRECTORIES, package_dir=PACKAGE_DIRECTORIES,
namespace_packages=['grpc'],
package_data=PACKAGE_DATA, package_data=PACKAGE_DATA,
install_requires=INSTALL_REQUIRES, install_requires=INSTALL_REQUIRES,
setup_requires=SETUP_REQUIRES, setup_requires=SETUP_REQUIRES,

@ -36,17 +36,6 @@
#include <grpc++/impl/codegen/config_protobuf.h> #include <grpc++/impl/codegen/config_protobuf.h>
#ifndef GRPC_CUSTOM_DESCRIPTOR
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
#endif
#ifndef GRPC_CUSTOM_CODEGENERATOR #ifndef GRPC_CUSTOM_CODEGENERATOR
#include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/compiler/code_generator.h>
#define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator #define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator
@ -84,12 +73,7 @@ namespace grpc {
typedef GRPC_CUSTOM_STRING string; typedef GRPC_CUSTOM_STRING string;
namespace protobuf { namespace protobuf {
typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
namespace compiler { namespace compiler {
typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator; typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator;
typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext; typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext;

@ -73,9 +73,10 @@ void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, c
vars["l"] = params.use_system_headers ? '<' : '"'; vars["l"] = params.use_system_headers ? '<' : '"';
vars["r"] = params.use_system_headers ? '>' : '"'; vars["r"] = params.use_system_headers ? '>' : '"';
if (!params.grpc_search_path.empty()) { auto& s = params.grpc_search_path;
vars["l"] += params.grpc_search_path; if (!s.empty()) {
if (params.grpc_search_path.back() != '/') { vars["l"] += s;
if (s[s.size()-1] != '/') {
vars["l"] += '/'; vars["l"] += '/';
} }
} }

@ -253,7 +253,8 @@ inline void GetComment(const grpc::protobuf::FileDescriptor *desc,
inline grpc::string GenerateCommentsWithPrefix( inline grpc::string GenerateCommentsWithPrefix(
const std::vector<grpc::string> &in, const grpc::string &prefix) { const std::vector<grpc::string> &in, const grpc::string &prefix) {
std::ostringstream oss; std::ostringstream oss;
for (const grpc::string &elem : in) { for (auto it = in.begin(); it != in.end(); it++) {
const grpc::string& elem = *it;
if (elem.empty()) { if (elem.empty()) {
oss << prefix << "\n"; oss << prefix << "\n";
} else if (elem[0] == ' ') { } else if (elem[0] == ' ') {

@ -74,8 +74,16 @@ grpc::string GetJSMessageFilename(const grpc::string& filename) {
// Given a filename like foo/bar/baz.proto, returns the root directory // Given a filename like foo/bar/baz.proto, returns the root directory
// path ../../ // path ../../
grpc::string GetRootPath(const grpc::string& filename) { grpc::string GetRootPath(const grpc::string& from_filename,
size_t slashes = std::count(filename.begin(), filename.end(), '/'); const grpc::string& to_filename) {
if (to_filename.find("google/protobuf") == 0) {
// Well-known types (.proto files in the google/protobuf directory) are
// assumed to come from the 'google-protobuf' npm package. We may want to
// generalize this exception later by letting others put generated code in
// their own npm packages.
return "google-protobuf/";
}
size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
if (slashes == 0) { if (slashes == 0) {
return "./"; return "./";
} }
@ -90,7 +98,7 @@ grpc::string GetRootPath(const grpc::string& filename) {
// from_file, assuming that both paths are relative to the same directory // from_file, assuming that both paths are relative to the same directory
grpc::string GetRelativePath(const grpc::string& from_file, grpc::string GetRelativePath(const grpc::string& from_file,
const grpc::string& to_file) { const grpc::string& to_file) {
return GetRootPath(from_file) + to_file; return GetRootPath(from_file, to_file) + to_file;
} }
/* Finds all message types used in all services in the file, and returns them /* Finds all message types used in all services in the file, and returns them

@ -457,8 +457,149 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
return true; return true;
} }
bool PrintStub(const grpc::string& package_qualified_service_name,
const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("class $Service$Stub(object):\n", "Service", service->name());
{
IndentScope raii_class_indent(out);
PrintAllComments(service, out);
out->Print("\n");
out->Print("def __init__(self, channel):\n");
{
IndentScope raii_init_indent(out);
out->Print("\"\"\"Constructor.\n");
out->Print("\n");
out->Print("Args:\n");
{
IndentScope raii_args_indent(out);
out->Print("channel: A grpc.Channel.\n");
}
out->Print("\"\"\"\n");
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
auto multi_callable_constructor =
grpc::string(method->client_streaming() ? "stream" : "unary") +
"_" +
grpc::string(method->server_streaming() ? "stream" : "unary");
grpc::string request_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(), service,
&request_module_and_class)) {
return false;
}
grpc::string response_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(), service,
&response_module_and_class)) {
return false;
}
out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
"Method", method->name(),
"MultiCallableConstructor", multi_callable_constructor);
{
IndentScope raii_first_attribute_indent(out);
IndentScope raii_second_attribute_indent(out);
out->Print(
"'/$PackageQualifiedService$/$Method$',\n",
"PackageQualifiedService", package_qualified_service_name,
"Method", method->name());
out->Print(
"request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
"RequestModuleAndClass", request_module_and_class);
out->Print(
"response_deserializer=$ResponseModuleAndClass$.FromString,\n",
"ResponseModuleAndClass", response_module_and_class);
out->Print(")\n");
}
}
}
}
return true;
}
bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("class $Service$Servicer(object):\n", "Service", service->name());
{
IndentScope raii_class_indent(out);
PrintAllComments(service, out);
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
grpc::string arg_name = method->client_streaming() ?
"request_iterator" : "request";
out->Print("\n");
out->Print("def $Method$(self, $ArgName$, context):\n",
"Method", method->name(), "ArgName", arg_name);
{
IndentScope raii_method_indent(out);
PrintAllComments(method, out);
out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
out->Print("context.set_details('Method not implemented!')\n");
out->Print("raise NotImplementedError('Method not implemented!')\n");
}
}
}
return true;
}
bool PrintAddServicerToServer(const grpc::string& package_qualified_service_name,
const ServiceDescriptor* service, Printer* out) {
out->Print("\n\n");
out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
"Service", service->name());
{
IndentScope raii_class_indent(out);
out->Print("rpc_method_handlers = {\n");
{
IndentScope raii_dict_first_indent(out);
IndentScope raii_dict_second_indent(out);
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
auto method_handler_constructor =
grpc::string(method->client_streaming() ? "stream" : "unary") +
"_" +
grpc::string(method->server_streaming() ? "stream" : "unary") +
"_rpc_method_handler";
grpc::string request_module_and_class;
if (!GetModuleAndMessagePath(method->input_type(), service,
&request_module_and_class)) {
return false;
}
grpc::string response_module_and_class;
if (!GetModuleAndMessagePath(method->output_type(), service,
&response_module_and_class)) {
return false;
}
out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n",
"Method", method->name(),
"MethodHandlerConstructor", method_handler_constructor);
{
IndentScope raii_call_first_indent(out);
IndentScope raii_call_second_indent(out);
out->Print("servicer.$Method$,\n", "Method", method->name());
out->Print("request_deserializer=$RequestModuleAndClass$.FromString,\n",
"RequestModuleAndClass", request_module_and_class);
out->Print("response_serializer=$ResponseModuleAndClass$.SerializeToString,\n",
"ResponseModuleAndClass", response_module_and_class);
}
out->Print("),\n");
}
}
out->Print("}\n");
out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
{
IndentScope raii_call_first_indent(out);
IndentScope raii_call_second_indent(out);
out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
"PackageQualifiedServiceName", package_qualified_service_name);
}
out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
}
return true;
}
bool PrintPreamble(const FileDescriptor* file, bool PrintPreamble(const FileDescriptor* file,
const GeneratorConfiguration& config, Printer* out) { const GeneratorConfiguration& config, Printer* out) {
out->Print("import $Package$\n", "Package", config.grpc_package_root);
out->Print("from $Package$ import implementations as beta_implementations\n", out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root); "Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n", out->Print("from $Package$ import interfaces as beta_interfaces\n",
@ -487,7 +628,10 @@ pair<bool, grpc::string> GetServices(const FileDescriptor* file,
for (int i = 0; i < file->service_count(); ++i) { for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i); auto service = file->service(i);
auto package_qualified_service_name = package + service->name(); auto package_qualified_service_name = package + service->name();
if (!(PrintBetaServicer(service, &out) && if (!(PrintStub(package_qualified_service_name, service, &out) &&
PrintServicer(service, &out) &&
PrintAddServicerToServer(package_qualified_service_name, service, &out) &&
PrintBetaServicer(service, &out) &&
PrintBetaStub(service, &out) && PrintBetaStub(service, &out) &&
PrintBetaServerFactory(package_qualified_service_name, service, &out) && PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
PrintBetaStubFactory(package_qualified_service_name, service, &out))) { PrintBetaStubFactory(package_qualified_service_name, service, &out))) {

@ -43,6 +43,7 @@ namespace grpc_python_generator {
// Data pertaining to configuration of the generator with respect to anything // Data pertaining to configuration of the generator with respect to anything
// that may be used internally at Google. // that may be used internally at Google.
struct GeneratorConfiguration { struct GeneratorConfiguration {
grpc::string grpc_package_root;
grpc::string beta_package_root; grpc::string beta_package_root;
}; };

@ -38,6 +38,7 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
grpc_python_generator::GeneratorConfiguration config; grpc_python_generator::GeneratorConfiguration config;
config.grpc_package_root = "grpc";
config.beta_package_root = "grpc.beta"; config.beta_package_root = "grpc.beta";
grpc_python_generator::PythonGrpcGenerator generator(config); grpc_python_generator::PythonGrpcGenerator generator(config);
return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);

@ -91,14 +91,14 @@ static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
} }
static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr, static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
bool success) { grpc_error *error) {
grpc_call_element *elem = ptr; grpc_call_element *elem = ptr;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
if (success) { if (error == GRPC_ERROR_NONE) {
extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand); extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand);
} }
calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
} }
static void server_mutate_op(grpc_call_element *elem, static void server_mutate_op(grpc_call_element *elem,

@ -75,7 +75,6 @@ typedef enum {
typedef struct { typedef struct {
gpr_mu mu; gpr_mu mu;
callback_phase phase; callback_phase phase;
int success;
grpc_closure on_complete; grpc_closure on_complete;
grpc_timer alarm; grpc_timer alarm;
grpc_connectivity_state state; grpc_connectivity_state state;
@ -122,7 +121,7 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
} }
static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
int due_to_completion) { bool due_to_completion, grpc_error *error) {
int delete = 0; int delete = 0;
if (due_to_completion) { if (due_to_completion) {
@ -130,14 +129,26 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
} }
gpr_mu_lock(&w->mu); gpr_mu_lock(&w->mu);
if (due_to_completion) { if (due_to_completion) {
w->success = 1; if (grpc_trace_operation_failures) {
GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
error = GRPC_ERROR_NONE;
} else {
if (error == GRPC_ERROR_NONE) {
error =
GRPC_ERROR_CREATE("Timed out waiting for connection state change");
} else if (error == GRPC_ERROR_CANCELLED) {
error = GRPC_ERROR_NONE;
}
} }
switch (w->phase) { switch (w->phase) {
case WAITING: case WAITING:
w->phase = CALLING_BACK; w->phase = CALLING_BACK;
grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->success, finished_completion, grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error),
w, &w->completion_storage); finished_completion, w, &w->completion_storage);
break; break;
case CALLING_BACK: case CALLING_BACK:
w->phase = CALLING_BACK_AND_FINISHED; w->phase = CALLING_BACK_AND_FINISHED;
@ -153,14 +164,18 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
if (delete) { if (delete) {
delete_state_watcher(exec_ctx, w); delete_state_watcher(exec_ctx, w);
} }
GRPC_ERROR_UNREF(error);
} }
static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw,
partly_done(exec_ctx, pw, 1); grpc_error *error) {
partly_done(exec_ctx, pw, true, GRPC_ERROR_REF(error));
} }
static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) { static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw,
partly_done(exec_ctx, pw, 0); grpc_error *error) {
partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error));
} }
void grpc_channel_watch_connectivity_state( void grpc_channel_watch_connectivity_state(
@ -185,7 +200,6 @@ void grpc_channel_watch_connectivity_state(
grpc_closure_init(&w->on_complete, watch_complete, w); grpc_closure_init(&w->on_complete, watch_complete, w);
w->phase = WAITING; w->phase = WAITING;
w->state = last_observed_state; w->state = last_observed_state;
w->success = 0;
w->cq = cq; w->cq = cq;
w->tag = tag; w->tag = tag;
w->channel = channel; w->channel = channel;

@ -117,6 +117,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx, static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
channel_data *chand, channel_data *chand,
grpc_connectivity_state state, grpc_connectivity_state state,
grpc_error *error,
const char *reason) { const char *reason) {
if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE || if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
state == GRPC_CHANNEL_SHUTDOWN) && state == GRPC_CHANNEL_SHUTDOWN) &&
@ -127,11 +128,13 @@ static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
/* mask= */ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY, /* mask= */ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY,
/* check= */ 0); /* check= */ 0);
} }
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, reason); grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
reason);
} }
static void on_lb_policy_state_changed_locked( static void on_lb_policy_state_changed_locked(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) { lb_policy_connectivity_watcher *w,
grpc_error *error) {
grpc_connectivity_state publish_state = w->state; grpc_connectivity_state publish_state = w->state;
/* check if the notification is for a stale policy */ /* check if the notification is for a stale policy */
if (w->lb_policy != w->chand->lb_policy) return; if (w->lb_policy != w->chand->lb_policy) return;
@ -143,18 +146,18 @@ static void on_lb_policy_state_changed_locked(
w->chand->lb_policy = NULL; w->chand->lb_policy = NULL;
} }
set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state, set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state,
"lb_changed"); GRPC_ERROR_REF(error), "lb_changed");
if (w->state != GRPC_CHANNEL_SHUTDOWN) { if (w->state != GRPC_CHANNEL_SHUTDOWN) {
watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state); watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
} }
} }
static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg, static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
lb_policy_connectivity_watcher *w = arg; lb_policy_connectivity_watcher *w = arg;
gpr_mu_lock(&w->chand->mu_config); gpr_mu_lock(&w->chand->mu_config);
on_lb_policy_state_changed_locked(exec_ctx, w); on_lb_policy_state_changed_locked(exec_ctx, w, error);
gpr_mu_unlock(&w->chand->mu_config); gpr_mu_unlock(&w->chand->mu_config);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy"); GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
@ -176,19 +179,22 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
} }
static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg, static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
channel_data *chand = arg; channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL; grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy; grpc_lb_policy *old_lb_policy;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
int exit_idle = 0; int exit_idle = 0;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
if (chand->incoming_configuration != NULL) { if (chand->incoming_configuration != NULL) {
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
if (lb_policy != NULL) { if (lb_policy != NULL) {
GRPC_LB_POLICY_REF(lb_policy, "channel"); GRPC_LB_POLICY_REF(lb_policy, "channel");
GRPC_LB_POLICY_REF(lb_policy, "config_change"); GRPC_LB_POLICY_REF(lb_policy, "config_change");
state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy); GRPC_ERROR_UNREF(state_error);
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
} }
grpc_client_config_unref(exec_ctx, chand->incoming_configuration); grpc_client_config_unref(exec_ctx, chand->incoming_configuration);
@ -208,7 +214,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL); NULL);
} else if (chand->resolver == NULL /* disconnected */) { } else if (chand->resolver == NULL /* disconnected */) {
grpc_closure_list_fail_all(&chand->waiting_for_config_closures); grpc_closure_list_fail_all(
&chand->waiting_for_config_closures,
GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1));
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL); NULL);
} }
@ -218,9 +226,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->exit_idle_when_lb_policy_arrives = 0; chand->exit_idle_when_lb_policy_arrives = 0;
} }
if (iomgr_success && chand->resolver) { if (error == GRPC_ERROR_NONE && chand->resolver) {
set_channel_connectivity_state_locked(exec_ctx, chand, state, set_channel_connectivity_state_locked(
"new_lb+resolver"); exec_ctx, chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver");
if (lb_policy != NULL) { if (lb_policy != NULL) {
watch_lb_policy(exec_ctx, chand, lb_policy, state); watch_lb_policy(exec_ctx, chand, lb_policy, state);
} }
@ -235,8 +243,12 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
chand->resolver = NULL; chand->resolver = NULL;
} }
grpc_error *refs[] = {error, state_error};
set_channel_connectivity_state_locked( set_channel_connectivity_state_locked(
exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, "resolver_gone"); exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs,
GPR_ARRAY_SIZE(refs)),
"resolver_gone");
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
} }
@ -256,6 +268,7 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
} }
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver"); GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
GRPC_ERROR_UNREF(state_error);
} }
static void cc_start_transport_op(grpc_exec_ctx *exec_ctx, static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
@ -263,7 +276,7 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_transport_op *op) { grpc_transport_op *op) {
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
GPR_ASSERT(op->set_accept_stream == false); GPR_ASSERT(op->set_accept_stream == false);
if (op->bind_pollset != NULL) { if (op->bind_pollset != NULL) {
@ -282,7 +295,9 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
if (op->send_ping != NULL) { if (op->send_ping != NULL) {
if (chand->lb_policy == NULL) { if (chand->lb_policy == NULL) {
grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL); grpc_exec_ctx_sched(exec_ctx, op->send_ping,
GRPC_ERROR_CREATE("Ping with no load balancing"),
NULL);
} else { } else {
grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping); grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
op->bind_pollset = NULL; op->bind_pollset = NULL;
@ -290,16 +305,19 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
op->send_ping = NULL; op->send_ping = NULL;
} }
if (op->disconnect && chand->resolver != NULL) { if (op->disconnect_with_error != GRPC_ERROR_NONE) {
set_channel_connectivity_state_locked(exec_ctx, chand, if (chand->resolver != NULL) {
GRPC_CHANNEL_SHUTDOWN, "disconnect"); set_channel_connectivity_state_locked(
exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
grpc_resolver_shutdown(exec_ctx, chand->resolver); grpc_resolver_shutdown(exec_ctx, chand->resolver);
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel"); GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
chand->resolver = NULL; chand->resolver = NULL;
if (!chand->started_resolving) { if (!chand->started_resolving) {
grpc_closure_list_fail_all(&chand->waiting_for_config_closures); grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures, GRPC_ERROR_REF(op->disconnect_with_error));
NULL); grpc_exec_ctx_enqueue_list(exec_ctx,
&chand->waiting_for_config_closures, NULL);
} }
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, grpc_pollset_set_del_pollset_set(exec_ctx,
@ -309,6 +327,8 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
chand->lb_policy = NULL; chand->lb_policy = NULL;
} }
} }
GRPC_ERROR_UNREF(op->disconnect_with_error);
}
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
} }
@ -327,16 +347,17 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connected_subchannel **connected_subchannel, grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready); grpc_closure *on_ready);
static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
continue_picking_args *cpa = arg; continue_picking_args *cpa = arg;
if (cpa->connected_subchannel == NULL) { if (cpa->connected_subchannel == NULL) {
/* cancelled, do nothing */ /* cancelled, do nothing */
} else if (!success) { } else if (error != GRPC_ERROR_NONE) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL);
} else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata, } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
cpa->initial_metadata_flags, cpa->initial_metadata_flags,
cpa->connected_subchannel, cpa->on_ready)) { cpa->connected_subchannel, cpa->on_ready)) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL); grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
} }
gpr_free(cpa); gpr_free(cpa);
} }
@ -361,11 +382,12 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
connected_subchannel); connected_subchannel);
} }
for (closure = chand->waiting_for_config_closures.head; closure != NULL; for (closure = chand->waiting_for_config_closures.head; closure != NULL;
closure = grpc_closure_next(closure)) { closure = closure->next_data.next) {
cpa = closure->cb_arg; cpa = closure->cb_arg;
if (cpa->connected_subchannel == connected_subchannel) { if (cpa->connected_subchannel == connected_subchannel) {
cpa->connected_subchannel = NULL; cpa->connected_subchannel = NULL;
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL); grpc_exec_ctx_sched(exec_ctx, cpa->on_ready,
GRPC_ERROR_CREATE("Pick cancelled"), NULL);
} }
} }
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
@ -397,10 +419,11 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
cpa->on_ready = on_ready; cpa->on_ready = on_ready;
cpa->elem = elem; cpa->elem = elem;
grpc_closure_init(&cpa->closure, continue_picking, cpa); grpc_closure_init(&cpa->closure, continue_picking, cpa);
grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure, grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
1); GRPC_ERROR_NONE);
} else { } else {
grpc_exec_ctx_enqueue(exec_ctx, on_ready, false, NULL); grpc_exec_ctx_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"),
NULL);
} }
gpr_mu_unlock(&chand->mu_config); gpr_mu_unlock(&chand->mu_config);
return 0; return 0;
@ -507,7 +530,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
channel_data *chand = elem->channel_data; channel_data *chand = elem->channel_data;
grpc_connectivity_state out; grpc_connectivity_state out;
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
out = grpc_connectivity_state_check(&chand->state_tracker); out = grpc_connectivity_state_check(&chand->state_tracker, NULL);
if (out == GRPC_CHANNEL_IDLE && try_to_connect) { if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy); grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
@ -534,7 +557,7 @@ typedef struct {
} external_connectivity_watcher; } external_connectivity_watcher;
static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
external_connectivity_watcher *w = arg; external_connectivity_watcher *w = arg;
grpc_closure *follow_up = w->on_complete; grpc_closure *follow_up = w->on_complete;
grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
@ -542,7 +565,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
"external_connectivity_watcher"); "external_connectivity_watcher");
gpr_free(w); gpr_free(w);
follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success); follow_up->cb(exec_ctx, follow_up->cb_arg, error);
} }
void grpc_client_channel_watch_connectivity_state( void grpc_client_channel_watch_connectivity_state(

@ -64,7 +64,7 @@ typedef struct {
grpc_transport *transport; grpc_transport *transport;
/** channel arguments (to be passed to the filters) */ /** channel arguments (to be passed to the filters) */
const grpc_channel_args *channel_args; grpc_channel_args *channel_args;
} grpc_connect_out_args; } grpc_connect_out_args;
struct grpc_connector_vtable { struct grpc_connector_vtable {

@ -60,8 +60,9 @@ static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
: gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, "LB_POLICY: 0x%" PRIxPTR " %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR
old_val + delta, reason); " [%s]",
(intptr_t)c, purpose, old_val, old_val + delta, reason);
#endif #endif
return old_val; return old_val;
} }
@ -138,6 +139,8 @@ void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
} }
grpc_connectivity_state grpc_lb_policy_check_connectivity( grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) { grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
return policy->vtable->check_connectivity(exec_ctx, policy); grpc_error **connectivity_error) {
return policy->vtable->check_connectivity(exec_ctx, policy,
connectivity_error);
} }

@ -77,8 +77,9 @@ struct grpc_lb_policy_vtable {
void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
/** check the current connectivity of the lb_policy */ /** check the current connectivity of the lb_policy */
grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx, grpc_connectivity_state (*check_connectivity)(
grpc_lb_policy *policy); grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_error **connectivity_error);
/** call notify when the connectivity state of a channel changes from *state. /** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the policy */ Updates *state with the new state of the policy */
@ -154,6 +155,7 @@ void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
grpc_closure *closure); grpc_closure *closure);
grpc_connectivity_state grpc_lb_policy_check_connectivity( grpc_connectivity_state grpc_lb_policy_check_connectivity(
grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy); grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_error **connectivity_error);
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_LB_POLICY_H */ #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_LB_POLICY_H */

@ -54,7 +54,7 @@
#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 #define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 2 #define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 #define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 #define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 #define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
@ -147,7 +147,7 @@ struct grpc_subchannel_call {
(((grpc_subchannel_call *)(callstack)) - 1) (((grpc_subchannel_call *)(callstack)) - 1)
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
bool iomgr_success); grpc_error *error);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
#define REF_REASON reason #define REF_REASON reason
@ -177,7 +177,7 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
*/ */
static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg, static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
grpc_connected_subchannel *c = arg; grpc_connected_subchannel *c = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c)); grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
gpr_free(c); gpr_free(c);
@ -200,7 +200,7 @@ void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
*/ */
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
grpc_subchannel *c = arg; grpc_subchannel *c = arg;
gpr_free((void *)c->filters); gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args); grpc_channel_args_destroy(c->args);
@ -290,8 +290,8 @@ void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
gpr_atm old_refs; gpr_atm old_refs;
old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF")); old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
if (old_refs == 1) { if (old_refs == 1) {
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c), grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(subchannel_destroy, c),
true, NULL); GRPC_ERROR_NONE, NULL);
} }
} }
@ -382,7 +382,8 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
args.initial_connect_string = c->initial_connect_string; args.initial_connect_string = c->initial_connect_string;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
GRPC_CHANNEL_CONNECTING, "state_change"); GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
"state_change");
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result, grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected); &c->connected);
} }
@ -393,16 +394,17 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
continue_connect(exec_ctx, c); continue_connect(exec_ctx, c);
} }
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c,
grpc_error **error) {
grpc_connectivity_state state; grpc_connectivity_state state;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
state = grpc_connectivity_state_check(&c->state_tracker); state = grpc_connectivity_state_check(&c->state_tracker, error);
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
return state; return state;
} }
static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg, static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
external_state_watcher *w = arg; external_state_watcher *w = arg;
grpc_closure *follow_up = w->notify; grpc_closure *follow_up = w->notify;
if (w->pollset_set != NULL) { if (w->pollset_set != NULL) {
@ -415,7 +417,7 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&w->subchannel->mu); gpr_mu_unlock(&w->subchannel->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher");
gpr_free(w); gpr_free(w);
follow_up->cb(exec_ctx, follow_up->cb_arg, success); follow_up->cb(exec_ctx, follow_up->cb_arg, error);
} }
void grpc_subchannel_notify_on_state_change( void grpc_subchannel_notify_on_state_change(
@ -469,7 +471,7 @@ void grpc_connected_subchannel_process_transport_op(
} }
static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p, static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
bool iomgr_success) { grpc_error *error) {
state_watcher *sw = p; state_watcher *sw = p;
grpc_subchannel *c = sw->subchannel; grpc_subchannel *c = sw->subchannel;
gpr_mu *mu = &c->mu; gpr_mu *mu = &c->mu;
@ -477,13 +479,13 @@ static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
gpr_mu_lock(mu); gpr_mu_lock(mu);
/* if we failed just leave this closure */ /* if we failed just leave this closure */
if (iomgr_success) {
if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
/* any errors on a subchannel ==> we're done, create a new one */ /* any errors on a subchannel ==> we're done, create a new one */
sw->connectivity_state = GRPC_CHANNEL_SHUTDOWN; sw->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
} }
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
sw->connectivity_state, "reflect_child"); sw->connectivity_state, GRPC_ERROR_REF(error),
"reflect_child");
if (sw->connectivity_state != GRPC_CHANNEL_SHUTDOWN) { if (sw->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL, exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
@ -491,7 +493,6 @@ static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
sw = NULL; sw = NULL;
} }
}
gpr_mu_unlock(mu); gpr_mu_unlock(mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher");
@ -592,17 +593,20 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
/* signal completion */ /* signal completion */
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
"connected"); GRPC_ERROR_NONE, "connected");
} }
static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) { static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_subchannel *c = arg; grpc_subchannel *c = arg;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
c->have_alarm = 0; c->have_alarm = 0;
if (c->disconnected) { if (c->disconnected) {
iomgr_success = 0; error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
} else {
GRPC_ERROR_REF(error);
} }
if (iomgr_success) { if (error == GRPC_ERROR_NONE) {
gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
c->next_attempt = c->next_attempt =
gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC)); gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
continue_connect(exec_ctx, c); continue_connect(exec_ctx, c);
@ -611,11 +615,13 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} }
GRPC_ERROR_UNREF(error);
} }
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
grpc_subchannel *c = arg; grpc_subchannel *c = arg;
grpc_channel_args *delete_channel_args = c->connecting_result.channel_args;
GRPC_SUBCHANNEL_WEAK_REF(c, "connected"); GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
@ -627,13 +633,26 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
GPR_ASSERT(!c->have_alarm); GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1; c->have_alarm = 1;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1),
"connect_failed"); "connect_failed");
gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
const char *errmsg = grpc_error_string(error);
gpr_log(GPR_INFO, "Connect failed: %s", errmsg);
if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
0) {
gpr_log(GPR_INFO, "Retry immediately");
} else {
gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
time_til_next.tv_sec, time_til_next.tv_nsec);
}
grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
grpc_error_free_string(errmsg);
} }
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
grpc_channel_args_destroy(delete_channel_args);
} }
/* /*
@ -641,7 +660,7 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
*/ */
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
bool success) { grpc_error *error) {
grpc_subchannel_call *c = call; grpc_subchannel_call *c = call;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_connected_subchannel *connection = c->connection; grpc_connected_subchannel *connection = c->connection;

@ -119,7 +119,7 @@ void grpc_connected_subchannel_process_transport_op(
/** poll the current connectivity state of a channel */ /** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity( grpc_connectivity_state grpc_subchannel_check_connectivity(
grpc_subchannel *channel); grpc_subchannel *channel, grpc_error **error);
/** call notify when the connectivity state of a channel changes from *state. /** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the channel */ Updates *state with the new state of the channel */

@ -43,14 +43,14 @@
#define CANCELLED_CALL ((grpc_subchannel_call *)1) #define CANCELLED_CALL ((grpc_subchannel_call *)1)
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder, static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
bool success); grpc_error *error);
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args, static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
bool success); grpc_error *error);
static void add_waiting_locked(grpc_subchannel_call_holder *holder, static void add_waiting_locked(grpc_subchannel_call_holder *holder,
grpc_transport_stream_op *op); grpc_transport_stream_op *op);
static void fail_locked(grpc_exec_ctx *exec_ctx, static void fail_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder); grpc_subchannel_call_holder *holder, grpc_error *error);
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder); grpc_subchannel_call_holder *holder);
@ -91,7 +91,8 @@ void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call = GET_CALL(holder); grpc_subchannel_call *call = GET_CALL(holder);
GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0); GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0);
if (call == CANCELLED_CALL) { if (call == CANCELLED_CALL) {
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return; return;
} }
@ -107,7 +108,8 @@ retry:
call = GET_CALL(holder); call = GET_CALL(holder);
if (call == CANCELLED_CALL) { if (call == CANCELLED_CALL) {
gpr_mu_unlock(&holder->mu); gpr_mu_unlock(&holder->mu);
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return; return;
} }
@ -124,7 +126,10 @@ retry:
} else { } else {
switch (holder->creation_phase) { switch (holder->creation_phase) {
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING: case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder,
grpc_error_set_int(GRPC_ERROR_CREATE("Cancelled"),
GRPC_ERROR_INT_GRPC_STATUS,
op->cancel_with_status));
break; break;
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL: case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL, holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
@ -132,7 +137,8 @@ retry:
break; break;
} }
gpr_mu_unlock(&holder->mu); gpr_mu_unlock(&holder->mu);
grpc_transport_stream_op_finish_with_failure(exec_ctx, op); grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return; return;
} }
@ -168,7 +174,8 @@ retry:
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0); GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
} }
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_subchannel_call_holder *holder = arg; grpc_subchannel_call_holder *holder = arg;
gpr_mu_lock(&holder->mu); gpr_mu_lock(&holder->mu);
GPR_ASSERT(holder->creation_phase == GPR_ASSERT(holder->creation_phase ==
@ -176,10 +183,14 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING; holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (holder->connected_subchannel == NULL) { if (holder->connected_subchannel == NULL) {
gpr_atm_no_barrier_store(&holder->subchannel_call, 1); gpr_atm_no_barrier_store(&holder->subchannel_call, 1);
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder,
GRPC_ERROR_CREATE_REFERENCING("Failed to create subchannel",
&error, 1));
} else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) { } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
/* already cancelled before subchannel became ready */ /* already cancelled before subchannel became ready */
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder,
GRPC_ERROR_CREATE_REFERENCING(
"Cancelled before creating subchannel", &error, 1));
} else { } else {
gpr_atm_rel_store( gpr_atm_rel_store(
&holder->subchannel_call, &holder->subchannel_call,
@ -205,18 +216,18 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
a->call = GET_CALL(holder); a->call = GET_CALL(holder);
if (a->call == CANCELLED_CALL) { if (a->call == CANCELLED_CALL) {
gpr_free(a); gpr_free(a);
fail_locked(exec_ctx, holder); fail_locked(exec_ctx, holder, GRPC_ERROR_CANCELLED);
return; return;
} }
holder->waiting_ops = NULL; holder->waiting_ops = NULL;
holder->waiting_ops_count = 0; holder->waiting_ops_count = 0;
holder->waiting_ops_capacity = 0; holder->waiting_ops_capacity = 0;
GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops"); GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true, grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a),
NULL); GRPC_ERROR_NONE, NULL);
} }
static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) { static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
retry_ops_args *a = args; retry_ops_args *a = args;
size_t i; size_t i;
for (i = 0; i < a->nops; i++) { for (i = 0; i < a->nops; i++) {
@ -241,13 +252,15 @@ static void add_waiting_locked(grpc_subchannel_call_holder *holder,
} }
static void fail_locked(grpc_exec_ctx *exec_ctx, static void fail_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder) { grpc_subchannel_call_holder *holder,
grpc_error *error) {
size_t i; size_t i;
for (i = 0; i < holder->waiting_ops_count; i++) { for (i = 0; i < holder->waiting_ops_count; i++) {
grpc_transport_stream_op_finish_with_failure(exec_ctx, grpc_transport_stream_op_finish_with_failure(
&holder->waiting_ops[i]); exec_ctx, &holder->waiting_ops[i], GRPC_ERROR_REF(error));
} }
holder->waiting_ops_count = 0; holder->waiting_ops_count = 0;
GRPC_ERROR_UNREF(error);
} }
char *grpc_subchannel_call_holder_get_peer( char *grpc_subchannel_call_holder_get_peer(

@ -103,8 +103,9 @@ static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
p->shutdown = 1; p->shutdown = 1;
pp = p->pending_picks; pp = p->pending_picks;
p->pending_picks = NULL; p->pending_picks = NULL;
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_SHUTDOWN, "shutdown"); exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE("Channel shutdown"), "shutdown");
/* cancel subscription */ /* cancel subscription */
if (selected != NULL) { if (selected != NULL) {
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
@ -120,7 +121,7 @@ static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
*pp->target = NULL; *pp->target = NULL;
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp); gpr_free(pp);
pp = next; pp = next;
} }
@ -139,7 +140,8 @@ static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE("Pick Cancelled"), NULL);
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -164,7 +166,8 @@ static void pf_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
initial_metadata_flags_eq) { initial_metadata_flags_eq) {
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE("Pick Cancelled"), NULL);
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -237,7 +240,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
} }
static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg, static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
pick_first_lb_policy *p = arg; pick_first_lb_policy *p = arg;
size_t i; size_t i;
size_t num_subchannels = p->num_subchannels; size_t num_subchannels = p->num_subchannels;
@ -258,12 +261,14 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
} }
static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
pick_first_lb_policy *p = arg; pick_first_lb_policy *p = arg;
grpc_subchannel *selected_subchannel; grpc_subchannel *selected_subchannel;
pending_pick *pp; pending_pick *pp;
grpc_connected_subchannel *selected; grpc_connected_subchannel *selected;
GRPC_ERROR_REF(error);
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
selected = GET_SELECTED(p); selected = GET_SELECTED(p);
@ -271,6 +276,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (p->shutdown) { if (p->shutdown) {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
GRPC_ERROR_UNREF(error);
return; return;
} else if (selected != NULL) { } else if (selected != NULL) {
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
@ -278,7 +284,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN; p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN;
} }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
p->checking_connectivity, "selected_changed"); p->checking_connectivity, GRPC_ERROR_REF(error),
"selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) { if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) {
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
exec_ctx, selected, p->base.interested_parties, exec_ctx, selected, p->base.interested_parties,
@ -291,7 +298,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
switch (p->checking_connectivity) { switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY: case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready"); GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
"connecting_ready");
selected_subchannel = p->subchannels[p->checking_subchannel]; selected_subchannel = p->subchannels[p->checking_subchannel];
selected = selected =
grpc_subchannel_get_connected_subchannel(selected_subchannel); grpc_subchannel_get_connected_subchannel(selected_subchannel);
@ -300,15 +308,16 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
/* drop the pick list: we are connected now */ /* drop the pick list: we are connected now */
GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
gpr_atm_rel_store(&p->selected, (gpr_atm)selected); gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
grpc_exec_ctx_enqueue( grpc_exec_ctx_sched(exec_ctx,
exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL); grpc_closure_create(destroy_subchannels, p),
GRPC_ERROR_NONE, NULL);
/* update any calls that were waiting for a pick */ /* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = selected; *pp->target = selected;
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp); gpr_free(pp);
} }
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
@ -320,12 +329,13 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
(p->checking_subchannel + 1) % p->num_subchannels; (p->checking_subchannel + 1) % p->num_subchannels;
if (p->checking_subchannel == 0) { if (p->checking_subchannel == 0) {
/* only trigger transient failure when we've tried all alternatives */ /* only trigger transient failure when we've tried all alternatives */
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure"); GRPC_ERROR_REF(error), "connecting_transient_failure");
} }
GRPC_ERROR_UNREF(error);
p->checking_connectivity = grpc_subchannel_check_connectivity( p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]); p->subchannels[p->checking_subchannel], &error);
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
@ -337,9 +347,9 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
break; break;
case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_CONNECTING, exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING,
"connecting_changed"); GRPC_ERROR_REF(error), "connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
p->base.interested_parties, &p->checking_connectivity, p->base.interested_parties, &p->checking_connectivity,
@ -352,38 +362,45 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
"pick_first"); "pick_first");
if (p->num_subchannels == 0) { if (p->num_subchannels == 0) {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_SHUTDOWN, exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels",
&error, 1),
"no_more_channels"); "no_more_channels");
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
NULL);
gpr_free(pp); gpr_free(pp);
} }
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
"pick_first_connectivity"); "pick_first_connectivity");
} else { } else {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
"subchannel_failed"); GRPC_ERROR_REF(error), "subchannel_failed");
p->checking_subchannel %= p->num_subchannels; p->checking_subchannel %= p->num_subchannels;
GRPC_ERROR_UNREF(error);
p->checking_connectivity = grpc_subchannel_check_connectivity( p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]); p->subchannels[p->checking_subchannel], &error);
goto loop; goto loop;
} }
} }
} }
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
GRPC_ERROR_UNREF(error);
} }
static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx, static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol) { grpc_lb_policy *pol,
grpc_error **error) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol; pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
grpc_connectivity_state st; grpc_connectivity_state st;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
st = grpc_connectivity_state_check(&p->state_tracker); st = grpc_connectivity_state_check(&p->state_tracker, error);
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
return st; return st;
} }
@ -406,7 +423,8 @@ static void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if (selected) { if (selected) {
grpc_connected_subchannel_ping(exec_ctx, selected, closure); grpc_connected_subchannel_ping(exec_ctx, selected, closure);
} else { } else {
grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"),
NULL);
} }
} }

@ -265,11 +265,13 @@ static void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
GRPC_ERROR_CREATE("Channel Shutdown"), NULL);
gpr_free(pp); gpr_free(pp);
} }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_SHUTDOWN, "shutdown"); exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE("Channel Shutdown"), "shutdown");
for (i = 0; i < p->num_subchannels; i++) { for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i]; subchannel_data *sd = p->subchannels[i];
grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
@ -291,7 +293,8 @@ static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_CANCELLED,
NULL);
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -317,7 +320,8 @@ static void rr_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
*pp->target = NULL; *pp->target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_CANCELLED,
NULL);
gpr_free(pp); gpr_free(pp);
} else { } else {
pp->next = p->pending_picks; pp->next = p->pending_picks;
@ -333,7 +337,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
p->started_picking = 1; p->started_picking = 1;
if (grpc_lb_round_robin_trace) { if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p, gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, p,
p->num_subchannels); p->num_subchannels);
} }
@ -396,7 +400,7 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
} }
static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { grpc_error *error) {
subchannel_data *sd = arg; subchannel_data *sd = arg;
round_robin_lb_policy *p = sd->policy; round_robin_lb_policy *p = sd->policy;
pending_pick *pp; pending_pick *pp;
@ -404,6 +408,7 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int unref = 0; int unref = 0;
GRPC_ERROR_REF(error);
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
if (p->shutdown) { if (p->shutdown) {
@ -412,7 +417,8 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
switch (sd->connectivity_state) { switch (sd->connectivity_state) {
case GRPC_CHANNEL_READY: case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready"); GRPC_CHANNEL_READY, GRPC_ERROR_REF(error),
"connecting_ready");
/* add the newly connected subchannel to the list of connected ones. /* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */ * Note that it goes to the "end of the line". */
sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel); sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
@ -436,7 +442,7 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
} }
grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
p->base.interested_parties); p->base.interested_parties);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp); gpr_free(pp);
} }
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
@ -445,9 +451,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
break; break;
case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
sd->connectivity_state, exec_ctx, &p->state_tracker, sd->connectivity_state,
"connecting_changed"); GRPC_ERROR_REF(error), "connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, p->base.interested_parties, exec_ctx, sd->subchannel, p->base.interested_parties,
&sd->connectivity_state, &sd->connectivity_changed_closure); &sd->connectivity_state, &sd->connectivity_changed_closure);
@ -463,9 +469,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
remove_disconnected_sc_locked(p, sd->ready_list_node); remove_disconnected_sc_locked(p, sd->ready_list_node);
sd->ready_list_node = NULL; sd->ready_list_node = NULL;
} }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure"); GRPC_ERROR_REF(error), "connecting_transient_failure");
break; break;
case GRPC_CHANNEL_SHUTDOWN: case GRPC_CHANNEL_SHUTDOWN:
if (sd->ready_list_node != NULL) { if (sd->ready_list_node != NULL) {
@ -482,19 +488,22 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
unref = 1; unref = 1;
if (p->num_subchannels == 0) { if (p->num_subchannels == 0) {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_SHUTDOWN, exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_REFERENCING("Round Robin Channels Exhausted",
&error, 1),
"no_more_channels"); "no_more_channels");
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
NULL);
gpr_free(pp); gpr_free(pp);
} }
} else { } else {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker, grpc_connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
"subchannel_failed"); GRPC_ERROR_REF(error), "subchannel_failed");
} }
} /* switch */ } /* switch */
} /* !unref */ } /* !unref */
@ -504,14 +513,17 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (unref) { if (unref) {
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
} }
GRPC_ERROR_UNREF(error);
} }
static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx, static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol) { grpc_lb_policy *pol,
grpc_error **error) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol; round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
grpc_connectivity_state st; grpc_connectivity_state st;
gpr_mu_lock(&p->mu); gpr_mu_lock(&p->mu);
st = grpc_connectivity_state_check(&p->state_tracker); st = grpc_connectivity_state_check(&p->state_tracker, error);
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
return st; return st;
} }
@ -539,7 +551,8 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_connected_subchannel_ping(exec_ctx, target, closure); grpc_connected_subchannel_ping(exec_ctx, target, closure);
} else { } else {
gpr_mu_unlock(&p->mu); gpr_mu_unlock(&p->mu);
grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL); grpc_exec_ctx_sched(exec_ctx, closure,
GRPC_ERROR_CREATE("Round Robin not connected"), NULL);
} }
} }

@ -82,6 +82,9 @@ typedef struct {
grpc_timer retry_timer; grpc_timer retry_timer;
/** retry backoff state */ /** retry backoff state */
gpr_backoff backoff_state; gpr_backoff backoff_state;
/** currently resolving addresses */
grpc_resolved_addresses *addresses;
} dns_resolver; } dns_resolver;
static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r); static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@ -108,7 +111,8 @@ static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
} }
if (r->next_completion != NULL) { if (r->next_completion != NULL) {
*r->target_config = NULL; *r->target_config = NULL;
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion,
GRPC_ERROR_CREATE("Resolver Shutdown"), NULL);
r->next_completion = NULL; r->next_completion = NULL;
} }
gpr_mu_unlock(&r->mu); gpr_mu_unlock(&r->mu);
@ -143,12 +147,12 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
} }
static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
dns_resolver *r = arg; dns_resolver *r = arg;
gpr_mu_lock(&r->mu); gpr_mu_lock(&r->mu);
r->have_retry_timer = false; r->have_retry_timer = false;
if (success) { if (error == GRPC_ERROR_NONE) {
if (!r->resolving) { if (!r->resolving) {
dns_start_resolving_locked(exec_ctx, r); dns_start_resolving_locked(exec_ctx, r);
} }
@ -159,13 +163,14 @@ static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
} }
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg, static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_resolved_addresses *addresses) { grpc_error *error) {
dns_resolver *r = arg; dns_resolver *r = arg;
grpc_client_config *config = NULL; grpc_client_config *config = NULL;
grpc_lb_policy *lb_policy; grpc_lb_policy *lb_policy;
gpr_mu_lock(&r->mu); gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving); GPR_ASSERT(r->resolving);
r->resolving = 0; r->resolving = 0;
grpc_resolved_addresses *addresses = r->addresses;
if (addresses != NULL) { if (addresses != NULL) {
grpc_lb_policy_args lb_policy_args; grpc_lb_policy_args lb_policy_args;
config = grpc_client_config_create(); config = grpc_client_config_create();
@ -183,11 +188,18 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now); gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now); gpr_timespec timeout = gpr_time_sub(next_try, now);
gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d.%09d seconds", const char *msg = grpc_error_string(error);
timeout.tv_sec, timeout.tv_nsec); gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
grpc_error_free_string(msg);
GPR_ASSERT(!r->have_retry_timer); GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true; r->have_retry_timer = true;
GRPC_RESOLVER_REF(&r->base, "retry-timer"); GRPC_RESOLVER_REF(&r->base, "retry-timer");
if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) <= 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
timeout.tv_nsec);
} else {
gpr_log(GPR_DEBUG, "retrying immediately");
}
grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r, grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
now); now);
} }
@ -207,7 +219,9 @@ static void dns_start_resolving_locked(grpc_exec_ctx *exec_ctx,
GRPC_RESOLVER_REF(&r->base, "dns-resolving"); GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving); GPR_ASSERT(!r->resolving);
r->resolving = 1; r->resolving = 1;
grpc_resolve_address(exec_ctx, r->name, r->default_port, dns_on_resolved, r); r->addresses = NULL;
grpc_resolve_address(exec_ctx, r->name, r->default_port,
grpc_closure_create(dns_on_resolved, r), &r->addresses);
} }
static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx, static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
@ -218,7 +232,7 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
if (r->resolved_config) { if (r->resolved_config) {
grpc_client_config_ref(r->resolved_config); grpc_client_config_ref(r->resolved_config);
} }
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL; r->next_completion = NULL;
r->published_version = r->resolved_version; r->published_version = r->resolved_version;
} }

@ -92,7 +92,7 @@ static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&r->mu); gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) { if (r->next_completion != NULL) {
*r->target_config = NULL; *r->target_config = NULL;
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL; r->next_completion = NULL;
} }
gpr_mu_unlock(&r->mu); gpr_mu_unlock(&r->mu);
@ -133,7 +133,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr"); GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
r->published = 1; r->published = 1;
*r->target_config = cfg; *r->target_config = cfg;
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL); grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL; r->next_completion = NULL;
} }
} }

@ -1,513 +0,0 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <grpc/grpc_zookeeper.h>
#include <zookeeper/zookeeper.h>
#include "src/core/ext/client_config/lb_policy_registry.h"
#include "src/core/ext/client_config/resolver_registry.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
/** Zookeeper session expiration time in milliseconds */
#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
typedef struct {
/** base class: must be first */
grpc_resolver base;
/** refcount */
gpr_refcount refs;
/** name to resolve */
char *name;
/** subchannel factory */
grpc_client_channel_factory *client_channel_factory;
/** load balancing policy name */
char *lb_policy_name;
/** mutex guarding the rest of the state */
gpr_mu mu;
/** are we currently resolving? */
int resolving;
/** which version of resolved_config have we published? */
int published_version;
/** which version of resolved_config is current? */
int resolved_version;
/** pending next completion, or NULL */
grpc_closure *next_completion;
/** target config address for next completion */
grpc_client_config **target_config;
/** current (fully resolved) config */
grpc_client_config *resolved_config;
/** zookeeper handle */
zhandle_t *zookeeper_handle;
/** zookeeper resolved addresses */
grpc_resolved_addresses *resolved_addrs;
/** total number of addresses to be resolved */
int resolved_total;
/** number of addresses resolved */
int resolved_num;
} zookeeper_resolver;
static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
zookeeper_resolver *r);
static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *r);
static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config,
grpc_closure *on_complete);
static const grpc_resolver_vtable zookeeper_resolver_vtable = {
zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
zookeeper_next};
static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver) {
zookeeper_resolver *r = (zookeeper_resolver *)resolver;
grpc_closure *call = NULL;
gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_config = NULL;
call = r->next_completion;
r->next_completion = NULL;
}
zookeeper_close(r->zookeeper_handle);
gpr_mu_unlock(&r->mu);
if (call != NULL) {
call->cb(exec_ctx, call->cb_arg, 1);
}
}
static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
grpc_resolver *resolver) {
zookeeper_resolver *r = (zookeeper_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->resolving == 0) {
zookeeper_start_resolving_locked(r);
}
gpr_mu_unlock(&r->mu);
}
static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
grpc_client_config **target_config,
grpc_closure *on_complete) {
zookeeper_resolver *r = (zookeeper_resolver *)resolver;
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->next_completion == NULL);
r->next_completion = on_complete;
r->target_config = target_config;
if (r->resolved_version == 0 && r->resolving == 0) {
zookeeper_start_resolving_locked(r);
} else {
zookeeper_maybe_finish_next_locked(exec_ctx, r);
}
gpr_mu_unlock(&r->mu);
}
/** Zookeeper global watcher for connection management
TODO: better connection management besides logs */
static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
int state, const char *path,
void *watcher_ctx) {
if (type == ZOO_SESSION_EVENT) {
if (state == ZOO_EXPIRED_SESSION_STATE) {
gpr_log(GPR_ERROR, "Zookeeper session expired");
} else if (state == ZOO_AUTH_FAILED_STATE) {
gpr_log(GPR_ERROR, "Zookeeper authentication failed");
}
}
}
/** Zookeeper watcher triggered by changes to watched nodes
Once triggered, it tries to resolve again to get updated addresses */
static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
const char *path, void *watcher_ctx) {
if (watcher_ctx != NULL) {
zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
if (state == ZOO_CONNECTED_STATE) {
gpr_mu_lock(&r->mu);
if (r->resolving == 0) {
zookeeper_start_resolving_locked(r);
}
gpr_mu_unlock(&r->mu);
}
}
}
/** Callback function after getting all resolved addresses
Creates a subchannel for each address */
static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_resolved_addresses *addresses) {
zookeeper_resolver *r = arg;
grpc_client_config *config = NULL;
grpc_lb_policy *lb_policy;
if (addresses != NULL) {
grpc_lb_policy_args lb_policy_args;
config = grpc_client_config_create();
lb_policy_args.addresses = addresses;
lb_policy_args.client_channel_factory = r->client_channel_factory;
lb_policy =
grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
if (lb_policy != NULL) {
grpc_client_config_set_lb_policy(config, lb_policy);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
}
grpc_resolved_addresses_destroy(addresses);
}
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving == 1);
r->resolving = 0;
if (r->resolved_config != NULL) {
grpc_client_config_unref(exec_ctx, r->resolved_config);
}
r->resolved_config = config;
r->resolved_version++;
zookeeper_maybe_finish_next_locked(exec_ctx, r);
gpr_mu_unlock(&r->mu);
GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving");
}
/** Callback function for each DNS resolved address */
static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg,
grpc_resolved_addresses *addresses) {
size_t i;
zookeeper_resolver *r = arg;
int resolve_done = 0;
gpr_mu_lock(&r->mu);
r->resolved_num++;
r->resolved_addrs->addrs =
gpr_realloc(r->resolved_addrs->addrs,
sizeof(grpc_resolved_address) *
(r->resolved_addrs->naddrs + addresses->naddrs));
for (i = 0; i < addresses->naddrs; i++) {
memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
addresses->addrs[i].addr, addresses->addrs[i].len);
r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
addresses->addrs[i].len;
}
r->resolved_addrs->naddrs += addresses->naddrs;
grpc_resolved_addresses_destroy(addresses);
/** Wait for all addresses to be resolved */
resolve_done = (r->resolved_num == r->resolved_total);
gpr_mu_unlock(&r->mu);
if (resolve_done) {
zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs);
}
}
/** Parses JSON format address of a zookeeper node */
static char *zookeeper_parse_address(const char *value, size_t value_len) {
grpc_json *json;
grpc_json *cur;
const char *host;
const char *port;
char *buffer;
char *address = NULL;
buffer = gpr_malloc(value_len);
memcpy(buffer, value, value_len);
json = grpc_json_parse_string_with_len(buffer, value_len);
if (json != NULL) {
host = NULL;
port = NULL;
for (cur = json->child; cur != NULL; cur = cur->next) {
if (!strcmp(cur->key, "host")) {
host = cur->value;
if (port != NULL) {
break;
}
} else if (!strcmp(cur->key, "port")) {
port = cur->value;
if (host != NULL) {
break;
}
}
}
if (host != NULL && port != NULL) {
gpr_asprintf(&address, "%s:%s", host, port);
}
grpc_json_destroy(json);
}
gpr_free(buffer);
return address;
}
static void zookeeper_get_children_node_completion(int rc, const char *value,
int value_len,
const struct Stat *stat,
const void *arg) {
char *address = NULL;
zookeeper_resolver *r = (zookeeper_resolver *)arg;
int resolve_done = 0;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
if (rc != 0) {
gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
grpc_exec_ctx_finish(&exec_ctx);
return;
}
address = zookeeper_parse_address(value, (size_t)value_len);
if (address != NULL) {
/** Further resolves address by DNS */
grpc_resolve_address(&exec_ctx, address, NULL, zookeeper_dns_resolved, r);
gpr_free(address);
} else {
gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
gpr_mu_lock(&r->mu);
r->resolved_total--;
resolve_done = (r->resolved_num == r->resolved_total);
gpr_mu_unlock(&r->mu);
if (resolve_done) {
zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs);
}
}
grpc_exec_ctx_finish(&exec_ctx);
}
static void zookeeper_get_children_completion(
int rc, const struct String_vector *children, const void *arg) {
char *path;
int status;
int i;
zookeeper_resolver *r = (zookeeper_resolver *)arg;
if (rc != 0) {
gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
return;
}
if (children->count == 0) {
gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
return;
}
r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
r->resolved_addrs->addrs = NULL;
r->resolved_addrs->naddrs = 0;
r->resolved_total = children->count;
/** TODO: Replace expensive heap allocation with stack
if we can get maximum length of zookeeper path */
for (i = 0; i < children->count; i++) {
gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
zookeeper_get_children_node_completion, r);
gpr_free(path);
if (status != 0) {
gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
}
}
}
static void zookeeper_get_node_completion(int rc, const char *value,
int value_len,
const struct Stat *stat,
const void *arg) {
int status;
char *address = NULL;
zookeeper_resolver *r = (zookeeper_resolver *)arg;
r->resolved_addrs = NULL;
r->resolved_total = 0;
r->resolved_num = 0;
if (rc != 0) {
gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
return;
}
/** If zookeeper node of path r->name does not have address
(i.e. service node), get its children */
address = zookeeper_parse_address(value, (size_t)value_len);
if (address != NULL) {
r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
r->resolved_addrs->addrs = NULL;
r->resolved_addrs->naddrs = 0;
r->resolved_total = 1;
/** Further resolves address by DNS */
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_resolve_address(&exec_ctx, address, NULL, zookeeper_dns_resolved, r);
gpr_free(address);
grpc_exec_ctx_finish(&exec_ctx);
return;
}
status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
r, zookeeper_get_children_completion, r);
if (status != 0) {
gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
}
}
static void zookeeper_resolve_address(zookeeper_resolver *r) {
int status;
status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
zookeeper_get_node_completion, r);
if (status != 0) {
gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
}
}
static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
GPR_ASSERT(r->resolving == 0);
r->resolving = 1;
zookeeper_resolve_address(r);
}
static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
zookeeper_resolver *r) {
if (r->next_completion != NULL &&
r->resolved_version != r->published_version) {
*r->target_config = r->resolved_config;
if (r->resolved_config != NULL) {
grpc_client_config_ref(r->resolved_config);
}
grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
r->next_completion = NULL;
r->published_version = r->resolved_version;
}
}
static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
zookeeper_resolver *r = (zookeeper_resolver *)gr;
gpr_mu_destroy(&r->mu);
if (r->resolved_config != NULL) {
grpc_client_config_unref(exec_ctx, r->resolved_config);
}
grpc_client_channel_factory_unref(exec_ctx, r->client_channel_factory);
gpr_free(r->name);
gpr_free(r->lb_policy_name);
gpr_free(r);
}
static grpc_resolver *zookeeper_create(grpc_resolver_args *args,
const char *lb_policy_name) {
zookeeper_resolver *r;
size_t length;
char *path = args->uri->path;
if (0 == strcmp(args->uri->authority, "")) {
gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
return NULL;
}
/** Removes the trailing slash if exists */
length = strlen(path);
if (length > 1 && path[length - 1] == '/') {
path[length - 1] = 0;
}
r = gpr_malloc(sizeof(zookeeper_resolver));
memset(r, 0, sizeof(*r));
gpr_ref_init(&r->refs, 1);
gpr_mu_init(&r->mu);
grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
r->name = gpr_strdup(path);
r->client_channel_factory = args->client_channel_factory;
grpc_client_channel_factory_ref(r->client_channel_factory);
r->lb_policy_name = gpr_strdup(lb_policy_name);
/** Initializes zookeeper client */
zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
r->zookeeper_handle =
zookeeper_init(args->uri->authority, zookeeper_global_watcher,
GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
if (r->zookeeper_handle == NULL) {
gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
return NULL;
}
return &r->base;
}
/*
* FACTORY
*/
static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
static char *zookeeper_factory_get_default_hostname(
grpc_resolver_factory *factory, grpc_uri *uri) {
return NULL;
}
static grpc_resolver *zookeeper_factory_create_resolver(
grpc_resolver_factory *factory, grpc_resolver_args *args) {
return zookeeper_create(args, "pick_first");
}
static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
zookeeper_factory_ref, zookeeper_factory_unref,
zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname,
"zookeeper"};
static grpc_resolver_factory zookeeper_resolver_factory = {
&zookeeper_factory_vtable};
static grpc_resolver_factory *zookeeper_resolver_factory_create() {
return &zookeeper_resolver_factory;
}
static void zookeeper_plugin_init() {
grpc_register_resolver_type(zookeeper_resolver_factory_create());
}
void grpc_zookeeper_register() {
GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ());
grpc_register_plugin(zookeeper_plugin_init, NULL);
}

@ -79,11 +79,11 @@ static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
} }
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
connector_unref(exec_ctx, arg); connector_unref(exec_ctx, arg);
} }
static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg; connector *c = arg;
grpc_closure *notify; grpc_closure *notify;
grpc_endpoint *tcp = c->tcp; grpc_endpoint *tcp = c->tcp;
@ -103,13 +103,13 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0); 0);
GPR_ASSERT(c->result->transport); GPR_ASSERT(c->result->transport);
c->result->channel_args = c->args.channel_args; c->result->channel_args = grpc_channel_args_copy(c->args.channel_args);
} else { } else {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
} }
notify = c->notify; notify = c->notify;
c->notify = NULL; c->notify = NULL;
notify->cb(exec_ctx, notify->cb_arg, 1); grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
} }
static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {} static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}

@ -90,7 +90,6 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_auth_context *auth_context) { grpc_auth_context *auth_context) {
connector *c = arg; connector *c = arg;
grpc_closure *notify; grpc_closure *notify;
grpc_channel_args *args_copy = NULL;
gpr_mu_lock(&c->mu); gpr_mu_lock(&c->mu);
if (c->connecting_endpoint == NULL) { if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
@ -109,26 +108,23 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL, grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0); 0);
auth_context_arg = grpc_auth_context_to_arg(auth_context); auth_context_arg = grpc_auth_context_to_arg(auth_context);
args_copy = grpc_channel_args_copy_and_add(c->args.channel_args, c->result->channel_args = grpc_channel_args_copy_and_add(
&auth_context_arg, 1); c->args.channel_args, &auth_context_arg, 1);
c->result->channel_args = args_copy;
} }
notify = c->notify; notify = c->notify;
c->notify = NULL; c->notify = NULL;
/* look at c->args which are connector args. */ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
notify->cb(exec_ctx, notify->cb_arg, 1);
if (args_copy != NULL) grpc_channel_args_destroy(args_copy);
} }
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { grpc_error *error) {
connector *c = arg; connector *c = arg;
grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector, grpc_channel_security_connector_do_handshake(
c->connecting_endpoint, exec_ctx, c->security_connector, c->connecting_endpoint, c->args.deadline,
on_secure_handshake_done, c); on_secure_handshake_done, c);
} }
static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg; connector *c = arg;
grpc_closure *notify; grpc_closure *notify;
grpc_endpoint *tcp = c->newly_connecting_endpoint; grpc_endpoint *tcp = c->newly_connecting_endpoint;
@ -147,13 +143,14 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
&c->initial_string_sent); &c->initial_string_sent);
} else { } else {
grpc_channel_security_connector_do_handshake( grpc_channel_security_connector_do_handshake(
exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c); exec_ctx, c->security_connector, tcp, c->args.deadline,
on_secure_handshake_done, c);
} }
} else { } else {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));
notify = c->notify; notify = c->notify;
c->notify = NULL; c->notify = NULL;
notify->cb(exec_ctx, notify->cb_arg, 1); grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
} }
} }
@ -175,7 +172,6 @@ static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
grpc_closure *notify) { grpc_closure *notify) {
connector *c = (connector *)con; connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL); GPR_ASSERT(c->notify == NULL);
GPR_ASSERT(notify->cb);
c->notify = notify; c->notify = notify;
c->args = *args; c->args = *args;
c->result = result; c->result = result;

@ -35,6 +35,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/http_server_filter.h" #include "src/core/lib/channel/http_server_filter.h"
@ -74,34 +75,40 @@ static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
grpc_closure *destroy_done) { grpc_closure *destroy_done) {
grpc_tcp_server *tcp = tcpp; grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_unref(exec_ctx, tcp); grpc_tcp_server_unref(exec_ctx, tcp);
grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL); grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_NONE, NULL);
} }
int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) { int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
grpc_resolved_addresses *resolved = NULL; grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL; grpc_tcp_server *tcp = NULL;
size_t i; size_t i;
unsigned count = 0; size_t count = 0;
int port_num = -1; int port_num = -1;
int port_temp; int port_temp;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE;
GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2, GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr)); (server, addr));
resolved = grpc_blocking_resolve_address(addr, "http"); grpc_error **errors = NULL;
if (!resolved) { err = grpc_blocking_resolve_address(addr, "https", &resolved);
if (err != GRPC_ERROR_NONE) {
goto error; goto error;
} }
tcp = grpc_tcp_server_create(NULL); err = grpc_tcp_server_create(NULL, &tcp);
GPR_ASSERT(tcp); if (err != GRPC_ERROR_NONE) {
goto error;
}
for (i = 0; i < resolved->naddrs; i++) { const size_t naddrs = resolved->naddrs;
port_temp = grpc_tcp_server_add_port( errors = gpr_malloc(sizeof(*errors) * naddrs);
for (i = 0; i < naddrs; i++) {
errors[i] = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr, tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len); resolved->addrs[i].len, &port_temp);
if (port_temp > 0) { if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) { if (port_num == -1) {
port_num = port_temp; port_num = port_temp;
} else { } else {
@ -111,13 +118,24 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
} }
} }
if (count == 0) { if (count == 0) {
gpr_log(GPR_ERROR, "No address added out of total %d resolved", char *msg;
resolved->naddrs); gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
gpr_free(msg);
goto error; goto error;
} } else if (count != naddrs) {
if (count != resolved->naddrs) { char *msg;
gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", gpr_asprintf(&msg, "Only %" PRIuPTR
count, resolved->naddrs); " addresses added out of total %" PRIuPTR " resolved",
count, naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
gpr_free(msg);
const char *warning_message = grpc_error_string(err);
gpr_log(GPR_INFO, "WARNING: %s", warning_message);
grpc_error_free_string(warning_message);
/* we managed to bind some addresses: continue */
} }
grpc_resolved_addresses_destroy(resolved); grpc_resolved_addresses_destroy(resolved);
@ -127,6 +145,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
/* Error path: cleanup and return */ /* Error path: cleanup and return */
error: error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (resolved) { if (resolved) {
grpc_resolved_addresses_destroy(resolved); grpc_resolved_addresses_destroy(resolved);
} }
@ -135,7 +154,18 @@ error:
} }
port_num = 0; port_num = 0;
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
grpc_error_free_string(msg);
GRPC_ERROR_UNREF(err);
done: done:
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
if (errors != NULL) {
for (i = 0; i < naddrs; i++) {
GRPC_ERROR_UNREF(errors[i]);
}
}
gpr_free(errors);
return port_num; return port_num;
} }

@ -37,6 +37,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@ -128,8 +129,10 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
state->state = statep; state->state = statep;
state_ref(state->state); state_ref(state->state);
state->accepting_pollset = accepting_pollset; state->accepting_pollset = accepting_pollset;
grpc_server_security_connector_do_handshake(exec_ctx, state->state->sc, grpc_server_security_connector_do_handshake(
acceptor, tcp, exec_ctx, state->state->sc, acceptor, tcp,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(120, GPR_TIMESPAN)),
on_secure_handshake_done, state); on_secure_handshake_done, state);
} }
@ -141,11 +144,12 @@ static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
on_accept, state); on_accept, state);
} }
static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) { static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_error *error) {
server_secure_state *state = statep; server_secure_state *state = statep;
if (state->destroy_callback != NULL) { if (state->destroy_callback != NULL) {
state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg, state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
success); GRPC_ERROR_REF(error));
} }
grpc_server_security_connector_shutdown(exec_ctx, state->sc); grpc_server_security_connector_shutdown(exec_ctx, state->sc);
state_unref(state); state_unref(state);
@ -171,12 +175,14 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_tcp_server *tcp = NULL; grpc_tcp_server *tcp = NULL;
server_secure_state *state = NULL; server_secure_state *state = NULL;
size_t i; size_t i;
unsigned count = 0; size_t count = 0;
int port_num = -1; int port_num = -1;
int port_temp; int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_status status = GRPC_SECURITY_ERROR;
grpc_server_security_connector *sc = NULL; grpc_server_security_connector *sc = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE;
grpc_error **errors = NULL;
GRPC_API_TRACE( GRPC_API_TRACE(
"grpc_server_add_secure_http2_port(" "grpc_server_add_secure_http2_port("
@ -184,26 +190,34 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
3, (server, addr, creds)); 3, (server, addr, creds));
/* create security context */ /* create security context */
if (creds == NULL) goto error; if (creds == NULL) {
err = GRPC_ERROR_CREATE(
"No credentials specified for secure server port (creds==NULL)");
goto error;
}
status = grpc_server_credentials_create_security_connector(creds, &sc); status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, char *msg;
gpr_asprintf(&msg,
"Unable to create secure server with credentials of type %s.", "Unable to create secure server with credentials of type %s.",
creds->type); creds->type);
err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status);
gpr_free(msg);
goto error; goto error;
} }
sc->channel_args = grpc_server_get_channel_args(server); sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */ /* resolve address */
resolved = grpc_blocking_resolve_address(addr, "https"); err = grpc_blocking_resolve_address(addr, "https", &resolved);
if (!resolved) { if (err != GRPC_ERROR_NONE) {
goto error; goto error;
} }
state = gpr_malloc(sizeof(*state)); state = gpr_malloc(sizeof(*state));
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
grpc_closure_init(&state->destroy_closure, destroy_done, state); grpc_closure_init(&state->destroy_closure, destroy_done, state);
tcp = grpc_tcp_server_create(&state->destroy_closure); err = grpc_tcp_server_create(&state->destroy_closure, &tcp);
if (!tcp) { if (err != GRPC_ERROR_NONE) {
goto error; goto error;
} }
@ -215,11 +229,12 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
gpr_mu_init(&state->mu); gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1); gpr_ref_init(&state->refcount, 1);
errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
for (i = 0; i < resolved->naddrs; i++) { for (i = 0; i < resolved->naddrs; i++) {
port_temp = grpc_tcp_server_add_port( errors[i] = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr, tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len); resolved->addrs[i].len, &port_temp);
if (port_temp > 0) { if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) { if (port_num == -1) {
port_num = port_temp; port_num = port_temp;
} else { } else {
@ -229,15 +244,31 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
} }
} }
if (count == 0) { if (count == 0) {
gpr_log(GPR_ERROR, "No address added out of total %d resolved", char *msg;
gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
resolved->naddrs); resolved->naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
gpr_free(msg);
goto error; goto error;
} } else if (count != resolved->naddrs) {
if (count != resolved->naddrs) { char *msg;
gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved", gpr_asprintf(&msg, "Only %" PRIuPTR
" addresses added out of total %" PRIuPTR " resolved",
count, resolved->naddrs); count, resolved->naddrs);
/* if it's an error, don't we want to goto error; here ? */ err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
gpr_free(msg);
const char *warning_message = grpc_error_string(err);
gpr_log(GPR_INFO, "WARNING: %s", warning_message);
grpc_error_free_string(warning_message);
/* we managed to bind some addresses: continue */
} else {
for (i = 0; i < resolved->naddrs; i++) {
GRPC_ERROR_UNREF(errors[i]);
}
} }
gpr_free(errors);
errors = NULL;
grpc_resolved_addresses_destroy(resolved); grpc_resolved_addresses_destroy(resolved);
/* Register with the server only upon success */ /* Register with the server only upon success */
@ -248,6 +279,13 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
/* Error path: cleanup and return */ /* Error path: cleanup and return */
error: error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (errors != NULL) {
for (i = 0; i < resolved->naddrs; i++) {
GRPC_ERROR_UNREF(errors[i]);
}
gpr_free(errors);
}
if (resolved) { if (resolved) {
grpc_resolved_addresses_destroy(resolved); grpc_resolved_addresses_destroy(resolved);
} }
@ -262,5 +300,9 @@ error:
} }
} }
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
const char *msg = grpc_error_string(err);
GRPC_ERROR_UNREF(err);
gpr_log(GPR_ERROR, "%s", msg);
grpc_error_free_string(msg);
return 0; return 0;
} }

@ -0,0 +1,232 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/support/string.h"
static uint8_t decode_table[] = {
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62, 0x40, 0x40, 0x40, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x40, 0x40, 0x40, 0x40};
static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
static bool input_is_valid(uint8_t *input_ptr, size_t length) {
size_t i;
for (i = 0; i < length; ++i) {
if ((decode_table[input_ptr[i]] & 0xC0) != 0) {
gpr_log(GPR_ERROR,
"Base64 decoding failed, invalid character '%c' in base64 "
"input.\n",
(char)(*input_ptr));
return false;
}
}
return true;
}
#define COMPOSE_OUTPUT_BYTE_0(input_ptr) \
(uint8_t)((decode_table[input_ptr[0]] << 2) | \
(decode_table[input_ptr[1]] >> 4))
#define COMPOSE_OUTPUT_BYTE_1(input_ptr) \
(uint8_t)((decode_table[input_ptr[1]] << 4) | \
(decode_table[input_ptr[2]] >> 2))
#define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
(uint8_t)((decode_table[input_ptr[2]] << 6) | decode_table[input_ptr[3]])
bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) {
size_t input_tail;
if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
return false;
}
// Process a block of 4 input characters and 3 output bytes
while (ctx->input_end >= ctx->input_cur + 4 &&
ctx->output_end >= ctx->output_cur + 3) {
if (!input_is_valid(ctx->input_cur, 4)) return false;
ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
ctx->output_cur += 3;
ctx->input_cur += 4;
}
// Process the tail of input data
input_tail = (size_t)(ctx->input_end - ctx->input_cur);
if (input_tail == 4) {
// Process the input data with pad chars
if (ctx->input_cur[3] == '=') {
if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
if (!input_is_valid(ctx->input_cur, 2)) return false;
*(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
ctx->input_cur += 4;
} else if (ctx->output_end >= ctx->output_cur + 2) {
if (!input_is_valid(ctx->input_cur, 3)) return false;
*(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
*(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
;
ctx->input_cur += 4;
}
}
} else if (ctx->contains_tail && input_tail > 1) {
// Process the input data without pad chars, but constains_tail is set
if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
if (!input_is_valid(ctx->input_cur, input_tail)) return false;
switch (input_tail) {
case 3:
ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
case 2:
ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
}
ctx->output_cur += tail_xtra[input_tail];
ctx->input_cur += input_tail;
}
}
return true;
}
gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
size_t input_length = GPR_SLICE_LENGTH(input);
size_t output_length = input_length / 4 * 3;
struct grpc_base64_decode_context ctx;
gpr_slice output;
if (input_length % 4 != 0) {
gpr_log(GPR_ERROR,
"Base64 decoding failed, input of "
"grpc_chttp2_base64_decode has a length of %d, which is not a "
"multiple of 4.\n",
(int)input_length);
return gpr_empty_slice();
}
if (input_length > 0) {
uint8_t *input_end = GPR_SLICE_END_PTR(input);
if (*(--input_end) == '=') {
output_length--;
if (*(--input_end) == '=') {
output_length--;
}
}
}
output = gpr_slice_malloc(output_length);
ctx.input_cur = GPR_SLICE_START_PTR(input);
ctx.input_end = GPR_SLICE_END_PTR(input);
ctx.output_cur = GPR_SLICE_START_PTR(output);
ctx.output_end = GPR_SLICE_END_PTR(output);
ctx.contains_tail = false;
if (!grpc_base64_decode_partial(&ctx)) {
char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
gpr_slice_unref(output);
return gpr_empty_slice();
}
GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
GPR_ASSERT(ctx.input_cur == GPR_SLICE_END_PTR(input));
return output;
}
gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
size_t output_length) {
size_t input_length = GPR_SLICE_LENGTH(input);
gpr_slice output = gpr_slice_malloc(output_length);
struct grpc_base64_decode_context ctx;
// The length of a base64 string cannot be 4 * n + 1
if (input_length % 4 == 1) {
gpr_log(GPR_ERROR,
"Base64 decoding failed, input of "
"grpc_chttp2_base64_decode_with_length has a length of %d, which "
"has a tail of 1 byte.\n",
(int)input_length);
gpr_slice_unref(output);
return gpr_empty_slice();
}
if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) {
gpr_log(GPR_ERROR,
"Base64 decoding failed, output_length %d is longer "
"than the max possible output length %d.\n",
(int)output_length,
(int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
gpr_slice_unref(output);
return gpr_empty_slice();
}
ctx.input_cur = GPR_SLICE_START_PTR(input);
ctx.input_end = GPR_SLICE_END_PTR(input);
ctx.output_cur = GPR_SLICE_START_PTR(output);
ctx.output_end = GPR_SLICE_END_PTR(output);
ctx.contains_tail = true;
if (!grpc_base64_decode_partial(&ctx)) {
char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
gpr_slice_unref(output);
return gpr_empty_slice();
}
GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
GPR_ASSERT(ctx.input_cur <= GPR_SLICE_END_PTR(input));
return output;
}

@ -0,0 +1,66 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
#include <grpc/support/slice.h>
#include <stdbool.h>
struct grpc_base64_decode_context {
/* input/output: */
uint8_t *input_cur;
uint8_t *input_end;
uint8_t *output_cur;
uint8_t *output_end;
/* Indicate if the decoder should handle the tail of input data*/
bool contains_tail;
};
/* base64 decode a grpc_base64_decode_context util either input_end is reached
or output_end is reached. When input_end is reached, (input_end - input_cur)
is less than 4. When output_end is reached, (output_end - output_cur) is less
than 3. Returns false if decoding is failed. */
bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx);
/* base64 decode a slice with pad chars. Returns a new slice, does not take
ownership of the input. Returns an empty slice if decoding is failed. */
gpr_slice grpc_chttp2_base64_decode(gpr_slice input);
/* base64 decode a slice without pad chars, data length is needed. Returns a new
slice, does not take ownership of the input. Returns an empty slice if
decoding is failed. */
gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
size_t output_length);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */

@ -85,19 +85,17 @@ int grpc_flowctl_trace = 0;
static const grpc_transport_vtable vtable; static const grpc_transport_vtable vtable;
/* forward declarations of various callbacks that we'll build closures around */ /* forward declarations of various callbacks that we'll build closures around */
static void writing_action(grpc_exec_ctx *exec_ctx, void *t, static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
bool iomgr_success_ignored); static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
static void reading_action(grpc_exec_ctx *exec_ctx, void *t, static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
bool iomgr_success_ignored);
static void parsing_action(grpc_exec_ctx *exec_ctx, void *t,
bool iomgr_success_ignored);
/** Set a transport level setting, and push it to our peer */ /** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value); uint32_t value);
/** Start disconnection chain */ /** Start disconnection chain */
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t); static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_error *error);
/** Perform a transport_op */ /** Perform a transport_op */
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
@ -135,7 +133,7 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set( static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_connectivity_state state, const char *reason); grpc_connectivity_state state, grpc_error *error, const char *reason);
static void check_read_ops(grpc_exec_ctx *exec_ctx, static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global); grpc_chttp2_transport_global *transport_global);
@ -149,7 +147,9 @@ static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s, grpc_chttp2_stream *s,
void *byte_stream); void *byte_stream);
static void fail_pending_writes(grpc_exec_ctx *exec_ctx, static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global); grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
grpc_error *error);
/******************************************************************************* /*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING * CONSTRUCTION/DESTRUCTION/REFCOUNTING
@ -194,7 +194,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
and maybe they hold resources that need to be freed */ and maybe they hold resources that need to be freed */
while (t->global.pings.next != &t->global.pings) { while (t->global.pings.next != &t->global.pings) {
grpc_chttp2_outstanding_ping *ping = t->global.pings.next; grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL); grpc_exec_ctx_sched(exec_ctx, ping->on_recv,
GRPC_ERROR_CREATE("Transport closed"), NULL);
ping->next->prev = ping->prev; ping->next->prev = ping->prev;
ping->prev->next = ping->next; ping->prev->next = ping->next;
gpr_free(ping); gpr_free(ping);
@ -409,7 +410,7 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_ignored, grpc_chttp2_stream *s_ignored,
void *arg_ignored) { void *arg_ignored) {
t->destroying = 1; t->destroying = 1;
drop_connection(exec_ctx, t); drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed"));
} }
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
@ -445,12 +446,11 @@ static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
static void close_transport_locked(grpc_exec_ctx *exec_ctx, static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored, grpc_error *error) {
void *arg_ignored) {
if (!t->closed) { if (!t->closed) {
t->closed = 1; t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN, connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
"close_transport"); GRPC_ERROR_REF(error), "close_transport");
if (t->ep) { if (t->ep) {
allow_endpoint_shutdown_locked(exec_ctx, t); allow_endpoint_shutdown_locked(exec_ctx, t);
} }
@ -463,6 +463,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
} }
} }
GRPC_ERROR_UNREF(error);
} }
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG
@ -551,7 +552,9 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
s->global.id == 0); s->global.id == 0);
GPR_ASSERT(!s->global.in_stream_map); GPR_ASSERT(!s->global.in_stream_map);
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
close_transport_locked(exec_ctx, t, NULL, NULL); close_transport_locked(
exec_ctx, t,
GRPC_ERROR_CREATE("Last stream closed after sending goaway"));
} }
if (!t->executor.parsing_active && s->global.id) { if (!t->executor.parsing_active && s->global.id) {
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map, GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
@ -645,7 +648,7 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
t->executor.writing_active = 1; t->executor.writing_active = 1;
REF_TRANSPORT(t, "writing"); REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t); prevent_endpoint_shutdown(t);
grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL); grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
} }
check_read_ops(exec_ctx, &t->global); check_read_ops(exec_ctx, &t->global);
@ -756,12 +759,12 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored, grpc_chttp2_stream *s_ignored,
void *a) { void *a) {
bool success = (bool)(uintptr_t)a; grpc_error *error = a;
allow_endpoint_shutdown_locked(exec_ctx, t); allow_endpoint_shutdown_locked(exec_ctx, t);
if (!success) { if (error != GRPC_ERROR_NONE) {
drop_connection(exec_ctx, t); drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
} }
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing); grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
@ -769,7 +772,8 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global, while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) { &stream_global)) {
fail_pending_writes(exec_ctx, stream_global); fail_pending_writes(exec_ctx, &t->global, stream_global,
GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
} }
@ -782,18 +786,18 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
} }
UNREF_TRANSPORT(exec_ctx, t, "writing"); UNREF_TRANSPORT(exec_ctx, t, "writing");
GRPC_ERROR_UNREF(error);
} }
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
void *transport_writing, bool success) { void *transport_writing, grpc_error *error) {
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing); grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, grpc_chttp2_run_with_global_lock(
terminate_writing_with_lock, exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0);
(void *)(uintptr_t)success, 0);
} }
static void writing_action(grpc_exec_ctx *exec_ctx, void *gt, static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
bool iomgr_success_ignored) { grpc_error *error) {
grpc_chttp2_transport *t = gt; grpc_chttp2_transport *t = gt;
GPR_TIMER_BEGIN("writing_action", 0); GPR_TIMER_BEGIN("writing_action", 0);
grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep); grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
@ -806,13 +810,19 @@ void grpc_chttp2_add_incoming_goaway(
char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII); char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
GRPC_CHTTP2_IF_TRACING( GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg)); gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
gpr_free(msg);
gpr_slice_unref(goaway_text); gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1; transport_global->seen_goaway = 1;
/* lie: use transient failure from the transport to indicate goaway has been /* lie: use transient failure from the transport to indicate goaway has been
* received */ * received */
connectivity_state_set(exec_ctx, transport_global, connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, "got_goaway"); exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_str(
grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
GRPC_ERROR_INT_HTTP2_ERROR,
(intptr_t)goaway_error),
GRPC_ERROR_STR_RAW_BYTES, msg),
"got_goaway");
gpr_free(msg);
} }
static void maybe_start_some_streams( static void maybe_start_some_streams(
@ -841,9 +851,9 @@ static void maybe_start_some_streams(
transport_global->next_stream_id += 2; transport_global->next_stream_id += 2;
if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) { if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
connectivity_state_set(exec_ctx, transport_global, connectivity_state_set(
GRPC_CHANNEL_TRANSIENT_FAILURE, exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
"no_more_stream_ids"); GRPC_ERROR_CREATE("Stream IDs exhausted"), "no_more_stream_ids");
} }
stream_global->outgoing_window = stream_global->outgoing_window =
@ -871,34 +881,40 @@ static void maybe_start_some_streams(
} }
#define CLOSURE_BARRIER_STATS_BIT (1 << 0) #define CLOSURE_BARRIER_STATS_BIT (1 << 0)
#define CLOSURE_BARRIER_FAILURE_BIT (1 << 1)
#define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16) #define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16)
static grpc_closure *add_closure_barrier(grpc_closure *closure) { static grpc_closure *add_closure_barrier(grpc_closure *closure) {
closure->final_data += CLOSURE_BARRIER_FIRST_REF_BIT; closure->next_data.scratch += CLOSURE_BARRIER_FIRST_REF_BIT;
return closure; return closure;
} }
void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, void grpc_chttp2_complete_closure_step(
grpc_chttp2_stream_global *stream_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_closure **pclosure, int success) { grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
grpc_error *error) {
grpc_closure *closure = *pclosure; grpc_closure *closure = *pclosure;
if (closure == NULL) { if (closure == NULL) {
GRPC_ERROR_UNREF(error);
return; return;
} }
closure->final_data -= CLOSURE_BARRIER_FIRST_REF_BIT; closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
if (!success) { if (error != GRPC_ERROR_NONE) {
closure->final_data |= CLOSURE_BARRIER_FAILURE_BIT; if (closure->error == GRPC_ERROR_NONE) {
closure->error =
GRPC_ERROR_CREATE("Error in HTTP transport completing operation");
closure->error = grpc_error_set_str(
closure->error, GRPC_ERROR_STR_TARGET_ADDRESS,
TRANSPORT_FROM_GLOBAL(transport_global)->peer_string);
}
closure->error = grpc_error_add_child(closure->error, error);
} }
if (closure->final_data < CLOSURE_BARRIER_FIRST_REF_BIT) { if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) {
if (closure->final_data & CLOSURE_BARRIER_STATS_BIT) { if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) {
grpc_transport_move_stats(&stream_global->stats, grpc_transport_move_stats(&stream_global->stats,
stream_global->collecting_stats); stream_global->collecting_stats);
stream_global->collecting_stats = NULL; stream_global->collecting_stats = NULL;
} }
grpc_exec_ctx_enqueue( grpc_exec_ctx_sched(exec_ctx, closure, closure->error, NULL);
exec_ctx, closure,
(closure->final_data & CLOSURE_BARRIER_FAILURE_BIT) == 0, NULL);
} }
*pclosure = NULL; *pclosure = NULL;
} }
@ -916,7 +932,7 @@ static int contains_non_ok_status(
return 0; return 0;
} }
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {} static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
@ -933,12 +949,13 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} }
/* use final_data as a barrier until enqueue time; the inital counter is /* use final_data as a barrier until enqueue time; the inital counter is
dropped at the end of this function */ dropped at the end of this function */
on_complete->final_data = CLOSURE_BARRIER_FIRST_REF_BIT; on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
on_complete->error = GRPC_ERROR_NONE;
if (op->collect_stats != NULL) { if (op->collect_stats != NULL) {
GPR_ASSERT(stream_global->collecting_stats == NULL); GPR_ASSERT(stream_global->collecting_stats == NULL);
stream_global->collecting_stats = op->collect_stats; stream_global->collecting_stats = op->collect_stats;
on_complete->final_data |= CLOSURE_BARRIER_STATS_BIT; on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT;
} }
if (op->cancel_with_status != GRPC_STATUS_OK) { if (op->cancel_with_status != GRPC_STATUS_OK) {
@ -964,7 +981,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) { if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"to-be-sent initial metadata size exceeds peer limit " "to-be-sent initial metadata size exceeds peer limit "
"(%lu vs. %lu)", "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit); metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global, cancel_from_api(exec_ctx, transport_global, stream_global,
GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
@ -985,8 +1002,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} }
} else { } else {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished, 0); &stream_global->send_initial_metadata_finished,
GRPC_ERROR_CREATE(
"Attempt to send initial metadata after stream was closed"));
} }
} }
} }
@ -997,7 +1016,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
stream_global->send_message_finished = add_closure_barrier(on_complete); stream_global->send_message_finished = add_closure_barrier(on_complete);
if (stream_global->write_closed) { if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, &stream_global->send_message_finished, 0); exec_ctx, transport_global, stream_global,
&stream_global->send_message_finished,
GRPC_ERROR_CREATE("Attempt to send message after stream was closed"));
} else { } else {
stream_global->send_message = op->send_message; stream_global->send_message = op->send_message;
if (stream_global->id != 0) { if (stream_global->id != 0) {
@ -1019,7 +1040,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) { if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"to-be-sent trailing metadata size exceeds peer limit " "to-be-sent trailing metadata size exceeds peer limit "
"(%lu vs. %lu)", "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit); metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global, cancel_from_api(exec_ctx, transport_global, stream_global,
GRPC_STATUS_RESOURCE_EXHAUSTED, NULL); GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
@ -1031,9 +1052,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
} }
if (stream_global->write_closed) { if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished, &stream_global->send_trailing_metadata_finished,
grpc_metadata_batch_is_empty(op->send_trailing_metadata)); grpc_metadata_batch_is_empty(op->send_trailing_metadata)
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
"stream was closed"));
} else if (stream_global->id != 0) { } else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding /* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */ bytes before going writable */
@ -1072,7 +1096,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
} }
grpc_chttp2_complete_closure_step(exec_ctx, stream_global, &on_complete, 1); grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
&on_complete, GRPC_ERROR_NONE);
GPR_TIMER_END("perform_stream_op_locked", 0); GPR_TIMER_END("perform_stream_op_locked", 0);
} }
@ -1109,7 +1134,7 @@ static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
for (ping = transport_global->pings.next; ping != &transport_global->pings; for (ping = transport_global->pings.next; ping != &transport_global->pings;
ping = ping->next) { ping = ping->next) {
if (0 == memcmp(opaque_8bytes, ping->id, 8)) { if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL); grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL);
ping->next->prev = ping->prev; ping->next->prev = ping->prev;
ping->prev->next = ping->next; ping->prev->next = ping->next;
gpr_free(ping); gpr_free(ping);
@ -1131,7 +1156,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused, grpc_chttp2_stream *s_unused,
void *stream_op) { void *stream_op) {
grpc_transport_op *op = stream_op; grpc_transport_op *op = stream_op;
bool close_transport = op->disconnect; grpc_error *close_transport = op->disconnect_with_error;
/* If there's a set_accept_stream ensure that we're not parsing /* If there's a set_accept_stream ensure that we're not parsing
to avoid changing things out from underneath */ to avoid changing things out from underneath */
@ -1142,7 +1167,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
return; return;
} }
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL); grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
if (op->on_connectivity_state_change != NULL) { if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change( grpc_connectivity_state_notify_on_state_change(
@ -1156,7 +1181,9 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
t->global.last_incoming_stream_id, t->global.last_incoming_stream_id,
(uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status), (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
gpr_slice_ref(*op->goaway_message), &t->global.qbuf); gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
close_transport = !grpc_chttp2_has_streams(t); close_transport = grpc_chttp2_has_streams(t)
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE("GOAWAY sent");
} }
if (op->set_accept_stream) { if (op->set_accept_stream) {
@ -1177,8 +1204,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
send_ping_locked(t, op->send_ping); send_ping_locked(t, op->send_ping);
} }
if (close_transport) { if (close_transport != GRPC_ERROR_NONE) {
close_transport_locked(exec_ctx, t, NULL, NULL); close_transport_locked(exec_ctx, t, close_transport);
} }
} }
@ -1214,8 +1241,8 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_metadata_buffer_publish( grpc_chttp2_incoming_metadata_buffer_publish(
&stream_global->received_initial_metadata, &stream_global->received_initial_metadata,
stream_global->recv_initial_metadata); stream_global->recv_initial_metadata);
grpc_exec_ctx_enqueue( grpc_exec_ctx_sched(exec_ctx, stream_global->recv_initial_metadata_ready,
exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL); GRPC_ERROR_NONE, NULL);
stream_global->recv_initial_metadata_ready = NULL; stream_global->recv_initial_metadata_ready = NULL;
} }
if (stream_global->recv_message_ready != NULL) { if (stream_global->recv_message_ready != NULL) {
@ -1228,13 +1255,13 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
*stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop( *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames); &stream_global->incoming_frames);
GPR_ASSERT(*stream_global->recv_message != NULL); GPR_ASSERT(*stream_global->recv_message != NULL);
grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
NULL); GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL; stream_global->recv_message_ready = NULL;
} else if (stream_global->published_trailing_metadata) { } else if (stream_global->published_trailing_metadata) {
*stream_global->recv_message = NULL; *stream_global->recv_message = NULL;
grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true, grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
NULL); GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL; stream_global->recv_message_ready = NULL;
} }
} }
@ -1255,8 +1282,8 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
&stream_global->received_trailing_metadata, &stream_global->received_trailing_metadata,
stream_global->recv_trailing_metadata); stream_global->recv_trailing_metadata);
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->recv_trailing_metadata_finished, 1); &stream_global->recv_trailing_metadata_finished, GRPC_ERROR_NONE);
} }
} }
} }
@ -1272,7 +1299,7 @@ static void decrement_active_streams_locked(
} }
static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
uint32_t id) { uint32_t id, grpc_error *error) {
size_t new_stream_count; size_t new_stream_count;
grpc_chttp2_stream *s = grpc_chttp2_stream *s =
grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id); grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
@ -1287,12 +1314,15 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
} }
if (s->parsing.data_parser.parsing_frame != NULL) { if (s->parsing.data_parser.parsing_frame != NULL) {
grpc_chttp2_incoming_byte_stream_finished( grpc_chttp2_incoming_byte_stream_finished(
exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0); exec_ctx, s->parsing.data_parser.parsing_frame,
GRPC_ERROR_CREATE_REFERENCING("Stream removed", &error, 1), 0);
s->parsing.data_parser.parsing_frame = NULL; s->parsing.data_parser.parsing_frame = NULL;
} }
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
close_transport_locked(exec_ctx, t, NULL, NULL); close_transport_locked(
exec_ctx, t,
GRPC_ERROR_CREATE("Last stream closed after sending GOAWAY"));
} }
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) { if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
@ -1305,6 +1335,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->global.concurrent_stream_count = (uint32_t)new_stream_count; t->global.concurrent_stream_count = (uint32_t)new_stream_count;
maybe_start_some_streams(exec_ctx, &t->global); maybe_start_some_streams(exec_ctx, &t->global);
} }
GRPC_ERROR_UNREF(error);
} }
static void cancel_from_api(grpc_exec_ctx *exec_ctx, static void cancel_from_api(grpc_exec_ctx *exec_ctx,
@ -1332,8 +1363,10 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
stream_global->seen_error = true; stream_global->seen_error = true;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
} }
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, grpc_chttp2_mark_stream_closed(
1); exec_ctx, transport_global, stream_global, 1, 1,
grpc_error_set_int(GRPC_ERROR_CREATE("Cancelled"),
GRPC_ERROR_INT_GRPC_STATUS, status));
} }
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
@ -1374,23 +1407,27 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
} }
static void fail_pending_writes(grpc_exec_ctx *exec_ctx, static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global) { grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
grpc_error *error) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, &stream_global->send_initial_metadata_finished, exec_ctx, transport_global, stream_global,
0); &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, &stream_global->send_trailing_metadata_finished, exec_ctx, transport_global, stream_global,
0); &stream_global->send_trailing_metadata_finished, GRPC_ERROR_REF(error));
grpc_chttp2_complete_closure_step(exec_ctx, stream_global, grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
&stream_global->send_message_finished, 0); &stream_global->send_message_finished,
error);
} }
void grpc_chttp2_mark_stream_closed( void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, int close_reads, grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
int close_writes) { grpc_error *error) {
if (stream_global->read_closed && stream_global->write_closed) { if (stream_global->read_closed && stream_global->write_closed) {
/* already closed */ /* already closed */
GRPC_ERROR_UNREF(error);
return; return;
} }
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
@ -1407,7 +1444,8 @@ void grpc_chttp2_mark_stream_closed(
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global, grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global); stream_global);
} else { } else {
fail_pending_writes(exec_ctx, stream_global); fail_pending_writes(exec_ctx, transport_global, stream_global,
GRPC_ERROR_REF(error));
} }
} }
if (stream_global->read_closed && stream_global->write_closed) { if (stream_global->read_closed && stream_global->write_closed) {
@ -1418,11 +1456,12 @@ void grpc_chttp2_mark_stream_closed(
} else { } else {
if (stream_global->id != 0) { if (stream_global->id != 0) {
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global), remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
stream_global->id); stream_global->id, GRPC_ERROR_REF(error));
} }
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
} }
} }
GRPC_ERROR_UNREF(error);
} }
static void close_from_api(grpc_exec_ctx *exec_ctx, static void close_from_api(grpc_exec_ctx *exec_ctx,
@ -1529,8 +1568,16 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status, grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
optional_message); optional_message);
grpc_error *err = GRPC_ERROR_CREATE("Stream closed");
err = grpc_error_set_int(err, GRPC_ERROR_INT_GRPC_STATUS, status);
if (optional_message) {
char *str =
gpr_dump_slice(*optional_message, GPR_DUMP_HEX | GPR_DUMP_ASCII);
err = grpc_error_set_str(err, GRPC_ERROR_STR_GRPC_MESSAGE, str);
gpr_free(str);
}
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1, grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
1); 1, err);
} }
static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global, static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
@ -1549,8 +1596,9 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb); grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
} }
static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) { static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
close_transport_locked(exec_ctx, t, NULL, NULL); grpc_error *error) {
close_transport_locked(exec_ctx, t, error);
end_all_the_calls(exec_ctx, t); end_all_the_calls(exec_ctx, t);
} }
@ -1581,20 +1629,22 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
static void reading_action_locked(grpc_exec_ctx *exec_ctx, static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg); grpc_chttp2_stream *s_unused, void *arg);
static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success); static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error);
static void post_reading_action_locked(grpc_exec_ctx *exec_ctx, static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg); grpc_chttp2_stream *s_unused, void *arg);
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg); grpc_chttp2_stream *s_unused, void *arg);
static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, bool success) { static void reading_action(grpc_exec_ctx *exec_ctx, void *tp,
grpc_error *error) {
/* Control flow: /* Control flow:
reading_action_locked -> reading_action_locked ->
(parse_unlocked -> post_parse_locked)? -> (parse_unlocked -> post_parse_locked)? ->
post_reading_action_locked */ post_reading_action_locked */
grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked, grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
(void *)(uintptr_t)success, 0); GRPC_ERROR_REF(error), 0);
} }
static void reading_action_locked(grpc_exec_ctx *exec_ctx, static void reading_action_locked(grpc_exec_ctx *exec_ctx,
@ -1602,7 +1652,7 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused, void *arg) { grpc_chttp2_stream *s_unused, void *arg) {
grpc_chttp2_transport_global *transport_global = &t->global; grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing; grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
bool success = (bool)(uintptr_t)arg; grpc_error *error = arg;
GPR_ASSERT(!t->executor.parsing_active); GPR_ASSERT(!t->executor.parsing_active);
if (!t->closed) { if (!t->closed) {
@ -1611,48 +1661,54 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_map_move_into(&t->new_stream_map, grpc_chttp2_stream_map_move_into(&t->new_stream_map,
&t->parsing_stream_map); &t->parsing_stream_map);
grpc_chttp2_prepare_to_read(transport_global, transport_parsing); grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
grpc_exec_ctx_enqueue(exec_ctx, &t->parsing_action, success, NULL); grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL);
} else { } else {
post_reading_action_locked(exec_ctx, t, s_unused, arg); post_reading_action_locked(exec_ctx, t, s_unused, arg);
} }
} }
static bool try_http_parsing(grpc_exec_ctx *exec_ctx, static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t) { grpc_chttp2_transport *t) {
grpc_http_parser parser; grpc_http_parser parser;
size_t i = 0; size_t i = 0;
bool success = false; grpc_error *error = GRPC_ERROR_NONE;
grpc_http_response response;
memset(&response, 0, sizeof(response));
grpc_http_parser_init(&parser); grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
for (; i < t->read_buffer.count && grpc_error *parse_error = GRPC_ERROR_NONE;
grpc_http_parser_parse(&parser, t->read_buffer.slices[i]); for (; i < t->read_buffer.count && parse_error == GRPC_ERROR_NONE; i++) {
i++) parse_error = grpc_http_parser_parse(&parser, t->read_buffer.slices[i]);
; }
if (grpc_http_parser_eof(&parser) && parser.type == GRPC_HTTP_RESPONSE) { if (parse_error == GRPC_ERROR_NONE &&
success = true; (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
GRPC_CHTTP2_IF_TRACING(gpr_log( error = grpc_error_set_int(
GPR_DEBUG, "Trying to connect an http1.x server, received status:%d", GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
parser.http.response.status)); GRPC_ERROR_INT_HTTP_STATUS, response.status);
} }
GRPC_ERROR_UNREF(parse_error);
grpc_http_parser_destroy(&parser); grpc_http_parser_destroy(&parser);
return success; grpc_http_response_destroy(&response);
return error;
} }
static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_chttp2_transport *t = arg; grpc_chttp2_transport *t = arg;
GPR_TIMER_BEGIN("reading_action.parse", 0); GPR_TIMER_BEGIN("reading_action.parse", 0);
size_t i = 0; size_t i = 0;
for (; i < t->read_buffer.count && grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
grpc_chttp2_perform_read(exec_ctx, &t->parsing, GRPC_ERROR_NONE};
for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
errors[1] = grpc_chttp2_perform_read(exec_ctx, &t->parsing,
t->read_buffer.slices[i]); t->read_buffer.slices[i]);
i++) };
;
if (i != t->read_buffer.count) { if (i != t->read_buffer.count) {
success = false;
gpr_slice_unref(t->optional_drop_message); gpr_slice_unref(t->optional_drop_message);
if (try_http_parsing(exec_ctx, t)) { errors[2] = try_http_parsing(exec_ctx, t);
if (errors[2] != GRPC_ERROR_NONE) {
t->optional_drop_message = gpr_slice_from_copied_string( t->optional_drop_message = gpr_slice_from_copied_string(
"Connection dropped: received http1.x response"); "Connection dropped: received http1.x response");
} else { } else {
@ -1660,9 +1716,18 @@ static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
"Connection dropped: received unparseable response"); "Connection dropped: received unparseable response");
} }
} }
grpc_error *err =
errors[0] == GRPC_ERROR_NONE && errors[1] == GRPC_ERROR_NONE &&
errors[2] == GRPC_ERROR_NONE
? GRPC_ERROR_NONE
: GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
GPR_ARRAY_SIZE(errors));
for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
GRPC_ERROR_UNREF(errors[i]);
}
GPR_TIMER_END("reading_action.parse", 0); GPR_TIMER_END("reading_action.parse", 0);
grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err,
(void *)(uintptr_t)success, 0); 0);
} }
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@ -1699,7 +1764,8 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(stream_global->in_stream_map); GPR_ASSERT(stream_global->in_stream_map);
GPR_ASSERT(stream_global->write_closed); GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed); GPR_ASSERT(stream_global->read_closed);
remove_stream(exec_ctx, t, stream_global->id); remove_stream(exec_ctx, t, stream_global->id,
GRPC_ERROR_CREATE("Stream removed"));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
} }
@ -1710,10 +1776,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, grpc_chttp2_stream *s_unused,
void *arg) { void *arg) {
bool success = (bool)(uintptr_t)arg; grpc_error *error = arg;
bool keep_reading = false; bool keep_reading = false;
if (!success || t->closed) { if (error == GRPC_ERROR_NONE && t->closed) {
drop_connection(exec_ctx, t); error = GRPC_ERROR_CREATE("Transport closed");
}
if (error != GRPC_ERROR_NONE) {
drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0; t->endpoint_reading = 0;
if (!t->executor.writing_active && t->ep) { if (!t->executor.writing_active && t->ep) {
grpc_endpoint_destroy(exec_ctx, t->ep); grpc_endpoint_destroy(exec_ctx, t->ep);
@ -1735,6 +1804,8 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
} else { } else {
UNREF_TRANSPORT(exec_ctx, t, "reading_action"); UNREF_TRANSPORT(exec_ctx, t, "reading_action");
} }
GRPC_ERROR_UNREF(error);
} }
/******************************************************************************* /*******************************************************************************
@ -1743,13 +1814,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set( static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_connectivity_state state, const char *reason) { grpc_connectivity_state state, grpc_error *error, const char *reason) {
GRPC_CHTTP2_IF_TRACING( GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "set connectivity_state=%d", state)); gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
grpc_connectivity_state_set( grpc_connectivity_state_set(
exec_ctx, exec_ctx,
&TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker, &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
state, reason); state, error, reason);
} }
/******************************************************************************* /*******************************************************************************
@ -1795,6 +1866,7 @@ static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx, static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs) { grpc_chttp2_incoming_byte_stream *bs) {
if (gpr_unref(&bs->refs)) { if (gpr_unref(&bs->refs)) {
GRPC_ERROR_UNREF(bs->error);
gpr_slice_buffer_destroy(&bs->slices); gpr_slice_buffer_destroy(&bs->slices);
gpr_free(bs); gpr_free(bs);
} }
@ -1863,9 +1935,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
} }
if (bs->slices.count > 0) { if (bs->slices.count > 0) {
*arg->slice = gpr_slice_buffer_take_first(&bs->slices); *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, true, NULL); grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL);
} else if (bs->failed) { } else if (bs->error != GRPC_ERROR_NONE) {
grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, false, NULL); grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_REF(bs->error),
NULL);
} else { } else {
bs->on_next = arg->on_complete; bs->on_next = arg->on_complete;
bs->next = arg->slice; bs->next = arg->slice;
@ -1922,7 +1995,7 @@ static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream; grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
if (bs->on_next != NULL) { if (bs->on_next != NULL) {
*bs->next = arg->slice; *bs->next = arg->slice;
grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL); grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
bs->on_next = NULL; bs->on_next = NULL;
} else { } else {
gpr_slice_buffer_add(&bs->slices, arg->slice); gpr_slice_buffer_add(&bs->slices, arg->slice);
@ -1940,13 +2013,30 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
sizeof(arg)); sizeof(arg));
} }
typedef struct {
grpc_chttp2_incoming_byte_stream *bs;
grpc_error *error;
} bs_fail_args;
static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs,
grpc_error *error) {
bs_fail_args *a = gpr_malloc(sizeof(*a));
a->bs = bs;
a->error = error;
return a;
}
static void incoming_byte_stream_finished_failed_locked( static void incoming_byte_stream_finished_failed_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
void *argp) { void *argp) {
grpc_chttp2_incoming_byte_stream *bs = argp; bs_fail_args *a = argp;
grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL); grpc_chttp2_incoming_byte_stream *bs = a->bs;
grpc_error *error = a->error;
gpr_free(a);
grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
bs->on_next = NULL; bs->on_next = NULL;
bs->failed = 1; GRPC_ERROR_UNREF(bs->error);
bs->error = error;
incoming_byte_stream_unref(exec_ctx, bs); incoming_byte_stream_unref(exec_ctx, bs);
} }
@ -1959,25 +2049,26 @@ static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
} }
void grpc_chttp2_incoming_byte_stream_finished( void grpc_chttp2_incoming_byte_stream_finished(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
int from_parsing_thread) { grpc_error *error, int from_parsing_thread) {
if (from_parsing_thread) { if (from_parsing_thread) {
if (success) { if (error == GRPC_ERROR_NONE) {
grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream, grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
incoming_byte_stream_finished_ok_locked, incoming_byte_stream_finished_ok_locked,
bs, 0); bs, 0);
} else { } else {
incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
bs->stream, bs);
}
} else {
if (success) {
grpc_chttp2_run_with_global_lock( grpc_chttp2_run_with_global_lock(
exec_ctx, bs->transport, bs->stream, exec_ctx, bs->transport, bs->stream,
incoming_byte_stream_finished_failed_locked, bs, 0); incoming_byte_stream_finished_failed_locked,
make_bs_fail_args(bs, error), 0);
}
} else { } else {
incoming_byte_stream_finished_failed_locked(exec_ctx, bs->transport, if (error == GRPC_ERROR_NONE) {
incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
bs->stream, bs); bs->stream, bs);
} else {
incoming_byte_stream_finished_failed_locked(
exec_ctx, bs->transport, bs->stream, make_bs_fail_args(bs, error));
} }
} }
} }
@ -2000,7 +2091,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
gpr_slice_buffer_init(&incoming_byte_stream->slices); gpr_slice_buffer_init(&incoming_byte_stream->slices);
incoming_byte_stream->on_next = NULL; incoming_byte_stream->on_next = NULL;
incoming_byte_stream->is_tail = 1; incoming_byte_stream->is_tail = 1;
incoming_byte_stream->failed = 0; incoming_byte_stream->error = GRPC_ERROR_NONE;
if (add_to_queue->head == NULL) { if (add_to_queue->head == NULL) {
add_to_queue->head = incoming_byte_stream; add_to_queue->head = incoming_byte_stream;
} else { } else {
@ -2019,10 +2110,13 @@ static char *format_flowctl_context_var(const char *context, const char *var,
int64_t val, uint32_t id, int64_t val, uint32_t id,
char **scope) { char **scope) {
char *underscore_pos; char *underscore_pos;
char *buf;
char *result; char *result;
if (context == NULL) { if (context == NULL) {
*scope = NULL; *scope = NULL;
gpr_asprintf(&result, "%s(%lld)", var, val); gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
result = gpr_leftpad(buf, ' ', 40);
gpr_free(buf);
return result; return result;
} }
underscore_pos = strchr(context, '_'); underscore_pos = strchr(context, '_');
@ -2033,7 +2127,9 @@ static char *format_flowctl_context_var(const char *context, const char *var,
gpr_asprintf(scope, "%s[%d]", tmp, id); gpr_asprintf(scope, "%s[%d]", tmp, id);
gpr_free(tmp); gpr_free(tmp);
} }
gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val); gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
result = gpr_leftpad(buf, ' ', 40);
gpr_free(buf);
return result; return result;
} }
@ -2054,6 +2150,8 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
uint32_t stream_id, int64_t val1, int64_t val2) { uint32_t stream_id, int64_t val1, int64_t val2) {
char *scope1; char *scope1;
char *scope2; char *scope2;
char *tmp_phase;
char *tmp_scope1;
char *label1 = char *label1 =
format_flowctl_context_var(context1, var1, val1, stream_id, &scope1); format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
char *label2 = char *label2 =
@ -2061,14 +2159,18 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
char *clisvr = is_client ? "client" : "server"; char *clisvr = is_client ? "client" : "server";
char *prefix; char *prefix;
gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1); tmp_phase = gpr_leftpad(phase, ' ', 8);
tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1);
gpr_free(tmp_phase);
gpr_free(tmp_scope1);
switch (op) { switch (op) {
case GRPC_CHTTP2_FLOWCTL_MOVE: case GRPC_CHTTP2_FLOWCTL_MOVE:
GPR_ASSERT(samestr(scope1, scope2)); GPR_ASSERT(samestr(scope1, scope2));
if (val2 != 0) { if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"%sMOVE % 40s <- % 40s giving %d", prefix, label1, label2, "%sMOVE %s <- %s giving %" PRId64, prefix, label1, label2,
val1 + val2); val1 + val2);
} }
break; break;
@ -2076,7 +2178,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0); GPR_ASSERT(val2 >= 0);
if (val2 != 0) { if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2, "%sCREDIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 + val2); val1 + val2);
} }
break; break;
@ -2084,7 +2186,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0); GPR_ASSERT(val2 >= 0);
if (val2 != 0) { if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2, "%sDEBIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 - val2); val1 - val2);
} }
break; break;
@ -2130,5 +2232,5 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport; grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */ REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
gpr_slice_buffer_addn(&t->read_buffer, slices, nslices); gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
reading_action(exec_ctx, t, 1); reading_action(exec_ctx, t, GRPC_ERROR_NONE);
} }

@ -37,13 +37,7 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
/* Common definitions for frame handling in the chttp2 transport */ #include "src/core/lib/iomgr/error.h"
typedef enum {
GRPC_CHTTP2_PARSE_OK,
GRPC_CHTTP2_STREAM_ERROR,
GRPC_CHTTP2_CONNECTION_ERROR
} grpc_chttp2_parse_error;
/* defined in internal.h */ /* defined in internal.h */
typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing; typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing;

@ -37,24 +37,25 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport.h" #include "src/core/lib/transport/transport.h"
grpc_chttp2_parse_error grpc_chttp2_data_parser_init( grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser) {
grpc_chttp2_data_parser *parser) {
parser->state = GRPC_CHTTP2_DATA_FH_0; parser->state = GRPC_CHTTP2_DATA_FH_0;
parser->parsing_frame = NULL; parser->parsing_frame = NULL;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser) { grpc_chttp2_data_parser *parser) {
grpc_byte_stream *bs; grpc_byte_stream *bs;
if (parser->parsing_frame) { if (parser->parsing_frame) {
grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame, grpc_chttp2_incoming_byte_stream_finished(
0, 1); exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"),
1);
} }
while ( while (
(bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) { (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
@ -62,11 +63,16 @@ void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
} }
} }
grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
grpc_chttp2_data_parser *parser, uint8_t flags) { uint8_t flags,
uint32_t stream_id) {
if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) { if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags); char *msg;
return GRPC_CHTTP2_STREAM_ERROR; gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
grpc_error *err = grpc_error_set_int(
GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
gpr_free(msg);
return err;
} }
if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) { if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@ -75,7 +81,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
parser->is_last_frame = 0; parser->is_last_frame = 0;
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
void grpc_chttp2_incoming_frame_queue_merge( void grpc_chttp2_incoming_frame_queue_merge(
@ -139,7 +145,7 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
stats->data_bytes += write_bytes; stats->data_bytes += write_bytes;
} }
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@ -149,19 +155,20 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_data_parser *p = parser; grpc_chttp2_data_parser *p = parser;
uint32_t message_flags; uint32_t message_flags;
grpc_chttp2_incoming_byte_stream *incoming_byte_stream; grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
char *msg;
if (is_last && p->is_last_frame) { if (is_last && p->is_last_frame) {
stream_parsing->received_close = 1; stream_parsing->received_close = 1;
} }
if (cur == end) { if (cur == end) {
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
switch (p->state) { switch (p->state) {
case GRPC_CHTTP2_DATA_ERROR: case GRPC_CHTTP2_DATA_ERROR:
p->state = GRPC_CHTTP2_DATA_ERROR; p->state = GRPC_CHTTP2_DATA_ERROR;
return GRPC_CHTTP2_STREAM_ERROR; return GRPC_ERROR_REF(p->error);
fh_0: fh_0:
case GRPC_CHTTP2_DATA_FH_0: case GRPC_CHTTP2_DATA_FH_0:
stream_parsing->stats.incoming.framing_bytes++; stream_parsing->stats.incoming.framing_bytes++;
@ -174,13 +181,23 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->is_frame_compressed = 1; /* GPR_TRUE */ p->is_frame_compressed = 1; /* GPR_TRUE */
break; break;
default: default:
gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type); gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
p->error = GRPC_ERROR_CREATE(msg);
p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
(intptr_t)stream_parsing->id);
gpr_free(msg);
msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
p->error =
grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
gpr_free(msg);
p->error =
grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
p->state = GRPC_CHTTP2_DATA_ERROR; p->state = GRPC_CHTTP2_DATA_ERROR;
return GRPC_CHTTP2_STREAM_ERROR; return GRPC_ERROR_REF(p->error);
} }
if (++cur == end) { if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_1; p->state = GRPC_CHTTP2_DATA_FH_1;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_CHTTP2_DATA_FH_1: case GRPC_CHTTP2_DATA_FH_1:
@ -188,7 +205,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size = ((uint32_t)*cur) << 24; p->frame_size = ((uint32_t)*cur) << 24;
if (++cur == end) { if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_2; p->state = GRPC_CHTTP2_DATA_FH_2;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_CHTTP2_DATA_FH_2: case GRPC_CHTTP2_DATA_FH_2:
@ -196,7 +213,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 16; p->frame_size |= ((uint32_t)*cur) << 16;
if (++cur == end) { if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_3; p->state = GRPC_CHTTP2_DATA_FH_3;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_CHTTP2_DATA_FH_3: case GRPC_CHTTP2_DATA_FH_3:
@ -204,7 +221,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 8; p->frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) { if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_4; p->state = GRPC_CHTTP2_DATA_FH_4;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_CHTTP2_DATA_FH_4: case GRPC_CHTTP2_DATA_FH_4:
@ -225,7 +242,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
stream_parsing); stream_parsing);
if (cur == end) { if (cur == end) {
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
uint32_t remaining = (uint32_t)(end - cur); uint32_t remaining = (uint32_t)(end - cur);
if (remaining == p->frame_size) { if (remaining == p->frame_size) {
@ -233,19 +250,19 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_incoming_byte_stream_push( grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame, exec_ctx, p->parsing_frame,
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
1); GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL; p->parsing_frame = NULL;
p->state = GRPC_CHTTP2_DATA_FH_0; p->state = GRPC_CHTTP2_DATA_FH_0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} else if (remaining > p->frame_size) { } else if (remaining > p->frame_size) {
stream_parsing->stats.incoming.data_bytes += p->frame_size; stream_parsing->stats.incoming.data_bytes += p->frame_size;
grpc_chttp2_incoming_byte_stream_push( grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame, exec_ctx, p->parsing_frame,
gpr_slice_sub(slice, (size_t)(cur - beg), gpr_slice_sub(slice, (size_t)(cur - beg),
(size_t)(cur + p->frame_size - beg))); (size_t)(cur + p->frame_size - beg)));
grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1, grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
1); GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL; p->parsing_frame = NULL;
cur += p->frame_size; cur += p->frame_size;
goto fh_0; /* loop */ goto fh_0; /* loop */
@ -256,9 +273,9 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg))); gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
p->frame_size -= remaining; p->frame_size -= remaining;
stream_parsing->stats.incoming.data_bytes += remaining; stream_parsing->stats.incoming.data_bytes += remaining;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
} }
GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
} }

@ -66,6 +66,7 @@ typedef struct {
uint8_t is_last_frame; uint8_t is_last_frame;
uint8_t frame_type; uint8_t frame_type;
uint32_t frame_size; uint32_t frame_size;
grpc_error *error;
int is_frame_compressed; int is_frame_compressed;
grpc_chttp2_incoming_frame_queue incoming_frames; grpc_chttp2_incoming_frame_queue incoming_frames;
@ -79,19 +80,19 @@ grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
grpc_chttp2_incoming_frame_queue *q); grpc_chttp2_incoming_frame_queue *q);
/* initialize per-stream state for data frame parsing */ /* initialize per-stream state for data frame parsing */
grpc_chttp2_parse_error grpc_chttp2_data_parser_init( grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser);
grpc_chttp2_data_parser *parser);
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx, void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser); grpc_chttp2_data_parser *parser);
/* start processing a new data frame */ /* start processing a new data frame */
grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame( grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
grpc_chttp2_data_parser *parser, uint8_t flags); uint8_t flags,
uint32_t stream_id);
/* handle a slice of a data frame - is_last indicates the last slice of a /* handle a slice of a data frame - is_last indicates the last slice of a
frame */ frame */
grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -38,6 +38,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) { void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
p->debug_data = NULL; p->debug_data = NULL;
@ -47,11 +48,15 @@ void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
gpr_free(p->debug_data); gpr_free(p->debug_data);
} }
grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p,
grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) { uint32_t length,
uint8_t flags) {
if (length < 8) { if (length < 8) {
gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length); char *msg;
return GRPC_CHTTP2_CONNECTION_ERROR; gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length);
grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
gpr_free(p->debug_data); gpr_free(p->debug_data);
@ -59,10 +64,10 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
p->debug_data = gpr_malloc(p->debug_length); p->debug_data = gpr_malloc(p->debug_length);
p->debug_pos = 0; p->debug_pos = 0;
p->state = GRPC_CHTTP2_GOAWAY_LSI0; p->state = GRPC_CHTTP2_GOAWAY_LSI0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@ -75,7 +80,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI0: case GRPC_CHTTP2_GOAWAY_LSI0:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI0; p->state = GRPC_CHTTP2_GOAWAY_LSI0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->last_stream_id = ((uint32_t)*cur) << 24; p->last_stream_id = ((uint32_t)*cur) << 24;
++cur; ++cur;
@ -83,7 +88,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI1: case GRPC_CHTTP2_GOAWAY_LSI1:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI1; p->state = GRPC_CHTTP2_GOAWAY_LSI1;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->last_stream_id |= ((uint32_t)*cur) << 16; p->last_stream_id |= ((uint32_t)*cur) << 16;
++cur; ++cur;
@ -91,7 +96,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI2: case GRPC_CHTTP2_GOAWAY_LSI2:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI2; p->state = GRPC_CHTTP2_GOAWAY_LSI2;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->last_stream_id |= ((uint32_t)*cur) << 8; p->last_stream_id |= ((uint32_t)*cur) << 8;
++cur; ++cur;
@ -99,7 +104,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI3: case GRPC_CHTTP2_GOAWAY_LSI3:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI3; p->state = GRPC_CHTTP2_GOAWAY_LSI3;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->last_stream_id |= ((uint32_t)*cur); p->last_stream_id |= ((uint32_t)*cur);
++cur; ++cur;
@ -107,7 +112,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR0: case GRPC_CHTTP2_GOAWAY_ERR0:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR0; p->state = GRPC_CHTTP2_GOAWAY_ERR0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->error_code = ((uint32_t)*cur) << 24; p->error_code = ((uint32_t)*cur) << 24;
++cur; ++cur;
@ -115,7 +120,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR1: case GRPC_CHTTP2_GOAWAY_ERR1:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR1; p->state = GRPC_CHTTP2_GOAWAY_ERR1;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->error_code |= ((uint32_t)*cur) << 16; p->error_code |= ((uint32_t)*cur) << 16;
++cur; ++cur;
@ -123,7 +128,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR2: case GRPC_CHTTP2_GOAWAY_ERR2:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR2; p->state = GRPC_CHTTP2_GOAWAY_ERR2;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->error_code |= ((uint32_t)*cur) << 8; p->error_code |= ((uint32_t)*cur) << 8;
++cur; ++cur;
@ -131,7 +136,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR3: case GRPC_CHTTP2_GOAWAY_ERR3:
if (cur == end) { if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR3; p->state = GRPC_CHTTP2_GOAWAY_ERR3;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
p->error_code |= ((uint32_t)*cur); p->error_code |= ((uint32_t)*cur);
++cur; ++cur;
@ -151,9 +156,9 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
gpr_slice_new(p->debug_data, p->debug_length, gpr_free); gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
p->debug_data = NULL; p->debug_data = NULL;
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR); GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
} }
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code, void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,

@ -63,9 +63,9 @@ typedef struct {
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p); void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p);
void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p); void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame( grpc_error *grpc_chttp2_goaway_parser_begin_frame(
grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags); grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse( grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -38,6 +38,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) { gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
gpr_slice slice = gpr_slice_malloc(9 + 8); gpr_slice slice = gpr_slice_malloc(9 + 8);
@ -57,18 +58,22 @@ gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
return slice; return slice;
} }
grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) { uint32_t length,
uint8_t flags) {
if (flags & 0xfe || length != 8) { if (flags & 0xfe || length != 8) {
gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags); char *msg;
return GRPC_CHTTP2_CONNECTION_ERROR; gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags);
grpc_error *error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return error;
} }
parser->byte = 0; parser->byte = 0;
parser->is_ack = flags; parser->is_ack = flags;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( grpc_error *grpc_chttp2_ping_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@ -93,5 +98,5 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
} }
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }

@ -46,9 +46,9 @@ typedef struct {
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes); gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame( grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags); uint32_t length, uint8_t flags);
grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse( grpc_error *grpc_chttp2_ping_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h" #include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
#include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/ext/transport/chttp2/transport/internal.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.h" #include "src/core/ext/transport/chttp2/transport/frame.h"
@ -67,18 +69,21 @@ gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
return slice; return slice;
} }
grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) { grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) {
if (length != 4) { if (length != 4) {
gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length, char *msg;
gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length,
flags); flags);
return GRPC_CHTTP2_CONNECTION_ERROR; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
parser->byte = 0; parser->byte = 0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@ -97,12 +102,13 @@ grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
if (p->byte == 4) { if (p->byte == 4) {
GPR_ASSERT(is_last); GPR_ASSERT(is_last);
stream_parsing->received_close = 1; stream_parsing->received_close = 1;
stream_parsing->saw_rst_stream = 1; stream_parsing->forced_close_error = grpc_error_set_int(
stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) | GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
(intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
(((uint32_t)p->reason_bytes[1]) << 16) | (((uint32_t)p->reason_bytes[1]) << 16) |
(((uint32_t)p->reason_bytes[2]) << 8) | (((uint32_t)p->reason_bytes[2]) << 8) |
(((uint32_t)p->reason_bytes[3])); (((uint32_t)p->reason_bytes[3]))));
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }

@ -47,9 +47,9 @@ typedef struct {
gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code, gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code,
grpc_transport_one_way_stats *stats); grpc_transport_one_way_stats *stats);
grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame( grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags); grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse( grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -36,7 +36,9 @@
#include <string.h> #include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@ -118,7 +120,7 @@ gpr_slice grpc_chttp2_settings_ack_create(void) {
return output; return output;
} }
grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings) { uint32_t *settings) {
parser->target_settings = settings; parser->target_settings = settings;
@ -129,31 +131,29 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
if (flags == GRPC_CHTTP2_FLAG_ACK) { if (flags == GRPC_CHTTP2_FLAG_ACK) {
parser->is_ack = 1; parser->is_ack = 1;
if (length != 0) { if (length != 0) {
gpr_log(GPR_ERROR, "non-empty settings ack frame received"); return GRPC_ERROR_CREATE("non-empty settings ack frame received");
return GRPC_CHTTP2_CONNECTION_ERROR;
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} else if (flags != 0) { } else if (flags != 0) {
gpr_log(GPR_ERROR, "invalid flags on settings frame"); return GRPC_ERROR_CREATE("invalid flags on settings frame");
return GRPC_CHTTP2_CONNECTION_ERROR;
} else if (length % 6 != 0) { } else if (length % 6 != 0) {
gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes"); return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
return GRPC_CHTTP2_CONNECTION_ERROR;
} else { } else {
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
} }
grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *p, grpc_exec_ctx *exec_ctx, void *p,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
grpc_chttp2_settings_parser *parser = p; grpc_chttp2_settings_parser *parser = p;
const uint8_t *cur = GPR_SLICE_START_PTR(slice); const uint8_t *cur = GPR_SLICE_START_PTR(slice);
const uint8_t *end = GPR_SLICE_END_PTR(slice); const uint8_t *end = GPR_SLICE_END_PTR(slice);
char *msg;
if (parser->is_ack) { if (parser->is_ack) {
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
for (;;) { for (;;) {
@ -168,7 +168,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
gpr_slice_buffer_add(&transport_parsing->qbuf, gpr_slice_buffer_add(&transport_parsing->qbuf,
grpc_chttp2_settings_ack_create()); grpc_chttp2_settings_ack_create());
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
parser->id = (uint16_t)(((uint16_t)*cur) << 8); parser->id = (uint16_t)(((uint16_t)*cur) << 8);
cur++; cur++;
@ -176,7 +176,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_ID1: case GRPC_CHTTP2_SPS_ID1:
if (cur == end) { if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_ID1; parser->state = GRPC_CHTTP2_SPS_ID1;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
parser->id = (uint16_t)(parser->id | (*cur)); parser->id = (uint16_t)(parser->id | (*cur));
cur++; cur++;
@ -184,7 +184,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL0: case GRPC_CHTTP2_SPS_VAL0:
if (cur == end) { if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL0; parser->state = GRPC_CHTTP2_SPS_VAL0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
parser->value = ((uint32_t)*cur) << 24; parser->value = ((uint32_t)*cur) << 24;
cur++; cur++;
@ -192,7 +192,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL1: case GRPC_CHTTP2_SPS_VAL1:
if (cur == end) { if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL1; parser->state = GRPC_CHTTP2_SPS_VAL1;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
parser->value |= ((uint32_t)*cur) << 16; parser->value |= ((uint32_t)*cur) << 16;
cur++; cur++;
@ -200,7 +200,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL2: case GRPC_CHTTP2_SPS_VAL2:
if (cur == end) { if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL2; parser->state = GRPC_CHTTP2_SPS_VAL2;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
parser->value |= ((uint32_t)*cur) << 8; parser->value |= ((uint32_t)*cur) << 8;
cur++; cur++;
@ -208,7 +208,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL3: case GRPC_CHTTP2_SPS_VAL3:
if (cur == end) { if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL3; parser->state = GRPC_CHTTP2_SPS_VAL3;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} else { } else {
parser->state = GRPC_CHTTP2_SPS_ID0; parser->state = GRPC_CHTTP2_SPS_ID0;
} }
@ -229,9 +229,11 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->last_incoming_stream_id, sp->error_value, transport_parsing->last_incoming_stream_id, sp->error_value,
gpr_slice_from_static_string("HTTP2 settings error"), gpr_slice_from_static_string("HTTP2 settings error"),
&transport_parsing->qbuf); &transport_parsing->qbuf);
gpr_log(GPR_ERROR, "invalid value %u passed for %s", gpr_asprintf(&msg, "invalid value %u passed for %s",
parser->value, sp->name); parser->value, sp->name);
return GRPC_CHTTP2_CONNECTION_ERROR; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
} }
if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
@ -249,7 +251,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->is_client ? "CLI" : "SVR", parser->id, transport_parsing->is_client ? "CLI" : "SVR", parser->id,
parser->value); parser->value);
} }
} else { } else if (grpc_http_trace) {
gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
parser->id, parser->value); parser->id, parser->value);
} }

@ -92,10 +92,10 @@ gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
/* Create an ack settings frame */ /* Create an ack settings frame */
gpr_slice grpc_chttp2_settings_ack_create(void); gpr_slice grpc_chttp2_settings_ack_create(void);
grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings); uint32_t *settings);
grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse( grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h" #include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/ext/transport/chttp2/transport/internal.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_window_update_create( gpr_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) { uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) {
@ -62,19 +64,22 @@ gpr_slice grpc_chttp2_window_update_create(
return slice; return slice;
} }
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) { grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) {
if (flags || length != 4) { if (flags || length != 4) {
gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length, char *msg;
gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length,
flags); flags);
return GRPC_CHTTP2_CONNECTION_ERROR; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
parser->byte = 0; parser->byte = 0;
parser->amount = 0; parser->amount = 0;
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@ -96,8 +101,11 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
if (p->byte == 4) { if (p->byte == 4) {
uint32_t received_update = p->amount; uint32_t received_update = p->amount;
if (received_update == 0 || (received_update & 0x80000000u)) { if (received_update == 0 || (received_update & 0x80000000u)) {
gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount); char *msg;
return GRPC_CHTTP2_CONNECTION_ERROR; gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount);
grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
GPR_ASSERT(is_last); GPR_ASSERT(is_last);
@ -115,5 +123,5 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
} }
} }
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }

@ -48,9 +48,9 @@ typedef struct {
gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta, gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta,
grpc_transport_one_way_stats *stats); grpc_transport_one_way_stats *stats);
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame( grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags); grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse( grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

File diff suppressed because it is too large Load Diff

@ -44,9 +44,8 @@
typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser; typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p, typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
const uint8_t *beg, grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end);
const uint8_t *end);
typedef struct { typedef struct {
char *str; char *str;
@ -59,6 +58,8 @@ struct grpc_chttp2_hpack_parser {
void (*on_header)(void *user_data, grpc_mdelem *md); void (*on_header)(void *user_data, grpc_mdelem *md);
void *on_header_user_data; void *on_header_user_data;
grpc_error *last_error;
/* current parse state - or a function that implements it */ /* current parse state - or a function that implements it */
grpc_chttp2_hpack_parser_state state; grpc_chttp2_hpack_parser_state state;
/* future states dependent on the opening op code */ /* future states dependent on the opening op code */
@ -103,12 +104,13 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p); void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
/* returns 1 on success, 0 on error */ /* returns 1 on success, 0 on error */
int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p, grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
const uint8_t *beg, const uint8_t *end); const uint8_t *beg,
const uint8_t *end);
/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
the transport */ the transport */
grpc_chttp2_parse_error grpc_chttp2_header_parser_parse( grpc_error *grpc_chttp2_header_parser_parse(
grpc_exec_ctx *exec_ctx, void *hpack_parser, grpc_exec_ctx *exec_ctx, void *hpack_parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);

@ -38,6 +38,7 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/support/murmur_hash.h" #include "src/core/lib/support/murmur_hash.h"
@ -262,18 +263,19 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
tbl->max_bytes = max_bytes; tbl->max_bytes = max_bytes;
} }
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
uint32_t bytes) { uint32_t bytes) {
if (tbl->current_table_bytes == bytes) { if (tbl->current_table_bytes == bytes) {
return 1; return GRPC_ERROR_NONE;
} }
if (bytes > tbl->max_bytes) { if (bytes > tbl->max_bytes) {
if (grpc_http_trace) { char *msg;
gpr_log(GPR_ERROR, gpr_asprintf(&msg,
"Attempt to make hpack table %d bytes when max is %d bytes", "Attempt to make hpack table %d bytes when max is %d bytes",
bytes, tbl->max_bytes); bytes, tbl->max_bytes);
} grpc_error *err = GRPC_ERROR_CREATE(msg);
return 0; gpr_free(msg);
return err;
} }
if (grpc_http_trace) { if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes); gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
@ -291,23 +293,25 @@ int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
rebuild_ents(tbl, new_cap); rebuild_ents(tbl, new_cap);
} }
} }
return 1; return GRPC_ERROR_NONE;
} }
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) { grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */ /* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) + size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) + GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD; GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) { if (tbl->current_table_bytes > tbl->max_bytes) {
if (grpc_http_trace) { char *msg;
gpr_log(GPR_ERROR, gpr_asprintf(
&msg,
"HPACK max table size reduced to %d but not reflected by hpack " "HPACK max table size reduced to %d but not reflected by hpack "
"stream (still at %d)", "stream (still at %d)",
tbl->max_bytes, tbl->current_table_bytes); tbl->max_bytes, tbl->current_table_bytes);
} grpc_error *err = GRPC_ERROR_CREATE(msg);
return 0; gpr_free(msg);
return err;
} }
/* we can't add elements bigger than the max table size */ /* we can't add elements bigger than the max table size */
@ -324,7 +328,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) { while (tbl->num_ents) {
evict1(tbl); evict1(tbl);
} }
return 1; return GRPC_ERROR_NONE;
} }
/* evict entries to ensure no overflow */ /* evict entries to ensure no overflow */
@ -339,7 +343,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* update accounting values */ /* update accounting values */
tbl->num_ents++; tbl->num_ents++;
tbl->mem_used += (uint32_t)elem_bytes; tbl->mem_used += (uint32_t)elem_bytes;
return 1; return GRPC_ERROR_NONE;
} }
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find( grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(

@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h" #include "src/core/lib/transport/metadata.h"
/* HPACK header table */ /* HPACK header table */
@ -87,14 +88,14 @@ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl); void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
uint32_t max_bytes); uint32_t max_bytes);
int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
uint32_t bytes); uint32_t bytes);
/* lookup a table entry based on its hpack index */ /* lookup a table entry based on its hpack index */
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl, grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
uint32_t index); uint32_t index);
/* add a table entry to the index */ /* add a table entry to the index */
int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
grpc_mdelem *md) GRPC_MUST_USE_RESULT; grpc_mdelem *md) GRPC_MUST_USE_RESULT;
/* Find a key/value pair in the table... returns the index in the table of the /* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */ most similar entry, or 0 if the value was not found */

@ -156,7 +156,7 @@ struct grpc_chttp2_incoming_byte_stream {
grpc_byte_stream base; grpc_byte_stream base;
gpr_refcount refs; gpr_refcount refs;
struct grpc_chttp2_incoming_byte_stream *next_message; struct grpc_chttp2_incoming_byte_stream *next_message;
int failed; grpc_error *error;
grpc_chttp2_transport *transport; grpc_chttp2_transport *transport;
grpc_chttp2_stream *stream; grpc_chttp2_stream *stream;
@ -275,10 +275,10 @@ struct grpc_chttp2_transport_parsing {
/* active parser */ /* active parser */
void *parser_data; void *parser_data;
grpc_chttp2_stream_parsing *incoming_stream; grpc_chttp2_stream_parsing *incoming_stream;
grpc_chttp2_parse_error (*parser)( grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data,
grpc_exec_ctx *exec_ctx, void *parser_user_data,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last); grpc_chttp2_stream_parsing *stream_parsing,
gpr_slice slice, int is_last);
/* received settings */ /* received settings */
uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS]; uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
@ -471,12 +471,12 @@ typedef struct {
} grpc_chttp2_stream_writing; } grpc_chttp2_stream_writing;
struct grpc_chttp2_stream_parsing { struct grpc_chttp2_stream_parsing {
/** saw some stream level error */
grpc_error *forced_close_error;
/** HTTP2 stream id for this stream, or zero if one has not been assigned */ /** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id; uint32_t id;
/** has this stream received a close */ /** has this stream received a close */
uint8_t received_close; uint8_t received_close;
/** saw a rst_stream */
uint8_t saw_rst_stream;
/** how many header frames have we received? */ /** how many header frames have we received? */
uint8_t header_frames_received; uint8_t header_frames_received;
/** which metadata did we get (on this parse) */ /** which metadata did we get (on this parse) */
@ -488,8 +488,6 @@ struct grpc_chttp2_stream_parsing {
int64_t incoming_window; int64_t incoming_window;
/** parsing state for data frames */ /** parsing state for data frames */
grpc_chttp2_data_parser data_parser; grpc_chttp2_data_parser data_parser;
/** reason give to rst_stream */
uint32_t rst_stream_reason;
/** amount of window given */ /** amount of window given */
int64_t outgoing_window; int64_t outgoing_window;
/** number of bytes received - reset at end of parse thread execution */ /** number of bytes received - reset at end of parse thread execution */
@ -532,7 +530,7 @@ void grpc_chttp2_perform_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
grpc_endpoint *endpoint); grpc_endpoint *endpoint);
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx, void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
void *transport_writing, bool success); void *transport_writing, grpc_error *error);
void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx, void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global, grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing); grpc_chttp2_transport_writing *writing);
@ -541,8 +539,8 @@ void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing); grpc_chttp2_transport_parsing *parsing);
/** Process one slice of incoming data; return 1 if the connection is still /** Process one slice of incoming data; return 1 if the connection is still
viable after reading, or 0 if the connection should be torn down */ viable after reading, or 0 if the connection should be torn down */
int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, grpc_error *grpc_chttp2_perform_read(
grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
gpr_slice slice); gpr_slice slice);
void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx, void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global, grpc_chttp2_transport_global *global,
@ -673,9 +671,10 @@ void grpc_chttp2_for_all_streams(
void grpc_chttp2_parsing_become_skip_parser( void grpc_chttp2_parsing_become_skip_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx, void grpc_chttp2_complete_closure_step(
grpc_chttp2_stream_global *stream_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_closure **pclosure, int success); grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
grpc_error *error);
void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx, void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *transport, grpc_chttp2_transport *transport,
@ -778,8 +777,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
grpc_status_code status, gpr_slice *details); grpc_status_code status, gpr_slice *details);
void grpc_chttp2_mark_stream_closed( void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, int close_reads, grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
int close_writes); grpc_error *error);
void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx, void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global); grpc_chttp2_transport_global *transport_global);
@ -811,8 +810,8 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs, grpc_chttp2_incoming_byte_stream *bs,
gpr_slice slice); gpr_slice slice);
void grpc_chttp2_incoming_byte_stream_finished( void grpc_chttp2_incoming_byte_stream_finished(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success, grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
int from_parsing_thread); grpc_error *error, int from_parsing_thread);
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *parsing, grpc_chttp2_transport_parsing *parsing,

@ -49,29 +49,29 @@
((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \ ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
parsing))) parsing)))
static int init_frame_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_frame_parser(
grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_header_frame_parser( static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation); int is_continuation);
static int init_data_frame_parser( static grpc_error *init_data_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static grpc_error *init_rst_stream_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_rst_stream_parser( static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_settings_frame_parser( static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_window_update_frame_parser( static grpc_error *init_ping_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_ping_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_goaway_parser(
grpc_chttp2_transport_parsing *transport_parsing); grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
static int init_goaway_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_skip_frame_parser(
grpc_chttp2_transport_parsing *transport_parsing);
static int init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header); int is_header);
static int parse_frame_slice(grpc_exec_ctx *exec_ctx, static grpc_error *parse_frame_slice(
grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
gpr_slice slice, int is_last); gpr_slice slice, int is_last);
void grpc_chttp2_prepare_to_read( void grpc_chttp2_prepare_to_read(
@ -230,38 +230,42 @@ void grpc_chttp2_publish_reads(
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global); grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
} }
if (stream_parsing->saw_rst_stream) { if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) { intptr_t reason;
grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status( bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
(grpc_chttp2_error_code)stream_parsing->rst_stream_reason); GRPC_ERROR_INT_HTTP2_ERROR, &reason);
char *status_details; if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
gpr_slice slice_details; grpc_status_code status_code =
gpr_asprintf(&status_details, "Received RST_STREAM err=%d", has_reason ? grpc_chttp2_http2_error_to_grpc_status(
stream_parsing->rst_stream_reason); (grpc_chttp2_error_code)reason)
slice_details = gpr_slice_from_copied_string(status_details); : GRPC_STATUS_INTERNAL;
gpr_free(status_details); const char *status_details =
grpc_error_string(stream_parsing->forced_close_error);
gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
grpc_error_free_string(status_details);
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
status_code, &slice_details); status_code, &slice_details);
} }
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
1, 1); 1, 1, stream_parsing->forced_close_error);
} }
if (stream_parsing->received_close) { if (stream_parsing->received_close) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
1, 0); 1, 0, GRPC_ERROR_NONE);
} }
} }
} }
int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx, grpc_error *grpc_chttp2_perform_read(
grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
gpr_slice slice) { gpr_slice slice) {
uint8_t *beg = GPR_SLICE_START_PTR(slice); uint8_t *beg = GPR_SLICE_START_PTR(slice);
uint8_t *end = GPR_SLICE_END_PTR(slice); uint8_t *end = GPR_SLICE_END_PTR(slice);
uint8_t *cur = beg; uint8_t *cur = beg;
grpc_error *err;
if (cur == end) return 1; if (cur == end) return GRPC_ERROR_NONE;
switch (transport_parsing->deframe_state) { switch (transport_parsing->deframe_state) {
case GRPC_DTS_CLIENT_PREFIX_0: case GRPC_DTS_CLIENT_PREFIX_0:
@ -291,7 +295,9 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) { while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
->deframe_state]) { ->deframe_state]) {
gpr_log(GPR_INFO, char *msg;
gpr_asprintf(
&msg,
"Connect string mismatch: expected '%c' (%d) got '%c' (%d) " "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
"at byte %d", "at byte %d",
GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
@ -299,13 +305,15 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
(int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
[transport_parsing->deframe_state], [transport_parsing->deframe_state],
*cur, (int)*cur, transport_parsing->deframe_state); *cur, (int)*cur, transport_parsing->deframe_state);
return 0; err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
++cur; ++cur;
++transport_parsing->deframe_state; ++transport_parsing->deframe_state;
} }
if (cur == end) { if (cur == end) {
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
dts_fh_0: dts_fh_0:
@ -314,7 +322,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16; transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_1; transport_parsing->deframe_state = GRPC_DTS_FH_1;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_1: case GRPC_DTS_FH_1:
@ -322,7 +330,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8; transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_2; transport_parsing->deframe_state = GRPC_DTS_FH_2;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_2: case GRPC_DTS_FH_2:
@ -330,7 +338,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= *cur; transport_parsing->incoming_frame_size |= *cur;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_3; transport_parsing->deframe_state = GRPC_DTS_FH_3;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_3: case GRPC_DTS_FH_3:
@ -338,7 +346,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_type = *cur; transport_parsing->incoming_frame_type = *cur;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_4; transport_parsing->deframe_state = GRPC_DTS_FH_4;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_4: case GRPC_DTS_FH_4:
@ -346,7 +354,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_flags = *cur; transport_parsing->incoming_frame_flags = *cur;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_5; transport_parsing->deframe_state = GRPC_DTS_FH_5;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_5: case GRPC_DTS_FH_5:
@ -354,7 +362,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24; transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_6; transport_parsing->deframe_state = GRPC_DTS_FH_6;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_6: case GRPC_DTS_FH_6:
@ -362,7 +370,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16; transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_7; transport_parsing->deframe_state = GRPC_DTS_FH_7;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_7: case GRPC_DTS_FH_7:
@ -370,15 +378,16 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8; transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_8; transport_parsing->deframe_state = GRPC_DTS_FH_8;
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FH_8: case GRPC_DTS_FH_8:
GPR_ASSERT(cur < end); GPR_ASSERT(cur < end);
transport_parsing->incoming_stream_id |= ((uint32_t)*cur); transport_parsing->incoming_stream_id |= ((uint32_t)*cur);
transport_parsing->deframe_state = GRPC_DTS_FRAME; transport_parsing->deframe_state = GRPC_DTS_FRAME;
if (!init_frame_parser(exec_ctx, transport_parsing)) { err = init_frame_parser(exec_ctx, transport_parsing);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
if (transport_parsing->incoming_stream_id != 0 && if (transport_parsing->incoming_stream_id != 0 &&
transport_parsing->incoming_stream_id > transport_parsing->incoming_stream_id >
@ -387,62 +396,69 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id; transport_parsing->incoming_stream_id;
} }
if (transport_parsing->incoming_frame_size == 0) { if (transport_parsing->incoming_frame_size == 0) {
if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(), err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
1)) { 1);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
transport_parsing->incoming_stream = NULL; transport_parsing->incoming_stream = NULL;
if (++cur == end) { if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_0; transport_parsing->deframe_state = GRPC_DTS_FH_0;
return 1; return GRPC_ERROR_NONE;
} }
goto dts_fh_0; /* loop */ goto dts_fh_0; /* loop */
} else if (transport_parsing->incoming_frame_size > } else if (transport_parsing->incoming_frame_size >
transport_parsing->max_frame_size) { transport_parsing->max_frame_size) {
gpr_log(GPR_DEBUG, "Frame size %d is larger than max frame size %d", char *msg;
gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
transport_parsing->max_frame_size); transport_parsing->max_frame_size);
return 0; err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
if (++cur == end) { if (++cur == end) {
return 1; return GRPC_ERROR_NONE;
} }
/* fallthrough */ /* fallthrough */
case GRPC_DTS_FRAME: case GRPC_DTS_FRAME:
GPR_ASSERT(cur < end); GPR_ASSERT(cur < end);
if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) { if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
if (!parse_frame_slice(exec_ctx, transport_parsing, err = parse_frame_slice(exec_ctx, transport_parsing,
gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
(size_t)(end - beg)), (size_t)(end - beg)),
1)) { 1);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
transport_parsing->deframe_state = GRPC_DTS_FH_0; transport_parsing->deframe_state = GRPC_DTS_FH_0;
transport_parsing->incoming_stream = NULL; transport_parsing->incoming_stream = NULL;
return 1; return GRPC_ERROR_NONE;
} else if ((uint32_t)(end - cur) > } else if ((uint32_t)(end - cur) >
transport_parsing->incoming_frame_size) { transport_parsing->incoming_frame_size) {
size_t cur_offset = (size_t)(cur - beg); size_t cur_offset = (size_t)(cur - beg);
if (!parse_frame_slice( err = parse_frame_slice(
exec_ctx, transport_parsing, exec_ctx, transport_parsing,
gpr_slice_sub_no_ref( gpr_slice_sub_no_ref(
slice, cur_offset, slice, cur_offset,
cur_offset + transport_parsing->incoming_frame_size), cur_offset + transport_parsing->incoming_frame_size),
1)) { 1);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
cur += transport_parsing->incoming_frame_size; cur += transport_parsing->incoming_frame_size;
transport_parsing->incoming_stream = NULL; transport_parsing->incoming_stream = NULL;
goto dts_fh_0; /* loop */ goto dts_fh_0; /* loop */
} else { } else {
if (!parse_frame_slice(exec_ctx, transport_parsing, err = parse_frame_slice(exec_ctx, transport_parsing,
gpr_slice_sub_no_ref(slice, (size_t)(cur - beg), gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
(size_t)(end - beg)), (size_t)(end - beg)),
0)) { 0);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
transport_parsing->incoming_frame_size -= (uint32_t)(end - cur); transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
return 1; return GRPC_ERROR_NONE;
} }
GPR_UNREACHABLE_CODE(return 0); GPR_UNREACHABLE_CODE(return 0);
} }
@ -450,23 +466,30 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
GPR_UNREACHABLE_CODE(return 0); GPR_UNREACHABLE_CODE(return 0);
} }
static int init_frame_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_frame_parser(
grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
if (transport_parsing->expect_continuation_stream_id != 0) { if (transport_parsing->expect_continuation_stream_id != 0) {
if (transport_parsing->incoming_frame_type != if (transport_parsing->incoming_frame_type !=
GRPC_CHTTP2_FRAME_CONTINUATION) { GRPC_CHTTP2_FRAME_CONTINUATION) {
gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x", char *msg;
gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
transport_parsing->incoming_frame_type); transport_parsing->incoming_frame_type);
return 0; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
if (transport_parsing->expect_continuation_stream_id != if (transport_parsing->expect_continuation_stream_id !=
transport_parsing->incoming_stream_id) { transport_parsing->incoming_stream_id) {
gpr_log(GPR_ERROR, char *msg;
gpr_asprintf(
&msg,
"Expected CONTINUATION frame for grpc_chttp2_stream %08x, got " "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
"grpc_chttp2_stream %08x", "grpc_chttp2_stream %08x",
transport_parsing->expect_continuation_stream_id, transport_parsing->expect_continuation_stream_id,
transport_parsing->incoming_stream_id); transport_parsing->incoming_stream_id);
return 0; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
return init_header_frame_parser(exec_ctx, transport_parsing, 1); return init_header_frame_parser(exec_ctx, transport_parsing, 1);
} }
@ -476,8 +499,7 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_HEADER: case GRPC_CHTTP2_FRAME_HEADER:
return init_header_frame_parser(exec_ctx, transport_parsing, 0); return init_header_frame_parser(exec_ctx, transport_parsing, 0);
case GRPC_CHTTP2_FRAME_CONTINUATION: case GRPC_CHTTP2_FRAME_CONTINUATION:
gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame"); return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame");
return 0;
case GRPC_CHTTP2_FRAME_RST_STREAM: case GRPC_CHTTP2_FRAME_RST_STREAM:
return init_rst_stream_parser(exec_ctx, transport_parsing); return init_rst_stream_parser(exec_ctx, transport_parsing);
case GRPC_CHTTP2_FRAME_SETTINGS: case GRPC_CHTTP2_FRAME_SETTINGS:
@ -489,22 +511,24 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_GOAWAY: case GRPC_CHTTP2_FRAME_GOAWAY:
return init_goaway_parser(exec_ctx, transport_parsing); return init_goaway_parser(exec_ctx, transport_parsing);
default: default:
if (grpc_http_trace) {
gpr_log(GPR_ERROR, "Unknown frame type %02x", gpr_log(GPR_ERROR, "Unknown frame type %02x",
transport_parsing->incoming_frame_type); transport_parsing->incoming_frame_type);
}
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
} }
} }
static grpc_chttp2_parse_error skip_parser( static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) { grpc_chttp2_stream_parsing *stream_parsing,
return GRPC_CHTTP2_PARSE_OK; gpr_slice slice, int is_last) {
return GRPC_ERROR_NONE;
} }
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); } static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
static int init_skip_frame_parser( static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header) { int is_header) {
if (is_header) { if (is_header) {
@ -519,7 +543,7 @@ static int init_skip_frame_parser(
} else { } else {
transport_parsing->parser = skip_parser; transport_parsing->parser = skip_parser;
} }
return 1; return GRPC_ERROR_NONE;
} }
void grpc_chttp2_parsing_become_skip_parser( void grpc_chttp2_parsing_become_skip_parser(
@ -529,22 +553,28 @@ void grpc_chttp2_parsing_become_skip_parser(
transport_parsing->parser == grpc_chttp2_header_parser_parse); transport_parsing->parser == grpc_chttp2_header_parser_parse);
} }
static grpc_chttp2_parse_error update_incoming_window( static grpc_error *update_incoming_window(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing) { grpc_chttp2_stream_parsing *stream_parsing) {
uint32_t incoming_frame_size = transport_parsing->incoming_frame_size; uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
if (incoming_frame_size > transport_parsing->incoming_window) { if (incoming_frame_size > transport_parsing->incoming_window) {
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", char *msg;
gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
transport_parsing->incoming_window); transport_parsing->incoming_window);
return GRPC_CHTTP2_CONNECTION_ERROR; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
if (incoming_frame_size > stream_parsing->incoming_window) { if (incoming_frame_size > stream_parsing->incoming_window) {
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d", char *msg;
gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
stream_parsing->incoming_window); stream_parsing->incoming_window);
return GRPC_CHTTP2_CONNECTION_ERROR; grpc_error *err = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return err;
} }
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window, GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
@ -555,15 +585,15 @@ static grpc_chttp2_parse_error update_incoming_window(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing); grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
return GRPC_CHTTP2_PARSE_OK; return GRPC_ERROR_NONE;
} }
static int init_data_frame_parser( static grpc_error *init_data_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
grpc_chttp2_stream_parsing *stream_parsing = grpc_chttp2_stream_parsing *stream_parsing =
grpc_chttp2_parsing_lookup_stream(transport_parsing, grpc_chttp2_parsing_lookup_stream(transport_parsing,
transport_parsing->incoming_stream_id); transport_parsing->incoming_stream_id);
grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK; grpc_error *err = GRPC_ERROR_NONE;
if (stream_parsing == NULL) { if (stream_parsing == NULL) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
} }
@ -571,33 +601,32 @@ static int init_data_frame_parser(
if (stream_parsing->received_close) { if (stream_parsing->received_close) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
} }
if (err == GRPC_CHTTP2_PARSE_OK) { if (err == GRPC_ERROR_NONE) {
err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing); err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing);
} }
if (err == GRPC_CHTTP2_PARSE_OK) { if (err == GRPC_ERROR_NONE) {
err = grpc_chttp2_data_parser_begin_frame( err = grpc_chttp2_data_parser_begin_frame(
&stream_parsing->data_parser, transport_parsing->incoming_frame_flags); &stream_parsing->data_parser, transport_parsing->incoming_frame_flags,
stream_parsing->id);
} }
switch (err) { if (err == GRPC_ERROR_NONE) {
case GRPC_CHTTP2_PARSE_OK:
transport_parsing->incoming_stream = stream_parsing; transport_parsing->incoming_stream = stream_parsing;
transport_parsing->parser = grpc_chttp2_data_parser_parse; transport_parsing->parser = grpc_chttp2_data_parser_parse;
transport_parsing->parser_data = &stream_parsing->data_parser; transport_parsing->parser_data = &stream_parsing->data_parser;
return 1; return GRPC_ERROR_NONE;
case GRPC_CHTTP2_STREAM_ERROR: } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
/* handle stream errors by closing the stream */
stream_parsing->received_close = 1; stream_parsing->received_close = 1;
stream_parsing->saw_rst_stream = 1; stream_parsing->forced_close_error = err;
stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
gpr_slice_buffer_add( gpr_slice_buffer_add(
&transport_parsing->qbuf, &transport_parsing->qbuf,
grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR, GRPC_CHTTP2_PROTOCOL_ERROR,
&stream_parsing->stats.outgoing)); &stream_parsing->stats.outgoing));
return init_skip_frame_parser(exec_ctx, transport_parsing, 0); return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
case GRPC_CHTTP2_CONNECTION_ERROR: } else {
return 0; return err;
} }
GPR_UNREACHABLE_CODE(return 0);
} }
static void free_timeout(void *p) { gpr_free(p); } static void free_timeout(void *p) { gpr_free(p); }
@ -649,7 +678,8 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) { if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) { if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%lu vs. %lu)", "received initial metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")",
new_size, metadata_size_limit); new_size, metadata_size_limit);
stream_parsing->seen_error = true; stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true; stream_parsing->exceeded_metadata_size = true;
@ -695,7 +725,8 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) { if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) { if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG,
"received trailing metadata size exceeds limit (%lu vs. %lu)", "received trailing metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR ")",
new_size, metadata_size_limit); new_size, metadata_size_limit);
stream_parsing->seen_error = true; stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true; stream_parsing->exceeded_metadata_size = true;
@ -711,7 +742,7 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
GPR_TIMER_END("on_trailing_header", 0); GPR_TIMER_END("on_trailing_header", 0);
} }
static int init_header_frame_parser( static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation) { int is_continuation) {
uint8_t is_eoh = (transport_parsing->incoming_frame_flags & uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
@ -806,15 +837,16 @@ static int init_header_frame_parser(
GRPC_CHTTP2_FLAG_HAS_PRIORITY)) { GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser); grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
} }
return 1; return GRPC_ERROR_NONE;
} }
static int init_window_update_frame_parser( static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame( grpc_error *err = grpc_chttp2_window_update_parser_begin_frame(
&transport_parsing->simple.window_update, &transport_parsing->simple.window_update,
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_flags); transport_parsing->incoming_frame_flags);
if (err != GRPC_ERROR_NONE) return err;
if (transport_parsing->incoming_stream_id != 0) { if (transport_parsing->incoming_stream_id != 0) {
grpc_chttp2_stream_parsing *stream_parsing = grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
@ -826,26 +858,27 @@ static int init_window_update_frame_parser(
} }
transport_parsing->parser = grpc_chttp2_window_update_parser_parse; transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.window_update; transport_parsing->parser_data = &transport_parsing->simple.window_update;
return ok; return GRPC_ERROR_NONE;
} }
static int init_ping_parser(grpc_exec_ctx *exec_ctx, static grpc_error *init_ping_parser(
grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame( grpc_error *err = grpc_chttp2_ping_parser_begin_frame(
&transport_parsing->simple.ping, &transport_parsing->simple.ping, transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_flags); transport_parsing->incoming_frame_flags);
if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_ping_parser_parse; transport_parsing->parser = grpc_chttp2_ping_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.ping; transport_parsing->parser_data = &transport_parsing->simple.ping;
return ok; return GRPC_ERROR_NONE;
} }
static int init_rst_stream_parser( static grpc_error *init_rst_stream_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame( grpc_error *err = grpc_chttp2_rst_stream_parser_begin_frame(
&transport_parsing->simple.rst_stream, &transport_parsing->simple.rst_stream,
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_flags); transport_parsing->incoming_frame_flags);
if (err != GRPC_ERROR_NONE) return err;
grpc_chttp2_stream_parsing *stream_parsing = grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream( transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
transport_parsing, transport_parsing->incoming_stream_id); transport_parsing, transport_parsing->incoming_stream_id);
@ -855,37 +888,32 @@ static int init_rst_stream_parser(
stream_parsing->stats.incoming.framing_bytes += 9; stream_parsing->stats.incoming.framing_bytes += 9;
transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse; transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.rst_stream; transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
return ok; return GRPC_ERROR_NONE;
} }
static int init_goaway_parser( static grpc_error *init_goaway_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame( grpc_error *err = grpc_chttp2_goaway_parser_begin_frame(
&transport_parsing->goaway_parser, &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_flags); transport_parsing->incoming_frame_flags);
if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_goaway_parser_parse; transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
transport_parsing->parser_data = &transport_parsing->goaway_parser; transport_parsing->parser_data = &transport_parsing->goaway_parser;
return ok; return GRPC_ERROR_NONE;
} }
static int init_settings_frame_parser( static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) { grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
int ok;
if (transport_parsing->incoming_stream_id != 0) { if (transport_parsing->incoming_stream_id != 0) {
gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d", return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream");
transport_parsing->incoming_stream_id);
return 0;
} }
ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame( grpc_error *err = grpc_chttp2_settings_parser_begin_frame(
&transport_parsing->simple.settings, &transport_parsing->simple.settings,
transport_parsing->incoming_frame_size, transport_parsing->incoming_frame_size,
transport_parsing->incoming_frame_flags, transport_parsing->incoming_frame_flags, transport_parsing->settings);
transport_parsing->settings); if (err != GRPC_ERROR_NONE) {
if (!ok) { return err;
return 0;
} }
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) { if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
transport_parsing->settings_ack_received = 1; transport_parsing->settings_ack_received = 1;
@ -899,7 +927,7 @@ static int init_settings_frame_parser(
} }
transport_parsing->parser = grpc_chttp2_settings_parser_parse; transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings; transport_parsing->parser_data = &transport_parsing->simple.settings;
return ok; return GRPC_ERROR_NONE;
} }
/* /*
@ -908,34 +936,37 @@ static int is_window_update_legal(int64_t window_update, int64_t window) {
} }
*/ */
static int parse_frame_slice(grpc_exec_ctx *exec_ctx, static grpc_error *parse_frame_slice(
grpc_chttp2_transport_parsing *transport_parsing, grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
gpr_slice slice, int is_last) { gpr_slice slice, int is_last) {
grpc_chttp2_stream_parsing *stream_parsing = grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream; transport_parsing->incoming_stream;
switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data, grpc_error *err = transport_parsing->parser(
transport_parsing, stream_parsing, slice, exec_ctx, transport_parsing->parser_data, transport_parsing,
is_last)) { stream_parsing, slice, is_last);
case GRPC_CHTTP2_PARSE_OK: if (err == GRPC_ERROR_NONE) {
if (stream_parsing) { if (stream_parsing) {
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
stream_parsing); stream_parsing);
} }
return 1; return GRPC_ERROR_NONE;
case GRPC_CHTTP2_STREAM_ERROR: } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
if (grpc_http_trace) {
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
grpc_error_free_string(msg);
}
grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing); grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
if (stream_parsing) { if (stream_parsing) {
stream_parsing->saw_rst_stream = 1; stream_parsing->forced_close_error = err;
stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
gpr_slice_buffer_add( gpr_slice_buffer_add(
&transport_parsing->qbuf, &transport_parsing->qbuf,
grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id, grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR, GRPC_CHTTP2_PROTOCOL_ERROR,
&stream_parsing->stats.outgoing)); &stream_parsing->stats.outgoing));
} else {
GRPC_ERROR_UNREF(err);
} }
return 1;
case GRPC_CHTTP2_CONNECTION_ERROR:
return 0;
} }
GPR_UNREACHABLE_CODE(return 0); return err;
} }

@ -187,7 +187,8 @@ void grpc_chttp2_perform_writes(
grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf, grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
&transport_writing->done_cb); &transport_writing->done_cb);
} else { } else {
grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL); grpc_exec_ctx_sched(exec_ctx, &transport_writing->done_cb, GRPC_ERROR_NONE,
NULL);
} }
} }
@ -334,25 +335,27 @@ void grpc_chttp2_cleanup_writing(
transport_global, transport_writing, &stream_global, &stream_writing)) { transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_writing->sent_initial_metadata) { if (stream_writing->sent_initial_metadata) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_initial_metadata_finished, 1); &stream_global->send_initial_metadata_finished, GRPC_ERROR_NONE);
} }
grpc_transport_move_one_way_stats(&stream_writing->stats, grpc_transport_move_one_way_stats(&stream_writing->stats,
&stream_global->stats.outgoing); &stream_global->stats.outgoing);
if (stream_writing->sent_message) { if (stream_writing->sent_message) {
GPR_ASSERT(stream_writing->send_message == NULL); GPR_ASSERT(stream_writing->send_message == NULL);
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, &stream_global->send_message_finished, 1); exec_ctx, transport_global, stream_global,
&stream_global->send_message_finished, GRPC_ERROR_NONE);
stream_writing->sent_message = 0; stream_writing->sent_message = 0;
} }
if (stream_writing->sent_trailing_metadata) { if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
exec_ctx, stream_global, exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished, 1); &stream_global->send_trailing_metadata_finished, GRPC_ERROR_NONE);
} }
if (stream_writing->sent_trailing_metadata) { if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
!transport_global->is_client, 1); !transport_global->is_client, 1,
GRPC_ERROR_NONE);
} }
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing"); GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
} }

@ -159,11 +159,11 @@ static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
static void enqueue_callbacks(grpc_closure *callback_list[]) { static void enqueue_callbacks(grpc_closure *callback_list[]) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
if (callback_list[0]) { if (callback_list[0]) {
grpc_exec_ctx_enqueue(&exec_ctx, callback_list[0], true, NULL); grpc_exec_ctx_sched(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL);
callback_list[0] = NULL; callback_list[0] = NULL;
} }
if (callback_list[1]) { if (callback_list[1]) {
grpc_exec_ctx_enqueue(&exec_ctx, callback_list[1], true, NULL); grpc_exec_ctx_sched(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL);
callback_list[1] = NULL; callback_list[1] = NULL;
} }
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);

@ -149,6 +149,7 @@ grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) {
void grpc_channel_args_destroy(grpc_channel_args *a) { void grpc_channel_args_destroy(grpc_channel_args *a) {
size_t i; size_t i;
if (!a) return;
for (i = 0; i < a->num_args; i++) { for (i = 0; i < a->num_args; i++) {
switch (a->args[i].type) { switch (a->args[i].type) {
case GRPC_ARG_STRING: case GRPC_ARG_STRING:
@ -212,7 +213,7 @@ static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) { grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
int *states_arg; int *states_arg = NULL;
grpc_channel_args *result = *a; grpc_channel_args *result = *a;
const int states_arg_found = const int states_arg_found =
find_compression_algorithm_states_bitset(*a, &states_arg); find_compression_algorithm_states_bitset(*a, &states_arg);

@ -154,11 +154,11 @@ static void process_send_initial_metadata(
static void continue_send_message(grpc_exec_ctx *exec_ctx, static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem); grpc_call_element *elem);
static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp; grpc_call_element *elem = elemp;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
gpr_slice_buffer_reset_and_unref(&calld->slices); gpr_slice_buffer_reset_and_unref(&calld->slices);
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success); calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
} }
static void finish_send_message(grpc_exec_ctx *exec_ctx, static void finish_send_message(grpc_exec_ctx *exec_ctx,
@ -177,8 +177,8 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
const float savings_ratio = 1.0f - (float)after_size / (float)before_size; const float savings_ratio = 1.0f - (float)after_size / (float)before_size;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name)); &algo_name));
gpr_log(GPR_DEBUG, gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
"Compressed[%s] %d bytes vs. %d bytes (%.2f%% savings)", " bytes (%.2f%% savings)",
algo_name, before_size, after_size, 100 * savings_ratio); algo_name, before_size, after_size, 100 * savings_ratio);
} }
gpr_slice_buffer_swap(&calld->slices, &tmp); gpr_slice_buffer_swap(&calld->slices, &tmp);
@ -188,9 +188,9 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
char *algo_name; char *algo_name;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm, GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name)); &algo_name));
gpr_log( gpr_log(GPR_DEBUG,
GPR_DEBUG, "Algorithm '%s' enabled but decided not to compress. Input size: "
"Algorithm '%s' enabled but decided not to compress. Input size: %d", "%" PRIuPTR,
algo_name, calld->slices.length); algo_name, calld->slices.length);
} }
} }
@ -206,7 +206,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_next_op(exec_ctx, elem, &calld->send_op); grpc_call_next_op(exec_ctx, elem, &calld->send_op);
} }
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) { static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp; grpc_call_element *elem = elemp;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
gpr_slice_buffer_add(&calld->slices, calld->incoming_slice); gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);

@ -101,7 +101,8 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
return md; return md;
} }
static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *error) {
grpc_call_element *elem = user_data; grpc_call_element *elem = user_data;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
client_recv_filter_args a; client_recv_filter_args a;
@ -109,7 +110,7 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
a.exec_ctx = exec_ctx; a.exec_ctx = exec_ctx;
grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter, grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
&a); &a);
calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
} }
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {

@ -142,10 +142,11 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
} }
} }
static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *err) {
grpc_call_element *elem = user_data; grpc_call_element *elem = user_data;
call_data *calld = elem->call_data; call_data *calld = elem->call_data;
if (success) { if (err == GRPC_ERROR_NONE) {
server_filter_args a; server_filter_args a;
a.elem = elem; a.elem = elem;
a.exec_ctx = exec_ctx; a.exec_ctx = exec_ctx;
@ -157,27 +158,35 @@ static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
calld->seen_path && calld->seen_authority) { calld->seen_path && calld->seen_authority) {
/* do nothing */ /* do nothing */
} else { } else {
err = GRPC_ERROR_CREATE("Bad incoming HTTP headers");
if (!calld->seen_path) { if (!calld->seen_path) {
gpr_log(GPR_ERROR, "Missing :path header"); err = grpc_error_add_child(err,
GRPC_ERROR_CREATE("Missing :path header"));
} }
if (!calld->seen_authority) { if (!calld->seen_authority) {
gpr_log(GPR_ERROR, "Missing :authority header"); err = grpc_error_add_child(
err, GRPC_ERROR_CREATE("Missing :authority header"));
} }
if (!calld->seen_method) { if (!calld->seen_method) {
gpr_log(GPR_ERROR, "Missing :method header"); err = grpc_error_add_child(err,
GRPC_ERROR_CREATE("Missing :method header"));
} }
if (!calld->seen_scheme) { if (!calld->seen_scheme) {
gpr_log(GPR_ERROR, "Missing :scheme header"); err = grpc_error_add_child(err,
GRPC_ERROR_CREATE("Missing :scheme header"));
} }
if (!calld->seen_te_trailers) { if (!calld->seen_te_trailers) {
gpr_log(GPR_ERROR, "Missing te trailers header"); err = grpc_error_add_child(
err, GRPC_ERROR_CREATE("Missing te: trailers header"));
} }
/* Error this call out */ /* Error this call out */
success = 0;
grpc_call_element_send_cancel(exec_ctx, elem); grpc_call_element_send_cancel(exec_ctx, elem);
} }
} else {
GRPC_ERROR_REF(err);
} }
calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success); calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err);
GRPC_ERROR_UNREF(err);
} }
static void hs_mutate_op(grpc_call_element *elem, static void hs_mutate_op(grpc_call_element *elem,

@ -39,12 +39,14 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/lib/http/format_request.h" #include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h" #include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/tcp_client.h" #include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
@ -59,8 +61,7 @@ typedef struct {
gpr_timespec deadline; gpr_timespec deadline;
int have_read_byte; int have_read_byte;
const grpc_httpcli_handshaker *handshaker; const grpc_httpcli_handshaker *handshaker;
grpc_httpcli_response_cb on_response; grpc_closure *on_done;
void *user_data;
grpc_httpcli_context *context; grpc_httpcli_context *context;
grpc_polling_entity *pollent; grpc_polling_entity *pollent;
grpc_iomgr_object iomgr_obj; grpc_iomgr_object iomgr_obj;
@ -69,6 +70,7 @@ typedef struct {
grpc_closure on_read; grpc_closure on_read;
grpc_closure done_write; grpc_closure done_write;
grpc_closure connected; grpc_closure connected;
grpc_error *overall_error;
} internal_request; } internal_request;
static grpc_httpcli_get_override g_get_override = NULL; static grpc_httpcli_get_override g_get_override = NULL;
@ -76,6 +78,7 @@ static grpc_httpcli_post_override g_post_override = NULL;
static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg, static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint, const char *host, grpc_endpoint *endpoint, const char *host,
gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void (*on_done)(grpc_exec_ctx *exec_ctx,
void *arg, void *arg,
grpc_endpoint *endpoint)) { grpc_endpoint *endpoint)) {
@ -93,14 +96,14 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
grpc_pollset_set_destroy(context->pollset_set); grpc_pollset_set_destroy(context->pollset_set);
} }
static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req); static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_error *due_to_error);
static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
int success) { grpc_error *error) {
grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent, grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent,
req->context->pollset_set); req->context->pollset_set);
req->on_response(exec_ctx, req->user_data, grpc_exec_ctx_sched(exec_ctx, req->on_done, error, NULL);
success ? &req->parser.http.response : NULL);
grpc_http_parser_destroy(&req->parser); grpc_http_parser_destroy(&req->parser);
if (req->addresses != NULL) { if (req->addresses != NULL) {
grpc_resolved_addresses_destroy(req->addresses); grpc_resolved_addresses_destroy(req->addresses);
@ -114,39 +117,49 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_iomgr_unregister_object(&req->iomgr_obj); grpc_iomgr_unregister_object(&req->iomgr_obj);
gpr_slice_buffer_destroy(&req->incoming); gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing); gpr_slice_buffer_destroy(&req->outgoing);
GRPC_ERROR_UNREF(req->overall_error);
gpr_free(req); gpr_free(req);
} }
static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success); static void append_error(internal_request *req, grpc_error *error) {
if (req->overall_error == GRPC_ERROR_NONE) {
req->overall_error = GRPC_ERROR_CREATE("Failed HTTP/1 client request");
}
grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1];
char *addr_text = grpc_sockaddr_to_uri((struct sockaddr *)addr->addr);
req->overall_error = grpc_error_add_child(
req->overall_error,
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text));
gpr_free(addr_text);
}
static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) { static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read); grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
} }
static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) { static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_error *error) {
internal_request *req = user_data; internal_request *req = user_data;
size_t i; size_t i;
for (i = 0; i < req->incoming.count; i++) { for (i = 0; i < req->incoming.count; i++) {
if (GPR_SLICE_LENGTH(req->incoming.slices[i])) { if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
req->have_read_byte = 1; req->have_read_byte = 1;
if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) { grpc_error *err =
finish(exec_ctx, req, 0); grpc_http_parser_parse(&req->parser, req->incoming.slices[i]);
if (err != GRPC_ERROR_NONE) {
finish(exec_ctx, req, err);
return; return;
} }
} }
} }
if (success) { if (error == GRPC_ERROR_NONE) {
do_read(exec_ctx, req); do_read(exec_ctx, req);
} else if (!req->have_read_byte) { } else if (!req->have_read_byte) {
next_address(exec_ctx, req); next_address(exec_ctx, req, GRPC_ERROR_REF(error));
} else { } else {
int parse_success = grpc_http_parser_eof(&req->parser); finish(exec_ctx, req, grpc_http_parser_eof(&req->parser));
if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) {
parse_success = 0;
}
finish(exec_ctx, req, parse_success);
} }
} }
@ -154,12 +167,12 @@ static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) {
do_read(exec_ctx, req); do_read(exec_ctx, req);
} }
static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg; internal_request *req = arg;
if (success) { if (error == GRPC_ERROR_NONE) {
on_written(exec_ctx, req); on_written(exec_ctx, req);
} else { } else {
next_address(exec_ctx, req); next_address(exec_ctx, req, GRPC_ERROR_REF(error));
} }
} }
@ -174,7 +187,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
internal_request *req = arg; internal_request *req = arg;
if (!ep) { if (!ep) {
next_address(exec_ctx, req); next_address(exec_ctx, req,
GRPC_ERROR_CREATE("Unexplained handshake failure"));
return; return;
} }
@ -182,23 +196,30 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
start_write(exec_ctx, req); start_write(exec_ctx, req);
} }
static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void on_connected(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
internal_request *req = arg; internal_request *req = arg;
if (!req->ep) { if (!req->ep) {
next_address(exec_ctx, req); next_address(exec_ctx, req, GRPC_ERROR_REF(error));
return; return;
} }
req->handshaker->handshake( req->handshaker->handshake(
exec_ctx, req, req->ep, exec_ctx, req, req->ep,
req->ssl_host_override ? req->ssl_host_override : req->host, req->ssl_host_override ? req->ssl_host_override : req->host,
on_handshake_done); req->deadline, on_handshake_done);
} }
static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) { static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_error *error) {
grpc_resolved_address *addr; grpc_resolved_address *addr;
if (error != GRPC_ERROR_NONE) {
append_error(req, error);
}
if (req->next_address == req->addresses->naddrs) { if (req->next_address == req->addresses->naddrs) {
finish(exec_ctx, req, 0); finish(exec_ctx, req,
GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets",
&req->overall_error, 1));
return; return;
} }
addr = &req->addresses->addrs[req->next_address++]; addr = &req->addresses->addrs[req->next_address++];
@ -208,34 +229,34 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
(struct sockaddr *)&addr->addr, addr->len, req->deadline); (struct sockaddr *)&addr->addr, addr->len, req->deadline);
} }
static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_resolved_addresses *addresses) {
internal_request *req = arg; internal_request *req = arg;
if (!addresses) { if (error != GRPC_ERROR_NONE) {
finish(exec_ctx, req, 0); finish(exec_ctx, req, error);
return; return;
} }
req->addresses = addresses;
req->next_address = 0; req->next_address = 0;
next_address(exec_ctx, req); next_address(exec_ctx, req, GRPC_ERROR_NONE);
} }
static void internal_request_begin( static void internal_request_begin(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, grpc_httpcli_context *context,
grpc_polling_entity *pollent, const grpc_httpcli_request *request, grpc_polling_entity *pollent,
gpr_timespec deadline, grpc_httpcli_response_cb on_response, const grpc_httpcli_request *request,
void *user_data, const char *name, gpr_slice request_text) { gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response *response,
const char *name, gpr_slice request_text) {
internal_request *req = gpr_malloc(sizeof(internal_request)); internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
req->request_text = request_text; req->request_text = request_text;
grpc_http_parser_init(&req->parser); grpc_http_parser_init(&req->parser, GRPC_HTTP_RESPONSE, response);
req->on_response = on_response; req->on_done = on_done;
req->user_data = user_data;
req->deadline = deadline; req->deadline = deadline;
req->handshaker = req->handshaker =
request->handshaker ? request->handshaker : &grpc_httpcli_plaintext; request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
req->context = context; req->context = context;
req->pollent = pollent; req->pollent = pollent;
req->overall_error = GRPC_ERROR_NONE;
grpc_closure_init(&req->on_read, on_read, req); grpc_closure_init(&req->on_read, on_read, req);
grpc_closure_init(&req->done_write, done_write, req); grpc_closure_init(&req->done_write, done_write, req);
gpr_slice_buffer_init(&req->incoming); gpr_slice_buffer_init(&req->incoming);
@ -248,22 +269,22 @@ static void internal_request_begin(
grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent, grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent,
req->context->pollset_set); req->context->pollset_set);
grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port, grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port,
on_resolved, req); grpc_closure_create(on_resolved, req), &req->addresses);
} }
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent, grpc_polling_entity *pollent,
const grpc_httpcli_request *request, const grpc_httpcli_request *request,
gpr_timespec deadline, gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response_cb on_response, void *user_data) { grpc_httpcli_response *response) {
char *name; char *name;
if (g_get_override && if (g_get_override &&
g_get_override(exec_ctx, request, deadline, on_response, user_data)) { g_get_override(exec_ctx, request, deadline, on_done, response)) {
return; return;
} }
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path); gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path);
internal_request_begin(exec_ctx, context, pollent, request, deadline, internal_request_begin(exec_ctx, context, pollent, request, deadline, on_done,
on_response, user_data, name, response, name,
grpc_httpcli_format_get_request(request)); grpc_httpcli_format_get_request(request));
gpr_free(name); gpr_free(name);
} }
@ -272,18 +293,18 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent, grpc_polling_entity *pollent,
const grpc_httpcli_request *request, const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size, const char *body_bytes, size_t body_size,
gpr_timespec deadline, gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response_cb on_response, void *user_data) { grpc_httpcli_response *response) {
char *name; char *name;
if (g_post_override && if (g_post_override &&
g_post_override(exec_ctx, request, body_bytes, body_size, deadline, g_post_override(exec_ctx, request, body_bytes, body_size, deadline,
on_response, user_data)) { on_done, response)) {
return; return;
} }
gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path); gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path);
internal_request_begin( internal_request_begin(
exec_ctx, context, pollent, request, deadline, on_response, user_data, exec_ctx, context, pollent, request, deadline, on_done, response, name,
name, grpc_httpcli_format_post_request(request, body_bytes, body_size)); grpc_httpcli_format_post_request(request, body_bytes, body_size));
gpr_free(name); gpr_free(name);
} }

@ -57,7 +57,7 @@ typedef struct grpc_httpcli_context {
typedef struct { typedef struct {
const char *default_port; const char *default_port;
void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint, void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
const char *host, const char *host, gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint)); grpc_endpoint *endpoint));
} grpc_httpcli_handshaker; } grpc_httpcli_handshaker;
@ -82,11 +82,6 @@ typedef struct grpc_httpcli_request {
/* Expose the parser response type as a httpcli response too */ /* Expose the parser response type as a httpcli response too */
typedef struct grpc_http_response grpc_httpcli_response; typedef struct grpc_http_response grpc_httpcli_response;
/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx,
void *user_data,
const grpc_http_response *response);
void grpc_httpcli_context_init(grpc_httpcli_context *context); void grpc_httpcli_context_init(grpc_httpcli_context *context);
void grpc_httpcli_context_destroy(grpc_httpcli_context *context); void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
@ -103,8 +98,8 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context, void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent, grpc_polling_entity *pollent,
const grpc_httpcli_request *request, const grpc_httpcli_request *request,
gpr_timespec deadline, gpr_timespec deadline, grpc_closure *on_complete,
grpc_httpcli_response_cb on_response, void *user_data); grpc_httpcli_response *response);
/* Asynchronously perform a HTTP POST. /* Asynchronously perform a HTTP POST.
'context' specifies the http context under which to do the post 'context' specifies the http context under which to do the post
@ -125,19 +120,19 @@ void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
grpc_polling_entity *pollent, grpc_polling_entity *pollent,
const grpc_httpcli_request *request, const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size, const char *body_bytes, size_t body_size,
gpr_timespec deadline, gpr_timespec deadline, grpc_closure *on_complete,
grpc_httpcli_response_cb on_response, void *user_data); grpc_httpcli_response *response);
/* override functions return 1 if they handled the request, 0 otherwise */ /* override functions return 1 if they handled the request, 0 otherwise */
typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx, typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
const grpc_httpcli_request *request, const grpc_httpcli_request *request,
gpr_timespec deadline, gpr_timespec deadline,
grpc_httpcli_response_cb on_response, grpc_closure *on_complete,
void *user_data); grpc_httpcli_response *response);
typedef int (*grpc_httpcli_post_override)( typedef int (*grpc_httpcli_post_override)(
grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request, grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size, gpr_timespec deadline, const char *body_bytes, size_t body_size, gpr_timespec deadline,
grpc_httpcli_response_cb on_response, void *user_data); grpc_closure *on_complete, grpc_httpcli_response *response);
void grpc_httpcli_set_override(grpc_httpcli_get_override get, void grpc_httpcli_set_override(grpc_httpcli_get_override get,
grpc_httpcli_post_override post); grpc_httpcli_post_override post);

@ -61,6 +61,7 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx, static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
gpr_timespec deadline,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
grpc_httpcli_ssl_channel_security_connector *c = grpc_httpcli_ssl_channel_security_connector *c =
@ -79,7 +80,7 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else { } else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
nonsecure_endpoint, cb, user_data); nonsecure_endpoint, deadline, cb, user_data);
} }
} }
@ -163,6 +164,7 @@ static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg, static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *tcp, const char *host, grpc_endpoint *tcp, const char *host,
gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg, void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint)) { grpc_endpoint *endpoint)) {
grpc_channel_security_connector *sc = NULL; grpc_channel_security_connector *sc = NULL;
@ -181,7 +183,7 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
pem_root_certs, pem_root_certs_size, host, &sc) == pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK); GRPC_SECURITY_OK);
grpc_channel_security_connector_do_handshake( grpc_channel_security_connector_do_handshake(
exec_ctx, sc, tcp, on_secure_transport_setup_done, c); exec_ctx, sc, tcp, deadline, on_secure_transport_setup_done, c);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
} }

@ -48,37 +48,38 @@ static char *buf2str(void *buffer, size_t length) {
return out; return out;
} }
static int handle_response_line(grpc_http_parser *parser) { static grpc_error *handle_response_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line; uint8_t *beg = parser->cur_line;
uint8_t *cur = beg; uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length; uint8_t *end = beg + parser->cur_line_length;
if (cur == end || *cur++ != 'H') goto error; if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') goto error; if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') goto error; if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
if (cur == end || *cur++ != '1') goto error; if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
if (cur == end || *cur++ != '.') goto error; if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
if (cur == end || *cur < '0' || *cur++ > '1') goto error; if (cur == end || *cur < '0' || *cur++ > '1') {
if (cur == end || *cur++ != ' ') goto error; return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
if (cur == end || *cur < '1' || *cur++ > '9') goto error; }
if (cur == end || *cur < '0' || *cur++ > '9') goto error; if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
if (cur == end || *cur < '0' || *cur++ > '9') goto error; if (cur == end || *cur < '1' || *cur++ > '9')
parser->http.response.status = return GRPC_ERROR_CREATE("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code");
parser->http.response->status =
(cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
if (cur == end || *cur++ != ' ') goto error; if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
/* we don't really care about the status code message */ /* we don't really care about the status code message */
return 1; return GRPC_ERROR_NONE;
error:
if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing response line");
return 0;
} }
static int handle_request_line(grpc_http_parser *parser) { static grpc_error *handle_request_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line; uint8_t *beg = parser->cur_line;
uint8_t *cur = beg; uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length; uint8_t *end = beg + parser->cur_line_length;
@ -87,84 +88,81 @@ static int handle_request_line(grpc_http_parser *parser) {
while (cur != end && *cur++ != ' ') while (cur != end && *cur++ != ' ')
; ;
if (cur == end) goto error; if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1)); parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
beg = cur; beg = cur;
while (cur != end && *cur++ != ' ') while (cur != end && *cur++ != ' ')
; ;
if (cur == end) goto error; if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1)); parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
if (cur == end || *cur++ != 'H') goto error; if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') goto error; if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') goto error; if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') goto error; if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
vers_major = (uint8_t)(*cur++ - '1' + 1); vers_major = (uint8_t)(*cur++ - '1' + 1);
++cur; ++cur;
if (cur == end) goto error; if (cur == end)
return GRPC_ERROR_CREATE("End of line in HTTP version string");
vers_minor = (uint8_t)(*cur++ - '1' + 1); vers_minor = (uint8_t)(*cur++ - '1' + 1);
if (vers_major == 1) { if (vers_major == 1) {
if (vers_minor == 0) { if (vers_minor == 0) {
parser->http.request.version = GRPC_HTTP_HTTP10; parser->http.request->version = GRPC_HTTP_HTTP10;
} else if (vers_minor == 1) { } else if (vers_minor == 1) {
parser->http.request.version = GRPC_HTTP_HTTP11; parser->http.request->version = GRPC_HTTP_HTTP11;
} else { } else {
goto error; return GRPC_ERROR_CREATE(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
} else if (vers_major == 2) { } else if (vers_major == 2) {
if (vers_minor == 0) { if (vers_minor == 0) {
parser->http.request.version = GRPC_HTTP_HTTP20; parser->http.request->version = GRPC_HTTP_HTTP20;
} else { } else {
goto error; return GRPC_ERROR_CREATE(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
} else { } else {
goto error; return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
} }
return 1; return GRPC_ERROR_NONE;
error:
if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing request line");
return 0;
} }
static int handle_first_line(grpc_http_parser *parser) { static grpc_error *handle_first_line(grpc_http_parser *parser) {
if (parser->cur_line[0] == 'H') { switch (parser->type) {
parser->type = GRPC_HTTP_RESPONSE; case GRPC_HTTP_REQUEST:
return handle_response_line(parser);
} else {
parser->type = GRPC_HTTP_REQUEST;
return handle_request_line(parser); return handle_request_line(parser);
case GRPC_HTTP_RESPONSE:
return handle_response_line(parser);
} }
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
} }
static int add_header(grpc_http_parser *parser) { static grpc_error *add_header(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line; uint8_t *beg = parser->cur_line;
uint8_t *cur = beg; uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length; uint8_t *end = beg + parser->cur_line_length;
size_t *hdr_count = NULL; size_t *hdr_count = NULL;
grpc_http_header **hdrs = NULL; grpc_http_header **hdrs = NULL;
grpc_http_header hdr = {NULL, NULL}; grpc_http_header hdr = {NULL, NULL};
grpc_error *error = GRPC_ERROR_NONE;
GPR_ASSERT(cur != end); GPR_ASSERT(cur != end);
if (*cur == ' ' || *cur == '\t') { if (*cur == ' ' || *cur == '\t') {
if (grpc_http1_trace) error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
gpr_log(GPR_ERROR, "Continued header lines not supported yet"); goto done;
goto error;
} }
while (cur != end && *cur != ':') { while (cur != end && *cur != ':') {
cur++; cur++;
} }
if (cur == end) { if (cur == end) {
if (grpc_http1_trace) { error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
gpr_log(GPR_ERROR, "Didn't find ':' in header string"); goto done;
}
goto error;
} }
GPR_ASSERT(cur >= beg); GPR_ASSERT(cur >= beg);
hdr.key = buf2str(beg, (size_t)(cur - beg)); hdr.key = buf2str(beg, (size_t)(cur - beg));
@ -176,14 +174,15 @@ static int add_header(grpc_http_parser *parser) {
GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length); GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length); hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
if (parser->type == GRPC_HTTP_RESPONSE) { switch (parser->type) {
hdr_count = &parser->http.response.hdr_count; case GRPC_HTTP_RESPONSE:
hdrs = &parser->http.response.hdrs; hdr_count = &parser->http.response->hdr_count;
} else if (parser->type == GRPC_HTTP_REQUEST) { hdrs = &parser->http.response->hdrs;
hdr_count = &parser->http.request.hdr_count; break;
hdrs = &parser->http.request.hdrs; case GRPC_HTTP_REQUEST:
} else { hdr_count = &parser->http.request->hdr_count;
return 0; hdrs = &parser->http.request->hdrs;
break;
} }
if (*hdr_count == parser->hdr_capacity) { if (*hdr_count == parser->hdr_capacity) {
@ -192,20 +191,21 @@ static int add_header(grpc_http_parser *parser) {
*hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)); *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
} }
(*hdrs)[(*hdr_count)++] = hdr; (*hdrs)[(*hdr_count)++] = hdr;
return 1;
error: done:
if (error != GRPC_ERROR_NONE) {
gpr_free(hdr.key); gpr_free(hdr.key);
gpr_free(hdr.value); gpr_free(hdr.value);
return 0; }
return error;
} }
static int finish_line(grpc_http_parser *parser) { static grpc_error *finish_line(grpc_http_parser *parser) {
grpc_error *err;
switch (parser->state) { switch (parser->state) {
case GRPC_HTTP_FIRST_LINE: case GRPC_HTTP_FIRST_LINE:
if (!handle_first_line(parser)) { err = handle_first_line(parser);
return 0; if (err != GRPC_ERROR_NONE) return err;
}
parser->state = GRPC_HTTP_HEADERS; parser->state = GRPC_HTTP_HEADERS;
break; break;
case GRPC_HTTP_HEADERS: case GRPC_HTTP_HEADERS:
@ -213,30 +213,31 @@ static int finish_line(grpc_http_parser *parser) {
parser->state = GRPC_HTTP_BODY; parser->state = GRPC_HTTP_BODY;
break; break;
} }
if (!add_header(parser)) { err = add_header(parser);
return 0; if (err != GRPC_ERROR_NONE) {
return err;
} }
break; break;
case GRPC_HTTP_BODY: case GRPC_HTTP_BODY:
GPR_UNREACHABLE_CODE(return 0); GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
} }
parser->cur_line_length = 0; parser->cur_line_length = 0;
return 1; return GRPC_ERROR_NONE;
} }
static int addbyte_body(grpc_http_parser *parser, uint8_t byte) { static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
size_t *body_length = NULL; size_t *body_length = NULL;
char **body = NULL; char **body = NULL;
if (parser->type == GRPC_HTTP_RESPONSE) { if (parser->type == GRPC_HTTP_RESPONSE) {
body_length = &parser->http.response.body_length; body_length = &parser->http.response->body_length;
body = &parser->http.response.body; body = &parser->http.response->body;
} else if (parser->type == GRPC_HTTP_REQUEST) { } else if (parser->type == GRPC_HTTP_REQUEST) {
body_length = &parser->http.request.body_length; body_length = &parser->http.request->body_length;
body = &parser->http.request.body; body = &parser->http.request->body;
} else { } else {
return 0; GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
} }
if (*body_length == parser->body_capacity) { if (*body_length == parser->body_capacity) {
@ -246,34 +247,34 @@ static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
(*body)[*body_length] = (char)byte; (*body)[*body_length] = (char)byte;
(*body_length)++; (*body_length)++;
return 1; return GRPC_ERROR_NONE;
} }
static int check_line(grpc_http_parser *parser) { static bool check_line(grpc_http_parser *parser) {
if (parser->cur_line_length >= 2 && if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\r' && parser->cur_line[parser->cur_line_length - 2] == '\r' &&
parser->cur_line[parser->cur_line_length - 1] == '\n') { parser->cur_line[parser->cur_line_length - 1] == '\n') {
return 1; return true;
} }
// HTTP request with \n\r line termiantors. // HTTP request with \n\r line termiantors.
else if (parser->cur_line_length >= 2 && else if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\n' && parser->cur_line[parser->cur_line_length - 2] == '\n' &&
parser->cur_line[parser->cur_line_length - 1] == '\r') { parser->cur_line[parser->cur_line_length - 1] == '\r') {
return 1; return true;
} }
// HTTP request with only \n line terminators. // HTTP request with only \n line terminators.
else if (parser->cur_line_length >= 1 && else if (parser->cur_line_length >= 1 &&
parser->cur_line[parser->cur_line_length - 1] == '\n') { parser->cur_line[parser->cur_line_length - 1] == '\n') {
parser->cur_line_end_length = 1; parser->cur_line_end_length = 1;
return 1; return true;
} }
return 0; return false;
} }
static int addbyte(grpc_http_parser *parser, uint8_t byte) { static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
switch (parser->state) { switch (parser->state) {
case GRPC_HTTP_FIRST_LINE: case GRPC_HTTP_FIRST_LINE:
case GRPC_HTTP_HEADERS: case GRPC_HTTP_HEADERS:
@ -288,7 +289,7 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
if (check_line(parser)) { if (check_line(parser)) {
return finish_line(parser); return finish_line(parser);
} else { } else {
return 1; return GRPC_ERROR_NONE;
} }
GPR_UNREACHABLE_CODE(return 0); GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTP_BODY: case GRPC_HTTP_BODY:
@ -297,46 +298,53 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
GPR_UNREACHABLE_CODE(return 0); GPR_UNREACHABLE_CODE(return 0);
} }
void grpc_http_parser_init(grpc_http_parser *parser) { void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
void *request_or_response) {
memset(parser, 0, sizeof(*parser)); memset(parser, 0, sizeof(*parser));
parser->state = GRPC_HTTP_FIRST_LINE; parser->state = GRPC_HTTP_FIRST_LINE;
parser->type = GRPC_HTTP_UNKNOWN; parser->type = type;
parser->http.request_or_response = request_or_response;
parser->cur_line_end_length = 2; parser->cur_line_end_length = 2;
} }
void grpc_http_parser_destroy(grpc_http_parser *parser) { void grpc_http_parser_destroy(grpc_http_parser *parser) {}
void grpc_http_request_destroy(grpc_http_request *request) {
size_t i; size_t i;
if (parser->type == GRPC_HTTP_RESPONSE) { gpr_free(request->body);
gpr_free(parser->http.response.body); for (i = 0; i < request->hdr_count; i++) {
for (i = 0; i < parser->http.response.hdr_count; i++) { gpr_free(request->hdrs[i].key);
gpr_free(parser->http.response.hdrs[i].key); gpr_free(request->hdrs[i].value);
gpr_free(parser->http.response.hdrs[i].value);
} }
gpr_free(parser->http.response.hdrs); gpr_free(request->hdrs);
} else if (parser->type == GRPC_HTTP_REQUEST) { gpr_free(request->method);
gpr_free(parser->http.request.body); gpr_free(request->path);
for (i = 0; i < parser->http.request.hdr_count; i++) { }
gpr_free(parser->http.request.hdrs[i].key);
gpr_free(parser->http.request.hdrs[i].value); void grpc_http_response_destroy(grpc_http_response *response) {
} size_t i;
gpr_free(parser->http.request.hdrs); gpr_free(response->body);
gpr_free(parser->http.request.method); for (i = 0; i < response->hdr_count; i++) {
gpr_free(parser->http.request.path); gpr_free(response->hdrs[i].key);
gpr_free(response->hdrs[i].value);
} }
gpr_free(response->hdrs);
} }
int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) { grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
size_t i; size_t i;
for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) { grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
return 0; if (err != GRPC_ERROR_NONE) return err;
}
} }
return 1; return GRPC_ERROR_NONE;
} }
int grpc_http_parser_eof(grpc_http_parser *parser) { grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
return parser->state == GRPC_HTTP_BODY; if (parser->state != GRPC_HTTP_BODY) {
return GRPC_ERROR_CREATE("Did not finish headers");
}
return GRPC_ERROR_NONE;
} }

@ -0,0 +1,357 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/lib/http/parser.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
int grpc_http1_trace = 0;
static char *buf2str(void *buffer, size_t length) {
char *out = gpr_malloc(length + 1);
memcpy(out, buffer, length);
out[length] = 0;
return out;
}
static grpc_error *handle_response_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
if (cur == end || *cur < '0' || *cur++ > '1') {
return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
}
if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
if (cur == end || *cur < '1' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code");
if (cur == end || *cur < '0' || *cur++ > '9')
return GRPC_ERROR_CREATE("Expected status code");
parser->http.response->status =
(cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
/* we don't really care about the status code message */
return GRPC_ERROR_NONE;
}
static grpc_error *handle_request_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
uint8_t vers_major = 0;
uint8_t vers_minor = 0;
while (cur != end && *cur++ != ' ')
;
if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
beg = cur;
while (cur != end && *cur++ != ' ')
;
if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
vers_major = (uint8_t)(*cur++ - '1' + 1);
++cur;
if (cur == end)
return GRPC_ERROR_CREATE("End of line in HTTP version string");
vers_minor = (uint8_t)(*cur++ - '1' + 1);
if (vers_major == 1) {
if (vers_minor == 0) {
parser->http.request->version = GRPC_HTTP_HTTP10;
} else if (vers_minor == 1) {
parser->http.request->version = GRPC_HTTP_HTTP11;
} else {
return GRPC_ERROR_CREATE(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else if (vers_major == 2) {
if (vers_minor == 0) {
parser->http.request->version = GRPC_HTTP_HTTP20;
} else {
return GRPC_ERROR_CREATE(
"Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else {
return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
return GRPC_ERROR_NONE;
}
static grpc_error *handle_first_line(grpc_http_parser *parser) {
switch (parser->type) {
case GRPC_HTTP_REQUEST:
return handle_request_line(parser);
case GRPC_HTTP_RESPONSE:
return handle_response_line(parser);
}
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
static grpc_error *add_header(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
size_t *hdr_count = NULL;
grpc_http_header **hdrs = NULL;
grpc_http_header hdr = {NULL, NULL};
grpc_error *error = GRPC_ERROR_NONE;
GPR_ASSERT(cur != end);
if (*cur == ' ' || *cur == '\t') {
error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
goto done;
}
while (cur != end && *cur != ':') {
cur++;
}
if (cur == end) {
<<<<<<< HEAD
error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
goto done;
=======
if (grpc_http1_trace) {
gpr_log(GPR_ERROR, "Didn't find ':' in header string");
}
goto error;
>>>>>>> a709afe241d8b264a1c326315f757b4a8d330207
}
GPR_ASSERT(cur >= beg);
hdr.key = buf2str(beg, (size_t)(cur - beg));
cur++; /* skip : */
while (cur != end && (*cur == ' ' || *cur == '\t')) {
cur++;
}
GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
switch (parser->type) {
case GRPC_HTTP_RESPONSE:
hdr_count = &parser->http.response->hdr_count;
hdrs = &parser->http.response->hdrs;
break;
case GRPC_HTTP_REQUEST:
hdr_count = &parser->http.request->hdr_count;
hdrs = &parser->http.request->hdrs;
break;
}
if (*hdr_count == parser->hdr_capacity) {
parser->hdr_capacity =
GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
*hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
}
(*hdrs)[(*hdr_count)++] = hdr;
done:
if (error != GRPC_ERROR_NONE) {
gpr_free(hdr.key);
gpr_free(hdr.value);
}
return error;
}
static grpc_error *finish_line(grpc_http_parser *parser) {
grpc_error *err;
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
err = handle_first_line(parser);
if (err != GRPC_ERROR_NONE) return err;
parser->state = GRPC_HTTP_HEADERS;
break;
case GRPC_HTTP_HEADERS:
if (parser->cur_line_length == parser->cur_line_end_length) {
parser->state = GRPC_HTTP_BODY;
break;
}
err = add_header(parser);
if (err != GRPC_ERROR_NONE) {
return err;
}
break;
case GRPC_HTTP_BODY:
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
parser->cur_line_length = 0;
return GRPC_ERROR_NONE;
}
static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
size_t *body_length = NULL;
char **body = NULL;
if (parser->type == GRPC_HTTP_RESPONSE) {
body_length = &parser->http.response->body_length;
body = &parser->http.response->body;
} else if (parser->type == GRPC_HTTP_REQUEST) {
body_length = &parser->http.request->body_length;
body = &parser->http.request->body;
} else {
GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
if (*body_length == parser->body_capacity) {
parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
*body = gpr_realloc((void *)*body, parser->body_capacity);
}
(*body)[*body_length] = (char)byte;
(*body_length)++;
return GRPC_ERROR_NONE;
}
static bool check_line(grpc_http_parser *parser) {
if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\r' &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
return true;
}
// HTTP request with \n\r line termiantors.
else if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\n' &&
parser->cur_line[parser->cur_line_length - 1] == '\r') {
return true;
}
// HTTP request with only \n line terminators.
else if (parser->cur_line_length >= 1 &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
parser->cur_line_end_length = 1;
return true;
}
return false;
}
static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
case GRPC_HTTP_HEADERS:
if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
if (grpc_http1_trace)
gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
return 0;
}
parser->cur_line[parser->cur_line_length] = byte;
parser->cur_line_length++;
if (check_line(parser)) {
return finish_line(parser);
} else {
return GRPC_ERROR_NONE;
}
GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTP_BODY:
return addbyte_body(parser, byte);
}
GPR_UNREACHABLE_CODE(return 0);
}
void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
void *request_or_response) {
memset(parser, 0, sizeof(*parser));
parser->state = GRPC_HTTP_FIRST_LINE;
parser->type = type;
parser->http.request_or_response = request_or_response;
parser->cur_line_end_length = 2;
}
void grpc_http_parser_destroy(grpc_http_parser *parser) {}
void grpc_http_request_destroy(grpc_http_request *request) {
size_t i;
gpr_free(request->body);
for (i = 0; i < request->hdr_count; i++) {
gpr_free(request->hdrs[i].key);
gpr_free(request->hdrs[i].value);
}
gpr_free(request->hdrs);
gpr_free(request->method);
gpr_free(request->path);
}
void grpc_http_response_destroy(grpc_http_response *response) {
size_t i;
gpr_free(response->body);
for (i = 0; i < response->hdr_count; i++) {
gpr_free(response->hdrs[i].key);
gpr_free(response->hdrs[i].value);
}
gpr_free(response->hdrs);
}
grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
size_t i;
for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
if (err != GRPC_ERROR_NONE) return err;
}
return GRPC_ERROR_NONE;
}
grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
if (parser->state != GRPC_HTTP_BODY) {
return GRPC_ERROR_CREATE("Did not finish headers");
}
return GRPC_ERROR_NONE;
}

@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include "src/core/lib/iomgr/error.h"
/* Maximum length of a header string of the form 'Key: Value\r\n' */ /* Maximum length of a header string of the form 'Key: Value\r\n' */
#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096 #define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096
@ -61,7 +62,6 @@ typedef enum {
typedef enum { typedef enum {
GRPC_HTTP_RESPONSE, GRPC_HTTP_RESPONSE,
GRPC_HTTP_REQUEST, GRPC_HTTP_REQUEST,
GRPC_HTTP_UNKNOWN
} grpc_http_type; } grpc_http_type;
/* A request */ /* A request */
@ -97,8 +97,9 @@ typedef struct {
grpc_http_type type; grpc_http_type type;
union { union {
grpc_http_response response; grpc_http_response *response;
grpc_http_request request; grpc_http_request *request;
void *request_or_response;
} http; } http;
size_t body_capacity; size_t body_capacity;
size_t hdr_capacity; size_t hdr_capacity;
@ -108,11 +109,15 @@ typedef struct {
size_t cur_line_end_length; size_t cur_line_end_length;
} grpc_http_parser; } grpc_http_parser;
void grpc_http_parser_init(grpc_http_parser *parser); void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
void *request_or_response);
void grpc_http_parser_destroy(grpc_http_parser *parser); void grpc_http_parser_destroy(grpc_http_parser *parser);
int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice); grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
int grpc_http_parser_eof(grpc_http_parser *parser); grpc_error *grpc_http_parser_eof(grpc_http_parser *parser);
void grpc_http_request_destroy(grpc_http_request *request);
void grpc_http_response_destroy(grpc_http_response *response);
extern int grpc_http1_trace; extern int grpc_http1_trace;

@ -39,25 +39,32 @@ void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg) { void *cb_arg) {
closure->cb = cb; closure->cb = cb;
closure->cb_arg = cb_arg; closure->cb_arg = cb_arg;
closure->final_data = 0;
} }
void grpc_closure_list_add(grpc_closure_list *closure_list, void grpc_closure_list_append(grpc_closure_list *closure_list,
grpc_closure *closure, bool success) { grpc_closure *closure, grpc_error *error) {
if (closure == NULL) return; if (closure == NULL) {
closure->final_data = (success != 0); GRPC_ERROR_UNREF(error);
return;
}
closure->error = error;
closure->next_data.next = NULL;
if (closure_list->head == NULL) { if (closure_list->head == NULL) {
closure_list->head = closure; closure_list->head = closure;
} else { } else {
closure_list->tail->final_data |= (uintptr_t)closure; closure_list->tail->next_data.next = closure;
} }
closure_list->tail = closure; closure_list->tail = closure;
} }
void grpc_closure_list_fail_all(grpc_closure_list *list) { void grpc_closure_list_fail_all(grpc_closure_list *list,
for (grpc_closure *c = list->head; c != NULL; c = grpc_closure_next(c)) { grpc_error *forced_failure) {
c->final_data &= ~(uintptr_t)1; for (grpc_closure *c = list->head; c != NULL; c = c->next_data.next) {
if (c->error == GRPC_ERROR_NONE) {
c->error = GRPC_ERROR_REF(forced_failure);
}
} }
GRPC_ERROR_UNREF(forced_failure);
} }
bool grpc_closure_list_empty(grpc_closure_list closure_list) { bool grpc_closure_list_empty(grpc_closure_list closure_list) {
@ -71,7 +78,7 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) {
if (dst->head == NULL) { if (dst->head == NULL) {
*dst = *src; *dst = *src;
} else { } else {
dst->tail->final_data |= (uintptr_t)src->head; dst->tail->next_data.next = src->head;
dst->tail = src->tail; dst->tail = src->tail;
} }
src->head = src->tail = NULL; src->head = src->tail = NULL;
@ -83,12 +90,13 @@ typedef struct {
grpc_closure wrapper; grpc_closure wrapper;
} wrapped_closure; } wrapped_closure;
static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
wrapped_closure *wc = arg; wrapped_closure *wc = arg;
grpc_iomgr_cb_func cb = wc->cb; grpc_iomgr_cb_func cb = wc->cb;
void *cb_arg = wc->cb_arg; void *cb_arg = wc->cb_arg;
gpr_free(wc); gpr_free(wc);
cb(exec_ctx, cb_arg, success); cb(exec_ctx, cb_arg, error);
} }
grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) { grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
@ -98,7 +106,3 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
grpc_closure_init(&wc->wrapper, closure_wrapper, wc); grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
return &wc->wrapper; return &wc->wrapper;
} }
grpc_closure *grpc_closure_next(grpc_closure *closure) {
return (grpc_closure *)(closure->final_data & ~(uintptr_t)1);
}

@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <stdbool.h> #include <stdbool.h>
#include "src/core/lib/iomgr/error.h"
struct grpc_closure; struct grpc_closure;
typedef struct grpc_closure grpc_closure; typedef struct grpc_closure grpc_closure;
@ -52,10 +53,10 @@ typedef struct grpc_closure_list {
/** gRPC Callback definition. /** gRPC Callback definition.
* *
* \param arg Arbitrary input. * \param arg Arbitrary input.
* \param success An indication on the state of the iomgr. On false, cleanup * \param error GRPC_ERROR_NONE if no error occurred, otherwise some grpc_error
* actions should be taken (eg, shutdown). */ * describing what went wrong */
typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg, typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
bool success); grpc_error *error);
/** A closure over a grpc_iomgr_cb_func. */ /** A closure over a grpc_iomgr_cb_func. */
struct grpc_closure { struct grpc_closure {
@ -65,10 +66,15 @@ struct grpc_closure {
/** Arguments to be passed to "cb". */ /** Arguments to be passed to "cb". */
void *cb_arg; void *cb_arg;
/** Once enqueued, contains in the lower bit the success of the closure, /** Once queued, the result of the closure. Before then: scratch space */
and in the upper bits the pointer to the next closure in the list. grpc_error *error;
Before enqueing for execution, this is usable for scratch data. */
uintptr_t final_data; /** Once queued, next indicates the next queued closure; before then, scratch
* space */
union {
grpc_closure *next;
uintptr_t scratch;
} next_data;
}; };
/** Initializes \a closure with \a cb and \a cb_arg. */ /** Initializes \a closure with \a cb and \a cb_arg. */
@ -81,13 +87,14 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
#define GRPC_CLOSURE_LIST_INIT \ #define GRPC_CLOSURE_LIST_INIT \
{ NULL, NULL } { NULL, NULL }
/** add \a closure to the end of \a list and set \a closure's success to \a /** add \a closure to the end of \a list
* success */ and set \a closure's result to \a error */
void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure, void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
bool success); grpc_error *error);
/** force all success bits in \a list to false */ /** force all success bits in \a list to false */
void grpc_closure_list_fail_all(grpc_closure_list *list); void grpc_closure_list_fail_all(grpc_closure_list *list,
grpc_error *forced_failure);
/** append all closures from \a src to \a dst and empty \a src. */ /** append all closures from \a src to \a dst and empty \a src. */
void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst); void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
@ -95,7 +102,4 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
/** return whether \a list is empty. */ /** return whether \a list is empty. */
bool grpc_closure_list_empty(grpc_closure_list list); bool grpc_closure_list_empty(grpc_closure_list list);
/** return the next pointer for a queued closure list */
grpc_closure *grpc_closure_next(grpc_closure *closure);
#endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */ #endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */

@ -82,7 +82,7 @@ char *grpc_endpoint_get_peer(grpc_endpoint *ep);
void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep, void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer *slices, grpc_closure *cb); gpr_slice_buffer *slices, grpc_closure *cb);
/* Causes any pending read/write callbacks to run immediately with /* Causes any pending and future read/write callbacks to run immediately with
success==0 */ success==0 */
void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep); void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);

@ -58,8 +58,8 @@ static void create_sockets(int sv[2]) {
GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0); GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
flags = fcntl(sv[1], F_GETFL, 0); flags = fcntl(sv[1], F_GETFL, 0);
GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0); GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0])); GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]) == GRPC_ERROR_NONE);
GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1])); GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
} }
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name, grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,

@ -0,0 +1,535 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "src/core/lib/iomgr/error.h"
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/avl.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#ifdef GPR_WINDOWS
#include <grpc/support/log_windows.h>
#endif
static void destroy_integer(void *key) {}
static void *copy_integer(void *key) { return key; }
static long compare_integers(void *key1, void *key2) {
return GPR_ICMP((uintptr_t)key1, (uintptr_t)key2);
}
static void destroy_string(void *str) { gpr_free(str); }
static void *copy_string(void *str) { return gpr_strdup(str); }
static void destroy_err(void *err) { GRPC_ERROR_UNREF(err); }
static void *copy_err(void *err) { return GRPC_ERROR_REF(err); }
static void destroy_time(void *tm) { gpr_free(tm); }
static gpr_timespec *box_time(gpr_timespec tm) {
gpr_timespec *out = gpr_malloc(sizeof(*out));
*out = tm;
return out;
}
static void *copy_time(void *tm) { return box_time(*(gpr_timespec *)tm); }
static const gpr_avl_vtable avl_vtable_ints = {destroy_integer, copy_integer,
compare_integers,
destroy_integer, copy_integer};
static const gpr_avl_vtable avl_vtable_strs = {destroy_integer, copy_integer,
compare_integers, destroy_string,
copy_string};
static const gpr_avl_vtable avl_vtable_times = {
destroy_integer, copy_integer, compare_integers, destroy_time, copy_time};
static const gpr_avl_vtable avl_vtable_errs = {
destroy_integer, copy_integer, compare_integers, destroy_err, copy_err};
static const char *error_int_name(grpc_error_ints key) {
switch (key) {
case GRPC_ERROR_INT_ERRNO:
return "errno";
case GRPC_ERROR_INT_FILE_LINE:
return "file_line";
case GRPC_ERROR_INT_STREAM_ID:
return "stream_id";
case GRPC_ERROR_INT_GRPC_STATUS:
return "grpc_status";
case GRPC_ERROR_INT_OFFSET:
return "offset";
case GRPC_ERROR_INT_INDEX:
return "index";
case GRPC_ERROR_INT_SIZE:
return "size";
case GRPC_ERROR_INT_HTTP2_ERROR:
return "http2_error";
case GRPC_ERROR_INT_TSI_CODE:
return "tsi_code";
case GRPC_ERROR_INT_SECURITY_STATUS:
return "security_status";
case GRPC_ERROR_INT_FD:
return "fd";
case GRPC_ERROR_INT_WSA_ERROR:
return "wsa_error";
case GRPC_ERROR_INT_HTTP_STATUS:
return "http_status";
}
GPR_UNREACHABLE_CODE(return "unknown");
}
static const char *error_str_name(grpc_error_strs key) {
switch (key) {
case GRPC_ERROR_STR_DESCRIPTION:
return "description";
case GRPC_ERROR_STR_OS_ERROR:
return "os_error";
case GRPC_ERROR_STR_TARGET_ADDRESS:
return "target_address";
case GRPC_ERROR_STR_SYSCALL:
return "syscall";
case GRPC_ERROR_STR_FILE:
return "file";
case GRPC_ERROR_STR_GRPC_MESSAGE:
return "grpc_message";
case GRPC_ERROR_STR_RAW_BYTES:
return "raw_bytes";
case GRPC_ERROR_STR_TSI_ERROR:
return "tsi_error";
case GRPC_ERROR_STR_FILENAME:
return "filename";
}
GPR_UNREACHABLE_CODE(return "unknown");
}
static const char *error_time_name(grpc_error_times key) {
switch (key) {
case GRPC_ERROR_TIME_CREATED:
return "created";
}
GPR_UNREACHABLE_CODE(return "unknown");
}
struct grpc_error {
gpr_refcount refs;
gpr_avl ints;
gpr_avl strs;
gpr_avl times;
gpr_avl errs;
uintptr_t next_err;
};
static bool is_special(grpc_error *err) {
return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM ||
err == GRPC_ERROR_CANCELLED;
}
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
const char *func) {
if (is_special(err)) return err;
gpr_log(GPR_DEBUG, "%p: %d -> %d [%s:%d %s]", err, err->refs.count,
err->refs.count + 1, file, line, func);
gpr_ref(&err->refs);
return err;
}
#else
grpc_error *grpc_error_ref(grpc_error *err) {
if (is_special(err)) return err;
gpr_ref(&err->refs);
return err;
}
#endif
static void error_destroy(grpc_error *err) {
GPR_ASSERT(!is_special(err));
gpr_avl_unref(err->ints);
gpr_avl_unref(err->strs);
gpr_avl_unref(err->errs);
gpr_avl_unref(err->times);
gpr_free(err);
}
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
void grpc_error_unref(grpc_error *err, const char *file, int line,
const char *func) {
if (is_special(err)) return;
gpr_log(GPR_DEBUG, "%p: %d -> %d [%s:%d %s]", err, err->refs.count,
err->refs.count - 1, file, line, func);
if (gpr_unref(&err->refs)) {
error_destroy(err);
}
}
#else
void grpc_error_unref(grpc_error *err) {
if (is_special(err)) return;
if (gpr_unref(&err->refs)) {
error_destroy(err);
}
}
#endif
grpc_error *grpc_error_create(const char *file, int line, const char *desc,
grpc_error **referencing,
size_t num_referencing) {
grpc_error *err = gpr_malloc(sizeof(*err));
if (err == NULL) { // TODO(ctiller): make gpr_malloc return NULL
return GRPC_ERROR_OOM;
}
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
#endif
err->ints = gpr_avl_add(gpr_avl_create(&avl_vtable_ints),
(void *)(uintptr_t)GRPC_ERROR_INT_FILE_LINE,
(void *)(uintptr_t)line);
err->strs = gpr_avl_add(
gpr_avl_add(gpr_avl_create(&avl_vtable_strs),
(void *)(uintptr_t)GRPC_ERROR_STR_FILE, gpr_strdup(file)),
(void *)(uintptr_t)GRPC_ERROR_STR_DESCRIPTION, gpr_strdup(desc));
err->errs = gpr_avl_create(&avl_vtable_errs);
err->next_err = 0;
for (size_t i = 0; i < num_referencing; i++) {
if (referencing[i] == GRPC_ERROR_NONE) continue;
err->errs = gpr_avl_add(err->errs, (void *)(err->next_err++),
GRPC_ERROR_REF(referencing[i]));
}
err->times = gpr_avl_add(gpr_avl_create(&avl_vtable_times),
(void *)(uintptr_t)GRPC_ERROR_TIME_CREATED,
box_time(gpr_now(GPR_CLOCK_REALTIME)));
gpr_ref_init(&err->refs, 1);
return err;
}
static grpc_error *copy_error_and_unref(grpc_error *in) {
if (is_special(in)) {
if (in == GRPC_ERROR_NONE) return GRPC_ERROR_CREATE("no error");
if (in == GRPC_ERROR_OOM) return GRPC_ERROR_CREATE("oom");
if (in == GRPC_ERROR_CANCELLED) return GRPC_ERROR_CREATE("cancelled");
return GRPC_ERROR_CREATE("unknown");
}
grpc_error *out = gpr_malloc(sizeof(*out));
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
gpr_log(GPR_DEBUG, "%p create copying", out);
#endif
out->ints = gpr_avl_ref(in->ints);
out->strs = gpr_avl_ref(in->strs);
out->errs = gpr_avl_ref(in->errs);
out->times = gpr_avl_ref(in->times);
out->next_err = in->next_err;
gpr_ref_init(&out->refs, 1);
GRPC_ERROR_UNREF(in);
return out;
}
grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
intptr_t value) {
grpc_error *new = copy_error_and_unref(src);
new->ints = gpr_avl_add(new->ints, (void *)(uintptr_t)which, (void *)value);
return new;
}
bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
void *pp;
if (gpr_avl_maybe_get(err->ints, (void *)(uintptr_t)which, &pp)) {
if (p != NULL) *p = (intptr_t)pp;
return true;
}
return false;
}
grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value) {
grpc_error *new = copy_error_and_unref(src);
new->strs =
gpr_avl_add(new->strs, (void *)(uintptr_t)which, gpr_strdup(value));
return new;
}
grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) {
grpc_error *new = copy_error_and_unref(src);
new->errs = gpr_avl_add(new->errs, (void *)(new->next_err++), child);
return new;
}
static const char *no_error_string = "null";
static const char *oom_error_string = "\"Out of memory\"";
static const char *cancelled_error_string = "\"Cancelled\"";
typedef struct {
char *key;
char *value;
} kv_pair;
typedef struct {
kv_pair *kvs;
size_t num_kvs;
size_t cap_kvs;
} kv_pairs;
static void append_kv(kv_pairs *kvs, char *key, char *value) {
if (kvs->num_kvs == kvs->cap_kvs) {
kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs);
}
kvs->kvs[kvs->num_kvs].key = key;
kvs->kvs[kvs->num_kvs].value = value;
kvs->num_kvs++;
}
static void collect_kvs(gpr_avl_node *node, char *key(void *k),
char *fmt(void *v), kv_pairs *kvs) {
if (node == NULL) return;
append_kv(kvs, key(node->key), fmt(node->value));
collect_kvs(node->left, key, fmt, kvs);
collect_kvs(node->right, key, fmt, kvs);
}
static char *key_int(void *p) {
return gpr_strdup(error_int_name((grpc_error_ints)(uintptr_t)p));
}
static char *key_str(void *p) {
return gpr_strdup(error_str_name((grpc_error_strs)(uintptr_t)p));
}
static char *key_time(void *p) {
return gpr_strdup(error_time_name((grpc_error_times)(uintptr_t)p));
}
static char *fmt_int(void *p) {
char *s;
gpr_asprintf(&s, "%" PRIdPTR, (intptr_t)p);
return s;
}
static void append_chr(char c, char **s, size_t *sz, size_t *cap) {
if (*sz == *cap) {
*cap = GPR_MAX(8, 3 * *cap / 2);
*s = gpr_realloc(*s, *cap);
}
(*s)[(*sz)++] = c;
}
static void append_str(const char *str, char **s, size_t *sz, size_t *cap) {
for (const char *c = str; *c; c++) {
append_chr(*c, s, sz, cap);
}
}
static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) {
static const char *hex = "0123456789abcdef";
append_chr('"', s, sz, cap);
for (const uint8_t *c = (const uint8_t *)str; *c; c++) {
if (*c < 32 || *c >= 127) {
append_chr('\\', s, sz, cap);
switch (*c) {
case '\b':
append_chr('b', s, sz, cap);
break;
case '\f':
append_chr('f', s, sz, cap);
break;
case '\n':
append_chr('n', s, sz, cap);
break;
case '\r':
append_chr('r', s, sz, cap);
break;
case '\t':
append_chr('t', s, sz, cap);
break;
default:
append_chr('u', s, sz, cap);
append_chr('0', s, sz, cap);
append_chr('0', s, sz, cap);
append_chr(hex[*c >> 4], s, sz, cap);
append_chr(hex[*c & 0x0f], s, sz, cap);
break;
}
} else {
append_chr((char)*c, s, sz, cap);
}
}
append_chr('"', s, sz, cap);
}
static char *fmt_str(void *p) {
char *s = NULL;
size_t sz = 0;
size_t cap = 0;
append_esc_str(p, &s, &sz, &cap);
append_chr(0, &s, &sz, &cap);
return s;
}
static char *fmt_time(void *p) {
gpr_timespec tm = *(gpr_timespec *)p;
char *out;
char *pfx = "!!";
switch (tm.clock_type) {
case GPR_CLOCK_MONOTONIC:
pfx = "@monotonic:";
break;
case GPR_CLOCK_REALTIME:
pfx = "@";
break;
case GPR_CLOCK_PRECISE:
pfx = "@precise:";
break;
case GPR_TIMESPAN:
pfx = "";
break;
}
gpr_asprintf(&out, "\"%s%" PRId64 ".%09d\"", pfx, tm.tv_sec, tm.tv_nsec);
return out;
}
static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap) {
if (n == NULL) return;
add_errs(n->left, s, sz, cap);
const char *e = grpc_error_string(n->value);
append_str(e, s, sz, cap);
grpc_error_free_string(e);
add_errs(n->right, s, sz, cap);
}
static char *errs_string(grpc_error *err) {
char *s = NULL;
size_t sz = 0;
size_t cap = 0;
append_chr('[', &s, &sz, &cap);
add_errs(err->errs.root, &s, &sz, &cap);
append_chr(']', &s, &sz, &cap);
append_chr(0, &s, &sz, &cap);
return s;
}
static int cmp_kvs(const void *a, const void *b) {
const kv_pair *ka = a;
const kv_pair *kb = b;
return strcmp(ka->key, kb->key);
}
static const char *finish_kvs(kv_pairs *kvs) {
char *s = NULL;
size_t sz = 0;
size_t cap = 0;
append_chr('{', &s, &sz, &cap);
for (size_t i = 0; i < kvs->num_kvs; i++) {
if (i != 0) append_chr(',', &s, &sz, &cap);
append_esc_str(kvs->kvs[i].key, &s, &sz, &cap);
gpr_free(kvs->kvs[i].key);
append_chr(':', &s, &sz, &cap);
append_str(kvs->kvs[i].value, &s, &sz, &cap);
gpr_free(kvs->kvs[i].value);
}
append_chr('}', &s, &sz, &cap);
append_chr(0, &s, &sz, &cap);
gpr_free(kvs->kvs);
return s;
}
void grpc_error_free_string(const char *str) {
if (str == no_error_string) return;
if (str == oom_error_string) return;
if (str == cancelled_error_string) return;
gpr_free((char *)str);
}
const char *grpc_error_string(grpc_error *err) {
if (err == GRPC_ERROR_NONE) return no_error_string;
if (err == GRPC_ERROR_OOM) return oom_error_string;
if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
kv_pairs kvs;
memset(&kvs, 0, sizeof(kvs));
collect_kvs(err->ints.root, key_int, fmt_int, &kvs);
collect_kvs(err->strs.root, key_str, fmt_str, &kvs);
collect_kvs(err->times.root, key_time, fmt_time, &kvs);
if (!gpr_avl_is_empty(err->errs)) {
append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
}
qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
return finish_kvs(&kvs);
}
grpc_error *grpc_os_error(const char *file, int line, int err,
const char *call_name) {
return grpc_error_set_str(
grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
GRPC_ERROR_INT_ERRNO, err),
GRPC_ERROR_STR_OS_ERROR, strerror(err)),
GRPC_ERROR_STR_SYSCALL, call_name);
}
#ifdef GPR_WINDOWS
grpc_error *grpc_wsa_error(const char *file, int line, int err,
const char *call_name) {
char *utf8_message = gpr_format_message(err);
grpc_error *error = grpc_error_set_str(
grpc_error_set_str(
grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
GRPC_ERROR_INT_WSA_ERROR, err),
GRPC_ERROR_STR_OS_ERROR, utf8_message),
GRPC_ERROR_STR_SYSCALL, call_name);
gpr_free(utf8_message);
return error;
}
#endif
bool grpc_log_if_error(const char *what, grpc_error *error, const char *file,
int line) {
if (error == GRPC_ERROR_NONE) return true;
const char *msg = grpc_error_string(error);
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
grpc_error_free_string(msg);
GRPC_ERROR_UNREF(error);
return false;
}

@ -0,0 +1,192 @@
/*
*
* Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_CORE_LIB_IOMGR_ERROR_H
#define GRPC_CORE_LIB_IOMGR_ERROR_H
#include <stdbool.h>
#include <stdint.h>
#include <grpc/support/time.h>
/// Opaque representation of an error.
/// Errors are refcounted objects that represent the result of an operation.
/// Ownership laws:
/// if a grpc_error is returned by a function, the caller owns a ref to that
/// instance
/// if a grpc_error is passed to a grpc_closure callback function (functions
/// with the signature:
/// void (*f)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error))
/// then those functions do not automatically own a ref to error
/// if a grpc_error is passed to *ANY OTHER FUNCTION* then that function takes
/// ownership of the error
/// Errors have:
/// a set of ints, strings, and timestamps that describe the error
/// always present are:
/// GRPC_ERROR_STR_FILE, GRPC_ERROR_INT_FILE_LINE - source location the error
/// was generated
/// GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error
/// GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened
/// an error can also have children; these are other errors that are believed
/// to have contributed to this one. By accumulating children, we can begin
/// to root cause high level failures from low level failures, without having
/// to derive execution paths from log lines
typedef struct grpc_error grpc_error;
typedef enum {
/// 'errno' from the operating system
GRPC_ERROR_INT_ERRNO,
/// __LINE__ from the call site creating the error
GRPC_ERROR_INT_FILE_LINE,
/// stream identifier: for errors that are associated with an individual
/// wire stream
GRPC_ERROR_INT_STREAM_ID,
/// grpc status code representing this error
GRPC_ERROR_INT_GRPC_STATUS,
/// offset into some binary blob (usually represented by
/// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
GRPC_ERROR_INT_OFFSET,
/// context sensitive index associated with the error
GRPC_ERROR_INT_INDEX,
/// context sensitive size associated with the error
GRPC_ERROR_INT_SIZE,
/// http2 error code associated with the error (see the HTTP2 RFC)
GRPC_ERROR_INT_HTTP2_ERROR,
/// TSI status code associated with the error
GRPC_ERROR_INT_TSI_CODE,
/// grpc_security_status associated with the error
GRPC_ERROR_INT_SECURITY_STATUS,
/// WSAGetLastError() reported when this error occurred
GRPC_ERROR_INT_WSA_ERROR,
/// File descriptor associated with this error
GRPC_ERROR_INT_FD,
/// HTTP status (i.e. 404)
GRPC_ERROR_INT_HTTP_STATUS,
} grpc_error_ints;
typedef enum {
/// top-level textual description of this error
GRPC_ERROR_STR_DESCRIPTION,
/// source file in which this error occurred
GRPC_ERROR_STR_FILE,
/// operating system description of this error
GRPC_ERROR_STR_OS_ERROR,
/// syscall that generated this error
GRPC_ERROR_STR_SYSCALL,
/// peer that we were trying to communicate when this error occurred
GRPC_ERROR_STR_TARGET_ADDRESS,
/// grpc status message associated with this error
GRPC_ERROR_STR_GRPC_MESSAGE,
/// hex dump (or similar) with the data that generated this error
GRPC_ERROR_STR_RAW_BYTES,
/// tsi error string associated with this error
GRPC_ERROR_STR_TSI_ERROR,
/// filename that we were trying to read/write when this error occurred
GRPC_ERROR_STR_FILENAME,
} grpc_error_strs;
typedef enum {
/// timestamp of error creation
GRPC_ERROR_TIME_CREATED,
} grpc_error_times;
#define GRPC_ERROR_NONE ((grpc_error *)NULL)
#define GRPC_ERROR_OOM ((grpc_error *)1)
#define GRPC_ERROR_CANCELLED ((grpc_error *)2)
const char *grpc_error_string(grpc_error *error);
void grpc_error_free_string(const char *str);
/// Create an error - but use GRPC_ERROR_CREATE instead
grpc_error *grpc_error_create(const char *file, int line, const char *desc,
grpc_error **referencing, size_t num_referencing);
/// Create an error (this is the preferred way of generating an error that is
/// not due to a system call - for system calls, use GRPC_OS_ERROR or
/// GRPC_WSA_ERROR as appropriate)
/// \a referencing is an array of num_referencing elements indicating one or
/// more errors that are believed to have contributed to this one
/// err = grpc_error_create(x, y, z, r, nr) is equivalent to:
/// err = grpc_error_create(x, y, z, NULL, 0);
/// for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]);
#define GRPC_ERROR_CREATE(desc) \
grpc_error_create(__FILE__, __LINE__, desc, NULL, 0)
// Create an error that references some other errors. This function adds a
// reference to each error in errs - it does not consume an existing reference
#define GRPC_ERROR_CREATE_REFERENCING(desc, errs, count) \
grpc_error_create(__FILE__, __LINE__, desc, errs, count)
//#define GRPC_ERROR_REFCOUNT_DEBUG
#ifdef GRPC_ERROR_REFCOUNT_DEBUG
grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
const char *func);
void grpc_error_unref(grpc_error *err, const char *file, int line,
const char *func);
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__, __func__)
#define GRPC_ERROR_UNREF(err) \
grpc_error_unref(err, __FILE__, __LINE__, __func__)
#else
grpc_error *grpc_error_ref(grpc_error *err);
void grpc_error_unref(grpc_error *err);
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif
grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
intptr_t value);
bool grpc_error_get_int(grpc_error *error, grpc_error_ints which, intptr_t *p);
grpc_error *grpc_error_set_time(grpc_error *src, grpc_error_times which,
gpr_timespec value);
grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
const char *value);
/// Add a child error: an error that is believed to have contributed to this
/// error occurring. Allows root causing high level errors from lower level
/// errors that contributed to them.
grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child);
grpc_error *grpc_os_error(const char *file, int line, int err,
const char *call_name);
/// create an error associated with errno!=0 (an 'operating system' error)
#define GRPC_OS_ERROR(err, call_name) \
grpc_os_error(__FILE__, __LINE__, err, call_name)
grpc_error *grpc_wsa_error(const char *file, int line, int err,
const char *call_name);
/// windows only: create an error associated with WSAGetLastError()!=0
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(__FILE__, __LINE__, err, call_name)
bool grpc_log_if_error(const char *what, grpc_error *error, const char *file,
int line);
#define GRPC_LOG_IF_ERROR(what, error) \
grpc_log_if_error((what), (error), __FILE__, __LINE__)
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */

@ -221,7 +221,8 @@ struct grpc_pollset {
struct grpc_pollset_vtable { struct grpc_pollset_vtable {
void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd, int and_unlock_pollset); struct grpc_fd *fd, int and_unlock_pollset);
void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *(*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_pollset_worker *worker, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now); gpr_timespec deadline, gpr_timespec now);
void (*finish_shutdown)(grpc_pollset *pollset); void (*finish_shutdown)(grpc_pollset *pollset);
@ -251,9 +252,9 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2 #define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
/* As per pollset_kick, with an extended set of flags (defined above) /* As per pollset_kick, with an extended set of flags (defined above)
-- mostly for fd_posix's use. */ -- mostly for fd_posix's use. */
static void pollset_kick_ext(grpc_pollset *p, static grpc_error *pollset_kick_ext(grpc_pollset *p,
grpc_pollset_worker *specific_worker, grpc_pollset_worker *specific_worker,
uint32_t flags); uint32_t flags) GRPC_MUST_USE_RESULT;
/* turn a pollset into a multipoller: platform specific */ /* turn a pollset into a multipoller: platform specific */
typedef void (*platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx, typedef void (*platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx,
@ -420,12 +421,13 @@ static bool fd_is_orphaned(grpc_fd *fd) {
return (gpr_atm_acq_load(&fd->refst) & 1) == 0; return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
} }
static void pollset_kick_locked(grpc_fd_watcher *watcher) { static grpc_error *pollset_kick_locked(grpc_fd_watcher *watcher) {
gpr_mu_lock(&watcher->pollset->mu); gpr_mu_lock(&watcher->pollset->mu);
GPR_ASSERT(watcher->worker); GPR_ASSERT(watcher->worker);
pollset_kick_ext(watcher->pollset, watcher->worker, grpc_error *err = pollset_kick_ext(watcher->pollset, watcher->worker,
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP); GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
gpr_mu_unlock(&watcher->pollset->mu); gpr_mu_unlock(&watcher->pollset->mu);
return err;
} }
static void maybe_wake_one_watcher_locked(grpc_fd *fd) { static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
@ -464,7 +466,7 @@ static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
} else { } else {
remove_fd_from_all_epoll_sets(fd->fd); remove_fd_from_all_epoll_sets(fd->fd);
} }
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL); grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
} }
static int fd_wrapped_fd(grpc_fd *fd) { static int fd_wrapped_fd(grpc_fd *fd) {
@ -513,15 +515,27 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); } static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#endif #endif
static grpc_error *fd_shutdown_error(bool shutdown) {
if (!shutdown) {
return GRPC_ERROR_NONE;
} else {
return GRPC_ERROR_CREATE("FD shutdown");
}
}
static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure **st, grpc_closure *closure) { grpc_closure **st, grpc_closure *closure) {
if (*st == CLOSURE_NOT_READY) { if (fd->shutdown) {
grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
NULL);
} else if (*st == CLOSURE_NOT_READY) {
/* not ready ==> switch to a waiting state by setting the closure */ /* not ready ==> switch to a waiting state by setting the closure */
*st = closure; *st = closure;
} else if (*st == CLOSURE_READY) { } else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */ /* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY; *st = CLOSURE_NOT_READY;
grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL); grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
NULL);
maybe_wake_one_watcher_locked(fd); maybe_wake_one_watcher_locked(fd);
} else { } else {
/* upcallptr was set to a different closure. This is an error! */ /* upcallptr was set to a different closure. This is an error! */
@ -544,7 +558,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0; return 0;
} else { } else {
/* waiting ==> queue closure */ /* waiting ==> queue closure */
grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL); grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
*st = CLOSURE_NOT_READY; *st = CLOSURE_NOT_READY;
return 1; return 1;
} }
@ -557,13 +571,24 @@ static void set_read_notifier_pollset_locked(
static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
GPR_ASSERT(!fd->shutdown); /* only shutdown once */
if (!fd->shutdown) {
fd->shutdown = 1; fd->shutdown = 1;
/* signal read/write closed to OS so that future operations fail */
shutdown(fd->fd, SHUT_RDWR);
set_ready_locked(exec_ctx, fd, &fd->read_closure); set_ready_locked(exec_ctx, fd, &fd->read_closure);
set_ready_locked(exec_ctx, fd, &fd->write_closure); set_ready_locked(exec_ctx, fd, &fd->write_closure);
}
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
} }
static bool fd_is_shutdown(grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
bool r = fd->shutdown;
gpr_mu_unlock(&fd->mu);
return r;
}
static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) { grpc_closure *closure) {
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
@ -744,10 +769,19 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker; worker->prev->next = worker->next->prev = worker;
} }
static void pollset_kick_ext(grpc_pollset *p, static void kick_append_error(grpc_error **composite, grpc_error *error) {
if (error == GRPC_ERROR_NONE) return;
if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("Kick Failure");
}
*composite = grpc_error_add_child(*composite, error);
}
static grpc_error *pollset_kick_ext(grpc_pollset *p,
grpc_pollset_worker *specific_worker, grpc_pollset_worker *specific_worker,
uint32_t flags) { uint32_t flags) {
GPR_TIMER_BEGIN("pollset_kick_ext", 0); GPR_TIMER_BEGIN("pollset_kick_ext", 0);
grpc_error *error = GRPC_ERROR_NONE;
/* pollset->mu already held */ /* pollset->mu already held */
if (specific_worker != NULL) { if (specific_worker != NULL) {
@ -757,25 +791,28 @@ static void pollset_kick_ext(grpc_pollset *p,
for (specific_worker = p->root_worker.next; for (specific_worker = p->root_worker.next;
specific_worker != &p->root_worker; specific_worker != &p->root_worker;
specific_worker = specific_worker->next) { specific_worker = specific_worker->next) {
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(
&error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
p->kicked_without_pollers = 1; p->kicked_without_pollers = true;
GPR_TIMER_END("pollset_kick_ext.broadcast", 0); GPR_TIMER_END("pollset_kick_ext.broadcast", 0);
} else if (gpr_tls_get(&g_current_thread_worker) != } else if (gpr_tls_get(&g_current_thread_worker) !=
(intptr_t)specific_worker) { (intptr_t)specific_worker) {
GPR_TIMER_MARK("different_thread_worker", 0); GPR_TIMER_MARK("different_thread_worker", 0);
if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
specific_worker->reevaluate_polling_on_wakeup = 1; specific_worker->reevaluate_polling_on_wakeup = true;
} }
specific_worker->kicked_specifically = 1; specific_worker->kicked_specifically = true;
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(&error,
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) { } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
GPR_TIMER_MARK("kick_yoself", 0); GPR_TIMER_MARK("kick_yoself", 0);
if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
specific_worker->reevaluate_polling_on_wakeup = 1; specific_worker->reevaluate_polling_on_wakeup = true;
} }
specific_worker->kicked_specifically = 1; specific_worker->kicked_specifically = true;
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(&error,
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
} else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) { } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) {
GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
@ -783,14 +820,9 @@ static void pollset_kick_ext(grpc_pollset *p,
specific_worker = pop_front_worker(p); specific_worker = pop_front_worker(p);
if (specific_worker != NULL) { if (specific_worker != NULL) {
if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
/* Prefer not to kick self. Push the worker to the end of the list and
* pop the one from front */
GPR_TIMER_MARK("kick_anonymous_not_self", 0); GPR_TIMER_MARK("kick_anonymous_not_self", 0);
push_back_worker(p, specific_worker); push_back_worker(p, specific_worker);
specific_worker = pop_front_worker(p); specific_worker = pop_front_worker(p);
/* If there was only one worker on the pollset, we would get the same
* worker we pushed (the one set on current thread local) back. If so,
* kick it only if GRPC_POLLSET_CAN_KICK_SELF flag is set */
if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 && if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
gpr_tls_get(&g_current_thread_worker) == gpr_tls_get(&g_current_thread_worker) ==
(intptr_t)specific_worker) { (intptr_t)specific_worker) {
@ -801,28 +833,30 @@ static void pollset_kick_ext(grpc_pollset *p,
if (specific_worker != NULL) { if (specific_worker != NULL) {
GPR_TIMER_MARK("finally_kick", 0); GPR_TIMER_MARK("finally_kick", 0);
push_back_worker(p, specific_worker); push_back_worker(p, specific_worker);
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(
&error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
} else { } else {
GPR_TIMER_MARK("kicked_no_pollers", 0); GPR_TIMER_MARK("kicked_no_pollers", 0);
p->kicked_without_pollers = 1; p->kicked_without_pollers = true;
} }
} }
GPR_TIMER_END("pollset_kick_ext", 0); GPR_TIMER_END("pollset_kick_ext", 0);
return error;
} }
static void pollset_kick(grpc_pollset *p, static grpc_error *pollset_kick(grpc_pollset *p,
grpc_pollset_worker *specific_worker) { grpc_pollset_worker *specific_worker) {
pollset_kick_ext(p, specific_worker, 0); return pollset_kick_ext(p, specific_worker, 0);
} }
/* global state management */ /* global state management */
static void pollset_global_init(void) { static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller); gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker); gpr_tls_init(&g_current_thread_worker);
grpc_wakeup_fd_init(&grpc_global_wakeup_fd); return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
} }
static void pollset_global_shutdown(void) { static void pollset_global_shutdown(void) {
@ -831,7 +865,9 @@ static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_worker); gpr_tls_destroy(&g_current_thread_worker);
} }
static void kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); } static grpc_error *kick_poller(void) {
return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
}
/* main interface */ /* main interface */
@ -894,14 +930,23 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) { static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs)); GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
pollset->vtable->finish_shutdown(pollset); pollset->vtable->finish_shutdown(pollset);
grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL); grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
} }
static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static void work_combine_error(grpc_error **composite, grpc_error *error) {
grpc_pollset_worker **worker_hdl, gpr_timespec now, if (error == GRPC_ERROR_NONE) return;
gpr_timespec deadline) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("pollset_work");
}
*composite = grpc_error_add_child(*composite, error);
}
static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker_hdl,
gpr_timespec now, gpr_timespec deadline) {
grpc_pollset_worker worker; grpc_pollset_worker worker;
*worker_hdl = &worker; *worker_hdl = &worker;
grpc_error *error = GRPC_ERROR_NONE;
/* pollset->mu already held */ /* pollset->mu already held */
int added_worker = 0; int added_worker = 0;
@ -917,7 +962,10 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
pollset->local_wakeup_cache = worker.wakeup_fd->next; pollset->local_wakeup_cache = worker.wakeup_fd->next;
} else { } else {
worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd)); worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
grpc_wakeup_fd_init(&worker.wakeup_fd->fd); error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
if (error != GRPC_ERROR_NONE) {
return error;
}
} }
worker.kicked_specifically = 0; worker.kicked_specifically = 0;
/* If there's work waiting for the pollset to be idle, and the /* If there's work waiting for the pollset to be idle, and the
@ -954,8 +1002,9 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset); gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
GPR_TIMER_BEGIN("maybe_work_and_unlock", 0); GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker, work_combine_error(&error,
deadline, now); pollset->vtable->maybe_work_and_unlock(
exec_ctx, pollset, &worker, deadline, now));
GPR_TIMER_END("maybe_work_and_unlock", 0); GPR_TIMER_END("maybe_work_and_unlock", 0);
locked = 0; locked = 0;
gpr_tls_set(&g_current_thread_poller, 0); gpr_tls_set(&g_current_thread_poller, 0);
@ -1017,6 +1066,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
*worker_hdl = NULL; *worker_hdl = NULL;
GPR_TIMER_END("pollset_work", 0); GPR_TIMER_END("pollset_work", 0);
return error;
} }
static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@ -1065,7 +1115,7 @@ typedef struct grpc_unary_promote_args {
} grpc_unary_promote_args; } grpc_unary_promote_args;
static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args, static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
bool success) { grpc_error *error) {
grpc_unary_promote_args *up_args = args; grpc_unary_promote_args *up_args = args;
const grpc_pollset_vtable *original_vtable = up_args->original_vtable; const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
grpc_pollset *pollset = up_args->pollset; grpc_pollset *pollset = up_args->pollset;
@ -1167,7 +1217,8 @@ static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
up_args->promotion_closure.cb = basic_do_promote; up_args->promotion_closure.cb = basic_do_promote;
up_args->promotion_closure.cb_arg = up_args; up_args->promotion_closure.cb_arg = up_args;
grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1); grpc_closure_list_append(&pollset->idle_jobs, &up_args->promotion_closure,
GRPC_ERROR_NONE);
pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST); pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
exit: exit:
@ -1176,11 +1227,9 @@ exit:
} }
} }
static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx, static grpc_error *basic_pollset_maybe_work_and_unlock(
grpc_pollset *pollset, grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
grpc_pollset_worker *worker, gpr_timespec deadline, gpr_timespec now) {
gpr_timespec deadline,
gpr_timespec now) {
#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) #define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR) #define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
@ -1190,6 +1239,7 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
int timeout; int timeout;
int r; int r;
nfds_t nfds; nfds_t nfds;
grpc_error *error = GRPC_ERROR_NONE;
fd = pollset->data.ptr; fd = pollset->data.ptr;
if (fd && fd_is_orphaned(fd)) { if (fd && fd_is_orphaned(fd)) {
@ -1230,7 +1280,7 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
if (r < 0) { if (r < 0) {
if (errno != EINTR) { if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
} }
if (fd) { if (fd) {
fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL); fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL);
@ -1241,10 +1291,12 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
} }
} else { } else {
if (pfd[0].revents & POLLIN_CHECK) { if (pfd[0].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
} }
if (pfd[1].revents & POLLIN_CHECK) { if (pfd[1].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
} }
if (nfds > 2) { if (nfds > 2) {
fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK, fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
@ -1257,6 +1309,8 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
if (fd) { if (fd) {
GRPC_FD_UNREF(fd, "basicpoll_begin"); GRPC_FD_UNREF(fd, "basicpoll_begin");
} }
return error;
} }
static void basic_pollset_destroy(grpc_pollset *pollset) { static void basic_pollset_destroy(grpc_pollset *pollset) {
@ -1317,7 +1371,7 @@ exit:
} }
} }
static void multipoll_with_poll_pollset_maybe_work_and_unlock( static grpc_error *multipoll_with_poll_pollset_maybe_work_and_unlock(
grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now) { gpr_timespec deadline, gpr_timespec now) {
#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR) #define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
@ -1331,6 +1385,7 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
/* TODO(ctiller): inline some elements to avoid an allocation */ /* TODO(ctiller): inline some elements to avoid an allocation */
grpc_fd_watcher *watchers; grpc_fd_watcher *watchers;
struct pollfd *pfds; struct pollfd *pfds;
grpc_error *error = GRPC_ERROR_NONE;
h = pollset->data.ptr; h = pollset->data.ptr;
timeout = poll_deadline_to_millis_timeout(deadline, now); timeout = poll_deadline_to_millis_timeout(deadline, now);
@ -1383,7 +1438,7 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
if (r < 0) { if (r < 0) {
if (errno != EINTR) { if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
} }
for (i = 2; i < pfd_count; i++) { for (i = 2; i < pfd_count; i++) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
@ -1394,10 +1449,12 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
} }
} else { } else {
if (pfds[0].revents & POLLIN_CHECK) { if (pfds[0].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
} }
if (pfds[1].revents & POLLIN_CHECK) { if (pfds[1].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
} }
for (i = 2; i < pfd_count; i++) { for (i = 2; i < pfd_count; i++) {
if (watchers[i].fd == NULL) { if (watchers[i].fd == NULL) {
@ -1411,6 +1468,8 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
gpr_free(pfds); gpr_free(pfds);
gpr_free(watchers); gpr_free(watchers);
return error;
} }
static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) { static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
@ -1601,7 +1660,7 @@ static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg, static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_status) { grpc_error *error) {
delayed_add *da = arg; delayed_add *da = arg;
if (!fd_is_orphaned(da->fd)) { if (!fd_is_orphaned(da->fd)) {
@ -1614,7 +1673,8 @@ static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
/* We don't care about this pollset anymore. */ /* We don't care about this pollset anymore. */
if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) { if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
da->pollset->called_shutdown = 1; da->pollset->called_shutdown = 1;
grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL); grpc_exec_ctx_sched(exec_ctx, da->pollset->shutdown_done, GRPC_ERROR_NONE,
NULL);
} }
} }
gpr_mu_unlock(&da->pollset->mu); gpr_mu_unlock(&da->pollset->mu);
@ -1638,14 +1698,14 @@ static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
GRPC_FD_REF(fd, "delayed_add"); GRPC_FD_REF(fd, "delayed_add");
grpc_closure_init(&da->closure, perform_delayed_add, da); grpc_closure_init(&da->closure, perform_delayed_add, da);
pollset->in_flight_cbs++; pollset->in_flight_cbs++;
grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL); grpc_exec_ctx_sched(exec_ctx, &da->closure, GRPC_ERROR_NONE, NULL);
} }
} }
/* TODO(klempner): We probably want to turn this down a bit */ /* TODO(klempner): We probably want to turn this down a bit */
#define GRPC_EPOLL_MAX_EVENTS 1000 #define GRPC_EPOLL_MAX_EVENTS 1000
static void multipoll_with_epoll_pollset_maybe_work_and_unlock( static grpc_error *multipoll_with_epoll_pollset_maybe_work_and_unlock(
grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker, grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now) { gpr_timespec deadline, gpr_timespec now) {
struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS]; struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
@ -1654,6 +1714,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
epoll_hdr *h = pollset->data.ptr; epoll_hdr *h = pollset->data.ptr;
int timeout_ms; int timeout_ms;
struct pollfd pfds[2]; struct pollfd pfds[2];
grpc_error *error = GRPC_ERROR_NONE;
/* If you want to ignore epoll's ability to sanely handle parallel pollers, /* If you want to ignore epoll's ability to sanely handle parallel pollers,
* for a more apples-to-apples performance comparison with poll, add a * for a more apples-to-apples performance comparison with poll, add a
@ -1682,13 +1743,14 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
if (poll_rv < 0) { if (poll_rv < 0) {
if (errno != EINTR) { if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
} }
} else if (poll_rv == 0) { } else if (poll_rv == 0) {
/* do nothing */ /* do nothing */
} else { } else {
if (pfds[0].revents) { if (pfds[0].revents) {
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd); work_combine_error(&error,
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
} }
if (pfds[1].revents) { if (pfds[1].revents) {
do { do {
@ -1696,7 +1758,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0); ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
if (ep_rv < 0) { if (ep_rv < 0) {
if (errno != EINTR) { if (errno != EINTR) {
gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno)); work_combine_error(&error, GRPC_OS_ERROR(errno, "epoll_wait"));
} }
} else { } else {
int i; int i;
@ -1708,7 +1770,8 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI); int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
int write_ev = ep_ev[i].events & EPOLLOUT; int write_ev = ep_ev[i].events & EPOLLOUT;
if (fd == NULL) { if (fd == NULL) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); work_combine_error(&error, grpc_wakeup_fd_consume_wakeup(
&grpc_global_wakeup_fd));
} else { } else {
if (read_ev || cancel) { if (read_ev || cancel) {
fd_become_readable(exec_ctx, fd, pollset); fd_become_readable(exec_ctx, fd, pollset);
@ -1722,6 +1785,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
} while (ep_rv == GRPC_EPOLL_MAX_EVENTS); } while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
} }
} }
return error;
} }
static void multipoll_with_epoll_pollset_finish_shutdown( static void multipoll_with_epoll_pollset_finish_shutdown(
@ -1938,6 +2002,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_wrapped_fd = fd_wrapped_fd, .fd_wrapped_fd = fd_wrapped_fd,
.fd_orphan = fd_orphan, .fd_orphan = fd_orphan,
.fd_shutdown = fd_shutdown, .fd_shutdown = fd_shutdown,
.fd_is_shutdown = fd_is_shutdown,
.fd_notify_on_read = fd_notify_on_read, .fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write, .fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015-2016, Google Inc. * Copyright 2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -217,9 +217,9 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2 #define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
/* As per pollset_kick, with an extended set of flags (defined above) /* As per pollset_kick, with an extended set of flags (defined above)
-- mostly for fd_posix's use. */ -- mostly for fd_posix's use. */
static void pollset_kick_ext(grpc_pollset *p, static grpc_error *pollset_kick_ext(grpc_pollset *p,
grpc_pollset_worker *specific_worker, grpc_pollset_worker *specific_worker,
uint32_t flags); uint32_t flags) GRPC_MUST_USE_RESULT;
/* Return 1 if the pollset has active threads in pollset_work (pollset must /* Return 1 if the pollset has active threads in pollset_work (pollset must
* be locked) */ * be locked) */
@ -328,12 +328,13 @@ static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
return notifier; return notifier;
} }
static void pollset_kick_locked(grpc_fd_watcher *watcher) { static grpc_error *pollset_kick_locked(grpc_fd_watcher *watcher) {
gpr_mu_lock(&watcher->pollset->mu); gpr_mu_lock(&watcher->pollset->mu);
GPR_ASSERT(watcher->worker); GPR_ASSERT(watcher->worker);
pollset_kick_ext(watcher->pollset, watcher->worker, grpc_error *err = pollset_kick_ext(watcher->pollset, watcher->worker,
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP); GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
gpr_mu_unlock(&watcher->pollset->mu); gpr_mu_unlock(&watcher->pollset->mu);
return err;
} }
static void maybe_wake_one_watcher_locked(grpc_fd *fd) { static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
@ -370,7 +371,7 @@ static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
if (!fd->released) { if (!fd->released) {
close(fd->fd); close(fd->fd);
} }
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL); grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
} }
static int fd_wrapped_fd(grpc_fd *fd) { static int fd_wrapped_fd(grpc_fd *fd) {
@ -419,15 +420,27 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); } static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#endif #endif
static grpc_error *fd_shutdown_error(bool shutdown) {
if (!shutdown) {
return GRPC_ERROR_NONE;
} else {
return GRPC_ERROR_CREATE("FD shutdown");
}
}
static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure **st, grpc_closure *closure) { grpc_closure **st, grpc_closure *closure) {
if (*st == CLOSURE_NOT_READY) { if (fd->shutdown) {
grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
NULL);
} else if (*st == CLOSURE_NOT_READY) {
/* not ready ==> switch to a waiting state by setting the closure */ /* not ready ==> switch to a waiting state by setting the closure */
*st = closure; *st = closure;
} else if (*st == CLOSURE_READY) { } else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */ /* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY; *st = CLOSURE_NOT_READY;
grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL); grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
NULL);
maybe_wake_one_watcher_locked(fd); maybe_wake_one_watcher_locked(fd);
} else { } else {
/* upcallptr was set to a different closure. This is an error! */ /* upcallptr was set to a different closure. This is an error! */
@ -450,7 +463,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0; return 0;
} else { } else {
/* waiting ==> queue closure */ /* waiting ==> queue closure */
grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL); grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
*st = CLOSURE_NOT_READY; *st = CLOSURE_NOT_READY;
return 1; return 1;
} }
@ -463,13 +476,24 @@ static void set_read_notifier_pollset_locked(
static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) { static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
GPR_ASSERT(!fd->shutdown); /* only shutdown once */
if (!fd->shutdown) {
fd->shutdown = 1; fd->shutdown = 1;
/* signal read/write closed to OS so that future operations fail */
shutdown(fd->fd, SHUT_RDWR);
set_ready_locked(exec_ctx, fd, &fd->read_closure); set_ready_locked(exec_ctx, fd, &fd->read_closure);
set_ready_locked(exec_ctx, fd, &fd->write_closure); set_ready_locked(exec_ctx, fd, &fd->write_closure);
}
gpr_mu_unlock(&fd->mu); gpr_mu_unlock(&fd->mu);
} }
static bool fd_is_shutdown(grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
bool r = fd->shutdown;
gpr_mu_unlock(&fd->mu);
return r;
}
static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) { grpc_closure *closure) {
gpr_mu_lock(&fd->mu); gpr_mu_lock(&fd->mu);
@ -631,10 +655,19 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker; worker->prev->next = worker->next->prev = worker;
} }
static void pollset_kick_ext(grpc_pollset *p, static void kick_append_error(grpc_error **composite, grpc_error *error) {
if (error == GRPC_ERROR_NONE) return;
if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("Kick Failure");
}
*composite = grpc_error_add_child(*composite, error);
}
static grpc_error *pollset_kick_ext(grpc_pollset *p,
grpc_pollset_worker *specific_worker, grpc_pollset_worker *specific_worker,
uint32_t flags) { uint32_t flags) {
GPR_TIMER_BEGIN("pollset_kick_ext", 0); GPR_TIMER_BEGIN("pollset_kick_ext", 0);
grpc_error *error = GRPC_ERROR_NONE;
/* pollset->mu already held */ /* pollset->mu already held */
if (specific_worker != NULL) { if (specific_worker != NULL) {
@ -644,25 +677,28 @@ static void pollset_kick_ext(grpc_pollset *p,
for (specific_worker = p->root_worker.next; for (specific_worker = p->root_worker.next;
specific_worker != &p->root_worker; specific_worker != &p->root_worker;
specific_worker = specific_worker->next) { specific_worker = specific_worker->next) {
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(
&error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
p->kicked_without_pollers = 1; p->kicked_without_pollers = true;
GPR_TIMER_END("pollset_kick_ext.broadcast", 0); GPR_TIMER_END("pollset_kick_ext.broadcast", 0);
} else if (gpr_tls_get(&g_current_thread_worker) != } else if (gpr_tls_get(&g_current_thread_worker) !=
(intptr_t)specific_worker) { (intptr_t)specific_worker) {
GPR_TIMER_MARK("different_thread_worker", 0); GPR_TIMER_MARK("different_thread_worker", 0);
if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
specific_worker->reevaluate_polling_on_wakeup = 1; specific_worker->reevaluate_polling_on_wakeup = true;
} }
specific_worker->kicked_specifically = 1; specific_worker->kicked_specifically = true;
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(&error,
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) { } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
GPR_TIMER_MARK("kick_yoself", 0); GPR_TIMER_MARK("kick_yoself", 0);
if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) { if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
specific_worker->reevaluate_polling_on_wakeup = 1; specific_worker->reevaluate_polling_on_wakeup = true;
} }
specific_worker->kicked_specifically = 1; specific_worker->kicked_specifically = true;
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(&error,
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
} else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) { } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) {
GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0); GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
@ -683,28 +719,31 @@ static void pollset_kick_ext(grpc_pollset *p,
if (specific_worker != NULL) { if (specific_worker != NULL) {
GPR_TIMER_MARK("finally_kick", 0); GPR_TIMER_MARK("finally_kick", 0);
push_back_worker(p, specific_worker); push_back_worker(p, specific_worker);
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd); kick_append_error(
&error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
} }
} else { } else {
GPR_TIMER_MARK("kicked_no_pollers", 0); GPR_TIMER_MARK("kicked_no_pollers", 0);
p->kicked_without_pollers = 1; p->kicked_without_pollers = true;
} }
} }
GPR_TIMER_END("pollset_kick_ext", 0); GPR_TIMER_END("pollset_kick_ext", 0);
GRPC_LOG_IF_ERROR("pollset_kick_ext", GRPC_ERROR_REF(error));
return error;
} }
static void pollset_kick(grpc_pollset *p, static grpc_error *pollset_kick(grpc_pollset *p,
grpc_pollset_worker *specific_worker) { grpc_pollset_worker *specific_worker) {
pollset_kick_ext(p, specific_worker, 0); return pollset_kick_ext(p, specific_worker, 0);
} }
/* global state management */ /* global state management */
static void pollset_global_init(void) { static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller); gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker); gpr_tls_init(&g_current_thread_worker);
grpc_wakeup_fd_init(&grpc_global_wakeup_fd); return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
} }
static void pollset_global_shutdown(void) { static void pollset_global_shutdown(void) {
@ -713,7 +752,9 @@ static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_worker); gpr_tls_destroy(&g_current_thread_worker);
} }
static void kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); } static grpc_error *kick_poller(void) {
return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
}
/* main interface */ /* main interface */
@ -783,14 +824,23 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
GRPC_FD_UNREF(pollset->fds[i], "multipoller"); GRPC_FD_UNREF(pollset->fds[i], "multipoller");
} }
pollset->fd_count = 0; pollset->fd_count = 0;
grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL); grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
} }
static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static void work_combine_error(grpc_error **composite, grpc_error *error) {
grpc_pollset_worker **worker_hdl, gpr_timespec now, if (error == GRPC_ERROR_NONE) return;
gpr_timespec deadline) { if (*composite == GRPC_ERROR_NONE) {
*composite = GRPC_ERROR_CREATE("pollset_work");
}
*composite = grpc_error_add_child(*composite, error);
}
static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker_hdl,
gpr_timespec now, gpr_timespec deadline) {
grpc_pollset_worker worker; grpc_pollset_worker worker;
*worker_hdl = &worker; *worker_hdl = &worker;
grpc_error *error = GRPC_ERROR_NONE;
/* pollset->mu already held */ /* pollset->mu already held */
int added_worker = 0; int added_worker = 0;
@ -806,7 +856,11 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
pollset->local_wakeup_cache = worker.wakeup_fd->next; pollset->local_wakeup_cache = worker.wakeup_fd->next;
} else { } else {
worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd)); worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
grpc_wakeup_fd_init(&worker.wakeup_fd->fd); error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
if (error != GRPC_ERROR_NONE) {
GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
return error;
}
} }
worker.kicked_specifically = 0; worker.kicked_specifically = 0;
/* If there's work waiting for the pollset to be idle, and the /* If there's work waiting for the pollset to be idle, and the
@ -890,7 +944,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (r < 0) { if (r < 0) {
if (errno != EINTR) { if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno)); work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
} }
for (i = 2; i < pfd_count; i++) { for (i = 2; i < pfd_count; i++) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL); fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
@ -901,10 +955,12 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
} else { } else {
if (pfds[0].revents & POLLIN_CHECK) { if (pfds[0].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd); work_combine_error(
&error, grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
} }
if (pfds[1].revents & POLLIN_CHECK) { if (pfds[1].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&worker.wakeup_fd->fd); work_combine_error(
&error, grpc_wakeup_fd_consume_wakeup(&worker.wakeup_fd->fd));
} }
for (i = 2; i < pfd_count; i++) { for (i = 2; i < pfd_count; i++) {
if (watchers[i].fd == NULL) { if (watchers[i].fd == NULL) {
@ -937,7 +993,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
/* If we're forced to re-evaluate polling (via pollset_kick with /* If we're forced to re-evaluate polling (via pollset_kick with
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
a loop */ a loop */
if (worker.reevaluate_polling_on_wakeup) { if (worker.reevaluate_polling_on_wakeup && error == GRPC_ERROR_NONE) {
worker.reevaluate_polling_on_wakeup = 0; worker.reevaluate_polling_on_wakeup = 0;
pollset->kicked_without_pollers = 0; pollset->kicked_without_pollers = 0;
if (queued_work || worker.kicked_specifically) { if (queued_work || worker.kicked_specifically) {
@ -982,6 +1038,8 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
*worker_hdl = NULL; *worker_hdl = NULL;
GPR_TIMER_END("pollset_work", 0); GPR_TIMER_END("pollset_work", 0);
GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
return error;
} }
static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@ -1172,6 +1230,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_wrapped_fd = fd_wrapped_fd, .fd_wrapped_fd = fd_wrapped_fd,
.fd_orphan = fd_orphan, .fd_orphan = fd_orphan,
.fd_shutdown = fd_shutdown, .fd_shutdown = fd_shutdown,
.fd_is_shutdown = fd_is_shutdown,
.fd_notify_on_read = fd_notify_on_read, .fd_notify_on_read = fd_notify_on_read,
.fd_notify_on_write = fd_notify_on_write, .fd_notify_on_write = fd_notify_on_write,
.fd_get_read_notifier_pollset = fd_get_read_notifier_pollset, .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
@ -1199,7 +1258,9 @@ static const grpc_event_engine_vtable vtable = {
}; };
const grpc_event_engine_vtable *grpc_init_poll_posix(void) { const grpc_event_engine_vtable *grpc_init_poll_posix(void) {
pollset_global_init(); if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
return NULL;
}
return &vtable; return &vtable;
} }

@ -153,6 +153,10 @@ void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
g_event_engine->fd_shutdown(exec_ctx, fd); g_event_engine->fd_shutdown(exec_ctx, fd);
} }
bool grpc_fd_is_shutdown(grpc_fd *fd) {
return g_event_engine->fd_is_shutdown(fd);
}
void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd, void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) { grpc_closure *closure) {
g_event_engine->fd_notify_on_read(exec_ctx, fd, closure); g_event_engine->fd_notify_on_read(exec_ctx, fd, closure);
@ -187,15 +191,15 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
g_event_engine->pollset_destroy(pollset); g_event_engine->pollset_destroy(pollset);
} }
void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker, gpr_timespec now, grpc_pollset_worker **worker, gpr_timespec now,
gpr_timespec deadline) { gpr_timespec deadline) {
g_event_engine->pollset_work(exec_ctx, pollset, worker, now, deadline); return g_event_engine->pollset_work(exec_ctx, pollset, worker, now, deadline);
} }
void grpc_pollset_kick(grpc_pollset *pollset, grpc_error *grpc_pollset_kick(grpc_pollset *pollset,
grpc_pollset_worker *specific_worker) { grpc_pollset_worker *specific_worker) {
g_event_engine->pollset_kick(pollset, specific_worker); return g_event_engine->pollset_kick(pollset, specific_worker);
} }
void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@ -245,6 +249,6 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
g_event_engine->pollset_set_del_fd(exec_ctx, pollset_set, fd); g_event_engine->pollset_set_del_fd(exec_ctx, pollset_set, fd);
} }
void grpc_kick_poller(void) { g_event_engine->kick_poller(); } grpc_error *grpc_kick_poller(void) { return g_event_engine->kick_poller(); }
#endif // GPR_POSIX_SOCKET #endif // GPR_POSIX_SOCKET

@ -55,6 +55,7 @@ typedef struct grpc_event_engine_vtable {
grpc_closure *closure); grpc_closure *closure);
void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd, void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure); grpc_closure *closure);
bool (*fd_is_shutdown)(grpc_fd *fd);
grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx, grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx,
grpc_fd *fd); grpc_fd *fd);
@ -63,10 +64,10 @@ typedef struct grpc_event_engine_vtable {
grpc_closure *closure); grpc_closure *closure);
void (*pollset_reset)(grpc_pollset *pollset); void (*pollset_reset)(grpc_pollset *pollset);
void (*pollset_destroy)(grpc_pollset *pollset); void (*pollset_destroy)(grpc_pollset *pollset);
void (*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_error *(*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker **worker, gpr_timespec now, grpc_pollset_worker **worker, gpr_timespec now,
gpr_timespec deadline); gpr_timespec deadline);
void (*pollset_kick)(grpc_pollset *pollset, grpc_error *(*pollset_kick)(grpc_pollset *pollset,
grpc_pollset_worker *specific_worker); grpc_pollset_worker *specific_worker);
void (*pollset_add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void (*pollset_add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd); struct grpc_fd *fd);
@ -90,7 +91,7 @@ typedef struct grpc_event_engine_vtable {
void (*pollset_set_del_fd)(grpc_exec_ctx *exec_ctx, void (*pollset_set_del_fd)(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_fd *fd); grpc_pollset_set *pollset_set, grpc_fd *fd);
void (*kick_poller)(void); grpc_error *(*kick_poller)(void);
void (*shutdown_engine)(void); void (*shutdown_engine)(void);
} grpc_event_engine_vtable; } grpc_event_engine_vtable;
@ -116,7 +117,10 @@ int grpc_fd_wrapped_fd(grpc_fd *fd);
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done, void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
int *release_fd, const char *reason); int *release_fd, const char *reason);
/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */ /* Has grpc_fd_shutdown been called on an fd? */
bool grpc_fd_is_shutdown(grpc_fd *fd);
/* Cause any current and future callbacks to fail. */
void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd); void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
/* Register read interest, causing read_cb to be called once when fd becomes /* Register read interest, causing read_cb to be called once when fd becomes

@ -63,11 +63,12 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
grpc_closure *c = exec_ctx->closure_list.head; grpc_closure *c = exec_ctx->closure_list.head;
exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL; exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
while (c != NULL) { while (c != NULL) {
bool success = (bool)(c->final_data & 1); grpc_closure *next = c->next_data.next;
grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1); grpc_error *error = c->error;
did_something = true; did_something = true;
GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0); GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
c->cb(exec_ctx, c->cb_arg, success); c->cb(exec_ctx, c->cb_arg, error);
GRPC_ERROR_UNREF(error);
GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0); GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
c = next; c = next;
} }
@ -81,11 +82,11 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
grpc_exec_ctx_flush(exec_ctx); grpc_exec_ctx_flush(exec_ctx);
} }
void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure, void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
bool success, grpc_error *error,
grpc_workqueue *offload_target_or_null) { grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL); GPR_ASSERT(offload_target_or_null == NULL);
grpc_closure_list_add(&exec_ctx->closure_list, closure, success); grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
} }
void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx, void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,

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

Loading…
Cancel
Save