Merge github.com:grpc/grpc into slice_with_exec_ctx

pull/8720/head^2
Craig Tiller 8 years ago
commit 397bff36b9
  1. 30
      BUILD
  2. 11
      CMakeLists.txt
  3. 13
      Makefile
  4. 4
      binding.gyp
  5. 24
      build.yaml
  6. 6
      config.m4
  7. 7
      doc/connection-backoff.md
  8. 12
      gRPC-Core.podspec
  9. 8
      grpc.gemspec
  10. 22
      include/grpc++/impl/codegen/completion_queue.h
  11. 2
      include/grpc++/impl/codegen/server_interface.h
  12. 8
      package.xml
  13. 55
      src/compiler/python_generator.cc
  14. 183
      src/core/ext/client_channel/http_connect_handshaker.c
  15. 18
      src/core/ext/client_channel/subchannel.c
  16. 18
      src/core/ext/lb_policy/grpclb/grpclb.c
  17. 16
      src/core/ext/resolver/dns/native/dns_resolver.c
  18. 269
      src/core/ext/transport/chttp2/client/chttp2_connector.c
  19. 52
      src/core/ext/transport/chttp2/client/chttp2_connector.h
  20. 153
      src/core/ext/transport/chttp2/client/insecure/channel_create.c
  21. 225
      src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
  22. 354
      src/core/ext/transport/chttp2/server/chttp2_server.c
  23. 78
      src/core/ext/transport/chttp2/server/chttp2_server.h
  24. 172
      src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
  25. 337
      src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
  26. 55
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  27. 7
      src/core/ext/transport/chttp2/transport/internal.h
  28. 211
      src/core/lib/channel/handshaker.c
  29. 83
      src/core/lib/channel/handshaker.h
  30. 102
      src/core/lib/http/httpcli_security_connector.c
  31. 11
      src/core/lib/iomgr/combiner.c
  32. 12
      src/core/lib/iomgr/resource_quota.c
  33. 6
      src/core/lib/iomgr/udp_server.c
  34. 377
      src/core/lib/security/transport/handshake.c
  35. 265
      src/core/lib/security/transport/security_connector.c
  36. 58
      src/core/lib/security/transport/security_connector.h
  37. 450
      src/core/lib/security/transport/security_handshaker.c
  38. 21
      src/core/lib/security/transport/security_handshaker.h
  39. 37
      src/core/lib/support/backoff.c
  40. 7
      src/core/lib/support/backoff.h
  41. 4
      src/core/lib/surface/call.c
  42. 14
      src/cpp/common/completion_queue_cc.cc
  43. 17
      src/cpp/server/server_cc.cc
  44. 1
      src/csharp/Grpc.Auth/Grpc.Auth.csproj
  45. 28
      src/csharp/Grpc.Auth/Grpc.Auth.nuspec
  46. 15
      src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
  47. 10
      src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
  48. 46
      src/csharp/Grpc.Core/CallOptions.cs
  49. 4
      src/csharp/Grpc.Core/Grpc.Core.csproj
  50. 35
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  51. 10
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  52. 60
      src/csharp/Grpc.Core/Internal/CallFlags.cs
  53. 20
      src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
  54. 17
      src/csharp/Grpc.Core/Internal/INativeCall.cs
  55. 10
      src/csharp/Grpc.Core/Internal/NativeMethods.cs
  56. 5
      src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
  57. 28
      src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
  58. 5
      src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
  59. 28
      src/csharp/Grpc.Reflection/Grpc.Reflection.nuspec
  60. 91
      src/csharp/build_packages.bat
  61. 7
      src/csharp/build_packages_dotnetcli.bat
  62. 1
      src/csharp/build_packages_dotnetcli.sh
  63. 21
      src/csharp/ext/grpc_csharp_ext.c
  64. 2
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  65. 16
      src/objective-c/tests/GRPCClientTests.m
  66. 26
      src/objective-c/tests/InteropTests.m
  67. 4
      src/objective-c/tests/Podfile
  68. 2
      src/php/tests/unit_tests/ChannelTest.php
  69. 4
      src/php/tests/unit_tests/ServerTest.php
  70. 30
      src/python/grpcio/grpc/__init__.py
  71. 88
      src/python/grpcio/grpc/_server.py
  72. 4
      src/python/grpcio/grpc_core_dependencies.py
  73. 6
      src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
  74. 1
      src/python/grpcio_tests/tests/tests.json
  75. 23
      src/python/grpcio_tests/tests/unit/_exit_test.py
  76. 41
      templates/src/csharp/build_packages_dotnetcli.bat.template
  77. 1
      templates/src/csharp/build_packages_dotnetcli.sh.template
  78. 9
      templates/tools/dockerfile/test/sanity/Dockerfile.template
  79. 119
      test/core/client_channel/lb_policies_test.c
  80. 10
      test/core/end2end/goaway_server_test.c
  81. 10
      test/core/end2end/tests/connectivity.c
  82. 2
      test/core/end2end/tests/payload.c
  83. 19
      test/core/end2end/tests/simple_delayed_request.c
  84. 24
      test/core/security/ssl_server_fuzzer.c
  85. 91
      test/core/support/backoff_test.c
  86. 5
      test/core/surface/server_chttp2_test.c
  87. 4
      test/cpp/end2end/server_crash_test.cc
  88. 2
      test/cpp/interop/interop_server.cc
  89. 4
      test/cpp/interop/interop_server_bootstrap.cc
  90. 2
      test/cpp/interop/interop_test.cc
  91. 6
      test/cpp/interop/server_helper.h
  92. 6
      test/cpp/qps/gen_build_yaml.py
  93. 64
      tools/dockerfile/push_testing_images.sh
  94. 8
      tools/dockerfile/test/sanity/Dockerfile
  95. 8
      tools/doxygen/Doxyfile.core.internal
  96. 40
      tools/internal_ci/linux/grpc_fuzzer_client.cfg
  97. 41
      tools/internal_ci/linux/grpc_fuzzer_client.sh
  98. 8
      tools/internal_ci/linux/grpc_master.cfg
  99. 10
      tools/internal_ci/linux/grpc_master.sh
  100. 11
      tools/run_tests/dockerize/build_and_run_docker.sh
  101. Some files were not shown because too many files have changed in this diff Show More

30
BUILD

@ -288,9 +288,9 @@ cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/security_handshaker.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h",
@ -299,6 +299,7 @@ cc_library(
"src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.h",
"src/core/ext/transport/chttp2/server/chttp2_server.h",
"src/core/ext/client_channel/client_channel.h",
"src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.h",
@ -314,6 +315,7 @@ cc_library(
"src/core/ext/client_channel/subchannel.h",
"src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.h",
"src/core/ext/transport/chttp2/client/chttp2_connector.h",
"src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
@ -482,9 +484,9 @@ cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_credentials.c",
"src/core/lib/security/transport/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.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",
@ -493,6 +495,7 @@ cc_library(
"src/core/lib/tsi/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/transport_security.c",
"src/core/ext/transport/chttp2/server/chttp2_server.c",
"src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
"src/core/ext/client_channel/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.c",
@ -512,6 +515,7 @@ cc_library(
"src/core/ext/client_channel/subchannel.c",
"src/core/ext/client_channel/subchannel_index.c",
"src/core/ext/client_channel/uri_parser.c",
"src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c",
@ -739,9 +743,9 @@ cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/security_handshaker.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h",
@ -750,6 +754,7 @@ cc_library(
"src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.h",
"src/core/ext/transport/chttp2/client/chttp2_connector.h",
"src/core/lib/surface/init.c",
"src/core/lib/channel/channel_args.c",
"src/core/lib/channel/channel_stack.c",
@ -923,9 +928,9 @@ cc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_credentials.c",
"src/core/lib/security/transport/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.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",
@ -934,6 +939,7 @@ cc_library(
"src/core/lib/tsi/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/transport_security.c",
"src/core/ext/transport/chttp2/client/chttp2_connector.c",
"src/core/plugin_registry/grpc_cronet_plugin_registry.c",
],
hdrs = [
@ -1100,6 +1106,8 @@ cc_library(
"src/core/ext/transport/chttp2/transport/stream_map.h",
"src/core/ext/transport/chttp2/transport/varint.h",
"src/core/ext/transport/chttp2/alpn/alpn.h",
"src/core/ext/transport/chttp2/server/chttp2_server.h",
"src/core/ext/transport/chttp2/client/chttp2_connector.h",
"src/core/ext/client_channel/client_channel.h",
"src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.h",
@ -1269,8 +1277,10 @@ cc_library(
"src/core/ext/transport/chttp2/transport/varint.c",
"src/core/ext/transport/chttp2/transport/writing.c",
"src/core/ext/transport/chttp2/alpn/alpn.c",
"src/core/ext/transport/chttp2/server/chttp2_server.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
"src/core/ext/transport/chttp2/client/chttp2_connector.c",
"src/core/ext/client_channel/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.c",
"src/core/ext/client_channel/client_channel_factory.c",
@ -1520,6 +1530,7 @@ cc_library(
"src/cpp/server/dynamic_thread_pool.h",
"src/cpp/server/thread_pool_interface.h",
"src/cpp/thread_manager/thread_manager.h",
"src/core/ext/transport/chttp2/client/chttp2_connector.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/chttp2_transport.h",
@ -1653,6 +1664,7 @@ cc_library(
"src/core/ext/client_channel/subchannel.h",
"src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.h",
"src/core/ext/transport/chttp2/server/chttp2_server.h",
"src/core/ext/census/aggregation.h",
"src/core/ext/census/base_resources.h",
"src/core/ext/census/census_interface.h",
@ -1699,6 +1711,7 @@ cc_library(
"src/cpp/codegen/codegen_init.cc",
"src/core/ext/transport/chttp2/client/insecure/channel_create.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
"src/core/ext/transport/chttp2/client/chttp2_connector.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/chttp2_plugin.c",
@ -1853,6 +1866,7 @@ cc_library(
"src/core/ext/client_channel/uri_parser.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/chttp2_server.c",
"src/core/ext/census/base_resources.c",
"src/core/ext/census/context.c",
"src/core/ext/census/gen/census.pb.c",
@ -2475,9 +2489,9 @@ objc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_credentials.c",
"src/core/lib/security/transport/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.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",
@ -2486,6 +2500,7 @@ objc_library(
"src/core/lib/tsi/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/transport_security.c",
"src/core/ext/transport/chttp2/server/chttp2_server.c",
"src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
"src/core/ext/client_channel/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.c",
@ -2505,6 +2520,7 @@ objc_library(
"src/core/ext/client_channel/subchannel.c",
"src/core/ext/client_channel/subchannel_index.c",
"src/core/ext/client_channel/uri_parser.c",
"src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c",
@ -2695,9 +2711,9 @@ objc_library(
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.h",
"src/core/lib/security/transport/handshake.h",
"src/core/lib/security/transport/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.h",
"src/core/lib/security/transport/security_handshaker.h",
"src/core/lib/security/transport/tsi_error.h",
"src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h",
@ -2706,6 +2722,7 @@ objc_library(
"src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.h",
"src/core/ext/transport/chttp2/server/chttp2_server.h",
"src/core/ext/client_channel/client_channel.h",
"src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.h",
@ -2721,6 +2738,7 @@ objc_library(
"src/core/ext/client_channel/subchannel.h",
"src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.h",
"src/core/ext/transport/chttp2/client/chttp2_connector.h",
"src/core/ext/lb_policy/grpclb/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.h",
"src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",

@ -437,9 +437,9 @@ add_library(grpc
src/core/lib/security/credentials/plugin/plugin_credentials.c
src/core/lib/security/credentials/ssl/ssl_credentials.c
src/core/lib/security/transport/client_auth_filter.c
src/core/lib/security/transport/handshake.c
src/core/lib/security/transport/secure_endpoint.c
src/core/lib/security/transport/security_connector.c
src/core/lib/security/transport/security_handshaker.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
@ -448,6 +448,7 @@ add_library(grpc
src/core/lib/tsi/fake_transport_security.c
src/core/lib/tsi/ssl_transport_security.c
src/core/lib/tsi/transport_security.c
src/core/ext/transport/chttp2/server/chttp2_server.c
src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
src/core/ext/client_channel/channel_connectivity.c
src/core/ext/client_channel/client_channel.c
@ -467,6 +468,7 @@ add_library(grpc
src/core/ext/client_channel/subchannel.c
src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.c
src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c
@ -738,9 +740,9 @@ add_library(grpc_cronet
src/core/lib/security/credentials/plugin/plugin_credentials.c
src/core/lib/security/credentials/ssl/ssl_credentials.c
src/core/lib/security/transport/client_auth_filter.c
src/core/lib/security/transport/handshake.c
src/core/lib/security/transport/secure_endpoint.c
src/core/lib/security/transport/security_connector.c
src/core/lib/security/transport/security_handshaker.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
@ -749,6 +751,7 @@ add_library(grpc_cronet
src/core/lib/tsi/fake_transport_security.c
src/core/lib/tsi/ssl_transport_security.c
src/core/lib/tsi/transport_security.c
src/core/ext/transport/chttp2/client/chttp2_connector.c
src/core/plugin_registry/grpc_cronet_plugin_registry.c
)
@ -954,8 +957,10 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/varint.c
src/core/ext/transport/chttp2/transport/writing.c
src/core/ext/transport/chttp2/alpn/alpn.c
src/core/ext/transport/chttp2/server/chttp2_server.c
src/core/ext/transport/chttp2/client/insecure/channel_create.c
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
src/core/ext/transport/chttp2/client/chttp2_connector.c
src/core/ext/client_channel/channel_connectivity.c
src/core/ext/client_channel/client_channel.c
src/core/ext/client_channel/client_channel_factory.c
@ -1263,6 +1268,7 @@ add_library(grpc++_cronet
src/cpp/codegen/codegen_init.cc
src/core/ext/transport/chttp2/client/insecure/channel_create.c
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
src/core/ext/transport/chttp2/client/chttp2_connector.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/chttp2_plugin.c
@ -1417,6 +1423,7 @@ add_library(grpc++_cronet
src/core/ext/client_channel/uri_parser.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/chttp2_server.c
src/core/ext/census/base_resources.c
src/core/ext/census/context.c
src/core/ext/census/gen/census.pb.c

@ -2776,9 +2776,9 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_credentials.c \
src/core/lib/security/transport/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.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 \
@ -2787,6 +2787,7 @@ LIBGRPC_SRC = \
src/core/lib/tsi/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/transport_security.c \
src/core/ext/transport/chttp2/server/chttp2_server.c \
src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.c \
@ -2806,6 +2807,7 @@ LIBGRPC_SRC = \
src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \
src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c \
@ -3095,9 +3097,9 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/security/credentials/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_credentials.c \
src/core/lib/security/transport/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.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 \
@ -3106,6 +3108,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/tsi/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/transport_security.c \
src/core/ext/transport/chttp2/client/chttp2_connector.c \
src/core/plugin_registry/grpc_cronet_plugin_registry.c \
PUBLIC_HEADERS_C += \
@ -3566,8 +3569,10 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/varint.c \
src/core/ext/transport/chttp2/transport/writing.c \
src/core/ext/transport/chttp2/alpn/alpn.c \
src/core/ext/transport/chttp2/server/chttp2_server.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
src/core/ext/transport/chttp2/client/chttp2_connector.c \
src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.c \
src/core/ext/client_channel/client_channel_factory.c \
@ -3987,6 +3992,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/codegen/codegen_init.cc \
src/core/ext/transport/chttp2/client/insecure/channel_create.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
src/core/ext/transport/chttp2/client/chttp2_connector.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/chttp2_plugin.c \
@ -4141,6 +4147,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/client_channel/uri_parser.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/chttp2_server.c \
src/core/ext/census/base_resources.c \
src/core/ext/census/context.c \
src/core/ext/census/gen/census.pb.c \
@ -16769,9 +16776,9 @@ src/core/lib/security/credentials/oauth2/oauth2_credentials.c: $(OPENSSL_DEP)
src/core/lib/security/credentials/plugin/plugin_credentials.c: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_credentials.c: $(OPENSSL_DEP)
src/core/lib/security/transport/client_auth_filter.c: $(OPENSSL_DEP)
src/core/lib/security/transport/handshake.c: $(OPENSSL_DEP)
src/core/lib/security/transport/secure_endpoint.c: $(OPENSSL_DEP)
src/core/lib/security/transport/security_connector.c: $(OPENSSL_DEP)
src/core/lib/security/transport/security_handshaker.c: $(OPENSSL_DEP)
src/core/lib/security/transport/server_auth_filter.c: $(OPENSSL_DEP)
src/core/lib/security/transport/tsi_error.c: $(OPENSSL_DEP)
src/core/lib/security/util/b64.c: $(OPENSSL_DEP)

@ -716,9 +716,9 @@
'src/core/lib/security/credentials/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_credentials.c',
'src/core/lib/security/transport/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.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',
@ -727,6 +727,7 @@
'src/core/lib/tsi/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/transport_security.c',
'src/core/ext/transport/chttp2/server/chttp2_server.c',
'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.c',
@ -746,6 +747,7 @@
'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c',
'src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c',

@ -496,9 +496,9 @@ filegroups:
- src/core/lib/security/credentials/plugin/plugin_credentials.h
- src/core/lib/security/credentials/ssl/ssl_credentials.h
- src/core/lib/security/transport/auth_filters.h
- src/core/lib/security/transport/handshake.h
- src/core/lib/security/transport/secure_endpoint.h
- src/core/lib/security/transport/security_connector.h
- src/core/lib/security/transport/security_handshaker.h
- src/core/lib/security/transport/tsi_error.h
- src/core/lib/security/util/b64.h
- src/core/lib/security/util/json_util.h
@ -519,9 +519,9 @@ filegroups:
- src/core/lib/security/credentials/plugin/plugin_credentials.c
- src/core/lib/security/credentials/ssl/ssl_credentials.c
- src/core/lib/security/transport/client_auth_filter.c
- src/core/lib/security/transport/handshake.c
- src/core/lib/security/transport/secure_endpoint.c
- src/core/lib/security/transport/security_connector.c
- src/core/lib/security/transport/security_handshaker.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
@ -622,11 +622,20 @@ filegroups:
- src/core/ext/transport/chttp2/alpn/alpn.c
deps:
- gpr
- name: grpc_transport_chttp2_client_connector
headers:
- src/core/ext/transport/chttp2/client/chttp2_connector.h
src:
- src/core/ext/transport/chttp2/client/chttp2_connector.c
uses:
- grpc_transport_chttp2
- grpc_base
- name: grpc_transport_chttp2_client_insecure
src:
- src/core/ext/transport/chttp2/client/insecure/channel_create.c
- src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
uses:
- grpc_transport_chttp2_client_connector
- grpc_transport_chttp2
- grpc_base
- grpc_client_channel
@ -638,6 +647,15 @@ filegroups:
- grpc_base
- grpc_client_channel
- grpc_secure
- grpc_transport_chttp2_client_connector
- name: grpc_transport_chttp2_server
headers:
- src/core/ext/transport/chttp2/server/chttp2_server.h
src:
- src/core/ext/transport/chttp2/server/chttp2_server.c
uses:
- grpc_transport_chttp2
- grpc_base
- name: grpc_transport_chttp2_server_insecure
src:
- src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@ -645,6 +663,7 @@ filegroups:
uses:
- grpc_transport_chttp2
- grpc_base
- grpc_transport_chttp2_server
- name: grpc_transport_chttp2_server_secure
src:
- src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@ -652,6 +671,7 @@ filegroups:
- grpc_transport_chttp2
- grpc_base
- grpc_secure
- grpc_transport_chttp2_server
- name: grpc_transport_cronet_client_secure
public_headers:
- include/grpc/grpc_cronet.h

@ -232,9 +232,9 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_credentials.c \
src/core/lib/security/transport/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.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 \
@ -243,6 +243,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/tsi/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/transport_security.c \
src/core/ext/transport/chttp2/server/chttp2_server.c \
src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.c \
@ -262,6 +263,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \
src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c \
@ -609,8 +611,10 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/dns/native)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/sockaddr)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/alpn)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/secure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)

@ -7,9 +7,10 @@ requests) and instead do some form of exponential backoff.
We have several parameters:
1. INITIAL_BACKOFF (how long to wait after the first failure before retrying)
2. MULTIPLIER (factor with which to multiply backoff after a failed retry)
3. MAX_BACKOFF (upper bound on backoff)
4. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
1. MULTIPLIER (factor with which to multiply backoff after a failed retry)
1. JITTER (by how much to randomize backoffs).
1. MAX_BACKOFF (upper bound on backoff)
1. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
complete)
## Proposed Backoff Algorithm

@ -378,9 +378,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/handshake.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h',
@ -389,6 +389,7 @@ Pod::Spec.new do |s|
'src/core/lib/tsi/ssl_types.h',
'src/core/lib/tsi/transport_security.h',
'src/core/lib/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/client_channel/client_channel.h',
'src/core/ext/client_channel/client_channel_factory.h',
'src/core/ext/client_channel/connector.h',
@ -404,6 +405,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/subchannel.h',
'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/lb_policy/grpclb/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
@ -576,9 +578,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_credentials.c',
'src/core/lib/security/transport/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.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',
@ -587,6 +589,7 @@ Pod::Spec.new do |s|
'src/core/lib/tsi/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/transport_security.c',
'src/core/ext/transport/chttp2/server/chttp2_server.c',
'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.c',
@ -606,6 +609,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c',
'src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c',
@ -781,9 +785,9 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.h',
'src/core/lib/security/transport/handshake.h',
'src/core/lib/security/transport/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.h',
'src/core/lib/security/transport/security_handshaker.h',
'src/core/lib/security/transport/tsi_error.h',
'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h',
@ -792,6 +796,7 @@ Pod::Spec.new do |s|
'src/core/lib/tsi/ssl_types.h',
'src/core/lib/tsi/transport_security.h',
'src/core/lib/tsi/transport_security_interface.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
'src/core/ext/client_channel/client_channel.h',
'src/core/ext/client_channel/client_channel_factory.h',
'src/core/ext/client_channel/connector.h',
@ -807,6 +812,7 @@ Pod::Spec.new do |s|
'src/core/ext/client_channel/subchannel.h',
'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/lb_policy/grpclb/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',

@ -297,9 +297,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.h )
s.files += %w( src/core/lib/security/transport/auth_filters.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/security_connector.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.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/json_util.h )
@ -308,6 +308,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/tsi/ssl_types.h )
s.files += %w( src/core/lib/tsi/transport_security.h )
s.files += %w( src/core/lib/tsi/transport_security_interface.h )
s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h )
s.files += %w( src/core/ext/client_channel/client_channel.h )
s.files += %w( src/core/ext/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/client_channel/connector.h )
@ -323,6 +324,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/subchannel.h )
s.files += %w( src/core/ext/client_channel/subchannel_index.h )
s.files += %w( src/core/ext/client_channel/uri_parser.h )
s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.h )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
@ -495,9 +497,9 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/plugin/plugin_credentials.c )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_credentials.c )
s.files += %w( src/core/lib/security/transport/client_auth_filter.c )
s.files += %w( src/core/lib/security/transport/handshake.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_handshaker.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 )
@ -506,6 +508,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/tsi/fake_transport_security.c )
s.files += %w( src/core/lib/tsi/ssl_transport_security.c )
s.files += %w( src/core/lib/tsi/transport_security.c )
s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.c )
s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.c )
s.files += %w( src/core/ext/client_channel/channel_connectivity.c )
s.files += %w( src/core/ext/client_channel/client_channel.c )
@ -525,6 +528,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/client_channel/subchannel.c )
s.files += %w( src/core/ext/client_channel/subchannel_index.c )
s.files += %w( src/core/ext/client_channel/uri_parser.c )
s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.c )
s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )

@ -52,6 +52,7 @@
#include <grpc++/impl/codegen/grpc_library.h>
#include <grpc++/impl/codegen/status.h>
#include <grpc++/impl/codegen/time.h>
#include <grpc/impl/codegen/atm.h>
struct grpc_completion_queue;
@ -101,6 +102,7 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// instance.
CompletionQueue() {
cq_ = g_core_codegen_interface->grpc_completion_queue_create(nullptr);
InitialAvalanching(); // reserve this for the future shutdown
}
/// Wrap \a take, taking ownership of the instance.
@ -151,7 +153,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// Request the shutdown of the queue.
///
/// \warning This method must be called at some point. Once invoked, \a Next
/// \warning This method must be called at some point if this completion queue
/// is accessed with Next or AsyncNext. Once invoked, \a Next
/// will start to return false and \a AsyncNext will return \a
/// NextStatus::SHUTDOWN. Only once either one of these methods does that
/// (that is, once the queue has been \em drained) can an instance of this
@ -165,6 +168,21 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// owership is performed.
grpc_completion_queue* cq() { return cq_; }
/// Manage state of avalanching operations : completion queue tags that
/// trigger other completion queue operations. The underlying core completion
/// queue should not really shutdown until all avalanching operations have
/// been finalized. Note that we maintain the requirement that an avalanche
/// registration must take place before CQ shutdown (which must be maintained
/// elsehwere)
void InitialAvalanching() {
gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
}
void RegisterAvalanching() {
gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(1));
};
void CompleteAvalanching();
private:
// Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation.
@ -229,6 +247,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
}
grpc_completion_queue* cq_; // owned
gpr_atm avalanches_in_flight_;
};
/// A specific type of completion queue used by the processing of notifications

@ -140,7 +140,7 @@ class ServerInterface : public CallHook {
ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq, void* tag,
bool delete_on_finalize);
virtual ~BaseAsyncRequest() {}
virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override;

@ -305,9 +305,9 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/auth_filters.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/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_handshaker.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/json_util.h" role="src" />
@ -316,6 +316,7 @@
<file baseinstalldir="/" name="src/core/lib/tsi/ssl_types.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/transport_security.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/connector.h" role="src" />
@ -331,6 +332,7 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
@ -503,9 +505,9 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/plugin/plugin_credentials.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/ssl/ssl_credentials.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/client_auth_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/handshake.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_handshaker.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" />
@ -514,6 +516,7 @@
<file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/ssl_transport_security.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/transport_security.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/chttp2_server.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/secure/secure_channel_create.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/channel_connectivity.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.c" role="src" />
@ -533,6 +536,7 @@
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/uri_parser.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />

@ -760,6 +760,32 @@ PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
PythonGrpcGenerator::~PythonGrpcGenerator() {}
static bool GenerateGrpc(GeneratorContext* context, PrivateGenerator& generator,
grpc::string file_name, bool generate_in_pb2_grpc) {
bool success;
std::unique_ptr<ZeroCopyOutputStream> output;
std::unique_ptr<CodedOutputStream> coded_output;
grpc::string grpc_code;
if (generate_in_pb2_grpc) {
output.reset(context->Open(file_name));
generator.generate_in_pb2_grpc = true;
} else {
output.reset(context->OpenForInsert(file_name, "module_scope"));
generator.generate_in_pb2_grpc = false;
}
coded_output.reset(new CodedOutputStream(output.get()));
tie(success, grpc_code) = generator.GetGrpcServices();
if (success) {
coded_output->WriteRaw(grpc_code.data(), grpc_code.size());
return true;
} else {
return false;
}
}
bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
const grpc::string& parameter,
GeneratorContext* context,
@ -780,28 +806,15 @@ bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
}
PrivateGenerator generator(config_, file);
std::unique_ptr<ZeroCopyOutputStream> pb2_output(
context->OpenForAppend(pb2_file_name));
std::unique_ptr<ZeroCopyOutputStream> grpc_output(
context->Open(pb2_grpc_file_name));
CodedOutputStream pb2_coded_out(pb2_output.get());
CodedOutputStream grpc_coded_out(grpc_output.get());
bool success = false;
grpc::string pb2_code;
grpc::string grpc_code;
generator.generate_in_pb2_grpc = false;
tie(success, pb2_code) = generator.GetGrpcServices();
if (success) {
generator.generate_in_pb2_grpc = true;
tie(success, grpc_code) = generator.GetGrpcServices();
if (success) {
pb2_coded_out.WriteRaw(pb2_code.data(), pb2_code.size());
grpc_coded_out.WriteRaw(grpc_code.data(), grpc_code.size());
return true;
}
if (parameter == "grpc_2_0") {
return GenerateGrpc(context, generator, pb2_grpc_file_name, true);
} else if (parameter == "") {
return GenerateGrpc(context, generator, pb2_grpc_file_name, true) &&
GenerateGrpc(context, generator, pb2_file_name, false);
} else {
*error = "Invalid parameter '" + parameter + "'.";
return false;
}
return false;
}
} // namespace grpc_python_generator

@ -41,10 +41,9 @@
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/uri_parser.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/env.h"
typedef struct http_connect_handshaker {
@ -54,59 +53,105 @@ typedef struct http_connect_handshaker {
char* proxy_server;
char* server_name;
gpr_refcount refcount;
gpr_mu mu;
bool shutdown;
// Endpoint and read buffer to destroy after a shutdown.
grpc_endpoint* endpoint_to_destroy;
grpc_slice_buffer* read_buffer_to_destroy;
// State saved while performing the handshake.
grpc_endpoint* endpoint;
grpc_channel_args* args;
grpc_handshaker_done_cb cb;
void* user_data;
grpc_handshaker_args* args;
grpc_closure* on_handshake_done;
// Objects for processing the HTTP CONNECT request and response.
grpc_slice_buffer write_buffer;
grpc_slice_buffer* read_buffer; // Ownership passes through this object.
grpc_closure request_done_closure;
grpc_closure response_read_closure;
grpc_http_parser http_parser;
grpc_http_response http_response;
grpc_timer timeout_timer;
gpr_refcount refcount;
} http_connect_handshaker;
// Unref and clean up handshaker.
static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx,
http_connect_handshaker* handshaker) {
if (gpr_unref(&handshaker->refcount)) {
gpr_mu_destroy(&handshaker->mu);
if (handshaker->endpoint_to_destroy != NULL) {
grpc_endpoint_destroy(exec_ctx, handshaker->endpoint_to_destroy);
}
if (handshaker->read_buffer_to_destroy != NULL) {
grpc_slice_buffer_destroy(handshaker->read_buffer_to_destroy);
gpr_free(handshaker->read_buffer_to_destroy);
}
gpr_free(handshaker->proxy_server);
gpr_free(handshaker->server_name);
grpc_slice_buffer_destroy_internal(exec_ctx, &handshaker->write_buffer);
grpc_slice_buffer_destroy(&handshaker->write_buffer);
grpc_http_parser_destroy(&handshaker->http_parser);
grpc_http_response_destroy(&handshaker->http_response);
gpr_free(handshaker);
}
}
// Callback invoked when deadline is exceeded.
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
http_connect_handshaker* handshaker = arg;
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
grpc_endpoint_shutdown(exec_ctx, handshaker->endpoint);
// Set args fields to NULL, saving the endpoint and read buffer for
// later destruction.
static void cleanup_args_for_failure_locked(
grpc_exec_ctx *exec_ctx, http_connect_handshaker* handshaker) {
handshaker->endpoint_to_destroy = handshaker->args->endpoint;
handshaker->args->endpoint = NULL;
handshaker->read_buffer_to_destroy = handshaker->args->read_buffer;
handshaker->args->read_buffer = NULL;
grpc_channel_args_destroy(exec_ctx, handshaker->args->args);
handshaker->args->args = NULL;
}
// If the handshake failed or we're shutting down, clean up and invoke the
// callback with the error.
static void handshake_failed_locked(grpc_exec_ctx* exec_ctx,
http_connect_handshaker* handshaker,
grpc_error* error) {
if (error == GRPC_ERROR_NONE) {
// If we were shut down after an endpoint operation succeeded but
// before the endpoint callback was invoked, we need to generate our
// own error.
error = GRPC_ERROR_CREATE("Handshaker shutdown");
}
http_connect_handshaker_unref(exec_ctx, handshaker);
if (!handshaker->shutdown) {
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
// Not shutting down, so the handshake failed. Clean up before
// invoking the callback.
cleanup_args_for_failure_locked(exec_ctx, handshaker);
// Set shutdown to true so that subsequent calls to
// http_connect_handshaker_shutdown() do nothing.
handshaker->shutdown = true;
}
// Invoke callback.
grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
}
// Callback invoked when finished writing HTTP CONNECT request.
static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
http_connect_handshaker* handshaker = arg;
if (error != GRPC_ERROR_NONE) {
// If the write failed, invoke the callback immediately with the error.
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args,
handshaker->read_buffer, handshaker->user_data,
GRPC_ERROR_REF(error));
gpr_mu_lock(&handshaker->mu);
if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
// If the write failed or we're shutting down, clean up and invoke the
// callback with the error.
handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error));
gpr_mu_unlock(&handshaker->mu);
http_connect_handshaker_unref(exec_ctx, handshaker);
} else {
// Otherwise, read the response.
grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer,
// The read callback inherits our ref to the handshaker.
grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
handshaker->args->read_buffer,
&handshaker->response_read_closure);
gpr_mu_unlock(&handshaker->mu);
}
}
@ -114,37 +159,41 @@ static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
http_connect_handshaker* handshaker = arg;
if (error != GRPC_ERROR_NONE) {
GRPC_ERROR_REF(error); // Take ref to pass to the handshake-done callback.
gpr_mu_lock(&handshaker->mu);
if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
// If the read failed or we're shutting down, clean up and invoke the
// callback with the error.
handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error));
goto done;
}
// Add buffer to parser.
for (size_t i = 0; i < handshaker->read_buffer->count; ++i) {
if (GRPC_SLICE_LENGTH(handshaker->read_buffer->slices[i]) > 0) {
for (size_t i = 0; i < handshaker->args->read_buffer->count; ++i) {
if (GRPC_SLICE_LENGTH(handshaker->args->read_buffer->slices[i]) > 0) {
size_t body_start_offset = 0;
error = grpc_http_parser_parse(&handshaker->http_parser,
handshaker->read_buffer->slices[i],
handshaker->args->read_buffer->slices[i],
&body_start_offset);
if (error != GRPC_ERROR_NONE) goto done;
if (error != GRPC_ERROR_NONE) {
handshake_failed_locked(exec_ctx, handshaker, error);
goto done;
}
if (handshaker->http_parser.state == GRPC_HTTP_BODY) {
// We've gotten back a successul response, so stop the timeout timer.
grpc_timer_cancel(exec_ctx, &handshaker->timeout_timer);
// Remove the data we've already read from the read buffer,
// leaving only the leftover bytes (if any).
grpc_slice_buffer tmp_buffer;
grpc_slice_buffer_init(&tmp_buffer);
if (body_start_offset <
GRPC_SLICE_LENGTH(handshaker->read_buffer->slices[i])) {
GRPC_SLICE_LENGTH(handshaker->args->read_buffer->slices[i])) {
grpc_slice_buffer_add(
&tmp_buffer,
grpc_slice_split_tail(&handshaker->read_buffer->slices[i],
grpc_slice_split_tail(&handshaker->args->read_buffer->slices[i],
body_start_offset));
}
grpc_slice_buffer_addn(&tmp_buffer,
&handshaker->read_buffer->slices[i + 1],
handshaker->read_buffer->count - i - 1);
grpc_slice_buffer_swap(handshaker->read_buffer, &tmp_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, &tmp_buffer);
&handshaker->args->read_buffer->slices[i + 1],
handshaker->args->read_buffer->count - i - 1);
grpc_slice_buffer_swap(handshaker->args->read_buffer, &tmp_buffer);
grpc_slice_buffer_destroy(&tmp_buffer);
break;
}
}
@ -161,10 +210,11 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
// complete (e.g., handling chunked transfer encoding or looking
// at the Content-Length: header).
if (handshaker->http_parser.state != GRPC_HTTP_BODY) {
grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
handshaker->read_buffer);
grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer,
grpc_slice_buffer_reset_and_unref(handshaker->args->read_buffer);
grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
handshaker->args->read_buffer,
&handshaker->response_read_closure);
gpr_mu_unlock(&handshaker->mu);
return;
}
// Make sure we got a 2xx response.
@ -175,11 +225,17 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
handshaker->http_response.status);
error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
handshake_failed_locked(exec_ctx, handshaker, error);
goto done;
}
// Success. Invoke handshake-done callback.
grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
done:
// Invoke handshake-done callback.
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args,
handshaker->read_buffer, handshaker->user_data, error);
// Set shutdown to true so that subsequent calls to
// http_connect_handshaker_shutdown() do nothing.
handshaker->shutdown = true;
gpr_mu_unlock(&handshaker->mu);
http_connect_handshaker_unref(exec_ctx, handshaker);
}
//
@ -193,21 +249,26 @@ static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx,
}
static void http_connect_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) {}
grpc_handshaker* handshaker_in) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
gpr_mu_lock(&handshaker->mu);
if (!handshaker->shutdown) {
handshaker->shutdown = true;
grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
cleanup_args_for_failure_locked(exec_ctx, handshaker);
}
gpr_mu_unlock(&handshaker->mu);
}
static void http_connect_handshaker_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in,
grpc_endpoint* endpoint, grpc_channel_args* args,
grpc_slice_buffer* read_buffer, gpr_timespec deadline,
grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb,
void* user_data) {
grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done,
grpc_handshaker_args* args) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
gpr_mu_lock(&handshaker->mu);
// Save state in the handshaker object.
handshaker->endpoint = endpoint;
handshaker->args = args;
handshaker->cb = cb;
handshaker->user_data = user_data;
handshaker->read_buffer = read_buffer;
handshaker->on_handshake_done = on_handshake_done;
// Send HTTP CONNECT request.
gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s",
handshaker->server_name, handshaker->proxy_server);
@ -219,16 +280,14 @@ static void http_connect_handshaker_do_handshake(
request.handshaker = &grpc_httpcli_plaintext;
grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
grpc_endpoint_write(exec_ctx, endpoint, &handshaker->write_buffer,
&handshaker->request_done_closure);
// Set timeout timer. The timer gets a reference to the handshaker.
// Take a new ref to be held by the write callback.
gpr_ref(&handshaker->refcount);
grpc_timer_init(exec_ctx, &handshaker->timeout_timer,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
on_timeout, handshaker, gpr_now(GPR_CLOCK_MONOTONIC));
grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer,
&handshaker->request_done_closure);
gpr_mu_unlock(&handshaker->mu);
}
static const struct grpc_handshaker_vtable http_connect_handshaker_vtable = {
static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
http_connect_handshaker_destroy, http_connect_handshaker_shutdown,
http_connect_handshaker_do_handshake};
@ -236,10 +295,11 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
const char* server_name) {
GPR_ASSERT(proxy_server != NULL);
GPR_ASSERT(server_name != NULL);
http_connect_handshaker* handshaker =
gpr_malloc(sizeof(http_connect_handshaker));
http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker));
memset(handshaker, 0, sizeof(*handshaker));
grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base);
gpr_mu_init(&handshaker->mu);
gpr_ref_init(&handshaker->refcount, 1);
handshaker->proxy_server = gpr_strdup(proxy_server);
handshaker->server_name = gpr_strdup(server_name);
grpc_slice_buffer_init(&handshaker->write_buffer);
@ -249,7 +309,6 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
handshaker);
grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE,
&handshaker->http_response);
gpr_ref_init(&handshaker->refcount, 1);
return &handshaker->base;
}

@ -337,16 +337,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
int initial_backoff_ms =
GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000;
int max_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
int min_backoff_ms = GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS * 1000;
bool fixed_reconnect_backoff = false;
if (c->args) {
for (size_t i = 0; i < c->args->num_args; i++) {
if (0 == strcmp(c->args->args[i].key,
"grpc.testing.fixed_reconnect_backoff")) {
"grpc.testing.fixed_reconnect_backoff_ms")) {
GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
fixed_reconnect_backoff = true;
initial_backoff_ms = max_backoff_ms = grpc_channel_arg_get_integer(
&c->args->args[i],
(grpc_integer_options){initial_backoff_ms, 100, INT_MAX});
initial_backoff_ms = min_backoff_ms = max_backoff_ms =
grpc_channel_arg_get_integer(
&c->args->args[i],
(grpc_integer_options){initial_backoff_ms, 100, INT_MAX});
} else if (0 == strcmp(c->args->args[i].key,
GRPC_ARG_MAX_RECONNECT_BACKOFF_MS)) {
fixed_reconnect_backoff = false;
@ -363,11 +365,11 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
}
}
gpr_backoff_init(
&c->backoff_state,
&c->backoff_state, initial_backoff_ms,
fixed_reconnect_backoff ? 1.0
: GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
fixed_reconnect_backoff ? 0.0 : GRPC_SUBCHANNEL_RECONNECT_JITTER,
initial_backoff_ms, max_backoff_ms);
min_backoff_ms, max_backoff_ms);
gpr_mu_init(&c->mu);
return grpc_subchannel_index_register(exec_ctx, key, c);
@ -638,9 +640,7 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
/* setup subchannel watching connected subchannel for changes; subchannel
ref
for connecting is donated
to the state watcher */
ref for connecting is donated to the state watcher */
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
grpc_connected_subchannel_notify_on_state_change(

@ -124,10 +124,11 @@
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/static_metadata.h"
#define BACKOFF_MULTIPLIER 1.6
#define BACKOFF_JITTER 0.2
#define BACKOFF_MIN_SECONDS 10
#define BACKOFF_MAX_SECONDS 60
#define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20
#define GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_GRPCLB_RECONNECT_JITTER 0.2
int grpc_lb_glb_trace = 0;
@ -1110,9 +1111,12 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&glb_policy->lb_on_response_received,
lb_on_response_received, glb_policy);
gpr_backoff_init(&glb_policy->lb_call_backoff_state, BACKOFF_MULTIPLIER,
BACKOFF_JITTER, BACKOFF_MIN_SECONDS * 1000,
BACKOFF_MAX_SECONDS * 1000);
gpr_backoff_init(&glb_policy->lb_call_backoff_state,
GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
GRPC_GRPCLB_RECONNECT_JITTER,
GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
}
static void lb_call_destroy_locked(glb_lb_policy *glb_policy) {

@ -46,10 +46,11 @@
#include "src/core/lib/support/backoff.h"
#include "src/core/lib/support/string.h"
#define BACKOFF_MULTIPLIER 1.6
#define BACKOFF_JITTER 0.2
#define BACKOFF_MIN_SECONDS 1
#define BACKOFF_MAX_SECONDS 120
#define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1
#define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct {
/** base class: must be first */
@ -269,8 +270,11 @@ static grpc_resolver *dns_create(grpc_resolver_args *args,
server_name_arg.value.string = (char *)path;
r->channel_args =
grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER,
BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000);
gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
GRPC_DNS_RECONNECT_JITTER,
GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
return &r->base;
}

@ -0,0 +1,269 @@
/*
*
* 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/ext/transport/chttp2/client/chttp2_connector.h"
#include <grpc/grpc.h>
#include <string.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/connector.h"
#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/security/transport/security_connector.h"
typedef struct {
grpc_connector base;
gpr_mu mu;
gpr_refcount refs;
bool shutdown;
bool connecting;
char *server_name;
grpc_chttp2_create_handshakers_func create_handshakers;
void *create_handshakers_user_data;
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
grpc_slice_buffer initial_string_buffer;
grpc_endpoint *endpoint; // Non-NULL until handshaking starts.
grpc_closure connected;
grpc_handshake_manager *handshake_mgr;
} chttp2_connector;
static void chttp2_connector_ref(grpc_connector *con) {
chttp2_connector *c = (chttp2_connector *)con;
gpr_ref(&c->refs);
}
static void chttp2_connector_unref(grpc_exec_ctx *exec_ctx,
grpc_connector *con) {
chttp2_connector *c = (chttp2_connector *)con;
if (gpr_unref(&c->refs)) {
/* c->initial_string_buffer does not need to be destroyed */
gpr_mu_destroy(&c->mu);
// If handshaking is not yet in progress, destroy the endpoint.
// Otherwise, the handshaker will do this for us.
if (c->endpoint != NULL) grpc_endpoint_destroy(exec_ctx, c->endpoint);
gpr_free(c->server_name);
gpr_free(c);
}
}
static void chttp2_connector_shutdown(grpc_exec_ctx *exec_ctx,
grpc_connector *con) {
chttp2_connector *c = (chttp2_connector *)con;
gpr_mu_lock(&c->mu);
c->shutdown = true;
if (c->handshake_mgr != NULL) {
grpc_handshake_manager_shutdown(exec_ctx, c->handshake_mgr);
}
// If handshaking is not yet in progress, shutdown the endpoint.
// Otherwise, the handshaker will do this for us.
if (!c->connecting && c->endpoint != NULL) {
grpc_endpoint_shutdown(exec_ctx, c->endpoint);
}
gpr_mu_unlock(&c->mu);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_handshaker_args *args = arg;
chttp2_connector *c = args->user_data;
gpr_mu_lock(&c->mu);
if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown");
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(exec_ctx, args->endpoint);
grpc_endpoint_destroy(exec_ctx, args->endpoint);
grpc_channel_args_destroy(exec_ctx, args->args);
grpc_slice_buffer_destroy(args->read_buffer);
gpr_free(args->read_buffer);
} else {
error = GRPC_ERROR_REF(error);
}
memset(c->result, 0, sizeof(*c->result));
} else {
c->result->transport =
grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 1);
GPR_ASSERT(c->result->transport);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport,
args->read_buffer);
c->result->channel_args = args->args;
}
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
c->handshake_mgr = NULL;
gpr_mu_unlock(&c->mu);
chttp2_connector_unref(exec_ctx, (grpc_connector *)c);
}
static void start_handshake_locked(grpc_exec_ctx *exec_ctx,
chttp2_connector *c) {
c->handshake_mgr = grpc_handshake_manager_create();
char *proxy_name = grpc_get_http_proxy_server();
if (proxy_name != NULL) {
grpc_handshake_manager_add(
c->handshake_mgr,
grpc_http_connect_handshaker_create(proxy_name, c->server_name));
gpr_free(proxy_name);
}
if (c->create_handshakers != NULL) {
c->create_handshakers(exec_ctx, c->create_handshakers_user_data,
c->handshake_mgr);
}
grpc_handshake_manager_do_handshake(
exec_ctx, c->handshake_mgr, c->endpoint, c->args.channel_args,
c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
c->endpoint = NULL; // Endpoint handed off to handshake manager.
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
chttp2_connector *c = arg;
gpr_mu_lock(&c->mu);
if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown");
} else {
error = GRPC_ERROR_REF(error);
}
memset(c->result, 0, sizeof(*c->result));
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
gpr_mu_unlock(&c->mu);
chttp2_connector_unref(exec_ctx, arg);
} else {
start_handshake_locked(exec_ctx, c);
gpr_mu_unlock(&c->mu);
}
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
chttp2_connector *c = arg;
gpr_mu_lock(&c->mu);
GPR_ASSERT(c->connecting);
c->connecting = false;
if (error != GRPC_ERROR_NONE || c->shutdown) {
if (error == GRPC_ERROR_NONE) {
error = GRPC_ERROR_CREATE("connector shutdown");
} else {
error = GRPC_ERROR_REF(error);
}
memset(c->result, 0, sizeof(*c->result));
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint);
gpr_mu_unlock(&c->mu);
chttp2_connector_unref(exec_ctx, arg);
} else {
GPR_ASSERT(c->endpoint != NULL);
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c);
grpc_slice_buffer_init(&c->initial_string_buffer);
grpc_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
grpc_endpoint_write(exec_ctx, c->endpoint, &c->initial_string_buffer,
&c->initial_string_sent);
} else {
start_handshake_locked(exec_ctx, c);
}
gpr_mu_unlock(&c->mu);
}
}
static void chttp2_connector_connect(grpc_exec_ctx *exec_ctx,
grpc_connector *con,
const grpc_connect_in_args *args,
grpc_connect_out_args *result,
grpc_closure *notify) {
chttp2_connector *c = (chttp2_connector *)con;
gpr_mu_lock(&c->mu);
GPR_ASSERT(c->notify == NULL);
c->notify = notify;
c->args = *args;
c->result = result;
GPR_ASSERT(c->endpoint == NULL);
chttp2_connector_ref(con); // Ref taken for callback.
grpc_closure_init(&c->connected, connected, c);
GPR_ASSERT(!c->connecting);
c->connecting = true;
grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint,
args->interested_parties, args->channel_args,
args->addr, args->deadline);
gpr_mu_unlock(&c->mu);
}
static const grpc_connector_vtable chttp2_connector_vtable = {
chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown,
chttp2_connector_connect};
grpc_connector *grpc_chttp2_connector_create(
grpc_exec_ctx *exec_ctx, const char *server_name,
grpc_chttp2_create_handshakers_func create_handshakers,
void *create_handshakers_user_data) {
chttp2_connector *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
c->base.vtable = &chttp2_connector_vtable;
gpr_mu_init(&c->mu);
gpr_ref_init(&c->refs, 1);
c->server_name = gpr_strdup(server_name);
c->create_handshakers = create_handshakers;
c->create_handshakers_user_data = create_handshakers_user_data;
return &c->base;
}

@ -0,0 +1,52 @@
/*
*
* 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 GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
#include "src/core/ext/client_channel/connector.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/exec_ctx.h"
typedef void (*grpc_chttp2_create_handshakers_func)(
grpc_exec_ctx* exec_ctx, void* user_data,
grpc_handshake_manager* handshake_mgr);
/// If \a create_handshakers is non-NULL, it will be called with
/// \a create_handshakers_user_data to add handshakers.
grpc_connector* grpc_chttp2_connector_create(
grpc_exec_ctx* exec_ctx, const char* server_name,
grpc_chttp2_create_handshakers_func create_handshakers,
void* create_handshakers_user_data);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H */

@ -33,138 +33,17 @@
#include <grpc/grpc.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/compress_filter.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/http_client_filter.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
//
// connector
//
typedef struct {
grpc_connector base;
gpr_refcount refs;
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
grpc_slice_buffer initial_string_buffer;
grpc_endpoint *tcp;
grpc_closure connected;
grpc_handshake_manager *handshake_mgr;
} connector;
static void connector_ref(grpc_connector *con) {
connector *c = (connector *)con;
gpr_ref(&c->refs);
}
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
/* c->initial_string_buffer does not need to be destroyed */
grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
gpr_free(c);
}
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
connector_unref(exec_ctx, arg);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
grpc_channel_args *args,
grpc_slice_buffer *read_buffer, void *user_data,
grpc_error *error) {
connector *c = user_data;
if (error != GRPC_ERROR_NONE) {
grpc_channel_args_destroy(exec_ctx, args);
gpr_free(read_buffer);
} else {
c->result->transport =
grpc_create_chttp2_transport(exec_ctx, args, endpoint, 1);
GPR_ASSERT(c->result->transport);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport,
read_buffer);
c->result->channel_args = args;
}
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_endpoint *tcp = c->tcp;
if (tcp != NULL) {
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c);
grpc_slice_buffer_init(&c->initial_string_buffer);
grpc_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
connector_ref(arg);
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent);
} else {
grpc_handshake_manager_do_handshake(
exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
}
} else {
memset(c->result, 0, sizeof(*c->result));
grpc_closure *notify = c->notify;
c->notify = NULL;
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_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
const grpc_connect_in_args *args,
grpc_connect_out_args *result,
grpc_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
GPR_ASSERT(notify->cb);
c->notify = notify;
c->args = *args;
c->result = result;
c->tcp = NULL;
grpc_closure_init(&c->connected, connected, c);
grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
args->interested_parties, args->channel_args,
args->addr, args->deadline);
}
static const grpc_connector_vtable connector_vtable = {
connector_ref, connector_unref, connector_shutdown, connector_connect};
//
// client_channel_factory
//
static void client_channel_factory_ref(
grpc_client_channel_factory *cc_factory) {}
@ -174,20 +53,11 @@ static void client_channel_factory_unref(
static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) {
connector *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
gpr_ref_init(&c->refs, 1);
c->handshake_mgr = grpc_handshake_manager_create();
char *proxy_name = grpc_get_http_proxy_server();
if (proxy_name != NULL) {
grpc_handshake_manager_add(
c->handshake_mgr,
grpc_http_connect_handshaker_create(proxy_name, args->server_name));
gpr_free(proxy_name);
}
grpc_subchannel *s = grpc_subchannel_create(exec_ctx, &c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_connector *connector = grpc_chttp2_connector_create(
exec_ctx, args->server_name, NULL /* create_handshakers */,
NULL /* user_data */);
grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
grpc_connector_unref(exec_ctx, connector);
return s;
}
@ -198,16 +68,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args);
if (!resolver) {
if (resolver == NULL) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel");
return NULL;
}
grpc_client_channel_finish_initialization(
exec_ctx, grpc_channel_get_channel_stack(channel), resolver, cc_factory);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
return channel;
}
@ -230,16 +98,13 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
GRPC_API_TRACE(
"grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
(target, args, reserved));
GPR_ASSERT(!reserved);
GPR_ASSERT(reserved == NULL);
grpc_client_channel_factory *factory =
(grpc_client_channel_factory *)&client_channel_factory;
grpc_channel *channel = client_channel_factory_create_channel(
&exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args);
grpc_client_channel_factory_unref(&exec_ctx, factory);
grpc_exec_ctx_finish(&exec_ctx);
return channel != NULL ? channel : grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL,
"Failed to create client channel");

@ -33,196 +33,19 @@
#include <grpc/grpc.h>
#include <stdlib.h>
#include <string.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h"
#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/resolver_registry.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/auth_filters.h"
#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/tsi/transport_security_interface.h"
//
// connector
//
typedef struct {
grpc_connector base;
gpr_refcount refs;
grpc_channel_security_connector *security_connector;
grpc_closure *notify;
grpc_connect_in_args args;
grpc_connect_out_args *result;
grpc_closure initial_string_sent;
grpc_slice_buffer initial_string_buffer;
gpr_mu mu;
grpc_endpoint *connecting_endpoint;
grpc_endpoint *newly_connecting_endpoint;
grpc_closure connected_closure;
grpc_handshake_manager *handshake_mgr;
// TODO(roth): Remove once we eliminate on_secure_handshake_done().
grpc_channel_args *tmp_args;
} connector;
static void connector_ref(grpc_connector *con) {
connector *c = (connector *)con;
gpr_ref(&c->refs);
}
static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
if (gpr_unref(&c->refs)) {
/* c->initial_string_buffer does not need to be destroyed */
grpc_channel_args_destroy(exec_ctx, c->tmp_args);
grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
gpr_free(c);
}
}
static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_security_status status,
grpc_endpoint *secure_endpoint,
grpc_auth_context *auth_context) {
connector *c = arg;
gpr_mu_lock(&c->mu);
grpc_error *error = GRPC_ERROR_NONE;
if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result));
gpr_mu_unlock(&c->mu);
} else if (status != GRPC_SECURITY_OK) {
error = grpc_error_set_int(GRPC_ERROR_CREATE("Secure handshake failed"),
GRPC_ERROR_INT_SECURITY_STATUS, status);
memset(c->result, 0, sizeof(*c->result));
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
} else {
grpc_arg auth_context_arg;
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
c->result->transport = grpc_create_chttp2_transport(
exec_ctx, c->args.channel_args, secure_endpoint, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL);
auth_context_arg = grpc_auth_context_to_arg(auth_context);
c->result->channel_args =
grpc_channel_args_copy_and_add(c->tmp_args, &auth_context_arg, 1);
}
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
grpc_channel_args *args,
grpc_slice_buffer *read_buffer, void *user_data,
grpc_error *error) {
connector *c = user_data;
c->tmp_args = args;
if (error != GRPC_ERROR_NONE) {
gpr_free(read_buffer);
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
} else {
// TODO(roth, jboeuf): Convert security connector handshaking to use new
// handshake API, and then move the code from on_secure_handshake_done()
// into this function.
grpc_channel_security_connector_do_handshake(
exec_ctx, c->security_connector, endpoint, read_buffer,
c->args.deadline, on_secure_handshake_done, c);
}
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
connector *c = arg;
grpc_handshake_manager_do_handshake(
exec_ctx, c->handshake_mgr, c->connecting_endpoint, c->args.channel_args,
c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
}
static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_endpoint *tcp = c->newly_connecting_endpoint;
if (tcp != NULL) {
gpr_mu_lock(&c->mu);
GPR_ASSERT(c->connecting_endpoint == NULL);
c->connecting_endpoint = tcp;
gpr_mu_unlock(&c->mu);
if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
c);
grpc_slice_buffer_init(&c->initial_string_buffer);
grpc_slice_buffer_add(&c->initial_string_buffer,
c->args.initial_connect_string);
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent);
} else {
grpc_handshake_manager_do_handshake(
exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
}
} else {
memset(c->result, 0, sizeof(*c->result));
grpc_closure *notify = c->notify;
c->notify = NULL;
grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
}
}
static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
connector *c = (connector *)con;
grpc_endpoint *ep;
gpr_mu_lock(&c->mu);
ep = c->connecting_endpoint;
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
if (ep) {
grpc_endpoint_shutdown(exec_ctx, ep);
}
}
static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
const grpc_connect_in_args *args,
grpc_connect_out_args *result,
grpc_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
c->notify = notify;
c->args = *args;
c->result = result;
gpr_mu_lock(&c->mu);
GPR_ASSERT(c->connecting_endpoint == NULL);
gpr_mu_unlock(&c->mu);
grpc_closure_init(&c->connected_closure, connected, c);
grpc_tcp_client_connect(
exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint,
args->interested_parties, args->channel_args, args->addr, args->deadline);
}
static const grpc_connector_vtable connector_vtable = {
connector_ref, connector_unref, connector_shutdown, connector_connect};
//
// client_channel_factory
//
typedef struct {
grpc_client_channel_factory base;
@ -246,26 +69,21 @@ static void client_channel_factory_unref(
}
}
static void create_handshakers(grpc_exec_ctx *exec_ctx,
void *security_connector,
grpc_handshake_manager *handshake_mgr) {
grpc_channel_security_connector_create_handshakers(
exec_ctx, security_connector, handshake_mgr);
}
static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) {
client_channel_factory *f = (client_channel_factory *)cc_factory;
connector *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c));
c->base.vtable = &connector_vtable;
c->security_connector = f->security_connector;
c->handshake_mgr = grpc_handshake_manager_create();
char *proxy_name = grpc_get_http_proxy_server();
if (proxy_name != NULL) {
grpc_handshake_manager_add(
c->handshake_mgr,
grpc_http_connect_handshaker_create(proxy_name, args->server_name));
gpr_free(proxy_name);
}
gpr_mu_init(&c->mu);
gpr_ref_init(&c->refs, 1);
grpc_subchannel *s = grpc_subchannel_create(exec_ctx, &c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_connector *connector = grpc_chttp2_connector_create(
exec_ctx, args->server_name, create_handshakers, f->security_connector);
grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
grpc_connector_unref(exec_ctx, connector);
return s;
}
@ -277,15 +95,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args);
if (resolver != NULL) {
grpc_client_channel_finish_initialization(
exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create");
} else {
if (resolver == NULL) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel");
channel = NULL;
return NULL;
}
grpc_client_channel_finish_initialization(
exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
return channel;
}
@ -320,8 +137,8 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
grpc_channel_security_connector *security_connector;
grpc_channel_args *new_args_from_connector;
if (grpc_channel_credentials_create_security_connector(
&exec_ctx, creds, target, args, &security_connector,
&new_args_from_connector) != GRPC_SECURITY_OK) {
&exec_ctx, creds, target, args, &security_connector, &new_args_from_connector) !=
GRPC_SECURITY_OK) {
grpc_exec_ctx_finish(&exec_ctx);
return grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL, "Failed to create security connector.");

@ -0,0 +1,354 @@
/*
*
* 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/ext/transport/chttp2/server/chttp2_server.h"
#include <grpc/grpc.h>
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/http_server_filter.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
void grpc_chttp2_server_handshaker_factory_create_handshakers(
grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory,
grpc_handshake_manager *handshake_mgr) {
if (handshaker_factory != NULL) {
handshaker_factory->vtable->create_handshakers(exec_ctx, handshaker_factory,
handshake_mgr);
}
}
void grpc_chttp2_server_handshaker_factory_destroy(
grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory) {
if (handshaker_factory != NULL) {
handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory);
}
}
typedef struct pending_handshake_manager_node {
grpc_handshake_manager *handshake_mgr;
struct pending_handshake_manager_node *next;
} pending_handshake_manager_node;
typedef struct {
grpc_server *server;
grpc_tcp_server *tcp_server;
grpc_channel_args *args;
grpc_chttp2_server_handshaker_factory *handshaker_factory;
gpr_mu mu;
bool shutdown;
grpc_closure tcp_server_shutdown_complete;
grpc_closure *server_destroy_listener_done;
pending_handshake_manager_node *pending_handshake_mgrs;
} server_state;
typedef struct {
server_state *server_state;
grpc_pollset *accepting_pollset;
grpc_tcp_server_acceptor *acceptor;
grpc_handshake_manager *handshake_mgr;
} server_connection_state;
static void pending_handshake_manager_add_locked(
server_state *state, grpc_handshake_manager *handshake_mgr) {
pending_handshake_manager_node *node = gpr_malloc(sizeof(*node));
node->handshake_mgr = handshake_mgr;
node->next = state->pending_handshake_mgrs;
state->pending_handshake_mgrs = node;
}
static void pending_handshake_manager_remove_locked(
server_state *state, grpc_handshake_manager *handshake_mgr) {
pending_handshake_manager_node **prev_node = &state->pending_handshake_mgrs;
for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
node != NULL; node = node->next) {
if (node->handshake_mgr == handshake_mgr) {
*prev_node = node->next;
gpr_free(node);
break;
}
prev_node = &node->next;
}
}
static void pending_handshake_manager_shutdown_locked(grpc_exec_ctx *exec_ctx,
server_state *state) {
pending_handshake_manager_node *prev_node = NULL;
for (pending_handshake_manager_node *node = state->pending_handshake_mgrs;
node != NULL; node = node->next) {
grpc_handshake_manager_shutdown(exec_ctx, node->handshake_mgr);
gpr_free(prev_node);
prev_node = node;
}
gpr_free(prev_node);
state->pending_handshake_mgrs = NULL;
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_handshaker_args *args = arg;
server_connection_state *connection_state = args->user_data;
gpr_mu_lock(&connection_state->server_state->mu);
if (error != GRPC_ERROR_NONE || connection_state->server_state->shutdown) {
const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
grpc_error_free_string(error_str);
if (error == GRPC_ERROR_NONE) {
// We were shut down after handshaking completed successfully, so
// destroy the endpoint here.
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(exec_ctx, args->endpoint);
grpc_endpoint_destroy(exec_ctx, args->endpoint);
grpc_channel_args_destroy(exec_ctx, args->args);
grpc_slice_buffer_destroy(args->read_buffer);
gpr_free(args->read_buffer);
}
} else {
grpc_transport *transport =
grpc_create_chttp2_transport(exec_ctx, args->args, args->endpoint, 0);
grpc_server_setup_transport(
exec_ctx, connection_state->server_state->server, transport,
connection_state->accepting_pollset, args->args);
grpc_chttp2_transport_start_reading(exec_ctx, transport, args->read_buffer);
grpc_channel_args_destroy(exec_ctx, args->args);
}
pending_handshake_manager_remove_locked(connection_state->server_state,
connection_state->handshake_mgr);
gpr_mu_unlock(&connection_state->server_state->mu);
grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp_server);
gpr_free(connection_state);
}
static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
grpc_pollset *accepting_pollset,
grpc_tcp_server_acceptor *acceptor) {
server_state *state = arg;
gpr_mu_lock(&state->mu);
if (state->shutdown) {
gpr_mu_unlock(&state->mu);
grpc_endpoint_destroy(exec_ctx, tcp);
return;
}
grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create();
pending_handshake_manager_add_locked(state, handshake_mgr);
gpr_mu_unlock(&state->mu);
grpc_tcp_server_ref(state->tcp_server);
server_connection_state *connection_state =
gpr_malloc(sizeof(*connection_state));
connection_state->server_state = state;
connection_state->accepting_pollset = accepting_pollset;
connection_state->acceptor = acceptor;
connection_state->handshake_mgr = handshake_mgr;
grpc_chttp2_server_handshaker_factory_create_handshakers(
exec_ctx, state->handshaker_factory, connection_state->handshake_mgr);
// TODO(roth): We should really get this timeout value from channel
// args instead of hard-coding it.
const gpr_timespec deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
grpc_handshake_manager_do_handshake(exec_ctx, connection_state->handshake_mgr,
tcp, state->args, deadline, acceptor,
on_handshake_done, connection_state);
}
/* Server callback: start listening on our ports */
static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
void *arg, grpc_pollset **pollsets,
size_t pollset_count) {
server_state *state = arg;
gpr_mu_lock(&state->mu);
state->shutdown = false;
gpr_mu_unlock(&state->mu);
grpc_tcp_server_start(exec_ctx, state->tcp_server, pollsets, pollset_count,
on_accept, state);
}
static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
server_state *state = arg;
/* ensure all threads have unlocked */
gpr_mu_lock(&state->mu);
grpc_closure *destroy_done = state->server_destroy_listener_done;
GPR_ASSERT(state->shutdown);
pending_handshake_manager_shutdown_locked(exec_ctx, state);
gpr_mu_unlock(&state->mu);
// Flush queued work before destroying handshaker factory, since that
// may do a synchronous unref.
grpc_exec_ctx_flush(exec_ctx);
grpc_chttp2_server_handshaker_factory_destroy(exec_ctx,
state->handshaker_factory);
if (destroy_done != NULL) {
destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
grpc_exec_ctx_flush(exec_ctx);
}
grpc_channel_args_destroy(exec_ctx, state->args);
gpr_mu_destroy(&state->mu);
gpr_free(state);
}
/* Server callback: destroy the tcp listener (so we don't generate further
callbacks) */
static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
grpc_server *server, void *arg,
grpc_closure *destroy_done) {
server_state *state = arg;
gpr_mu_lock(&state->mu);
state->shutdown = true;
state->server_destroy_listener_done = destroy_done;
grpc_tcp_server *tcp_server = state->tcp_server;
gpr_mu_unlock(&state->mu);
grpc_tcp_server_shutdown_listeners(exec_ctx, tcp_server);
grpc_tcp_server_unref(exec_ctx, tcp_server);
}
grpc_error *grpc_chttp2_server_add_port(
grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
grpc_channel_args *args,
grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp_server = NULL;
size_t i;
size_t count = 0;
int port_temp;
grpc_error *err = GRPC_ERROR_NONE;
server_state *state = NULL;
grpc_error **errors = NULL;
*port_num = -1;
/* resolve address */
err = grpc_blocking_resolve_address(addr, "https", &resolved);
if (err != GRPC_ERROR_NONE) {
goto error;
}
state = gpr_malloc(sizeof(*state));
memset(state, 0, sizeof(*state));
grpc_closure_init(&state->tcp_server_shutdown_complete,
tcp_server_shutdown_complete, state);
err = grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete,
args, &tcp_server);
if (err != GRPC_ERROR_NONE) {
goto error;
}
state->server = server;
state->tcp_server = tcp_server;
state->args = args;
state->handshaker_factory = handshaker_factory;
state->shutdown = true;
gpr_mu_init(&state->mu);
const size_t naddrs = resolved->naddrs;
errors = gpr_malloc(sizeof(*errors) * naddrs);
for (i = 0; i < naddrs; i++) {
errors[i] =
grpc_tcp_server_add_port(tcp_server, &resolved->addrs[i], &port_temp);
if (errors[i] == GRPC_ERROR_NONE) {
if (*port_num == -1) {
*port_num = port_temp;
} else {
GPR_ASSERT(*port_num == port_temp);
}
count++;
}
}
if (count == 0) {
char *msg;
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;
} else if (count != naddrs) {
char *msg;
gpr_asprintf(&msg, "Only %" PRIuPTR
" 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);
/* Register with the server only upon success */
grpc_server_add_listener(exec_ctx, server, state, server_start_listener,
server_destroy_listener);
goto done;
/* Error path: cleanup and return */
error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
if (tcp_server) {
grpc_tcp_server_unref(exec_ctx, tcp_server);
} else {
grpc_channel_args_destroy(exec_ctx, args);
grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, handshaker_factory);
gpr_free(state);
}
*port_num = 0;
done:
if (errors != NULL) {
for (i = 0; i < naddrs; i++) {
GRPC_ERROR_UNREF(errors[i]);
}
gpr_free(errors);
}
return err;
}

@ -0,0 +1,78 @@
/*
*
* 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_SERVER_CHTTP2_SERVER_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H
#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/exec_ctx.h"
/// A server handshaker factory is used to create handshakers for server
/// connections.
typedef struct grpc_chttp2_server_handshaker_factory
grpc_chttp2_server_handshaker_factory;
typedef struct {
void (*create_handshakers)(
grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory,
grpc_handshake_manager *handshake_mgr);
void (*destroy)(grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory);
} grpc_chttp2_server_handshaker_factory_vtable;
struct grpc_chttp2_server_handshaker_factory {
const grpc_chttp2_server_handshaker_factory_vtable *vtable;
};
void grpc_chttp2_server_handshaker_factory_create_handshakers(
grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory,
grpc_handshake_manager *handshake_mgr);
void grpc_chttp2_server_handshaker_factory_destroy(
grpc_exec_ctx *exec_ctx,
grpc_chttp2_server_handshaker_factory *handshaker_factory);
/// Adds a port to \a server. Sets \a port_num to the port number.
/// If \a handshaker_factory is not NULL, it will be used to create
/// handshakers for the port.
/// Takes ownership of \a args and \a handshaker_factory.
grpc_error *grpc_chttp2_server_add_port(
grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
grpc_channel_args *args,
grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */

@ -33,180 +33,28 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/http_server_filter.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
typedef struct server_connect_state {
grpc_server *server;
grpc_pollset *accepting_pollset;
grpc_tcp_server_acceptor *acceptor;
grpc_handshake_manager *handshake_mgr;
} server_connect_state;
static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
grpc_channel_args *args,
grpc_slice_buffer *read_buffer, void *user_data,
grpc_error *error) {
server_connect_state *state = user_data;
if (error != GRPC_ERROR_NONE) {
const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
grpc_error_free_string(error_str);
GRPC_ERROR_UNREF(error);
grpc_handshake_manager_shutdown(exec_ctx, state->handshake_mgr);
gpr_free(read_buffer);
} else {
// Beware that the call to grpc_create_chttp2_transport() has to happen
// before grpc_tcp_server_destroy(). This is fine here, but similar code
// asynchronously doing a handshake instead of calling
// grpc_tcp_server_start() (as in server_secure_chttp2.c) needs to add
// synchronization to avoid this case.
grpc_transport *transport =
grpc_create_chttp2_transport(exec_ctx, args, endpoint, 0);
grpc_server_setup_transport(exec_ctx, state->server, transport,
state->accepting_pollset,
grpc_server_get_channel_args(state->server));
grpc_chttp2_transport_start_reading(exec_ctx, transport, read_buffer);
}
// Clean up.
grpc_channel_args_destroy(exec_ctx, args);
grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr);
gpr_free(state);
}
static void on_accept(grpc_exec_ctx *exec_ctx, void *server, grpc_endpoint *tcp,
grpc_pollset *accepting_pollset,
grpc_tcp_server_acceptor *acceptor) {
server_connect_state *state = gpr_malloc(sizeof(server_connect_state));
state->server = server;
state->accepting_pollset = accepting_pollset;
state->acceptor = acceptor;
state->handshake_mgr = grpc_handshake_manager_create();
// TODO(roth): We should really get this timeout value from channel
// args instead of hard-coding it.
const gpr_timespec deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
grpc_handshake_manager_do_handshake(
exec_ctx, state->handshake_mgr, tcp, grpc_server_get_channel_args(server),
deadline, acceptor, on_handshake_done, state);
}
/* Server callback: start listening on our ports */
static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
grpc_pollset **pollsets, size_t pollset_count) {
grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, on_accept,
server);
}
/* Server callback: destroy the tcp listener (so we don't generate further
callbacks) */
static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
grpc_closure *destroy_done) {
grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
grpc_tcp_server_unref(exec_ctx, tcp);
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) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL;
size_t i;
size_t count = 0;
int port_num = -1;
int port_temp;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE;
int port_num = 0;
GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr));
grpc_error **errors = NULL;
err = grpc_blocking_resolve_address(addr, "https", &resolved);
if (err != GRPC_ERROR_NONE) {
goto error;
}
err = grpc_tcp_server_create(&exec_ctx, NULL,
grpc_server_get_channel_args(server), &tcp);
grpc_error *err = grpc_chttp2_server_add_port(
&exec_ctx, server, addr,
grpc_channel_args_copy(grpc_server_get_channel_args(server)),
NULL /* handshaker_factory */, &port_num);
if (err != GRPC_ERROR_NONE) {
goto error;
}
const size_t naddrs = resolved->naddrs;
errors = gpr_malloc(sizeof(*errors) * naddrs);
for (i = 0; i < naddrs; i++) {
errors[i] = grpc_tcp_server_add_port(tcp, &resolved->addrs[i], &port_temp);
if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
GPR_ASSERT(port_num == port_temp);
}
count++;
}
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
grpc_error_free_string(msg);
GRPC_ERROR_UNREF(err);
}
if (count == 0) {
char *msg;
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;
} else if (count != naddrs) {
char *msg;
gpr_asprintf(&msg, "Only %" PRIuPTR
" 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);
/* Register with the server only upon success */
grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy);
goto done;
/* Error path: cleanup and return */
error:
GPR_ASSERT(err != GRPC_ERROR_NONE);
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
if (tcp) {
grpc_tcp_server_unref(&exec_ctx, tcp);
}
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:
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;
}

@ -38,218 +38,62 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/channel/http_server_filter.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/auth_filters.h"
#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
typedef struct server_secure_state {
grpc_server *server;
grpc_tcp_server *tcp;
grpc_server_security_connector *sc;
grpc_server_credentials *creds;
bool is_shutdown;
gpr_mu mu;
grpc_closure tcp_server_shutdown_complete;
grpc_closure *server_destroy_listener_done;
} server_secure_state;
typedef struct server_secure_connect {
server_secure_state *server_state;
grpc_pollset *accepting_pollset;
grpc_tcp_server_acceptor *acceptor;
grpc_handshake_manager *handshake_mgr;
// TODO(roth): Remove the following two fields when we eliminate
// grpc_server_security_connector_do_handshake().
gpr_timespec deadline;
grpc_channel_args *args;
} server_secure_connect;
static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_security_status status,
grpc_endpoint *secure_endpoint,
grpc_auth_context *auth_context) {
server_secure_connect *connection_state = statep;
if (status == GRPC_SECURITY_OK) {
if (secure_endpoint) {
gpr_mu_lock(&connection_state->server_state->mu);
if (!connection_state->server_state->is_shutdown) {
grpc_transport *transport = grpc_create_chttp2_transport(
exec_ctx, grpc_server_get_channel_args(
connection_state->server_state->server),
secure_endpoint, 0);
grpc_arg args_to_add[2];
args_to_add[0] = grpc_server_credentials_to_arg(
connection_state->server_state->creds);
args_to_add[1] = grpc_auth_context_to_arg(auth_context);
grpc_channel_args *args_copy = grpc_channel_args_copy_and_add(
connection_state->args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
grpc_server_setup_transport(
exec_ctx, connection_state->server_state->server, transport,
connection_state->accepting_pollset, args_copy);
grpc_channel_args_destroy(exec_ctx, args_copy);
grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL);
} else {
/* We need to consume this here, because the server may already have
* gone away. */
grpc_endpoint_destroy(exec_ctx, secure_endpoint);
}
gpr_mu_unlock(&connection_state->server_state->mu);
}
} else {
gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
}
grpc_channel_args_destroy(exec_ctx, connection_state->args);
grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp);
gpr_free(connection_state);
}
static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
grpc_channel_args *args,
grpc_slice_buffer *read_buffer, void *user_data,
grpc_error *error) {
server_secure_connect *connection_state = user_data;
if (error != GRPC_ERROR_NONE) {
const char *error_str = grpc_error_string(error);
gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
grpc_error_free_string(error_str);
GRPC_ERROR_UNREF(error);
grpc_channel_args_destroy(exec_ctx, args);
gpr_free(read_buffer);
grpc_handshake_manager_shutdown(exec_ctx, connection_state->handshake_mgr);
grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp);
gpr_free(connection_state);
return;
}
grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
connection_state->handshake_mgr = NULL;
// TODO(roth, jboeuf): Convert security connector handshaking to use new
// handshake API, and then move the code from on_secure_handshake_done()
// into this function.
connection_state->args = args;
grpc_server_security_connector_do_handshake(
exec_ctx, connection_state->server_state->sc, connection_state->acceptor,
endpoint, read_buffer, connection_state->deadline,
on_secure_handshake_done, connection_state);
}
static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
grpc_pollset *accepting_pollset,
grpc_tcp_server_acceptor *acceptor) {
server_secure_state *server_state = statep;
server_secure_connect *connection_state = NULL;
gpr_mu_lock(&server_state->mu);
if (server_state->is_shutdown) {
gpr_mu_unlock(&server_state->mu);
grpc_endpoint_destroy(exec_ctx, tcp);
return;
}
gpr_mu_unlock(&server_state->mu);
grpc_tcp_server_ref(server_state->tcp);
connection_state = gpr_malloc(sizeof(*connection_state));
connection_state->server_state = server_state;
connection_state->accepting_pollset = accepting_pollset;
connection_state->acceptor = acceptor;
connection_state->handshake_mgr = grpc_handshake_manager_create();
// TODO(roth): We should really get this timeout value from channel
// args instead of hard-coding it.
connection_state->deadline = gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
grpc_handshake_manager_do_handshake(
exec_ctx, connection_state->handshake_mgr, tcp,
grpc_server_get_channel_args(connection_state->server_state->server),
connection_state->deadline, acceptor, on_handshake_done,
connection_state);
typedef struct {
grpc_chttp2_server_handshaker_factory base;
grpc_server_security_connector *security_connector;
} server_security_handshaker_factory;
static void server_security_handshaker_factory_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf,
grpc_handshake_manager *handshake_mgr) {
server_security_handshaker_factory *handshaker_factory =
(server_security_handshaker_factory *)hf;
grpc_server_security_connector_create_handshakers(
exec_ctx, handshaker_factory->security_connector, handshake_mgr);
}
/* Server callback: start listening on our ports */
static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
void *statep, grpc_pollset **pollsets,
size_t pollset_count) {
server_secure_state *server_state = statep;
gpr_mu_lock(&server_state->mu);
server_state->is_shutdown = false;
gpr_mu_unlock(&server_state->mu);
grpc_tcp_server_start(exec_ctx, server_state->tcp, pollsets, pollset_count,
on_accept, server_state);
static void server_security_handshaker_factory_destroy(
grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf) {
server_security_handshaker_factory *handshaker_factory =
(server_security_handshaker_factory *)hf;
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &handshaker_factory->security_connector->base,
"server");
gpr_free(hf);
}
static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *statep,
grpc_error *error) {
server_secure_state *server_state = statep;
/* ensure all threads have unlocked */
gpr_mu_lock(&server_state->mu);
grpc_closure *destroy_done = server_state->server_destroy_listener_done;
GPR_ASSERT(server_state->is_shutdown);
gpr_mu_unlock(&server_state->mu);
/* clean up */
grpc_server_security_connector_shutdown(exec_ctx, server_state->sc);
/* Flush queued work before a synchronous unref. */
grpc_exec_ctx_flush(exec_ctx);
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &server_state->sc->base, "server");
grpc_server_credentials_unref(exec_ctx, server_state->creds);
if (destroy_done != NULL) {
destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
grpc_exec_ctx_flush(exec_ctx);
}
gpr_free(server_state);
}
static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
grpc_server *server, void *statep,
grpc_closure *callback) {
server_secure_state *server_state = statep;
grpc_tcp_server *tcp;
gpr_mu_lock(&server_state->mu);
server_state->is_shutdown = true;
server_state->server_destroy_listener_done = callback;
tcp = server_state->tcp;
gpr_mu_unlock(&server_state->mu);
grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
grpc_tcp_server_unref(exec_ctx, server_state->tcp);
}
static const grpc_chttp2_server_handshaker_factory_vtable
server_security_handshaker_factory_vtable = {
server_security_handshaker_factory_create_handshakers,
server_security_handshaker_factory_destroy};
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_server_credentials *creds) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL;
server_secure_state *server_state = NULL;
size_t i;
size_t count = 0;
int port_num = -1;
int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR;
grpc_server_security_connector *sc = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE;
grpc_error **errors = NULL;
grpc_server_security_connector *sc = NULL;
int port_num = 0;
GRPC_API_TRACE(
"grpc_server_add_secure_http2_port("
"server=%p, addr=%s, creds=%p)",
3, (server, addr, creds));
/* create security context */
// Create security context.
if (creds == NULL) {
err = GRPC_ERROR_CREATE(
"No credentials specified for secure server port (creds==NULL)");
goto error;
goto done;
}
status =
grpc_security_status status =
grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
if (status != GRPC_SECURITY_OK) {
char *msg;
@ -259,107 +103,28 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status);
gpr_free(msg);
goto error;
goto done;
}
sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */
err = grpc_blocking_resolve_address(addr, "https", &resolved);
if (err != GRPC_ERROR_NONE) {
goto error;
}
server_state = gpr_malloc(sizeof(*server_state));
memset(server_state, 0, sizeof(*server_state));
grpc_closure_init(&server_state->tcp_server_shutdown_complete,
tcp_server_shutdown_complete, server_state);
err = grpc_tcp_server_create(&exec_ctx,
&server_state->tcp_server_shutdown_complete,
grpc_server_get_channel_args(server), &tcp);
// Create handshaker factory.
server_security_handshaker_factory *handshaker_factory =
gpr_malloc(sizeof(*handshaker_factory));
memset(handshaker_factory, 0, sizeof(*handshaker_factory));
handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable;
handshaker_factory->security_connector = sc;
// Create channel args.
grpc_arg channel_arg = grpc_server_credentials_to_arg(creds);
grpc_channel_args *args = grpc_channel_args_copy_and_add(
grpc_server_get_channel_args(server), &channel_arg, 1);
// Add server port.
err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args,
&handshaker_factory->base, &port_num);
done:
grpc_exec_ctx_finish(&exec_ctx);
if (err != GRPC_ERROR_NONE) {
goto error;
const char *msg = grpc_error_string(err);
gpr_log(GPR_ERROR, "%s", msg);
grpc_error_free_string(msg);
GRPC_ERROR_UNREF(err);
}
server_state->server = server;
server_state->tcp = tcp;
server_state->sc = sc;
server_state->creds = grpc_server_credentials_ref(creds);
server_state->is_shutdown = true;
gpr_mu_init(&server_state->mu);
errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
for (i = 0; i < resolved->naddrs; i++) {
errors[i] = grpc_tcp_server_add_port(tcp, &resolved->addrs[i], &port_temp);
if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
GPR_ASSERT(port_num == port_temp);
}
count++;
}
}
if (count == 0) {
char *msg;
gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
resolved->naddrs);
err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
gpr_free(msg);
goto error;
} else if (count != resolved->naddrs) {
char *msg;
gpr_asprintf(&msg, "Only %" PRIuPTR
" addresses added out of total %" PRIuPTR " resolved",
count, resolved->naddrs);
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);
/* Register with the server only upon success */
grpc_server_add_listener(&exec_ctx, server, server_state,
server_start_listener, server_destroy_listener);
grpc_exec_ctx_finish(&exec_ctx);
return port_num;
/* Error path: cleanup and return */
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) {
grpc_resolved_addresses_destroy(resolved);
}
if (tcp) {
grpc_tcp_server_unref(&exec_ctx, tcp);
} else {
if (sc) {
grpc_exec_ctx_flush(&exec_ctx);
GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "server");
}
if (server_state) {
gpr_free(server_state);
}
}
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;
}

@ -112,9 +112,6 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
void *byte_stream,
grpc_error *error_ignored);
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_error *error);
static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
grpc_error *error);
@ -605,11 +602,13 @@ static void set_write_state(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
write_state_name(t->write_state),
write_state_name(st), reason));
t->write_state = st;
if (st == GRPC_CHTTP2_WRITE_STATE_IDLE &&
t->close_transport_on_writes_finished != NULL) {
grpc_error *err = t->close_transport_on_writes_finished;
t->close_transport_on_writes_finished = NULL;
close_transport_locked(exec_ctx, t, err);
if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
grpc_exec_ctx_enqueue_list(exec_ctx, &t->run_after_write, NULL);
if (t->close_transport_on_writes_finished != NULL) {
grpc_error *err = t->close_transport_on_writes_finished;
t->close_transport_on_writes_finished = NULL;
close_transport_locked(exec_ctx, t, err);
}
}
}
@ -707,8 +706,6 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
}
}
grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
switch (t->write_state) {
case GRPC_CHTTP2_WRITE_STATE_IDLE:
GPR_UNREACHABLE_CODE(break);
@ -737,6 +734,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
break;
}
grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
GPR_TIMER_END("terminate_writing_with_lock", 0);
}
@ -826,7 +825,14 @@ static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
}
}
/* Flag that this closure barrier wants stats to be updated before finishing */
#define CLOSURE_BARRIER_STATS_BIT (1 << 0)
/* Flag that this closure barrier may be covering a write in a pollset, and so
we should not complete this closure until we can prove that the write got
scheduled */
#define CLOSURE_BARRIER_MAY_COVER_WRITE (1 << 1)
/* First bit of the reference count, stored in the high order bits (with the low
bits being used for flags defined above) */
#define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16)
static grpc_closure *add_closure_barrier(grpc_closure *closure) {
@ -853,6 +859,16 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
return;
}
closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
if (grpc_http_trace) {
const char *errstr = grpc_error_string(error);
gpr_log(GPR_DEBUG,
"complete_closure_step: %p refs=%d flags=0x%04x desc=%s err=%s",
closure,
(int)(closure->next_data.scratch / CLOSURE_BARRIER_FIRST_REF_BIT),
(int)(closure->next_data.scratch % CLOSURE_BARRIER_FIRST_REF_BIT),
desc, errstr);
grpc_error_free_string(errstr);
}
if (error != GRPC_ERROR_NONE) {
if (closure->error_data.error == GRPC_ERROR_NONE) {
closure->error_data.error =
@ -869,7 +885,13 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
grpc_transport_move_stats(&s->stats, s->collecting_stats);
s->collecting_stats = NULL;
}
grpc_closure_run(exec_ctx, closure, closure->error_data.error);
if ((t->write_state == GRPC_CHTTP2_WRITE_STATE_IDLE) ||
!(closure->next_data.scratch & CLOSURE_BARRIER_MAY_COVER_WRITE)) {
grpc_closure_run(exec_ctx, closure, closure->error_data.error);
} else {
grpc_closure_list_append(&t->run_after_write, closure,
closure->error_data.error);
}
}
}
@ -1014,6 +1036,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (op->send_initial_metadata != NULL) {
GPR_ASSERT(s->send_initial_metadata_finished == NULL);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->send_initial_metadata_finished = add_closure_barrier(on_complete);
s->send_initial_metadata = op->send_initial_metadata;
const size_t metadata_size =
@ -1067,6 +1090,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
}
if (op->send_message != NULL) {
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
if (s->write_closed) {
grpc_chttp2_complete_closure_step(
@ -1104,6 +1128,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
if (op->send_trailing_metadata != NULL) {
GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
on_complete->next_data.scratch |= CLOSURE_BARRIER_MAY_COVER_WRITE;
s->send_trailing_metadata_finished = add_closure_barrier(on_complete);
s->send_trailing_metadata = op->send_trailing_metadata;
const size_t metadata_size =
@ -1538,9 +1563,9 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s,
return error;
}
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_error *error) {
void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error) {
error =
removal_error(error, s, "Pending writes failed due to stream closure");
s->send_initial_metadata = NULL;
@ -1594,7 +1619,7 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
if (close_writes && !s->write_closed) {
s->write_closed_error = GRPC_ERROR_REF(error);
s->write_closed = true;
fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
grpc_chttp2_fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
if (s->read_closed && s->write_closed) {

@ -327,6 +327,9 @@ struct grpc_chttp2_transport {
*/
grpc_error *close_transport_on_writes_finished;
/* a list of closures to run after writes are finished */
grpc_closure_list run_after_write;
/* buffer pool state */
/** have we scheduled a benign cleanup? */
bool benign_reclaimer_registered;
@ -689,4 +692,8 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -38,67 +38,66 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/timer.h"
//
// grpc_handshaker
//
void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
grpc_handshaker* handshaker) {
handshaker->vtable = vtable;
}
void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) {
static void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) {
handshaker->vtable->destroy(exec_ctx, handshaker);
}
void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) {
static void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) {
handshaker->vtable->shutdown(exec_ctx, handshaker);
}
void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker,
grpc_endpoint* endpoint,
grpc_channel_args* args,
grpc_slice_buffer* read_buffer,
gpr_timespec deadline,
grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data) {
handshaker->vtable->do_handshake(exec_ctx, handshaker, endpoint, args,
read_buffer, deadline, acceptor, cb,
user_data);
static void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker,
grpc_tcp_server_acceptor* acceptor,
grpc_closure* on_handshake_done,
grpc_handshaker_args* args) {
handshaker->vtable->do_handshake(exec_ctx, handshaker, acceptor,
on_handshake_done, args);
}
//
// grpc_handshake_manager
//
// State used while chaining handshakers.
struct grpc_handshaker_state {
// The index of the handshaker to invoke next.
size_t index;
// The deadline for all handshakers.
gpr_timespec deadline;
// The acceptor to call the handshakers with.
grpc_tcp_server_acceptor* acceptor;
// The final callback and user_data to invoke after the last handshaker.
grpc_handshaker_done_cb final_cb;
void* final_user_data;
};
struct grpc_handshake_manager {
gpr_mu mu;
gpr_refcount refs;
bool shutdown;
// An array of handshakers added via grpc_handshake_manager_add().
size_t count;
grpc_handshaker** handshakers;
// State used while chaining handshakers.
struct grpc_handshaker_state* state;
// The index of the handshaker to invoke next and closure to invoke it.
size_t index;
grpc_closure call_next_handshaker;
// The acceptor to call the handshakers with.
grpc_tcp_server_acceptor* acceptor;
// Deadline timer across all handshakers.
grpc_timer deadline_timer;
// The final callback and user_data to invoke after the last handshaker.
grpc_closure on_handshake_done;
void* user_data;
// Handshaker args.
grpc_handshaker_args args;
};
grpc_handshake_manager* grpc_handshake_manager_create() {
grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager));
memset(mgr, 0, sizeof(*mgr));
gpr_mu_init(&mgr->mu);
gpr_ref_init(&mgr->refs, 1);
return mgr;
}
@ -106,6 +105,7 @@ static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; }
void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
grpc_handshaker* handshaker) {
gpr_mu_lock(&mgr->mu);
// To avoid allocating memory for each handshaker we add, we double
// the number of elements every time we need more.
size_t realloc_count = 0;
@ -119,85 +119,116 @@ void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
gpr_realloc(mgr->handshakers, realloc_count * sizeof(grpc_handshaker*));
}
mgr->handshakers[mgr->count++] = handshaker;
gpr_mu_unlock(&mgr->mu);
}
static void grpc_handshake_manager_unref(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) {
if (gpr_unref(&mgr->refs)) {
for (size_t i = 0; i < mgr->count; ++i) {
grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
}
gpr_free(mgr->handshakers);
gpr_mu_destroy(&mgr->mu);
gpr_free(mgr);
}
}
void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) {
for (size_t i = 0; i < mgr->count; ++i) {
grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
}
gpr_free(mgr->handshakers);
gpr_free(mgr);
grpc_handshake_manager_unref(exec_ctx, mgr);
}
void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) {
for (size_t i = 0; i < mgr->count; ++i) {
grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[i]);
gpr_mu_lock(&mgr->mu);
// Shutdown the handshaker that's currently in progress, if any.
if (!mgr->shutdown && mgr->index > 0) {
mgr->shutdown = true;
grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1]);
}
if (mgr->state != NULL) {
gpr_free(mgr->state);
mgr->state = NULL;
gpr_mu_unlock(&mgr->mu);
}
// Helper function to call either the next handshaker or the
// on_handshake_done callback.
// Returns true if we've scheduled the on_handshake_done callback.
static bool call_next_handshaker_locked(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr,
grpc_error* error) {
GPR_ASSERT(mgr->index <= mgr->count);
// If we got an error or we've been shut down or we've finished the last
// handshaker, invoke the on_handshake_done callback. Otherwise, call the
// next handshaker.
if (error != GRPC_ERROR_NONE || mgr->shutdown || mgr->index == mgr->count) {
// Cancel deadline timer, since we're invoking the on_handshake_done
// callback now.
grpc_timer_cancel(exec_ctx, &mgr->deadline_timer);
grpc_exec_ctx_sched(exec_ctx, &mgr->on_handshake_done, error, NULL);
mgr->shutdown = true;
} else {
grpc_handshaker_do_handshake(exec_ctx, mgr->handshakers[mgr->index],
mgr->acceptor, &mgr->call_next_handshaker,
&mgr->args);
}
++mgr->index;
return mgr->shutdown;
}
// A function used as the handshaker-done callback when chaining
// handshakers together.
static void call_next_handshaker(grpc_exec_ctx* exec_ctx,
grpc_endpoint* endpoint,
grpc_channel_args* args,
grpc_slice_buffer* read_buffer,
void* user_data, grpc_error* error) {
grpc_handshake_manager* mgr = user_data;
GPR_ASSERT(mgr->state != NULL);
GPR_ASSERT(mgr->state->index < mgr->count);
// If we got an error, skip all remaining handshakers and invoke the
// caller-supplied callback immediately.
if (error != GRPC_ERROR_NONE) {
mgr->state->final_cb(exec_ctx, endpoint, args, read_buffer,
mgr->state->final_user_data, error);
return;
static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
grpc_handshake_manager* mgr = arg;
gpr_mu_lock(&mgr->mu);
bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_REF(error));
gpr_mu_unlock(&mgr->mu);
// If we're invoked the final callback, we won't be coming back
// to this function, so we can release our reference to the
// handshake manager.
if (done) {
grpc_handshake_manager_unref(exec_ctx, mgr);
}
grpc_handshaker_done_cb cb = call_next_handshaker;
// If this is the last handshaker, use the caller-supplied callback
// and user_data instead of chaining back to this function again.
if (mgr->state->index == mgr->count - 1) {
cb = mgr->state->final_cb;
user_data = mgr->state->final_user_data;
}
// Invoke handshaker.
grpc_handshaker_do_handshake(
exec_ctx, mgr->handshakers[mgr->state->index], endpoint, args,
read_buffer, mgr->state->deadline, mgr->state->acceptor, cb, user_data);
++mgr->state->index;
// If this is the last handshaker, clean up state.
if (mgr->state->index == mgr->count) {
gpr_free(mgr->state);
mgr->state = NULL;
}
// Callback invoked when deadline is exceeded.
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
grpc_handshake_manager* mgr = arg;
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
grpc_handshake_manager_shutdown(exec_ctx, mgr);
}
grpc_handshake_manager_unref(exec_ctx, mgr);
}
void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
grpc_endpoint* endpoint, const grpc_channel_args* args,
grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data) {
grpc_channel_args* args_copy = grpc_channel_args_copy(args);
grpc_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer));
grpc_slice_buffer_init(read_buffer);
if (mgr->count == 0) {
// No handshakers registered, so we just immediately call the done
// callback with the passed-in endpoint.
cb(exec_ctx, endpoint, args_copy, read_buffer, user_data, GRPC_ERROR_NONE);
} else {
GPR_ASSERT(mgr->state == NULL);
mgr->state = gpr_malloc(sizeof(struct grpc_handshaker_state));
memset(mgr->state, 0, sizeof(*mgr->state));
mgr->state->deadline = deadline;
mgr->state->acceptor = acceptor;
mgr->state->final_cb = cb;
mgr->state->final_user_data = user_data;
call_next_handshaker(exec_ctx, endpoint, args_copy, read_buffer, mgr,
GRPC_ERROR_NONE);
grpc_iomgr_cb_func on_handshake_done, void* user_data) {
gpr_mu_lock(&mgr->mu);
GPR_ASSERT(mgr->index == 0);
GPR_ASSERT(!mgr->shutdown);
// Construct handshaker args. These will be passed through all
// handshakers and eventually be freed by the on_handshake_done callback.
mgr->args.endpoint = endpoint;
mgr->args.args = grpc_channel_args_copy(channel_args);
mgr->args.user_data = user_data;
mgr->args.read_buffer = gpr_malloc(sizeof(*mgr->args.read_buffer));
grpc_slice_buffer_init(mgr->args.read_buffer);
// Initialize state needed for calling handshakers.
mgr->acceptor = acceptor;
grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr);
grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args);
// Start deadline timer, which owns a ref.
gpr_ref(&mgr->refs);
grpc_timer_init(exec_ctx, &mgr->deadline_timer,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC));
// Start first handshaker, which also owns a ref.
gpr_ref(&mgr->refs);
bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);
gpr_mu_unlock(&mgr->mu);
if (done) {
grpc_handshake_manager_unref(exec_ctx, mgr);
}
}

@ -54,15 +54,30 @@
typedef struct grpc_handshaker grpc_handshaker;
/// Callback type invoked when a handshaker is done.
/// Takes ownership of \a args and \a read_buffer.
typedef void (*grpc_handshaker_done_cb)(grpc_exec_ctx* exec_ctx,
grpc_endpoint* endpoint,
grpc_channel_args* args,
grpc_slice_buffer* read_buffer,
void* user_data, grpc_error* error);
struct grpc_handshaker_vtable {
/// Arguments passed through handshakers and to the on_handshake_done callback.
///
/// For handshakers, all members are input/output parameters; for
/// example, a handshaker may read from or write to \a endpoint and
/// then later replace it with a wrapped endpoint. Similarly, a
/// handshaker may modify \a args.
///
/// A handshaker takes ownership of the members while a handshake is in
/// progress. Upon failure or shutdown of an in-progress handshaker,
/// the handshaker is responsible for destroying the members and setting
/// them to NULL before invoking the on_handshake_done callback.
///
/// For the on_handshake_done callback, all members are input arguments,
/// which the callback takes ownership of.
typedef struct {
grpc_endpoint* endpoint;
grpc_channel_args* args;
grpc_slice_buffer* read_buffer;
// User data passed through the handshake manager. Not used by
// individual handshakers.
void* user_data;
} grpc_handshaker_args;
typedef struct {
/// Destroys the handshaker.
void (*destroy)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
@ -70,44 +85,26 @@ struct grpc_handshaker_vtable {
/// aborted in the middle).
void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
/// Performs handshaking. When finished, calls \a cb with \a user_data.
/// Takes ownership of \a args.
/// Takes ownership of \a read_buffer, which contains leftover bytes read
/// from the endpoint by the previous handshaker.
/// Performs handshaking, modifying \a args as needed (e.g., to
/// replace \a endpoint with a wrapped endpoint).
/// When finished, invokes \a on_handshake_done.
/// \a acceptor will be NULL for client-side handshakers.
void (*do_handshake)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker,
grpc_endpoint* endpoint, grpc_channel_args* args,
grpc_slice_buffer* read_buffer, gpr_timespec deadline,
grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data);
};
grpc_closure* on_handshake_done,
grpc_handshaker_args* args);
} grpc_handshaker_vtable;
/// Base struct. To subclass, make this the first member of the
/// implementation struct.
struct grpc_handshaker {
const struct grpc_handshaker_vtable* vtable;
const grpc_handshaker_vtable* vtable;
};
/// Called by concrete implementations to initialize the base struct.
void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
grpc_handshaker* handshaker);
/// Convenient wrappers for invoking methods via the vtable.
/// These probably do not need to be called from anywhere but
/// grpc_handshake_manager.
void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker);
void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker);
void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker,
grpc_endpoint* endpoint,
grpc_channel_args* args,
grpc_slice_buffer* read_buffer,
gpr_timespec deadline,
grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data);
///
/// grpc_handshake_manager
///
@ -134,15 +131,21 @@ void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr);
/// Invokes handshakers in the order they were added.
/// Does NOT take ownership of \a args. Instead, makes a copy before
/// Takes ownership of \a endpoint, and then passes that ownership to
/// the \a on_handshake_done callback.
/// Does NOT take ownership of \a channel_args. Instead, makes a copy before
/// invoking the first handshaker.
/// \a acceptor will be NULL for client-side handshakers.
/// Invokes \a cb with \a user_data after either a handshaker fails or
/// all handshakers have completed successfully.
///
/// When done, invokes \a on_handshake_done with a grpc_handshaker_args
/// object as its argument. If the callback is invoked with error !=
/// GRPC_ERROR_NONE, then handshaking failed and the handshaker has done
/// the necessary clean-up. Otherwise, the callback takes ownership of
/// the arguments.
void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
grpc_endpoint* endpoint, const grpc_channel_args* args,
grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
grpc_handshaker_done_cb cb, void* user_data);
grpc_iomgr_cb_func on_handshake_done, void* user_data);
#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */

@ -38,7 +38,9 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/security/transport/handshake.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/ssl_transport_security.h"
@ -48,8 +50,7 @@ typedef struct {
char *secure_peer_name;
} grpc_httpcli_ssl_channel_security_connector;
static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc;
if (c->handshaker_factory != NULL) {
@ -59,52 +60,42 @@ static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx,
gpr_free(sc);
}
static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer,
gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
static void httpcli_ssl_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_handshake_manager *handshake_mgr) {
grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc;
tsi_result result = TSI_OK;
tsi_handshaker *handshaker;
if (c->handshaker_factory == NULL) {
gpr_free(read_buffer);
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
return;
}
result = tsi_ssl_handshaker_factory_create_handshaker(
c->handshaker_factory, c->secure_peer_name, &handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
gpr_free(read_buffer);
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
nonsecure_endpoint, read_buffer, deadline, cb,
user_data);
tsi_handshaker *handshaker = NULL;
if (c->handshaker_factory != NULL) {
tsi_result result = tsi_ssl_handshaker_factory_create_handshaker(
c->handshaker_factory, c->secure_peer_name, &handshaker);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
}
}
grpc_security_create_handshakers(exec_ctx, handshaker, &sc->base,
handshake_mgr);
}
static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb,
void *user_data) {
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked) {
grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc;
grpc_security_status status = GRPC_SECURITY_OK;
grpc_error *error = GRPC_ERROR_NONE;
/* Check the peer name. */
if (c->secure_peer_name != NULL &&
!tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
c->secure_peer_name);
status = GRPC_SECURITY_ERROR;
char *msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
c->secure_peer_name);
error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
}
cb(exec_ctx, user_data, status, NULL);
grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
@ -112,9 +103,8 @@ static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_check_peer};
static grpc_security_status httpcli_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, const unsigned char *pem_root_certs,
size_t pem_root_certs_size, const char *secure_peer_name,
grpc_channel_security_connector **sc) {
grpc_exec_ctx *exec_ctx, const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const char *secure_peer_name, grpc_channel_security_connector **sc) {
tsi_result result = TSI_OK;
grpc_httpcli_ssl_channel_security_connector *c;
@ -142,7 +132,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
*sc = NULL;
return GRPC_SECURITY_ERROR;
}
c->base.do_handshake = httpcli_ssl_do_handshake;
c->base.create_handshakers = httpcli_ssl_create_handshakers;
*sc = &c->base;
return GRPC_SECURITY_OK;
}
@ -152,19 +142,25 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
typedef struct {
void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint);
void *arg;
grpc_handshake_manager *handshake_mgr;
} on_done_closure;
static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
grpc_security_status status,
grpc_endpoint *secure_endpoint,
grpc_auth_context *auth_context) {
on_done_closure *c = rp;
if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_handshaker_args *args = arg;
on_done_closure *c = args->user_data;
if (error != GRPC_ERROR_NONE) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
grpc_error_free_string(msg);
c->func(exec_ctx, c->arg, NULL);
} else {
c->func(exec_ctx, c->arg, secure_endpoint);
grpc_channel_args_destroy(exec_ctx, args->args);
grpc_slice_buffer_destroy(args->read_buffer);
gpr_free(args->read_buffer);
c->func(exec_ctx, c->arg, args->endpoint);
}
grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
gpr_free(c);
}
@ -185,12 +181,16 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
}
c->func = on_done;
c->arg = arg;
c->handshake_mgr = grpc_handshake_manager_create();
GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
exec_ctx, pem_root_certs, pem_root_certs_size, host, &sc) ==
exec_ctx, pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK);
grpc_channel_security_connector_do_handshake(
exec_ctx, sc, tcp, NULL, deadline, on_secure_transport_setup_done, c);
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &sc->base, "httpcli");
grpc_channel_security_connector_create_handshakers(exec_ctx, sc,
c->handshake_mgr);
grpc_handshake_manager_do_handshake(
exec_ctx, c->handshake_mgr, tcp, NULL /* channel_args */, deadline,
NULL /* acceptor */, on_handshake_done, c /* user_data */);
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx,&sc->base, "httpcli");
}
const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};

@ -90,6 +90,12 @@ static bool is_covered_by_poller(grpc_combiner *lock) {
gpr_atm_acq_load(&lock->elements_covered_by_poller) > 0;
}
#define IS_COVERED_BY_POLLER_FMT "(final=%d elems=%" PRIdPTR ")->%d"
#define IS_COVERED_BY_POLLER_ARGS(lock) \
(lock)->final_list_covered_by_poller, \
gpr_atm_acq_load(&(lock)->elements_covered_by_poller), \
is_covered_by_poller((lock))
grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) {
grpc_combiner *lock = gpr_malloc(sizeof(*lock));
lock->next_combiner_on_this_exec_ctx = NULL;
@ -197,9 +203,10 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) {
GRPC_COMBINER_TRACE(
gpr_log(GPR_DEBUG,
"C:%p grpc_combiner_continue_exec_ctx workqueue=%p "
"is_covered_by_poller=%d exec_ctx_ready_to_finish=%d "
"is_covered_by_poller=" IS_COVERED_BY_POLLER_FMT
" exec_ctx_ready_to_finish=%d "
"time_to_execute_final_list=%d",
lock, lock->optional_workqueue, is_covered_by_poller(lock),
lock, lock->optional_workqueue, IS_COVERED_BY_POLLER_ARGS(lock),
grpc_exec_ctx_ready_to_finish(exec_ctx),
lock->time_to_execute_final_list));

@ -144,6 +144,12 @@ struct grpc_resource_quota {
/* Closure around rq_reclamation_done */
grpc_closure rq_reclamation_done_closure;
/* This is only really usable for debugging: it's always a stale pointer, but
a stale pointer that might just be fresh enough to guide us to where the
reclamation system is stuck */
grpc_closure *debug_only_last_initiated_reclaimer;
grpc_resource_user *debug_only_last_reclaimer_resource_user;
/* Roots of all resource user lists */
grpc_resource_user *roots[GRPC_RULIST_COUNT];
@ -225,6 +231,7 @@ static void rulist_remove(grpc_resource_user *resource_user, grpc_rulist list) {
resource_user->links[list].prev;
resource_user->links[list].prev->links[list].next =
resource_user->links[list].next;
resource_user->links[list].next = resource_user->links[list].prev = NULL;
}
/*******************************************************************************
@ -340,6 +347,9 @@ static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
resource_quota->reclaiming = true;
grpc_resource_quota_ref_internal(resource_quota);
grpc_closure *c = resource_user->reclaimers[destructive];
GPR_ASSERT(c);
resource_quota->debug_only_last_reclaimer_resource_user = resource_user;
resource_quota->debug_only_last_initiated_reclaimer = c;
resource_user->reclaimers[destructive] = NULL;
grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE);
return true;
@ -465,6 +475,8 @@ static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
GRPC_ERROR_CANCELLED, NULL);
resource_user->reclaimers[0] = NULL;
resource_user->reclaimers[1] = NULL;
rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
}
static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {

@ -388,7 +388,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
/* Try listening on IPv6 first. */
addr = &wild6;
// TODO(rjshade): Test and propagate the returned grpc_error*:
grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP,
&dsmode, &fd));
allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
@ -402,7 +403,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
}
// TODO(rjshade): Test and propagate the returned grpc_error*:
grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP,
&dsmode, &fd));
if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
}

@ -1,377 +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 "src/core/lib/security/transport/handshake.h"
#include <stdbool.h>
#include <string.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/tsi_error.h"
#include "src/core/lib/slice/slice_internal.h"
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
typedef struct {
grpc_security_connector *connector;
tsi_handshaker *handshaker;
bool is_client_side;
unsigned char *handshake_buffer;
size_t handshake_buffer_size;
grpc_endpoint *wrapped_endpoint;
grpc_endpoint *secure_endpoint;
grpc_slice_buffer left_overs;
grpc_slice_buffer incoming;
grpc_slice_buffer outgoing;
grpc_security_handshake_done_cb cb;
void *user_data;
grpc_closure on_handshake_data_sent_to_peer;
grpc_closure on_handshake_data_received_from_peer;
grpc_auth_context *auth_context;
grpc_timer timer;
gpr_refcount refs;
} grpc_security_handshake;
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
void *setup,
grpc_error *error);
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
grpc_error *error);
static void security_connector_remove_handshake(grpc_security_handshake *h) {
GPR_ASSERT(!h->is_client_side);
grpc_security_connector_handshake_list *node;
grpc_security_connector_handshake_list *tmp;
grpc_server_security_connector *sc =
(grpc_server_security_connector *)h->connector;
gpr_mu_lock(&sc->mu);
node = sc->handshaking_handshakes;
if (node && node->handshake == h) {
sc->handshaking_handshakes = node->next;
gpr_free(node);
gpr_mu_unlock(&sc->mu);
return;
}
while (node) {
if (node->next->handshake == h) {
tmp = node->next;
node->next = node->next->next;
gpr_free(tmp);
gpr_mu_unlock(&sc->mu);
return;
}
node = node->next;
}
gpr_mu_unlock(&sc->mu);
}
static void unref_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_handshake *h) {
if (gpr_unref(&h->refs)) {
if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, &h->left_overs);
grpc_slice_buffer_destroy_internal(exec_ctx, &h->outgoing);
grpc_slice_buffer_destroy_internal(exec_ctx, &h->incoming);
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, h->connector, "handshake");
gpr_free(h);
}
}
static void security_handshake_done(grpc_exec_ctx *exec_ctx,
grpc_security_handshake *h,
grpc_error *error) {
grpc_timer_cancel(exec_ctx, &h->timer);
if (!h->is_client_side) {
security_connector_remove_handshake(h);
}
if (error == GRPC_ERROR_NONE) {
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint,
h->auth_context);
} else {
const char *msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg);
grpc_error_free_string(msg);
if (h->secure_endpoint != NULL) {
grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
grpc_endpoint_destroy(exec_ctx, h->secure_endpoint);
} else {
grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
}
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL);
}
unref_handshake(exec_ctx, h);
GRPC_ERROR_UNREF(error);
}
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_security_status status,
grpc_auth_context *auth_context) {
grpc_security_handshake *h = user_data;
tsi_frame_protector *protector;
tsi_result result;
if (status != GRPC_SECURITY_OK) {
security_handshake_done(
exec_ctx, h,
grpc_error_set_int(GRPC_ERROR_CREATE("Error checking peer."),
GRPC_ERROR_INT_SECURITY_STATUS, status));
return;
}
h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake");
result =
tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
if (result != TSI_OK) {
security_handshake_done(
exec_ctx, h,
grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Frame protector creation failed"), result));
return;
}
h->secure_endpoint =
grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
h->left_overs.slices, h->left_overs.count);
h->left_overs.count = 0;
h->left_overs.length = 0;
security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE);
return;
}
static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
tsi_peer peer;
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
if (result != TSI_OK) {
security_handshake_done(
exec_ctx, h, grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Peer extraction failed"), result));
return;
}
grpc_security_connector_check_peer(exec_ctx, h->connector, peer,
on_peer_checked, h);
}
static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
grpc_security_handshake *h) {
size_t offset = 0;
tsi_result result = TSI_OK;
grpc_slice to_send;
do {
size_t to_send_size = h->handshake_buffer_size - offset;
result = tsi_handshaker_get_bytes_to_send_to_peer(
h->handshaker, h->handshake_buffer + offset, &to_send_size);
offset += to_send_size;
if (result == TSI_INCOMPLETE_DATA) {
h->handshake_buffer_size *= 2;
h->handshake_buffer =
gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
}
} while (result == TSI_INCOMPLETE_DATA);
if (result != TSI_OK) {
security_handshake_done(exec_ctx, h,
grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
to_send =
grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing);
grpc_slice_buffer_add(&h->outgoing, to_send);
/* TODO(klempner,jboeuf): This should probably use the client setup
deadline */
grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing,
&h->on_handshake_data_sent_to_peer);
}
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
void *handshake,
grpc_error *error) {
grpc_security_handshake *h = handshake;
size_t consumed_slice_size = 0;
tsi_result result = TSI_OK;
size_t i;
size_t num_left_overs;
int has_left_overs_in_current_slice = 0;
if (error != GRPC_ERROR_NONE) {
security_handshake_done(
exec_ctx, h,
GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1));
return;
}
for (i = 0; i < h->incoming.count; i++) {
consumed_slice_size = GRPC_SLICE_LENGTH(h->incoming.slices[i]);
result = tsi_handshaker_process_bytes_from_peer(
h->handshaker, GRPC_SLICE_START_PTR(h->incoming.slices[i]),
&consumed_slice_size);
if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
}
if (tsi_handshaker_is_in_progress(h->handshaker)) {
/* We may need more data. */
if (result == TSI_INCOMPLETE_DATA) {
grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
&h->on_handshake_data_received_from_peer);
return;
} else {
send_handshake_bytes_to_peer(exec_ctx, h);
return;
}
}
if (result != TSI_OK) {
security_handshake_done(exec_ctx, h,
grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
/* Handshake is done and successful this point. */
has_left_overs_in_current_slice =
(consumed_slice_size < GRPC_SLICE_LENGTH(h->incoming.slices[i]));
num_left_overs =
(has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1;
if (num_left_overs == 0) {
check_peer(exec_ctx, h);
return;
}
/* Put the leftovers in our buffer (ownership transfered). */
if (has_left_overs_in_current_slice) {
grpc_slice_buffer_add(
&h->left_overs,
grpc_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
grpc_slice_unref_internal(
exec_ctx,
h->incoming.slices[i]); /* split_tail above increments refcount. */
}
grpc_slice_buffer_addn(
&h->left_overs, &h->incoming.slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice);
check_peer(exec_ctx, h);
}
/* If handshake is NULL, the handshake is done. */
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
void *handshake, grpc_error *error) {
grpc_security_handshake *h = handshake;
/* Make sure that write is OK. */
if (error != GRPC_ERROR_NONE) {
if (handshake != NULL)
security_handshake_done(
exec_ctx, h,
GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1));
return;
}
/* We may be done. */
if (tsi_handshaker_is_in_progress(h->handshaker)) {
/* TODO(klempner,jboeuf): This should probably use the client setup
deadline */
grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming,
&h->on_handshake_data_received_from_peer);
} else {
check_peer(exec_ctx, h);
}
}
static void on_timeout(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_security_handshake *h = arg;
if (error == GRPC_ERROR_NONE) {
grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
}
unref_handshake(exec_ctx, h);
}
void grpc_do_security_handshake(
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
grpc_security_connector *connector, bool is_client_side,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer,
gpr_timespec deadline, grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_security_connector_handshake_list *handshake_node;
grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
memset(h, 0, sizeof(grpc_security_handshake));
h->handshaker = handshaker;
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
h->is_client_side = is_client_side;
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
h->wrapped_endpoint = nonsecure_endpoint;
h->user_data = user_data;
h->cb = cb;
gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */
grpc_closure_init(&h->on_handshake_data_sent_to_peer,
on_handshake_data_sent_to_peer, h);
grpc_closure_init(&h->on_handshake_data_received_from_peer,
on_handshake_data_received_from_peer, h);
grpc_slice_buffer_init(&h->left_overs);
grpc_slice_buffer_init(&h->outgoing);
grpc_slice_buffer_init(&h->incoming);
if (read_buffer != NULL) {
grpc_slice_buffer_move_into(read_buffer, &h->incoming);
gpr_free(read_buffer);
}
if (!is_client_side) {
grpc_server_security_connector *server_connector =
(grpc_server_security_connector *)connector;
handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
handshake_node->handshake = h;
gpr_mu_lock(&server_connector->mu);
handshake_node->next = server_connector->handshaking_handshakes;
server_connector->handshaking_handshakes = handshake_node;
gpr_mu_unlock(&server_connector->mu);
}
send_handshake_bytes_to_peer(exec_ctx, h);
grpc_timer_init(exec_ctx, &h->timer,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC));
}
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
void *handshake) {
grpc_security_handshake *h = handshake;
grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
}

@ -46,8 +46,8 @@
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/transport/handshake.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/fake_transport_security.h"
@ -111,58 +111,34 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
return NULL;
}
void grpc_server_security_connector_shutdown(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
grpc_security_connector_handshake_list *tmp;
gpr_mu_lock(&connector->mu);
while (connector->handshaking_handshakes) {
tmp = connector->handshaking_handshakes;
grpc_security_handshake_shutdown(
exec_ctx, connector->handshaking_handshakes->handshake);
connector->handshaking_handshakes = tmp->next;
gpr_free(tmp);
void grpc_channel_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
grpc_handshake_manager *handshake_mgr) {
if (connector != NULL) {
connector->create_handshakers(exec_ctx, connector, handshake_mgr);
}
gpr_mu_unlock(&connector->mu);
}
void grpc_channel_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer,
gpr_timespec deadline, grpc_security_handshake_done_cb cb,
void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
gpr_free(read_buffer);
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, read_buffer, deadline,
cb, user_data);
}
}
void grpc_server_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
gpr_free(read_buffer);
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, read_buffer,
deadline, cb, user_data);
void grpc_server_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector,
grpc_handshake_manager *handshake_mgr) {
if (connector != NULL) {
connector->create_handshakers(exec_ctx, connector, handshake_mgr);
}
}
void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
tsi_peer peer,
grpc_security_peer_check_cb cb,
void *user_data) {
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked) {
if (sc == NULL) {
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
grpc_exec_ctx_sched(
exec_ctx, on_peer_checked,
GRPC_ERROR_CREATE("cannot check peer -- no security connector"), NULL);
tsi_peer_destruct(&peer);
} else {
sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data);
sc->vtable->check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
}
}
@ -195,8 +171,7 @@ grpc_security_connector *grpc_security_connector_ref(
}
#ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
const char *file, int line,
const char *reason) {
if (sc == NULL) return;
@ -204,8 +179,7 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
"SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
(int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
#else
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
if (sc == NULL) return;
#endif
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc);
@ -258,53 +232,47 @@ grpc_security_connector *grpc_find_security_connector_in_args(
/* -- Fake implementation. -- */
static void fake_channel_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
static void fake_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_call_credentials_unref(exec_ctx, c->request_metadata_creds);
gpr_free(sc);
}
static void fake_server_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
gpr_mu_destroy(&c->mu);
gpr_free(sc);
}
static void fake_server_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { gpr_free(sc); }
static void fake_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb, void *user_data) {
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked) {
const char *prop_name;
grpc_security_status status = GRPC_SECURITY_OK;
grpc_auth_context *auth_context = NULL;
grpc_error *error = GRPC_ERROR_NONE;
*auth_context = NULL;
if (peer.property_count != 1) {
gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
status = GRPC_SECURITY_ERROR;
error = GRPC_ERROR_CREATE("Fake peers should only have 1 property.");
goto end;
}
prop_name = peer.properties[0].name;
if (prop_name == NULL ||
strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
prop_name == NULL ? "<EMPTY>" : prop_name);
status = GRPC_SECURITY_ERROR;
char *msg;
gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
prop_name == NULL ? "<EMPTY>" : prop_name);
error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
goto end;
}
if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
peer.properties[0].value.length)) {
gpr_log(GPR_ERROR, "Invalid value for cert type property.");
status = GRPC_SECURITY_ERROR;
error = GRPC_ERROR_CREATE("Invalid value for cert type property.");
goto end;
}
auth_context = grpc_auth_context_create(NULL);
*auth_context = grpc_auth_context_create(NULL);
grpc_auth_context_add_cstring_property(
auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
*auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
end:
cb(exec_ctx, user_data, status, auth_context);
grpc_auth_context_unref(auth_context);
grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
@ -317,26 +285,20 @@ static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, GRPC_SECURITY_OK);
}
static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer,
gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
true, nonsecure_endpoint, read_buffer, deadline,
cb, user_data);
static void fake_channel_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_handshake_manager *handshake_mgr) {
grpc_security_create_handshakers(
exec_ctx, tsi_create_fake_handshaker(true /* is_client */), &sc->base,
handshake_mgr);
}
static void fake_server_do_handshake(
static void fake_server_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data) {
grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
false, nonsecure_endpoint, read_buffer, deadline,
cb, user_data);
grpc_handshake_manager *handshake_mgr) {
grpc_security_create_handshakers(
exec_ctx, tsi_create_fake_handshaker(false /* is_client */), &sc->base,
handshake_mgr);
}
static grpc_security_connector_vtable fake_channel_vtable = {
@ -354,7 +316,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
c->base.vtable = &fake_channel_vtable;
c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
c->check_call_host = fake_channel_check_call_host;
c->do_handshake = fake_channel_do_handshake;
c->create_handshakers = fake_channel_create_handshakers;
return c;
}
@ -366,8 +328,7 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create(
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->do_handshake = fake_server_do_handshake;
gpr_mu_init(&c->mu);
c->create_handshakers = fake_server_create_handshakers;
return c;
}
@ -385,8 +346,7 @@ typedef struct {
tsi_ssl_handshaker_factory *handshaker_factory;
} grpc_ssl_server_security_connector;
static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc;
grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
@ -398,15 +358,12 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
gpr_free(sc);
}
static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc) {
static void ssl_server_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
gpr_mu_destroy(&c->base.mu);
gpr_free(sc);
}
@ -425,49 +382,33 @@ static grpc_security_status ssl_create_handshaker(
return GRPC_SECURITY_OK;
}
static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer,
gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
static void ssl_channel_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_handshake_manager *handshake_mgr) {
grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc;
tsi_handshaker *handshaker;
grpc_security_status status = ssl_create_handshaker(
c->handshaker_factory, true,
c->overridden_target_name != NULL ? c->overridden_target_name
: c->target_name,
&handshaker);
if (status != GRPC_SECURITY_OK) {
gpr_free(read_buffer);
cb(exec_ctx, user_data, status, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
nonsecure_endpoint, read_buffer, deadline, cb,
user_data);
}
}
static void ssl_server_do_handshake(
// Instantiate TSI handshaker.
tsi_handshaker *tsi_hs = NULL;
ssl_create_handshaker(c->handshaker_factory, true /* is_client */,
c->overridden_target_name != NULL
? c->overridden_target_name
: c->target_name,
&tsi_hs);
// Create handshakers.
grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
}
static void ssl_server_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data) {
grpc_handshake_manager *handshake_mgr) {
grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
tsi_handshaker *handshaker;
grpc_security_status status =
ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
if (status != GRPC_SECURITY_OK) {
gpr_free(read_buffer);
cb(exec_ctx, user_data, status, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
nonsecure_endpoint, read_buffer, deadline, cb,
user_data);
}
// Instantiate TSI handshaker.
tsi_handshaker *tsi_hs = NULL;
ssl_create_handshaker(c->handshaker_factory, false /* is_client */,
NULL /* peer_name */, &tsi_hs);
// Create handshakers.
grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
}
static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
@ -524,57 +465,53 @@ grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
return ctx;
}
static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
const char *peer_name,
const tsi_peer *peer,
grpc_auth_context **auth_context) {
static grpc_error *ssl_check_peer(grpc_security_connector *sc,
const char *peer_name, const tsi_peer *peer,
grpc_auth_context **auth_context) {
/* Check the ALPN. */
const tsi_peer_property *p =
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
if (p == NULL) {
gpr_log(GPR_ERROR, "Missing selected ALPN property.");
return GRPC_SECURITY_ERROR;
return GRPC_ERROR_CREATE(
"Cannot check peer: missing selected ALPN property.");
}
if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
gpr_log(GPR_ERROR, "Invalid ALPN value.");
return GRPC_SECURITY_ERROR;
return GRPC_ERROR_CREATE("Cannot check peer: invalid ALPN value.");
}
/* Check the peer name if specified. */
if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR;
char *msg;
gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name);
grpc_error *error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
return error;
}
*auth_context = tsi_ssl_peer_to_auth_context(peer);
return GRPC_SECURITY_OK;
return GRPC_ERROR_NONE;
}
static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb,
void *user_data) {
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked) {
grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc;
grpc_security_status status;
grpc_auth_context *auth_context = NULL;
status = ssl_check_peer(sc, c->overridden_target_name != NULL
? c->overridden_target_name
: c->target_name,
&peer, &auth_context);
cb(exec_ctx, user_data, status, auth_context);
grpc_auth_context_unref(auth_context);
grpc_error *error = ssl_check_peer(sc, c->overridden_target_name != NULL
? c->overridden_target_name
: c->target_name,
&peer, auth_context);
grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb,
void *user_data) {
grpc_auth_context *auth_context = NULL;
grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked) {
grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context);
tsi_peer_destruct(&peer);
cb(exec_ctx, user_data, status, auth_context);
grpc_auth_context_unref(auth_context);
grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
}
static void add_shallow_auth_property_to_peer(tsi_peer *peer,
@ -724,8 +661,8 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
return GRPC_SLICE_LENGTH(default_pem_root_certs);
}
grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds,
grpc_security_status grpc_ssl_channel_security_connector_create(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
@ -771,7 +708,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host;
c->base.do_handshake = ssl_channel_do_handshake;
c->base.create_handshakers = ssl_channel_create_handshakers;
gpr_split_host_port(target_name, &c->target_name, &port);
gpr_free(port);
if (overridden_target_name != NULL) {
@ -802,8 +739,7 @@ error:
}
grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
grpc_server_security_connector **sc) {
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@ -847,8 +783,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
*sc = NULL;
goto error;
}
gpr_mu_init(&c->base.mu);
c->base.do_handshake = ssl_server_do_handshake;
c->base.create_handshakers = ssl_server_create_handshakers;
*sc = &c->base;
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);

@ -35,6 +35,8 @@
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
#include <grpc/grpc_security.h>
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/tsi/transport_security_interface.h"
@ -57,21 +59,11 @@ typedef struct grpc_security_connector grpc_security_connector;
#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx,
void *user_data,
grpc_security_status status,
grpc_auth_context *auth_context);
/* Ownership of the secure_endpoint is transfered. */
typedef void (*grpc_security_handshake_done_cb)(
grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status,
grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context);
typedef struct {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc);
void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
tsi_peer peer, grpc_security_peer_check_cb cb,
void *user_data);
tsi_peer peer, grpc_auth_context **auth_context,
grpc_closure *on_peer_checked);
} grpc_security_connector_vtable;
typedef struct grpc_security_connector_handshake_list {
@ -109,12 +101,12 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
#endif
/* Check the peer. Callee takes ownership of the peer object.
The callback will include the resulting auth_context. */
Sets *auth_context and invokes on_peer_checked when done. */
void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
tsi_peer peer,
grpc_security_peer_check_cb cb,
void *user_data);
grpc_auth_context **auth_context,
grpc_closure *on_peer_checked);
/* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
@ -144,11 +136,9 @@ struct grpc_channel_security_connector {
grpc_channel_security_connector *sc, const char *host,
grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data);
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_handshake_manager *handshake_mgr);
};
/* Checks that the host that will be set for a call is acceptable. */
@ -157,11 +147,10 @@ void grpc_channel_security_connector_check_call_host(
const char *host, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data);
/* Handshake. */
void grpc_channel_security_connector_do_handshake(
/* Registers handshakers with \a handshake_mgr. */
void grpc_channel_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer,
gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
grpc_handshake_manager *handshake_mgr);
/* --- server_security_connector object. ---
@ -172,25 +161,14 @@ typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector {
grpc_security_connector base;
gpr_mu mu;
grpc_security_connector_handshake_list *handshaking_handshakes;
const grpc_channel_args *channel_args;
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_handshake_manager *handshake_mgr);
};
void grpc_server_security_connector_do_handshake(
void grpc_server_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
void grpc_server_security_connector_shutdown(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
grpc_handshake_manager *handshake_mgr);
/* --- Creation security connectors. --- */

@ -0,0 +1,450 @@
/*
*
* 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/security/transport/security_handshaker.h"
#include <stdbool.h>
#include <string.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
#include "src/core/lib/security/transport/tsi_error.h"
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
typedef struct {
grpc_handshaker base;
// State set at creation time.
tsi_handshaker *handshaker;
grpc_security_connector *connector;
gpr_mu mu;
gpr_refcount refs;
bool shutdown;
// Endpoint and read buffer to destroy after a shutdown.
grpc_endpoint *endpoint_to_destroy;
grpc_slice_buffer *read_buffer_to_destroy;
// State saved while performing the handshake.
grpc_handshaker_args *args;
grpc_closure *on_handshake_done;
unsigned char *handshake_buffer;
size_t handshake_buffer_size;
grpc_slice_buffer left_overs;
grpc_slice_buffer outgoing;
grpc_closure on_handshake_data_sent_to_peer;
grpc_closure on_handshake_data_received_from_peer;
grpc_closure on_peer_checked;
grpc_auth_context *auth_context;
} security_handshaker;
static void security_handshaker_unref(grpc_exec_ctx *exec_ctx,
security_handshaker *h) {
if (gpr_unref(&h->refs)) {
gpr_mu_destroy(&h->mu);
tsi_handshaker_destroy(h->handshaker);
if (h->endpoint_to_destroy != NULL) {
grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy);
}
if (h->read_buffer_to_destroy != NULL) {
grpc_slice_buffer_destroy(h->read_buffer_to_destroy);
gpr_free(h->read_buffer_to_destroy);
}
gpr_free(h->handshake_buffer);
grpc_slice_buffer_destroy(&h->left_overs);
grpc_slice_buffer_destroy(&h->outgoing);
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, h->connector, "handshake");
gpr_free(h);
}
}
// Set args fields to NULL, saving the endpoint and read buffer for
// later destruction.
static void cleanup_args_for_failure_locked(grpc_exec_ctx *exec_ctx, security_handshaker *h) {
h->endpoint_to_destroy = h->args->endpoint;
h->args->endpoint = NULL;
h->read_buffer_to_destroy = h->args->read_buffer;
h->args->read_buffer = NULL;
grpc_channel_args_destroy(exec_ctx, h->args->args);
h->args->args = NULL;
}
// If the handshake failed or we're shutting down, clean up and invoke the
// callback with the error.
static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx,
security_handshaker *h,
grpc_error *error) {
if (error == GRPC_ERROR_NONE) {
// If we were shut down after the handshake succeeded but before an
// endpoint callback was invoked, we need to generate our own error.
error = GRPC_ERROR_CREATE("Handshaker shutdown");
}
const char *msg = grpc_error_string(error);
gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg);
grpc_error_free_string(msg);
if (!h->shutdown) {
// TODO(ctiller): It is currently necessary to shutdown endpoints
// before destroying them, even if we know that there are no
// pending read/write callbacks. This should be fixed, at which
// point this can be removed.
grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
// Not shutting down, so the write failed. Clean up before
// invoking the callback.
cleanup_args_for_failure_locked(exec_ctx, h);
}
// Invoke callback.
grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL);
}
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
security_handshaker *h = arg;
gpr_mu_lock(&h->mu);
if (error != GRPC_ERROR_NONE || h->shutdown) {
security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error));
goto done;
}
// Get frame protector.
tsi_frame_protector *protector;
tsi_result result =
tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
if (result != TSI_OK) {
error = grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Frame protector creation failed"), result);
security_handshake_failed_locked(exec_ctx, h, error);
goto done;
}
// Success.
// Create secure endpoint.
h->args->endpoint = grpc_secure_endpoint_create(
protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count);
h->left_overs.count = 0;
h->left_overs.length = 0;
// Clear out the read buffer before it gets passed to the transport,
// since any excess bytes were already copied to h->left_overs.
grpc_slice_buffer_reset_and_unref(h->args->read_buffer);
// Add auth context to channel args.
grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context);
grpc_channel_args *tmp_args = h->args->args;
h->args->args =
grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1);
grpc_channel_args_destroy(exec_ctx, tmp_args);
// Invoke callback.
grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE, NULL);
// Set shutdown to true so that subsequent calls to
// security_handshaker_shutdown() do nothing.
h->shutdown = true;
done:
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
}
static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx,
security_handshaker *h) {
tsi_peer peer;
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
if (result != TSI_OK) {
return grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Peer extraction failed"), result);
}
grpc_security_connector_check_peer(exec_ctx, h->connector, peer,
&h->auth_context, &h->on_peer_checked);
return GRPC_ERROR_NONE;
}
static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx,
security_handshaker *h) {
// Get data to send.
tsi_result result = TSI_OK;
size_t offset = 0;
do {
size_t to_send_size = h->handshake_buffer_size - offset;
result = tsi_handshaker_get_bytes_to_send_to_peer(
h->handshaker, h->handshake_buffer + offset, &to_send_size);
offset += to_send_size;
if (result == TSI_INCOMPLETE_DATA) {
h->handshake_buffer_size *= 2;
h->handshake_buffer =
gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
}
} while (result == TSI_INCOMPLETE_DATA);
if (result != TSI_OK) {
return grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Handshake failed"),
result);
}
// Send data.
grpc_slice to_send =
grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
grpc_slice_buffer_reset_and_unref(&h->outgoing);
grpc_slice_buffer_add(&h->outgoing, to_send);
grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing,
&h->on_handshake_data_sent_to_peer);
return GRPC_ERROR_NONE;
}
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
void *arg, grpc_error *error) {
security_handshaker *h = arg;
gpr_mu_lock(&h->mu);
if (error != GRPC_ERROR_NONE || h->shutdown) {
security_handshake_failed_locked(
exec_ctx, h,
GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1));
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
// Process received data.
tsi_result result = TSI_OK;
size_t consumed_slice_size = 0;
size_t i;
for (i = 0; i < h->args->read_buffer->count; i++) {
consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]);
result = tsi_handshaker_process_bytes_from_peer(
h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]),
&consumed_slice_size);
if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
}
if (tsi_handshaker_is_in_progress(h->handshaker)) {
/* We may need more data. */
if (result == TSI_INCOMPLETE_DATA) {
grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
&h->on_handshake_data_received_from_peer);
goto done;
} else {
error = send_handshake_bytes_to_peer_locked(exec_ctx, h);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
goto done;
}
}
if (result != TSI_OK) {
security_handshake_failed_locked(
exec_ctx, h, grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Handshake failed"), result));
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
/* Handshake is done and successful this point. */
bool has_left_overs_in_current_slice =
(consumed_slice_size <
GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]));
size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) +
h->args->read_buffer->count - i - 1;
if (num_left_overs > 0) {
/* Put the leftovers in our buffer (ownership transfered). */
if (has_left_overs_in_current_slice) {
grpc_slice_buffer_add(
&h->left_overs,
grpc_slice_split_tail(&h->args->read_buffer->slices[i],
consumed_slice_size));
/* split_tail above increments refcount. */
grpc_slice_unref(h->args->read_buffer->slices[i]);
}
grpc_slice_buffer_addn(
&h->left_overs, &h->args->read_buffer->slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice);
}
// Check peer.
error = check_peer_locked(exec_ctx, h);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
done:
gpr_mu_unlock(&h->mu);
}
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
security_handshaker *h = arg;
gpr_mu_lock(&h->mu);
if (error != GRPC_ERROR_NONE || h->shutdown) {
security_handshake_failed_locked(
exec_ctx, h,
GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1));
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
/* We may be done. */
if (tsi_handshaker_is_in_progress(h->handshaker)) {
grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
&h->on_handshake_data_received_from_peer);
} else {
error = check_peer_locked(exec_ctx, h);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
}
gpr_mu_unlock(&h->mu);
}
//
// public handshaker API
//
static void security_handshaker_destroy(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker) {
security_handshaker *h = (security_handshaker *)handshaker;
security_handshaker_unref(exec_ctx, h);
}
static void security_handshaker_shutdown(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker) {
security_handshaker *h = (security_handshaker *)handshaker;
gpr_mu_lock(&h->mu);
if (!h->shutdown) {
h->shutdown = true;
grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
cleanup_args_for_failure_locked(exec_ctx, h);
}
gpr_mu_unlock(&h->mu);
}
static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker,
grpc_tcp_server_acceptor *acceptor,
grpc_closure *on_handshake_done,
grpc_handshaker_args *args) {
security_handshaker *h = (security_handshaker *)handshaker;
gpr_mu_lock(&h->mu);
h->args = args;
h->on_handshake_done = on_handshake_done;
gpr_ref(&h->refs);
grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
return;
}
gpr_mu_unlock(&h->mu);
}
static const grpc_handshaker_vtable security_handshaker_vtable = {
security_handshaker_destroy, security_handshaker_shutdown,
security_handshaker_do_handshake};
static grpc_handshaker *security_handshaker_create(
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
grpc_security_connector *connector) {
security_handshaker *h = gpr_malloc(sizeof(security_handshaker));
memset(h, 0, sizeof(security_handshaker));
grpc_handshaker_init(&security_handshaker_vtable, &h->base);
h->handshaker = handshaker;
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
gpr_mu_init(&h->mu);
gpr_ref_init(&h->refs, 1);
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
grpc_closure_init(&h->on_handshake_data_sent_to_peer,
on_handshake_data_sent_to_peer, h);
grpc_closure_init(&h->on_handshake_data_received_from_peer,
on_handshake_data_received_from_peer, h);
grpc_closure_init(&h->on_peer_checked, on_peer_checked, h);
grpc_slice_buffer_init(&h->left_overs);
grpc_slice_buffer_init(&h->outgoing);
return &h->base;
}
//
// fail_handshaker
//
static void fail_handshaker_destroy(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker) {
gpr_free(handshaker);
}
static void fail_handshaker_shutdown(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker) {}
static void fail_handshaker_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_handshaker *handshaker,
grpc_tcp_server_acceptor *acceptor,
grpc_closure *on_handshake_done,
grpc_handshaker_args *args) {
grpc_exec_ctx_sched(exec_ctx, on_handshake_done,
GRPC_ERROR_CREATE("Failed to create security handshaker"),
NULL);
}
static const grpc_handshaker_vtable fail_handshaker_vtable = {
fail_handshaker_destroy, fail_handshaker_shutdown,
fail_handshaker_do_handshake};
static grpc_handshaker *fail_handshaker_create() {
grpc_handshaker *h = gpr_malloc(sizeof(*h));
grpc_handshaker_init(&fail_handshaker_vtable, h);
return h;
}
//
// exported functions
//
void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx,
tsi_handshaker *handshaker,
grpc_security_connector *connector,
grpc_handshake_manager *handshake_mgr) {
// If no TSI handshaker was created, add a handshaker that always fails.
// Otherwise, add a real security handshaker.
if (handshaker == NULL) {
grpc_handshake_manager_add(handshake_mgr, fail_handshaker_create());
} else {
grpc_handshake_manager_add(
handshake_mgr,
security_handshaker_create(exec_ctx, handshaker, connector));
}
}

@ -31,20 +31,17 @@
*
*/
#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H
#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/security/transport/security_connector.h"
/* Calls the callback upon completion. Takes owership of handshaker and
* read_buffer. */
void grpc_do_security_handshake(
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
grpc_security_connector *connector, bool is_client_side,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer,
gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
/// Creates any necessary security handshakers and adds them to
/// \a handshake_mgr.
void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx,
tsi_handshaker *handshaker,
grpc_security_connector *connector,
grpc_handshake_manager *handshake_mgr);
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H */
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */

@ -35,8 +35,10 @@
#include <grpc/support/useful.h>
void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
double multiplier, double jitter,
int64_t min_timeout_millis, int64_t max_timeout_millis) {
backoff->initial_connect_timeout = initial_connect_timeout;
backoff->multiplier = multiplier;
backoff->jitter = jitter;
backoff->min_timeout_millis = min_timeout_millis;
@ -45,9 +47,10 @@ void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
}
gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) {
backoff->current_timeout_millis = backoff->min_timeout_millis;
return gpr_time_add(
now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
backoff->current_timeout_millis = backoff->initial_connect_timeout;
const int64_t first_timeout =
GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
return gpr_time_add(now, gpr_time_from_millis(first_timeout, GPR_TIMESPAN));
}
/* Generate a random number between 0 and 1. */
@ -57,20 +60,28 @@ static double generate_uniform_random_number(uint32_t *rng_state) {
}
gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) {
double new_timeout_millis =
const double new_timeout_millis =
backoff->multiplier * (double)backoff->current_timeout_millis;
double jitter_range = backoff->jitter * new_timeout_millis;
double jitter =
backoff->current_timeout_millis =
GPR_MIN((int64_t)new_timeout_millis, backoff->max_timeout_millis);
const double jitter_range_width = backoff->jitter * new_timeout_millis;
const double jitter =
(2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
jitter_range;
jitter_range_width;
backoff->current_timeout_millis =
GPR_CLAMP((int64_t)(new_timeout_millis + jitter),
backoff->min_timeout_millis, backoff->max_timeout_millis);
return gpr_time_add(
(int64_t)((double)(backoff->current_timeout_millis) + jitter);
const gpr_timespec current_deadline = gpr_time_add(
now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
const gpr_timespec min_deadline = gpr_time_add(
now, gpr_time_from_millis(backoff->min_timeout_millis, GPR_TIMESPAN));
return gpr_time_max(current_deadline, min_deadline);
}
void gpr_backoff_reset(gpr_backoff *backoff) {
// forces step() to return a timeout of min_timeout_millis
backoff->current_timeout_millis = 0;
backoff->current_timeout_millis = backoff->initial_connect_timeout;
}

@ -37,7 +37,9 @@
#include <grpc/support/time.h>
typedef struct {
/// const: multiplier between retry attempts
/// const: how long to wait after the first failure before retrying
int64_t initial_connect_timeout;
/// const: factor with which to multiply backoff after a failed retry
double multiplier;
/// const: amount to randomize backoffs
double jitter;
@ -54,7 +56,8 @@ typedef struct {
} gpr_backoff;
/// Initialize backoff machinery - does not need to be destroyed
void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
double multiplier, double jitter,
int64_t min_timeout_millis, int64_t max_timeout_millis);
/// Begin retry loop: returns a timespec for the NEXT retry

@ -1557,6 +1557,10 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
/* IF this is a server, then GRPC_OP_RECV_INITIAL_METADATA *must* come
from server.c. In that case, it's coming from accept_stream, and in
that case we're not necessarily covered by a poller. */
stream_op->covered_by_poller = call->is_client;
call->received_initial_metadata = 1;
call->buffered_metadata[0] = op->data.recv_initial_metadata;
grpc_closure_init(&call->receiving_initial_metadata_ready,

@ -43,11 +43,21 @@ namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {}
CompletionQueue::CompletionQueue(grpc_completion_queue* take) : cq_(take) {
InitialAvalanching();
}
void CompletionQueue::Shutdown() {
g_gli_initializer.summon();
grpc_completion_queue_shutdown(cq_);
CompleteAvalanching();
}
void CompletionQueue::CompleteAvalanching() {
// Check if this was the last avalanching operation
if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_,
static_cast<gpr_atm>(-1)) == 1) {
grpc_completion_queue_shutdown(cq_);
}
}
CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(

@ -510,12 +510,6 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
ShutdownTag shutdown_tag; // Dummy shutdown tag
grpc_server_shutdown_and_notify(server_, shutdown_cq.cq(), &shutdown_tag);
// Shutdown all ThreadManagers. This will try to gracefully stop all the
// threads in the ThreadManagers (once they process any inflight requests)
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Shutdown(); // ThreadManager's Shutdown()
}
shutdown_cq.Shutdown();
void* tag;
@ -531,6 +525,12 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
// Else in case of SHUTDOWN or GOT_EVENT, it means that the server has
// successfully shutdown
// Shutdown all ThreadManagers. This will try to gracefully stop all the
// threads in the ThreadManagers (once they process any inflight requests)
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Shutdown(); // ThreadManager's Shutdown()
}
// Wait for threads in all ThreadManagers to terminate
for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) {
(*it)->Wait();
@ -575,9 +575,14 @@ ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
tag_(tag),
delete_on_finalize_(delete_on_finalize),
call_(nullptr) {
call_cq_->RegisterAvalanching(); // This op will trigger more ops
memset(&initial_metadata_array_, 0, sizeof(initial_metadata_array_));
}
ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() {
call_cq_->CompleteAvalanching();
}
bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
bool* status) {
if (*status) {

@ -87,7 +87,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Auth.nuspec" />
<None Include="Grpc.Auth.project.json" />
<None Include="packages.config" />
</ItemGroup>

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>Grpc.Auth</id>
<title>gRPC C# Auth</title>
<summary>Auth library for C# implementation of gRPC - an RPC library and framework</summary>
<description>Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Release $version$ of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
<dependencies>
<dependency id="Google.Apis.Auth" version="1.15.0" />
<dependency id="Grpc.Core" version="$version$" />
</dependencies>
</metadata>
<files>
<file src="bin/ReleaseSigned/Grpc.Auth.dll" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Auth.pdb" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Auth.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>

@ -67,6 +67,9 @@ namespace Grpc.Core.Tests
var credentials = new FakeCallCredentials();
Assert.AreSame(credentials, options.WithCredentials(credentials).Credentials);
var flags = CallFlags.WaitForReady | CallFlags.CacheableRequest;
Assert.AreEqual(flags, options.WithFlags(flags).Flags);
// Check that the original instance is unchanged.
Assert.IsNull(options.Headers);
Assert.IsNull(options.Deadline);
@ -74,6 +77,7 @@ namespace Grpc.Core.Tests
Assert.IsNull(options.WriteOptions);
Assert.IsNull(options.PropagationToken);
Assert.IsNull(options.Credentials);
Assert.AreEqual(default(CallFlags), options.Flags);
}
[Test]
@ -94,5 +98,16 @@ namespace Grpc.Core.Tests
Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken);
Assert.Throws(typeof(ArgumentException), () => new CallOptions(cancellationToken: token, propagationToken: propagationToken2).Normalize());
}
[Test]
public void WaitForReady()
{
var callOptions = new CallOptions();
Assert.IsFalse(callOptions.IsWaitForReady);
Assert.AreEqual(CallFlags.WaitForReady, callOptions.WithWaitForReady().Flags);
Assert.IsTrue(callOptions.WithWaitForReady().IsWaitForReady);
Assert.IsFalse(callOptions.WithWaitForReady(true).WithWaitForReady(false).IsWaitForReady);
}
}
}

@ -115,27 +115,27 @@ namespace Grpc.Core.Internal.Tests
return "PEER";
}
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
}
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
throw new NotImplementedException();
}
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
}
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
}
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
}

@ -50,6 +50,7 @@ namespace Grpc.Core
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
CallCredentials credentials;
CallFlags flags;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@ -69,6 +70,7 @@ namespace Grpc.Core
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
this.credentials = credentials;
this.flags = default(CallFlags);
}
/// <summary>
@ -125,6 +127,24 @@ namespace Grpc.Core
get { return this.credentials; }
}
/// <summary>
/// If <c>true</c> and and channel is in <c>ChannelState.TransientFailure</c>, the call will attempt waiting for the channel to recover
/// instead of failing immediately (which is the default "FailFast" semantics).
/// Note: experimental API that can change or be removed without any prior notice.
/// </summary>
public bool IsWaitForReady
{
get { return (this.flags & CallFlags.WaitForReady) == CallFlags.WaitForReady; }
}
/// <summary>
/// Flags to use for this call.
/// </summary>
internal CallFlags Flags
{
get { return this.flags; }
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
@ -197,6 +217,32 @@ namespace Grpc.Core
return newOptions;
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with "WaitForReady" semantics enabled/disabled.
/// <see cref="IsWaitForReady"/>.
/// Note: experimental API that can change or be removed without any prior notice.
/// </summary>
public CallOptions WithWaitForReady(bool waitForReady = true)
{
if (waitForReady)
{
return WithFlags(this.flags | CallFlags.WaitForReady);
}
return WithFlags(this.flags & ~CallFlags.WaitForReady);
}
/// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Flags</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
/// <param name="flags">The call flags.</param>
internal CallOptions WithFlags(CallFlags flags)
{
var newOptions = this;
newOptions.flags = flags;
return newOptions;
}
/// <summary>
/// Returns a new instance of <see cref="CallOptions"/> with
/// all previously unset values set to their defaults and deadline and cancellation

@ -140,9 +140,9 @@
<Compile Include="Logging\LogLevelFilterLogger.cs" />
<Compile Include="Internal\RequestCallContextSafeHandle.cs" />
<Compile Include="Utils\TaskUtils.cs" />
<Compile Include="Internal\CallFlags.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
<None Include="Grpc.Core.project.json" />
<None Include="packages.config" />
</ItemGroup>
@ -154,4 +154,4 @@
<Link>roots.pem</Link>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>Grpc.Core</id>
<title>gRPC C# Core</title>
<summary>Core C# implementation of gRPC - an RPC library and framework</summary>
<description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Release $version$ of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="System.Interactive.Async" version="3.1.1" />
</dependencies>
</metadata>
<files>
<file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
<file src="Grpc.Core.targets" target="\build\net45\Grpc.Core.targets" />
<!-- without backslashes in the the source path, nuget won't copy the files -->
<file src="..\nativelibs\windows_x86\grpc_csharp_ext.dll" target="/runtimes/win/native/grpc_csharp_ext.x86.dll" />
<file src="..\nativelibs\windows_x64\grpc_csharp_ext.dll" target="/runtimes/win/native/grpc_csharp_ext.x64.dll" />
<file src="..\nativelibs\linux_x86\libgrpc_csharp_ext.so" target="/runtimes/linux/native/libgrpc_csharp_ext.x86.so" />
<file src="..\nativelibs\linux_x64\libgrpc_csharp_ext.so" target="/runtimes/linux/native/libgrpc_csharp_ext.x64.so" />
<file src="..\nativelibs\macosx_x86\libgrpc_csharp_ext.dylib" target="/runtimes/osx/native/libgrpc_csharp_ext.x86.dylib" />
<file src="..\nativelibs\macosx_x64\libgrpc_csharp_ext.dylib" target="/runtimes/osx/native/libgrpc_csharp_ext.x64.dylib" />
</files>
</package>

@ -106,7 +106,7 @@ namespace Grpc.Core.Internal
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
using (var ctx = BatchContextSafeHandle.Create())
{
call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall());
call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
var ev = cq.Pluck(ctx.Handle);
@ -150,7 +150,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartUnary(HandleUnaryResponse, payload, metadataArray, GetWriteFlagsForCall());
call.StartUnary(HandleUnaryResponse, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
}
@ -174,7 +174,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartClientStreaming(HandleUnaryResponse, metadataArray);
call.StartClientStreaming(HandleUnaryResponse, metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
@ -200,7 +200,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall());
call.StartServerStreaming(HandleFinished, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
}
@ -222,7 +222,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
call.StartDuplexStreaming(HandleFinished, metadataArray);
call.StartDuplexStreaming(HandleFinished, metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
}

@ -0,0 +1,60 @@
#region Copyright notice and license
// 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.
#endregion
using System;
namespace Grpc.Core.Internal
{
/// <summary>
/// Flags to enable special call behaviors (client-side only).
/// </summary>
[Flags]
internal enum CallFlags
{
/// <summary>
/// The call is idempotent (retrying the call doesn't change the outcome of the operation).
/// </summary>
IdempotentRequest = 0x10,
/// <summary>
/// If channel is in <c>ChannelState.TransientFailure</c>, attempt waiting for the channel to recover
/// instead of failing the call immediately.
/// </summary>
WaitForReady = 0x20,
/// <summary>
/// The call is cacheable. gRPC is free to use GET verb */
/// </summary>
CacheableRequest = 0x40
}
}

@ -63,50 +63,50 @@ namespace Grpc.Core.Internal
Native.grpcsharp_call_set_credentials(this, credentials).CheckOk();
}
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags)
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
.CheckOk();
}
}
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags)
Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
.CheckOk();
}
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk();
Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags).CheckOk();
}
}
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}

@ -31,6 +31,7 @@
#endregion
using System;
using Grpc.Core;
namespace Grpc.Core.Internal
{
@ -54,19 +55,19 @@ namespace Grpc.Core.Internal
{
void Cancel();
void CancelWithStatus(Grpc.Core.Status status);
void CancelWithStatus(Status status);
string GetPeer();
void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray);
void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray);
void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartReceiveMessage(ReceivedMessageHandler callback);
@ -74,11 +75,11 @@ namespace Grpc.Core.Internal
void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray);
void StartSendMessage(SendCompletionHandler callback, byte[] payload, Grpc.Core.WriteFlags writeFlags, bool sendEmptyInitialMetadata);
void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
void StartSendCloseFromClient(SendCompletionHandler callback);
void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, Grpc.Core.WriteFlags writeFlags);
void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
void StartServerSide(ReceivedCloseOnServerHandler callback);
}

@ -325,14 +325,14 @@ namespace Grpc.Core.Internal
public delegate CallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
public delegate CallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags,
MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -62,13 +62,12 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.HealthCheck.nuspec" />
<None Include="Grpc.HealthCheck.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
</ItemGroup>

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>Grpc.HealthCheck</id>
<title>gRPC C# Healthchecking</title>
<summary>Implementation of gRPC health service</summary>
<description>Example implementation of grpc.health.v1 service that can be used for health-checking.</description>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC health check</tags>
<dependencies>
<dependency id="Google.Protobuf" version="$ProtobufVersion$" />
<dependency id="Grpc.Core" version="$version$" />
<dependency id="System.Interactive.Async" version="3.1.1" />
</dependencies>
</metadata>
<files>
<file src="bin/ReleaseSigned/Grpc.HealthCheck.dll" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.HealthCheck.pdb" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.HealthCheck.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -63,13 +63,12 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Reflection.nuspec" />
<None Include="Grpc.Reflection.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
<Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
</ItemGroup>

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>Grpc.Reflection</id>
<title>gRPC C# Reflection</title>
<summary>Implementation of gRPC reflection service</summary>
<description>Provides information about services running on a gRPC C# server.</description>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<copyright>Copyright 2016, Google Inc.</copyright>
<tags>gRPC reflection</tags>
<dependencies>
<dependency id="Google.Protobuf" version="$ProtobufVersion$" />
<dependency id="Grpc.Core" version="$version$" />
<dependency id="System.Interactive.Async" version="3.1.1" />
</dependencies>
</metadata>
<files>
<file src="bin/ReleaseSigned/Grpc.Reflection.dll" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Reflection.pdb" target="lib/net45" />
<file src="bin/ReleaseSigned/Grpc.Reflection.xml" target="lib/net45" />
<file src="**\*.cs" target="src" />
</files>
</package>

@ -1,91 +0,0 @@
@rem Copyright 2016, Google Inc.
@rem All rights reserved.
@rem
@rem Redistribution and use in source and binary forms, with or without
@rem modification, are permitted provided that the following conditions are
@rem met:
@rem
@rem * Redistributions of source code must retain the above copyright
@rem notice, this list of conditions and the following disclaimer.
@rem * Redistributions in binary form must reproduce the above
@rem copyright notice, this list of conditions and the following disclaimer
@rem in the documentation and/or other materials provided with the
@rem distribution.
@rem * Neither the name of Google Inc. nor the names of its
@rem contributors may be used to endorse or promote products derived from
@rem this software without specific prior written permission.
@rem
@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Builds gRPC NuGet packages
@rem This way of building nuget packages is now obsolete. C# nuget packages
@rem with CoreCLR support are now being built using the dotnet cli
@rem in build_packages_dotnetcli.sh
@rem Current package versions
set VERSION=1.1.0-dev
set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
@rem Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this?
xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86\
xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64\
xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86\
xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64\
xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86\
xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64\
@rem Collect protoc artifacts built by the previous build step
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x64\
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x64\
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64\
@rem Fetch all dependencies
%NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
setlocal
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
@rem We won't use the native libraries from this step, but without this Grpc.sln will fail.
msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error
msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
endlocal
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\
@rem create a zipfile with the artifacts as well
powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_obsolete.zip');"
xcopy /Y /I csharp_nugets_obsolete.zip ..\..\artifacts\
goto :EOF
:error
echo Failed!
exit /b %errorlevel%

@ -28,7 +28,7 @@
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Current package versions
set VERSION=1.0.1
set VERSION=1.1.0-dev
set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe
@ -61,9 +61,10 @@ xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* pr
%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
%NUGET% pack Grpc.nuspec -Version "1.0.1" -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version "1.0.1" -OutputDirectory ..\..\artifacts
%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error

@ -63,6 +63,7 @@ dotnet restore .
dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
nuget pack Grpc.nuspec -Version "1.1.0-dev" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "1.1.0-dev" -OutputDirectory ../../artifacts

@ -521,8 +521,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
const char *send_buffer, size_t send_buffer_len,
grpc_metadata_array *initial_metadata, uint32_t write_flags) {
const char *send_buffer, size_t send_buffer_len, uint32_t write_flags,
grpc_metadata_array *initial_metadata, uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[6];
memset(ops, 0, sizeof(ops));
@ -532,7 +532,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
@ -575,7 +575,8 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_client_streaming(grpc_call *call,
grpcsharp_batch_context *ctx,
grpc_metadata_array *initial_metadata) {
grpc_metadata_array *initial_metadata,
uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[4];
memset(ops, 0, sizeof(ops));
@ -585,7 +586,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
@ -617,7 +618,8 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer,
size_t send_buffer_len, grpc_metadata_array *initial_metadata, uint32_t write_flags) {
size_t send_buffer_len, uint32_t write_flags,
grpc_metadata_array *initial_metadata, uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[4];
memset(ops, 0, sizeof(ops));
@ -627,7 +629,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
@ -660,7 +662,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_duplex_streaming(grpc_call *call,
grpcsharp_batch_context *ctx,
grpc_metadata_array *initial_metadata) {
grpc_metadata_array *initial_metadata,
uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[2];
memset(ops, 0, sizeof(ops));
@ -670,7 +673,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
ops[0].flags = 0;
ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;

@ -112,7 +112,7 @@
}
- (void)dealloc {
gpr_free(_op.data.send_message);
grpc_byte_buffer_destroy(_op.data.send_message);
}
@end

@ -43,6 +43,8 @@
#import <RxLibrary/GRXWriteable.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#define TEST_TIMEOUT 16
static NSString * const kHostAddress = @"localhost:5050";
static NSString * const kPackage = @"grpc.testing";
static NSString * const kService = @"TestService";
@ -137,7 +139,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:4 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testEmptyRPC {
@ -159,7 +161,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testSimpleProtoRPC {
@ -191,7 +193,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testMetadata {
@ -225,7 +227,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:4 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponseMetadataKVO {
@ -256,7 +258,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testUserAgentPrefix {
@ -287,7 +289,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
// TODO(makarandd): Move to a different file that contains only unit tests
@ -347,7 +349,7 @@ static GRPCProtoMethod *kUnaryCallMethod;
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -46,6 +46,8 @@
#import <RxLibrary/GRXBufferedPipe.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#define TEST_TIMEOUT 32
// Convenience constructors for the generated proto messages:
@interface RMTStreamingOutputCallRequest (Constructors)
@ -124,7 +126,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:4 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testLargeUnaryRPC {
@ -147,7 +149,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)test4MBResponsesAreAccepted {
@ -164,7 +166,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOverMaxSizeFailWithActionableMessage {
@ -185,7 +187,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testResponsesOver4MBAreAcceptedIfOptedIn {
@ -205,7 +207,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:16 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testClientStreamingRPC {
@ -238,7 +240,7 @@
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testServerStreamingRPC {
@ -275,7 +277,7 @@
}
}];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testPingPongRPC {
@ -319,7 +321,7 @@
[expectation fulfill];
}
}];
[self waitForExpectationsWithTimeout:4 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
#ifndef GRPC_COMPILE_WITH_CRONET
@ -335,7 +337,7 @@
XCTAssert(done, @"Unexpected response: %@", response);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:2 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
#endif
@ -361,7 +363,7 @@
[call cancel];
XCTAssertEqual(call.state, GRXWriterStateFinished);
[self waitForExpectationsWithTimeout:1 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testCancelAfterFirstResponseRPC {
@ -396,7 +398,7 @@
}
}];
[call start];
[self waitForExpectationsWithTimeout:8 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
- (void)testRPCAfterClosingOpenConnections {
@ -420,7 +422,7 @@
}];
}];
[self waitForExpectationsWithTimeout:4 handler:nil];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end

@ -84,9 +84,9 @@ post_install do |installer|
end
# CocoaPods creates duplicated library targets of gRPC-Core when the test targets include
# non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core.'
# non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core'
# and require the same error suppresion.
if target.name == 'gRPC-Core' or target.name.start_with?('gRPC-Core.')
if target.name.start_with?('gRPC-Core')
target.build_configurations.each do |config|
# TODO(zyc): Remove this setting after the issue is resolved
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void

@ -99,7 +99,7 @@ class ChannelTest extends PHPUnit_Framework_TestCase
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$time = new Grpc\Timeval(1000);
$state = $this->channel->watchConnectivityState(123, $time);
$state = $this->channel->watchConnectivityState(1, $time);
$this->assertTrue($state);
unset($time);
}

@ -67,9 +67,9 @@ class ServerTest extends PHPUnit_Framework_TestCase
public function testRequestCall()
{
$this->server = new Grpc\Server();
$port = $this->server->addHttp2Port('0.0.0.0:8888');
$port = $this->server->addHttp2Port('0.0.0.0:0');
$this->server->start();
$channel = new Grpc\Channel('localhost:8888',
$channel = new Grpc\Channel('localhost:' . $port,
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$deadline = Grpc\Timeval::infFuture();

@ -904,6 +904,21 @@ class Server(six.with_metaclass(abc.ABCMeta)):
"""
raise NotImplementedError()
@abc.abstractmethod
def add_shutdown_handler(self, shutdown_handler):
"""Adds a handler to be called on server shutdown.
Shutdown handlers are run on server stop() or in the event that a running
server is destroyed unexpectedly. The handlers are run in series before
the stop grace period.
Args:
shutdown_handler: A function taking a single arg, a time in seconds
within which the handler should complete. None indicates the handler can
run for any duration.
"""
raise NotImplementedError()
@abc.abstractmethod
def start(self):
"""Starts this Server's service of RPCs.
@ -914,7 +929,7 @@ class Server(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
def stop(self, grace):
def stop(self, grace, shutdown_handler_grace=None):
"""Stops this Server's service of RPCs.
All calls to this method immediately stop service of new RPCs. When existing
@ -937,6 +952,8 @@ class Server(six.with_metaclass(abc.ABCMeta)):
aborted by this Server's stopping. If None, all RPCs will be aborted
immediately and this method will block until this Server is completely
stopped.
shutdown_handler_grace: A duration of time in seconds or None. This
value is passed to all shutdown handlers.
Returns:
A threading.Event that will be set when this Server has completely
@ -1231,7 +1248,8 @@ def secure_channel(target, credentials, options=None):
credentials._credentials)
def server(thread_pool, handlers=None, options=None):
def server(thread_pool, handlers=None, options=None, exit_grace=None,
exit_shutdown_handler_grace=None):
"""Creates a Server with which RPCs can be serviced.
Args:
@ -1244,13 +1262,19 @@ def server(thread_pool, handlers=None, options=None):
returned Server is started.
options: A sequence of string-value pairs according to which to configure
the created server.
exit_grace: The grace period to use when terminating
running servers at interpreter exit. None indicates unspecified.
exit_shutdown_handler_grace: The shutdown handler grace to use when
terminating running servers at interpreter exit. None indicates
unspecified.
Returns:
A Server with which RPCs can be serviced.
"""
from grpc import _server
return _server.Server(thread_pool, () if handlers is None else handlers,
() if options is None else options)
() if options is None else options, exit_grace,
exit_shutdown_handler_grace)
################################### __all__ #################################

@ -60,7 +60,8 @@ _CANCELLED = 'cancelled'
_EMPTY_FLAGS = 0
_EMPTY_METADATA = cygrpc.Metadata(())
_UNEXPECTED_EXIT_SERVER_GRACE = 1.0
_DEFAULT_EXIT_GRACE = 1.0
_DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE = 5.0
def _serialized_request(request_event):
@ -595,14 +596,18 @@ class _ServerStage(enum.Enum):
class _ServerState(object):
def __init__(self, completion_queue, server, generic_handlers, thread_pool):
def __init__(self, completion_queue, server, generic_handlers, thread_pool,
exit_grace, exit_shutdown_handler_grace):
self.lock = threading.Lock()
self.completion_queue = completion_queue
self.server = server
self.generic_handlers = list(generic_handlers)
self.thread_pool = thread_pool
self.exit_grace = exit_grace
self.exit_shutdown_handler_grace = exit_shutdown_handler_grace
self.stage = _ServerStage.STOPPED
self.shutdown_events = None
self.shutdown_handlers = []
# TODO(https://github.com/grpc/grpc/issues/6597): eliminate these fields.
self.rpc_states = set()
@ -672,41 +677,45 @@ def _serve(state):
return
def _stop(state, grace):
with state.lock:
if state.stage is _ServerStage.STOPPED:
shutdown_event = threading.Event()
shutdown_event.set()
return shutdown_event
else:
if state.stage is _ServerStage.STARTED:
state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG)
def _stop(state, grace, shutdown_handler_grace):
shutdown_event = threading.Event()
def cancel_all_calls_after_grace():
with state.lock:
if state.stage is _ServerStage.STOPPED:
shutdown_event.set()
return
elif state.stage is _ServerStage.STARTED:
do_shutdown = True
state.stage = _ServerStage.GRACE
state.shutdown_events = []
state.due.add(_SHUTDOWN_TAG)
shutdown_event = threading.Event()
else:
do_shutdown = False
state.shutdown_events.append(shutdown_event)
if grace is None:
if do_shutdown:
# Run Shutdown Handlers without the lock
for handler in state.shutdown_handlers:
handler(shutdown_handler_grace)
with state.lock:
state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG)
state.stage = _ServerStage.GRACE
state.due.add(_SHUTDOWN_TAG)
if not shutdown_event.wait(timeout=grace):
with state.lock:
state.server.cancel_all_calls()
# TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
for rpc_state in state.rpc_states:
with rpc_state.condition:
rpc_state.client = _CANCELLED
rpc_state.condition.notify_all()
else:
def cancel_all_calls_after_grace():
shutdown_event.wait(timeout=grace)
with state.lock:
state.server.cancel_all_calls()
# TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
for rpc_state in state.rpc_states:
with rpc_state.condition:
rpc_state.client = _CANCELLED
rpc_state.condition.notify_all()
thread = threading.Thread(target=cancel_all_calls_after_grace)
thread.start()
return shutdown_event
shutdown_event.wait()
if grace is None:
cancel_all_calls_after_grace()
else:
threading.Thread(target=cancel_all_calls_after_grace).start()
return shutdown_event
@ -716,12 +725,12 @@ def _start(state):
raise ValueError('Cannot start already-started server!')
state.server.start()
state.stage = _ServerStage.STARTED
_request_call(state)
_request_call(state)
def cleanup_server(timeout):
if timeout is None:
_stop(state, _UNEXPECTED_EXIT_SERVER_GRACE).wait()
_stop(state, state.exit_grace, state.exit_shutdown_handler_grace).wait()
else:
_stop(state, timeout).wait()
_stop(state, timeout, 0).wait()
thread = _common.CleanupThread(
cleanup_server, target=_serve, args=(state,))
@ -729,12 +738,16 @@ def _start(state):
class Server(grpc.Server):
def __init__(self, thread_pool, generic_handlers, options):
def __init__(self, thread_pool, generic_handlers, options, exit_grace,
exit_shutdown_handler_grace):
completion_queue = cygrpc.CompletionQueue()
server = cygrpc.Server(_common.channel_args(options))
server.register_completion_queue(completion_queue)
self._state = _ServerState(
completion_queue, server, generic_handlers, thread_pool)
completion_queue, server, generic_handlers, thread_pool,
_DEFAULT_EXIT_GRACE if exit_grace is None else exit_grace,
_DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE if exit_shutdown_handler_grace
is None else exit_shutdown_handler_grace)
def add_generic_rpc_handlers(self, generic_rpc_handlers):
_add_generic_handlers(self._state, generic_rpc_handlers)
@ -745,11 +758,14 @@ class Server(grpc.Server):
def add_secure_port(self, address, server_credentials):
return _add_secure_port(self._state, _common.encode(address), server_credentials)
def add_shutdown_handler(self, handler):
self._state.shutdown_handlers.append(handler)
def start(self):
_start(self._state)
def stop(self, grace):
return _stop(self._state, grace)
def stop(self, grace, shutdown_handler_grace=None):
return _stop(self._state, grace, shutdown_handler_grace)
def __del__(self):
_stop(self._state, None)
_stop(self._state, None, None)

@ -226,9 +226,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_credentials.c',
'src/core/lib/security/transport/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.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',
@ -237,6 +237,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/tsi/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/transport_security.c',
'src/core/ext/transport/chttp2/server/chttp2_server.c',
'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.c',
@ -256,6 +257,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c',
'src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c',

@ -167,7 +167,7 @@ class SameSeparateTest(unittest.TestCase, SeparateTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
'--grpc_python_out={}'.format(self.grpc_python_out_directory),
'--grpc_python_out=grpc_2_0:{}'.format(self.grpc_python_out_directory),
same_proto_file,
])
if protoc_result != 0:
@ -241,7 +241,7 @@ class SplitCommonTest(unittest.TestCase, CommonTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
'--grpc_python_out={}'.format(self.python_out_directory),
'--grpc_python_out={}'.format(self.grpc_python_out_directory),
services_proto_file,
messages_proto_file,
])
@ -285,7 +285,7 @@ class SplitSeparateTest(unittest.TestCase, SeparateTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
'--grpc_python_out={}'.format(self.grpc_python_out_directory),
'--grpc_python_out=grpc_2_0:{}'.format(self.grpc_python_out_directory),
services_proto_file,
messages_proto_file,
])

@ -27,6 +27,7 @@
"unit._cython.cygrpc_test.TypeSmokeTest",
"unit._empty_message_test.EmptyMessageTest",
"unit._exit_test.ExitTest",
"unit._exit_test.ShutdownHandlerTest",
"unit._metadata_code_details_test.MetadataCodeDetailsTest",
"unit._metadata_test.MetadataTest",
"unit._rpc_test.RPCTest",

@ -43,6 +43,8 @@ import threading
import time
import unittest
import grpc
from grpc.framework.foundation import logging_pool
from tests.unit import _exit_scenarios
SCENARIO_FILE = os.path.abspath(os.path.join(
@ -52,7 +54,7 @@ BASE_COMMAND = [INTERPRETER, SCENARIO_FILE]
BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt']
INIT_TIME = 1.0
SHUTDOWN_GRACE = 5.0
processes = []
process_lock = threading.Lock()
@ -182,5 +184,24 @@ class ExitTest(unittest.TestCase):
interrupt_and_wait(process)
class _ShutDownHandler(object):
def __init__(self):
self.seen_handler_grace = None
def shutdown_handler(self, handler_grace):
self.seen_handler_grace = handler_grace
class ShutdownHandlerTest(unittest.TestCase):
def test_shutdown_handler(self):
server = grpc.server(logging_pool.pool(1))
handler = _ShutDownHandler()
server.add_shutdown_handler(handler.shutdown_handler)
server.start()
server.stop(0, shutdown_handler_grace=SHUTDOWN_GRACE).wait()
self.assertEqual(SHUTDOWN_GRACE, handler.seen_handler_grace)
if __name__ == '__main__':
unittest.main(verbosity=2)

@ -29,18 +29,17 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Builds gRPC NuGet packages
@rem This way of building nuget packages is now obsolete. C# nuget packages
@rem with CoreCLR support are now being built using the dotnet cli
@rem in build_packages_dotnetcli.sh
@rem Current package versions
set VERSION=${settings.csharp_version}
set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
set DOTNET=C:\dotnet\dotnet.exe
set -ex
mkdir -p ..\..\artifacts${"\\"}
@rem Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this?
@ -59,32 +58,22 @@
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86${"\\"}
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64${"\\"}
@rem Fetch all dependencies
%%NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
setlocal
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
@rem We won't use the native libraries from this step, but without this Grpc.sln will fail.
msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error
msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
%%DOTNET% restore . || goto :error
endlocal
%%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
%%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
%%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
%%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
%%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts${"\\"}
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
@rem create a zipfile with the artifacts as well
powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_obsolete.zip');"
xcopy /Y /I csharp_nugets_obsolete.zip ..\..\artifacts${"\\"}
powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_windows_dotnetcli.zip');"
xcopy /Y /I csharp_nugets_windows_dotnetcli.zip ..\..\artifacts\ || goto :error
goto :EOF

@ -65,6 +65,7 @@
dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
nuget pack Grpc.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts

@ -48,9 +48,12 @@
#======================================
# More sanity test dependencies (bazel)
RUN apt-get install -y openjdk-8-jdk
# TOOD(jtattermusch): pin the bazel version
RUN git clone https://github.com/bazelbuild/bazel.git /bazel
RUN cd /bazel && ./compile.sh
# Check out Bazel version 0.4.1 since this version allows running
# ./compile.sh without a local protoc dependency
# TODO(mattkwong): install dependencies to support latest Bazel version if newer
# version is needed
RUN git clone https://github.com/bazelbuild/bazel.git /bazel && \
cd /bazel && git checkout tags/0.4.1 && ./compile.sh
RUN ln -s /bazel/output/bazel /bin/
#===================

@ -64,9 +64,11 @@ typedef struct servers_fixture {
} servers_fixture;
typedef struct request_sequences {
size_t n;
int *connections;
int *connectivity_states;
size_t n; /* number of iterations */
int *connections; /* indexed by the interation number, value is the index of
the server it connected to or -1 if none */
int *connectivity_states; /* indexed by the interation number, value is the
client connectivity state */
} request_sequences;
typedef void (*verifier_fn)(const servers_fixture *, grpc_channel *,
@ -481,7 +483,7 @@ void run_spec(const test_spec *spec) {
gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str);
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff";
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = RETRY_TIMEOUT;
arg_array[1].type = GRPC_ARG_STRING;
arg_array[1].key = GRPC_ARG_LB_POLICY_NAME;
@ -519,7 +521,7 @@ static grpc_channel *create_client(const servers_fixture *f) {
gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str);
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff";
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = RETRY_TIMEOUT;
arg_array[1].type = GRPC_ARG_STRING;
arg_array[1].key = GRPC_ARG_LB_POLICY_NAME;
@ -784,15 +786,17 @@ static void verify_total_carnage_round_robin(const servers_fixture *f,
}
}
/* no server is ever available. The persistent state is TRANSIENT_FAILURE */
/* no server is ever available. The persistent state is TRANSIENT_FAILURE. May
* also be CONNECTING if, under load, this check took too long to run and some
* subchannel already transitioned to retrying. */
for (size_t i = 0; i < sequences->n; i++) {
const grpc_connectivity_state actual = sequences->connectivity_states[i];
const grpc_connectivity_state expected = GRPC_CHANNEL_TRANSIENT_FAILURE;
if (actual != expected) {
if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
actual != GRPC_CHANNEL_CONNECTING) {
gpr_log(GPR_ERROR,
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
"at iteration #%d",
grpc_connectivity_state_name(expected),
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
"GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
"'%s' at iteration #%d",
grpc_connectivity_state_name(actual), (int)i);
abort();
}
@ -829,8 +833,7 @@ static void verify_partial_carnage_round_robin(
}
/* We can assert that the first client channel state should be READY, when all
* servers were available; and that the last one should be TRANSIENT_FAILURE,
* after all servers are gone. */
* servers were available */
grpc_connectivity_state actual = sequences->connectivity_states[0];
grpc_connectivity_state expected = GRPC_CHANNEL_READY;
if (actual != expected) {
@ -842,17 +845,21 @@ static void verify_partial_carnage_round_robin(
abort();
}
/* ... and that the last one should be TRANSIENT_FAILURE, after all servers
* are gone. May also be CONNECTING if, under load, this check took too long
* to run and the subchannel already transitioned to retrying. */
actual = sequences->connectivity_states[num_iters - 1];
expected = GRPC_CHANNEL_TRANSIENT_FAILURE;
if (actual != expected) {
gpr_log(GPR_ERROR,
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' "
"at iteration #%d",
grpc_connectivity_state_name(expected),
grpc_connectivity_state_name(actual), (int)num_iters - 1);
abort();
for (i = 0; i < sequences->n; i++) {
if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
actual != GRPC_CHANNEL_CONNECTING) {
gpr_log(GPR_ERROR,
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
"GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
"'%s' at iteration #%d",
grpc_connectivity_state_name(actual), (int)i);
abort();
}
}
gpr_free(expected_connection_sequence);
}
@ -877,68 +884,21 @@ static void verify_rebirth_round_robin(const servers_fixture *f,
grpc_channel *client,
const request_sequences *sequences,
const size_t num_iters) {
int *expected_connection_sequence;
size_t i, j, unique_seq_last_idx, unique_seq_first_idx;
const size_t expected_seq_length = f->num_servers;
int *seen_elements;
dump_array("actual_connection_sequence", sequences->connections, num_iters);
/* verify conn. seq. expectation */
/* get the first unique run of length "num_servers". */
expected_connection_sequence = gpr_malloc(sizeof(int) * expected_seq_length);
seen_elements = gpr_malloc(sizeof(int) * expected_seq_length);
unique_seq_last_idx = ~(size_t)0;
memset(seen_elements, 0, sizeof(int) * expected_seq_length);
for (i = 0; i < num_iters; i++) {
if (sequences->connections[i] < 0 ||
seen_elements[sequences->connections[i]] != 0) {
/* if anything breaks the uniqueness of the run, back to square zero */
memset(seen_elements, 0, sizeof(int) * expected_seq_length);
continue;
}
seen_elements[sequences->connections[i]] = 1;
for (j = 0; j < expected_seq_length; j++) {
if (seen_elements[j] == 0) break;
}
if (j == expected_seq_length) { /* seen all the elements */
unique_seq_last_idx = i;
break;
}
}
/* make sure we found a valid run */
dump_array("seen_elements", seen_elements, expected_seq_length);
for (j = 0; j < expected_seq_length; j++) {
GPR_ASSERT(seen_elements[j] != 0);
}
GPR_ASSERT(unique_seq_last_idx != ~(size_t)0);
unique_seq_first_idx = (unique_seq_last_idx - expected_seq_length + 1);
memcpy(expected_connection_sequence,
sequences->connections + unique_seq_first_idx,
sizeof(int) * expected_seq_length);
/* first iteration succeeds */
GPR_ASSERT(sequences->connections[0] != -1);
/* then we fail for a while... */
GPR_ASSERT(sequences->connections[1] == -1);
/* ... but should be up at "unique_seq_first_idx" */
GPR_ASSERT(sequences->connections[unique_seq_first_idx] != -1);
for (j = 0, i = unique_seq_first_idx; i < num_iters; i++) {
const int actual = sequences->connections[i];
const int expected =
expected_connection_sequence[j++ % expected_seq_length];
if (actual != expected) {
print_failed_expectations(expected_connection_sequence,
sequences->connections, expected_seq_length,
num_iters);
abort();
/* ... but should be up eventually */
size_t first_iter_back_up = ~0ul;
for (size_t i = 2; i < sequences->n; ++i) {
if (sequences->connections[i] != -1) {
first_iter_back_up = i;
break;
}
}
GPR_ASSERT(first_iter_back_up != ~0ul);
/* We can assert that the first client channel state should be READY, when all
* servers were available; same thing for the last one. In the middle
@ -966,7 +926,7 @@ static void verify_rebirth_round_robin(const servers_fixture *f,
}
bool found_failure_status = false;
for (i = 1; i < sequences->n - 1; i++) {
for (size_t i = 1; i < sequences->n - 1; i++) {
if (sequences->connectivity_states[i] == GRPC_CHANNEL_TRANSIENT_FAILURE) {
found_failure_status = true;
break;
@ -978,14 +938,11 @@ static void verify_rebirth_round_robin(const servers_fixture *f,
"CONNECTIVITY STATUS SEQUENCE FAILURE: "
"GRPC_CHANNEL_TRANSIENT_FAILURE status not found. Got the following "
"instead:");
for (i = 0; i < num_iters; i++) {
for (size_t i = 0; i < num_iters; i++) {
gpr_log(GPR_ERROR, "[%d]: %s", (int)i,
grpc_connectivity_state_name(sequences->connectivity_states[i]));
}
}
gpr_free(expected_connection_sequence);
gpr_free(seen_elements);
}
int main(int argc, char **argv) {

@ -126,8 +126,16 @@ int main(int argc, char **argv) {
char *addr;
grpc_channel_args client_args;
grpc_arg arg_array[1];
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = 1000;
client_args.args = arg_array;
client_args.num_args = 1;
/* create a channel that picks first amongst the servers */
grpc_channel *chan = grpc_insecure_channel_create("test", NULL, NULL);
grpc_channel *chan = grpc_insecure_channel_create("test", &client_args, NULL);
/* and an initial call to them */
grpc_call *call1 = grpc_channel_create_call(
chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq, "/foo", "127.0.0.1",

@ -68,7 +68,15 @@ static void test_connectivity(grpc_end2end_test_config config) {
gpr_thd_options thdopt = gpr_thd_options_default();
gpr_thd_id thdid;
config.init_client(&f, NULL);
grpc_channel_args client_args;
grpc_arg arg_array[1];
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = 1000;
client_args.args = arg_array;
client_args.num_args = 1;
config.init_client(&f, &client_args);
ce.channel = f.client;
ce.cq = f.cq;

@ -126,7 +126,7 @@ static void request_response_with_payload(grpc_end2end_test_config config,
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer *response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_timespec deadline = five_seconds_time();
gpr_timespec deadline = n_seconds_time(60);
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_op ops[6];
grpc_op *op;

@ -200,21 +200,36 @@ static void simple_delayed_request_body(grpc_end2end_test_config config,
static void test_simple_delayed_request_short(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f;
grpc_channel_args client_args;
grpc_arg arg_array[1];
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = 1000;
client_args.args = arg_array;
client_args.num_args = 1;
gpr_log(GPR_INFO, "%s/%s", "test_simple_delayed_request_short", config.name);
f = config.create_fixture(NULL, NULL);
simple_delayed_request_body(config, &f, NULL, NULL, 100000);
simple_delayed_request_body(config, &f, &client_args, NULL, 100000);
end_test(&f);
config.tear_down_data(&f);
}
static void test_simple_delayed_request_long(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f;
grpc_channel_args client_args;
grpc_arg arg_array[1];
arg_array[0].type = GRPC_ARG_INTEGER;
arg_array[0].key = "grpc.testing.fixed_reconnect_backoff_ms";
arg_array[0].value.integer = 1000;
client_args.args = arg_array;
client_args.num_args = 1;
gpr_log(GPR_INFO, "%s/%s", "test_simple_delayed_request_long", config.name);
f = config.create_fixture(NULL, NULL);
/* This timeout should be longer than a single retry */
simple_delayed_request_body(config, &f, NULL, NULL, 1500000);
simple_delayed_request_body(config, &f, &client_args, NULL, 1500000);
end_test(&f);
config.tear_down_data(&f);
}

@ -58,17 +58,14 @@ struct handshake_state {
bool done_callback_called;
};
static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_security_status status,
grpc_endpoint *secure_endpoint,
grpc_auth_context *auth_context) {
struct handshake_state *state = (struct handshake_state *)statep;
static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_handshaker_args *args = arg;
struct handshake_state *state = args->user_data;
GPR_ASSERT(state->done_callback_called == false);
state->done_callback_called = true;
// The fuzzer should not pass the handshake.
GPR_ASSERT(status != GRPC_SECURITY_OK);
GPR_ASSERT(secure_endpoint == NULL);
GPR_ASSERT(auth_context == NULL);
GPR_ASSERT(error != GRPC_ERROR_NONE);
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@ -108,15 +105,17 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
grpc_security_status status =
grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
GPR_ASSERT(status == GRPC_SECURITY_OK);
sc->channel_args = NULL;
gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(1, GPR_TIMESPAN));
struct handshake_state state;
state.done_callback_called = false;
grpc_server_security_connector_do_handshake(&exec_ctx, sc, NULL,
mock_endpoint, NULL, deadline,
on_secure_handshake_done, &state);
grpc_handshake_manager *handshake_mgr = grpc_handshake_manager_create();
grpc_server_security_connector_create_handshakers(&exec_ctx, sc,
handshake_mgr);
grpc_handshake_manager_do_handshake(
&exec_ctx, handshake_mgr, mock_endpoint, NULL /* channel_args */,
deadline, NULL /* acceptor */, on_handshake_done, &state);
grpc_exec_ctx_flush(&exec_ctx);
// If the given string happens to be part of the correct client hello, the
@ -129,6 +128,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
GPR_ASSERT(state.done_callback_called);
grpc_handshake_manager_destroy(&exec_ctx, handshake_mgr);
GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "test");
grpc_server_credentials_release(creds);
grpc_slice_unref(cert_slice);

@ -39,61 +39,110 @@
static void test_constant_backoff(void) {
gpr_backoff backoff;
gpr_backoff_init(&backoff, 1.0, 0.0, 1000, 1000);
gpr_backoff_init(&backoff, 200 /* initial timeout */, 1.0 /* multiplier */,
0.0 /* jitter */, 100 /* min timeout */,
1000 /* max timeout */);
gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 1000);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
for (int i = 0; i < 10000; i++) {
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 1000);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
now = next;
}
}
static void test_no_jitter_backoff(void) {
static void test_min_connect(void) {
gpr_backoff backoff;
gpr_backoff_init(&backoff, 2.0, 0.0, 1, 513);
gpr_backoff_init(&backoff, 100 /* initial timeout */, 1.0 /* multiplier */,
0.0 /* jitter */, 200 /* min timeout */,
1000 /* max timeout */);
gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(3, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
}
static void test_no_jitter_backoff(void) {
gpr_backoff backoff;
gpr_backoff_init(&backoff, 2 /* initial timeout */, 2.0 /* multiplier */,
0.0 /* jitter */, 1 /* min timeout */,
513 /* max timeout */);
// x_1 = 2
// x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(7, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(6, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(15, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(14, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(31, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(30, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(63, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(62, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(127, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(126, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(255, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(254, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(511, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(510, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1023, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1022, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1536, GPR_TIMESPAN), next) == 0);
// Hit the maximum timeout. From this point onwards, retries will increase
// only by max timeout.
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1535, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2049, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2048, GPR_TIMESPAN), next) == 0);
now = next;
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2562, GPR_TIMESPAN), next) == 0);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(2561, GPR_TIMESPAN), next) == 0);
}
static void test_jitter_backoff(void) {
const int64_t initial_timeout = 500;
const double jitter = 0.1;
gpr_backoff backoff;
gpr_backoff_init(&backoff, initial_timeout, 1.0 /* multiplier */, jitter,
100 /* min timeout */, 1000 /* max timeout */);
backoff.rng_state = 0; // force consistent PRNG
gpr_timespec now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now);
GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 500);
int64_t expected_next_lower_bound =
(int64_t)((double)initial_timeout * (1 - jitter));
int64_t expected_next_upper_bound =
(int64_t)((double)initial_timeout * (1 + jitter));
for (int i = 0; i < 10000; i++) {
next = gpr_backoff_step(&backoff, now);
// next-now must be within (jitter*100)% of the previous timeout.
const int64_t timeout_millis = gpr_time_to_millis(gpr_time_sub(next, now));
GPR_ASSERT(timeout_millis >= expected_next_lower_bound);
GPR_ASSERT(timeout_millis <= expected_next_upper_bound);
expected_next_lower_bound =
(int64_t)((double)timeout_millis * (1 - jitter));
expected_next_upper_bound =
(int64_t)((double)timeout_millis * (1 + jitter));
now = next;
}
}
int main(int argc, char **argv) {
@ -101,7 +150,9 @@ int main(int argc, char **argv) {
gpr_time_init();
test_constant_backoff();
test_min_connect();
test_no_jitter_backoff();
test_jitter_backoff();
return 0;
}

@ -44,8 +44,11 @@
#include "test/core/util/test_config.h"
void test_unparsable_target(void) {
int port = grpc_server_add_insecure_http2_port(NULL, "[");
grpc_channel_args args = {0, NULL};
grpc_server *server = grpc_server_create(&args, NULL);
int port = grpc_server_add_insecure_http2_port(server, "[");
GPR_ASSERT(port == 0);
grpc_server_destroy(server);
}
void test_add_same_port_twice() {

@ -138,7 +138,7 @@ TEST_F(CrashTest, ResponseStream) {
auto server = CreateServerAndClient("response");
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(5, GPR_TIMESPAN)));
gpr_time_from_seconds(60, GPR_TIMESPAN)));
KillClient();
server->Shutdown();
GPR_ASSERT(HadOneResponseStream());
@ -148,7 +148,7 @@ TEST_F(CrashTest, BidiStream) {
auto server = CreateServerAndClient("bidi");
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(5, GPR_TIMESPAN)));
gpr_time_from_seconds(60, GPR_TIMESPAN)));
KillClient();
server->Shutdown();
GPR_ASSERT(HadOneBidiStream());

@ -344,7 +344,7 @@ void grpc::testing::interop::RunServer(
}
std::unique_ptr<Server> server(builder.BuildAndStart());
gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());
while (!g_got_sigint) {
while (!gpr_atm_no_barrier_load(&g_got_sigint)) {
sleep(5);
}
}

@ -37,10 +37,10 @@
#include "test/cpp/interop/server_helper.h"
#include "test/cpp/util/test_config.h"
bool grpc::testing::interop::g_got_sigint = false;
gpr_atm grpc::testing::interop::g_got_sigint;
static void sigint_handler(int x) {
grpc::testing::interop::g_got_sigint = true;
gpr_atm_no_barrier_store(&grpc::testing::interop::g_got_sigint, true);
}
int main(int argc, char** argv) {

@ -126,7 +126,7 @@ int main(int argc, char** argv) {
return 1;
}
/* wait a little */
sleep(2);
sleep(10);
/* start the clients */
ret = test_client(root, "127.0.0.1", port);
if (ret != 0) return ret;

@ -36,9 +36,11 @@
#include <memory>
#include <grpc/compression.h>
#include <grpc/impl/codegen/atm.h>
#include <grpc++/security/server_credentials.h>
#include <grpc++/server_context.h>
#include <grpc/compression.h>
namespace grpc {
namespace testing {
@ -62,7 +64,7 @@ class InteropServerContextInspector {
namespace interop {
extern bool g_got_sigint;
extern gpr_atm g_got_sigint;
void RunServer(std::shared_ptr<ServerCredentials> creds);
} // namespace interop

@ -91,7 +91,7 @@ print yaml.dump({
'boringssl': True,
'defaults': 'boringssl',
'cpu_cost': guess_cpu(scenario_json, False),
'exclude_configs': ['tsan'],
'exclude_configs': ['tsan', 'asan'],
'timeout_seconds': 6*60
}
for scenario_json in scenario_config.CXXLanguage().scenarios()
@ -99,7 +99,7 @@ print yaml.dump({
] + [
{
'name': 'json_run_localhost',
'shortname': 'json_run_localhost:%s' % scenario_json['name'],
'shortname': 'json_run_localhost:%s_low_thread_count' % scenario_json['name'],
'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
'ci_platforms': ['linux'],
'platforms': ['linux'],
@ -108,7 +108,7 @@ print yaml.dump({
'boringssl': True,
'defaults': 'boringssl',
'cpu_cost': guess_cpu(scenario_json, True),
'exclude_configs': sorted(c for c in configs_from_yaml if c != 'tsan'),
'exclude_configs': sorted(c for c in configs_from_yaml if c not in ('tsan', 'asan')),
'timeout_seconds': 6*60
}
for scenario_json in scenario_config.CXXLanguage().scenarios()

@ -0,0 +1,64 @@
#!/bin/bash
# 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.
#
# Builds selected testing docker images and pushes them to dockerhub.
# Useful for testing environments where it's impractical (or impossible)
# to rely on docker images being cached locally after they've been built
# for the first time (which might be costly especially for some images).
# NOTE: gRPC docker images intended to be used by end users are NOT
# pushed using this script (they're built automatically by dockerhub).
# This script is only for "internal" images we use when testing gRPC.
set -ex
cd $(dirname $0)/../..
git_root=$(pwd)
cd -
DOCKERHUB_ORGANIZATION=grpctesting
for DOCKERFILE_DIR in tools/dockerfile/test/fuzzer
do
# Generate image name based on Dockerfile checksum. That works well as long
# as can count on dockerfiles being written in a way that changing the logical
# contents of the docker image always changes the SHA (e.g. using "ADD file"
# cmd in the dockerfile in not ok as contents of the added file will not be
# reflected in the SHA).
DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
# skip the image if it already exists in the repo
curl --silent -f -lSL https://registry.hub.docker.com/v2/repositories/${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}/tags/latest > /dev/null \
&& continue
docker build -t ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME} ${DOCKERFILE_DIR}
# "docker login" needs to be run in advance
docker push ${DOCKERHUB_ORGANIZATION}/${DOCKER_IMAGE_NAME}
done

@ -93,9 +93,11 @@ RUN pip install simplejson mako
#======================================
# More sanity test dependencies (bazel)
RUN apt-get install -y openjdk-8-jdk
# TOOD(jtattermusch): pin the bazel version
RUN git clone https://github.com/bazelbuild/bazel.git /bazel
RUN cd /bazel && ./compile.sh
# Check out Bazel version 0.4.1 since this version allows running
# ./compile.sh without a local protoc dependency
# TODO(mattkwong): install dependencies to support latest Bazel version if newer
# version is needed
RUN git clone https://github.com/bazelbuild/bazel.git /bazel && cd /bazel && git checkout tags/0.4.1 && ./compile.sh
RUN ln -s /bazel/output/bazel /bin/
#===================

@ -920,9 +920,9 @@ src/core/lib/security/credentials/oauth2/oauth2_credentials.h \
src/core/lib/security/credentials/plugin/plugin_credentials.h \
src/core/lib/security/credentials/ssl/ssl_credentials.h \
src/core/lib/security/transport/auth_filters.h \
src/core/lib/security/transport/handshake.h \
src/core/lib/security/transport/secure_endpoint.h \
src/core/lib/security/transport/security_connector.h \
src/core/lib/security/transport/security_handshaker.h \
src/core/lib/security/transport/tsi_error.h \
src/core/lib/security/util/b64.h \
src/core/lib/security/util/json_util.h \
@ -931,6 +931,7 @@ src/core/lib/tsi/ssl_transport_security.h \
src/core/lib/tsi/ssl_types.h \
src/core/lib/tsi/transport_security.h \
src/core/lib/tsi/transport_security_interface.h \
src/core/ext/transport/chttp2/server/chttp2_server.h \
src/core/ext/client_channel/client_channel.h \
src/core/ext/client_channel/client_channel_factory.h \
src/core/ext/client_channel/connector.h \
@ -946,6 +947,7 @@ src/core/ext/client_channel/resolver_registry.h \
src/core/ext/client_channel/subchannel.h \
src/core/ext/client_channel/subchannel_index.h \
src/core/ext/client_channel/uri_parser.h \
src/core/ext/transport/chttp2/client/chttp2_connector.h \
src/core/ext/lb_policy/grpclb/grpclb.h \
src/core/ext/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
@ -1118,9 +1120,9 @@ src/core/lib/security/credentials/oauth2/oauth2_credentials.c \
src/core/lib/security/credentials/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_credentials.c \
src/core/lib/security/transport/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.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 \
@ -1129,6 +1131,7 @@ src/core/lib/surface/init_secure.c \
src/core/lib/tsi/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/transport_security.c \
src/core/ext/transport/chttp2/server/chttp2_server.c \
src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.c \
@ -1148,6 +1151,7 @@ src/core/ext/client_channel/resolver_registry.c \
src/core/ext/client_channel/subchannel.c \
src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.c \
src/core/ext/transport/chttp2/client/chttp2_connector.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/client/insecure/channel_create.c \

@ -0,0 +1,40 @@
#!/bin/bash
# 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.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/linux/grpc_fuzzer_client.sh"
timeout_mins: 1440 # 24 hours is the maximum allowed value
action {
define_artifacts {
regex: "git/grpc/fuzzer_output/**"
}
}

@ -0,0 +1,41 @@
#!/bin/bash
# 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.
set -ex
# change to grpc repo root
cd $(dirname $0)/../../..
git submodule update --init
# download fuzzer docker image from dockerhub
export DOCKERHUB_ORGANIZATION=grpctesting
# runtime 23 * 60 mins
config=asan-trace-cmp runtime=82800 tools/jenkins/run_fuzzer.sh client_fuzzer

@ -31,4 +31,10 @@
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/linux/run_tests.sh"
build_file: "grpc/tools/internal_ci/linux/grpc_master.sh"
timeout_mins: 60
action {
define_artifacts {
regex: "**/sponge_log.xml"
}
}

@ -42,4 +42,12 @@ docker --version || true
git submodule update --init
tools/run_tests/run_tests.py -l c --build_only
tools/run_tests/run_tests.py -l c -t -x sponge_log.xml || FAILED="true"
# kill port_server.py to prevent the build from hanging
ps aux | grep port_server\\.py | awk '{print $2}' | xargs kill -9
if [ "$FAILED" != "" ]
then
exit 1
fi

@ -41,13 +41,20 @@ cd -
# DOCKERFILE_DIR - Directory in which Dockerfile file is located.
# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
# OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
# DOCKERHUB_ORGANIZATION - If set, pull a prebuilt image from given dockerhub org.
# $@ - Extra args to pass to docker run
# Use image name based on Dockerfile location checksum
DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ )
# Make sure docker image has been built. Should be instantaneous if so.
docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR
if [ "$DOCKERHUB_ORGANIZATION" != "" ]
then
DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME
docker pull $DOCKER_IMAGE_NAME
else
# Make sure docker image has been built. Should be instantaneous if so.
docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR
fi
# Choose random name for docker container
CONTAINER_NAME="build_and_run_docker_$(uuidgen)"

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

Loading…
Cancel
Save