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. 2
      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. 86
      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/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h", "src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.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/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.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/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
@ -299,6 +299,7 @@ cc_library(
"src/core/lib/tsi/ssl_types.h", "src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h", "src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.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.h",
"src/core/ext/client_channel/client_channel_factory.h", "src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.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.h",
"src/core/ext/client_channel/subchannel_index.h", "src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.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/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.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", "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/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c", "src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.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/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c",
"src/core/ext/client_channel/channel_connectivity.c", "src/core/ext/client_channel/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.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.c",
"src/core/ext/client_channel/subchannel_index.c", "src/core/ext/client_channel/subchannel_index.c",
"src/core/ext/client_channel/uri_parser.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.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h", "src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.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/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.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/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
@ -750,6 +754,7 @@ cc_library(
"src/core/lib/tsi/ssl_types.h", "src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h", "src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.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/surface/init.c",
"src/core/lib/channel/channel_args.c", "src/core/lib/channel/channel_args.c",
"src/core/lib/channel/channel_stack.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/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c", "src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.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/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/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", "src/core/plugin_registry/grpc_cronet_plugin_registry.c",
], ],
hdrs = [ hdrs = [
@ -1100,6 +1106,8 @@ cc_library(
"src/core/ext/transport/chttp2/transport/stream_map.h", "src/core/ext/transport/chttp2/transport/stream_map.h",
"src/core/ext/transport/chttp2/transport/varint.h", "src/core/ext/transport/chttp2/transport/varint.h",
"src/core/ext/transport/chttp2/alpn/alpn.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.h",
"src/core/ext/client_channel/client_channel_factory.h", "src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.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/varint.c",
"src/core/ext/transport/chttp2/transport/writing.c", "src/core/ext/transport/chttp2/transport/writing.c",
"src/core/ext/transport/chttp2/alpn/alpn.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.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.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/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.c", "src/core/ext/client_channel/client_channel.c",
"src/core/ext/client_channel/client_channel_factory.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/dynamic_thread_pool.h",
"src/cpp/server/thread_pool_interface.h", "src/cpp/server/thread_pool_interface.h",
"src/cpp/thread_manager/thread_manager.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_decoder.h",
"src/core/ext/transport/chttp2/transport/bin_encoder.h", "src/core/ext/transport/chttp2/transport/bin_encoder.h",
"src/core/ext/transport/chttp2/transport/chttp2_transport.h", "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
@ -1653,6 +1664,7 @@ cc_library(
"src/core/ext/client_channel/subchannel.h", "src/core/ext/client_channel/subchannel.h",
"src/core/ext/client_channel/subchannel_index.h", "src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.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/aggregation.h",
"src/core/ext/census/base_resources.h", "src/core/ext/census/base_resources.h",
"src/core/ext/census/census_interface.h", "src/core/ext/census/census_interface.h",
@ -1699,6 +1711,7 @@ cc_library(
"src/cpp/codegen/codegen_init.cc", "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.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create_posix.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_decoder.c",
"src/core/ext/transport/chttp2/transport/bin_encoder.c", "src/core/ext/transport/chttp2/transport/bin_encoder.c",
"src/core/ext/transport/chttp2/transport/chttp2_plugin.c", "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
@ -1853,6 +1866,7 @@ cc_library(
"src/core/ext/client_channel/uri_parser.c", "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.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/server/chttp2_server.c",
"src/core/ext/census/base_resources.c", "src/core/ext/census/base_resources.c",
"src/core/ext/census/context.c", "src/core/ext/census/context.c",
"src/core/ext/census/gen/census.pb.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/plugin/plugin_credentials.c",
"src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c",
"src/core/lib/security/transport/handshake.c",
"src/core/lib/security/transport/secure_endpoint.c", "src/core/lib/security/transport/secure_endpoint.c",
"src/core/lib/security/transport/security_connector.c", "src/core/lib/security/transport/security_connector.c",
"src/core/lib/security/transport/security_handshaker.c",
"src/core/lib/security/transport/server_auth_filter.c", "src/core/lib/security/transport/server_auth_filter.c",
"src/core/lib/security/transport/tsi_error.c", "src/core/lib/security/transport/tsi_error.c",
"src/core/lib/security/util/b64.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/fake_transport_security.c",
"src/core/lib/tsi/ssl_transport_security.c", "src/core/lib/tsi/ssl_transport_security.c",
"src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c",
"src/core/ext/client_channel/channel_connectivity.c", "src/core/ext/client_channel/channel_connectivity.c",
"src/core/ext/client_channel/client_channel.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.c",
"src/core/ext/client_channel/subchannel_index.c", "src/core/ext/client_channel/subchannel_index.c",
"src/core/ext/client_channel/uri_parser.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.c",
"src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
"src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.h",
"src/core/lib/security/credentials/ssl/ssl_credentials.h", "src/core/lib/security/credentials/ssl/ssl_credentials.h",
"src/core/lib/security/transport/auth_filters.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/secure_endpoint.h",
"src/core/lib/security/transport/security_connector.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/transport/tsi_error.h",
"src/core/lib/security/util/b64.h", "src/core/lib/security/util/b64.h",
"src/core/lib/security/util/json_util.h", "src/core/lib/security/util/json_util.h",
@ -2706,6 +2722,7 @@ objc_library(
"src/core/lib/tsi/ssl_types.h", "src/core/lib/tsi/ssl_types.h",
"src/core/lib/tsi/transport_security.h", "src/core/lib/tsi/transport_security.h",
"src/core/lib/tsi/transport_security_interface.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.h",
"src/core/ext/client_channel/client_channel_factory.h", "src/core/ext/client_channel/client_channel_factory.h",
"src/core/ext/client_channel/connector.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.h",
"src/core/ext/client_channel/subchannel_index.h", "src/core/ext/client_channel/subchannel_index.h",
"src/core/ext/client_channel/uri_parser.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/grpclb.h",
"src/core/ext/lb_policy/grpclb/load_balancer_api.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", "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/plugin/plugin_credentials.c
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c
src/core/lib/security/transport/handshake.c
src/core/lib/security/transport/secure_endpoint.c src/core/lib/security/transport/secure_endpoint.c
src/core/lib/security/transport/security_connector.c src/core/lib/security/transport/security_connector.c
src/core/lib/security/transport/security_handshaker.c
src/core/lib/security/transport/server_auth_filter.c src/core/lib/security/transport/server_auth_filter.c
src/core/lib/security/transport/tsi_error.c src/core/lib/security/transport/tsi_error.c
src/core/lib/security/util/b64.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/fake_transport_security.c
src/core/lib/tsi/ssl_transport_security.c src/core/lib/tsi/ssl_transport_security.c
src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c
src/core/ext/client_channel/channel_connectivity.c src/core/ext/client_channel/channel_connectivity.c
src/core/ext/client_channel/client_channel.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.c
src/core/ext/client_channel/subchannel_index.c src/core/ext/client_channel/subchannel_index.c
src/core/ext/client_channel/uri_parser.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.c
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.c
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c
src/core/lib/security/transport/handshake.c
src/core/lib/security/transport/secure_endpoint.c src/core/lib/security/transport/secure_endpoint.c
src/core/lib/security/transport/security_connector.c src/core/lib/security/transport/security_connector.c
src/core/lib/security/transport/security_handshaker.c
src/core/lib/security/transport/server_auth_filter.c src/core/lib/security/transport/server_auth_filter.c
src/core/lib/security/transport/tsi_error.c src/core/lib/security/transport/tsi_error.c
src/core/lib/security/util/b64.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/fake_transport_security.c
src/core/lib/tsi/ssl_transport_security.c src/core/lib/tsi/ssl_transport_security.c
src/core/lib/tsi/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 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/varint.c
src/core/ext/transport/chttp2/transport/writing.c src/core/ext/transport/chttp2/transport/writing.c
src/core/ext/transport/chttp2/alpn/alpn.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.c
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.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/channel_connectivity.c
src/core/ext/client_channel/client_channel.c src/core/ext/client_channel/client_channel.c
src/core/ext/client_channel/client_channel_factory.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/cpp/codegen/codegen_init.cc
src/core/ext/transport/chttp2/client/insecure/channel_create.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/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_decoder.c
src/core/ext/transport/chttp2/transport/bin_encoder.c src/core/ext/transport/chttp2/transport/bin_encoder.c
src/core/ext/transport/chttp2/transport/chttp2_plugin.c src/core/ext/transport/chttp2/transport/chttp2_plugin.c
@ -1417,6 +1423,7 @@ add_library(grpc++_cronet
src/core/ext/client_channel/uri_parser.c 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.c
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
src/core/ext/transport/chttp2/server/chttp2_server.c
src/core/ext/census/base_resources.c src/core/ext/census/base_resources.c
src/core/ext/census/context.c src/core/ext/census/context.c
src/core/ext/census/gen/census.pb.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/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \ src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \ src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.c \
src/core/lib/security/transport/server_auth_filter.c \ src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \ src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.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/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.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.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.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.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \ src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \ src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.c \
src/core/lib/security/transport/server_auth_filter.c \ src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \ src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.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/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/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 \ src/core/plugin_registry/grpc_cronet_plugin_registry.c \
PUBLIC_HEADERS_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/varint.c \
src/core/ext/transport/chttp2/transport/writing.c \ src/core/ext/transport/chttp2/transport/writing.c \
src/core/ext/transport/chttp2/alpn/alpn.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.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.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/channel_connectivity.c \
src/core/ext/client_channel/client_channel.c \ src/core/ext/client_channel/client_channel.c \
src/core/ext/client_channel/client_channel_factory.c \ src/core/ext/client_channel/client_channel_factory.c \
@ -3987,6 +3992,7 @@ LIBGRPC++_CRONET_SRC = \
src/cpp/codegen/codegen_init.cc \ 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.c \
src/core/ext/transport/chttp2/client/insecure/channel_create_posix.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_decoder.c \
src/core/ext/transport/chttp2/transport/bin_encoder.c \ src/core/ext/transport/chttp2/transport/bin_encoder.c \
src/core/ext/transport/chttp2/transport/chttp2_plugin.c \ src/core/ext/transport/chttp2/transport/chttp2_plugin.c \
@ -4141,6 +4147,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/client_channel/uri_parser.c \ 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.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/server/chttp2_server.c \
src/core/ext/census/base_resources.c \ src/core/ext/census/base_resources.c \
src/core/ext/census/context.c \ src/core/ext/census/context.c \
src/core/ext/census/gen/census.pb.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/plugin/plugin_credentials.c: $(OPENSSL_DEP)
src/core/lib/security/credentials/ssl/ssl_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/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/secure_endpoint.c: $(OPENSSL_DEP)
src/core/lib/security/transport/security_connector.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/server_auth_filter.c: $(OPENSSL_DEP)
src/core/lib/security/transport/tsi_error.c: $(OPENSSL_DEP) src/core/lib/security/transport/tsi_error.c: $(OPENSSL_DEP)
src/core/lib/security/util/b64.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/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c', 'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c', 'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c', 'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c', 'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c', 'src/core/lib/security/util/b64.c',
@ -727,6 +727,7 @@
'src/core/lib/tsi/fake_transport_security.c', 'src/core/lib/tsi/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.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.c',
'src/core/ext/client_channel/subchannel_index.c', 'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.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.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.h
- src/core/lib/security/credentials/ssl/ssl_credentials.h - src/core/lib/security/credentials/ssl/ssl_credentials.h
- src/core/lib/security/transport/auth_filters.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/secure_endpoint.h
- src/core/lib/security/transport/security_connector.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/transport/tsi_error.h
- src/core/lib/security/util/b64.h - src/core/lib/security/util/b64.h
- src/core/lib/security/util/json_util.h - src/core/lib/security/util/json_util.h
@ -519,9 +519,9 @@ filegroups:
- src/core/lib/security/credentials/plugin/plugin_credentials.c - src/core/lib/security/credentials/plugin/plugin_credentials.c
- src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c
- src/core/lib/security/transport/handshake.c
- src/core/lib/security/transport/secure_endpoint.c - src/core/lib/security/transport/secure_endpoint.c
- src/core/lib/security/transport/security_connector.c - src/core/lib/security/transport/security_connector.c
- src/core/lib/security/transport/security_handshaker.c
- src/core/lib/security/transport/server_auth_filter.c - src/core/lib/security/transport/server_auth_filter.c
- src/core/lib/security/transport/tsi_error.c - src/core/lib/security/transport/tsi_error.c
- src/core/lib/security/util/b64.c - src/core/lib/security/util/b64.c
@ -622,11 +622,20 @@ filegroups:
- src/core/ext/transport/chttp2/alpn/alpn.c - src/core/ext/transport/chttp2/alpn/alpn.c
deps: deps:
- gpr - 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 - name: grpc_transport_chttp2_client_insecure
src: src:
- src/core/ext/transport/chttp2/client/insecure/channel_create.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/insecure/channel_create_posix.c
uses: uses:
- grpc_transport_chttp2_client_connector
- grpc_transport_chttp2 - grpc_transport_chttp2
- grpc_base - grpc_base
- grpc_client_channel - grpc_client_channel
@ -638,6 +647,15 @@ filegroups:
- grpc_base - grpc_base
- grpc_client_channel - grpc_client_channel
- grpc_secure - 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 - name: grpc_transport_chttp2_server_insecure
src: src:
- src/core/ext/transport/chttp2/server/insecure/server_chttp2.c - src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@ -645,6 +663,7 @@ filegroups:
uses: uses:
- grpc_transport_chttp2 - grpc_transport_chttp2
- grpc_base - grpc_base
- grpc_transport_chttp2_server
- name: grpc_transport_chttp2_server_secure - name: grpc_transport_chttp2_server_secure
src: src:
- src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c - src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@ -652,6 +671,7 @@ filegroups:
- grpc_transport_chttp2 - grpc_transport_chttp2
- grpc_base - grpc_base
- grpc_secure - grpc_secure
- grpc_transport_chttp2_server
- name: grpc_transport_cronet_client_secure - name: grpc_transport_cronet_client_secure
public_headers: public_headers:
- include/grpc/grpc_cronet.h - 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/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \ src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \ src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.c \
src/core/lib/security/transport/server_auth_filter.c \ src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \ src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.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/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.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.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.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.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.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/dns/native)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/resolver/sockaddr) 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/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/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/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/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/server/secure)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport) 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: We have several parameters:
1. INITIAL_BACKOFF (how long to wait after the first failure before retrying) 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) 1. MULTIPLIER (factor with which to multiply backoff after a failed retry)
3. MAX_BACKOFF (upper bound on backoff) 1. JITTER (by how much to randomize backoffs).
4. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to 1. MAX_BACKOFF (upper bound on backoff)
1. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
complete) complete)
## Proposed Backoff Algorithm ## 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/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h', 'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.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/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.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/transport/tsi_error.h',
'src/core/lib/security/util/b64.h', 'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h', 'src/core/lib/security/util/json_util.h',
@ -389,6 +389,7 @@ Pod::Spec.new do |s|
'src/core/lib/tsi/ssl_types.h', 'src/core/lib/tsi/ssl_types.h',
'src/core/lib/tsi/transport_security.h', 'src/core/lib/tsi/transport_security.h',
'src/core/lib/tsi/transport_security_interface.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.h',
'src/core/ext/client_channel/client_channel_factory.h', 'src/core/ext/client_channel/client_channel_factory.h',
'src/core/ext/client_channel/connector.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.h',
'src/core/ext/client_channel/subchannel_index.h', 'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.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/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.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', '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/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c', 'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c', 'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c', 'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c', 'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.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/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.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.c',
'src/core/ext/client_channel/subchannel_index.c', 'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.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.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.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/plugin/plugin_credentials.h',
'src/core/lib/security/credentials/ssl/ssl_credentials.h', 'src/core/lib/security/credentials/ssl/ssl_credentials.h',
'src/core/lib/security/transport/auth_filters.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/secure_endpoint.h',
'src/core/lib/security/transport/security_connector.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/transport/tsi_error.h',
'src/core/lib/security/util/b64.h', 'src/core/lib/security/util/b64.h',
'src/core/lib/security/util/json_util.h', 'src/core/lib/security/util/json_util.h',
@ -792,6 +796,7 @@ Pod::Spec.new do |s|
'src/core/lib/tsi/ssl_types.h', 'src/core/lib/tsi/ssl_types.h',
'src/core/lib/tsi/transport_security.h', 'src/core/lib/tsi/transport_security.h',
'src/core/lib/tsi/transport_security_interface.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.h',
'src/core/ext/client_channel/client_channel_factory.h', 'src/core/ext/client_channel/client_channel_factory.h',
'src/core/ext/client_channel/connector.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.h',
'src/core/ext/client_channel/subchannel_index.h', 'src/core/ext/client_channel/subchannel_index.h',
'src/core/ext/client_channel/uri_parser.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/grpclb.h',
'src/core/ext/lb_policy/grpclb/load_balancer_api.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', '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/plugin/plugin_credentials.h )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_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/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/secure_endpoint.h )
s.files += %w( src/core/lib/security/transport/security_connector.h ) s.files += %w( src/core/lib/security/transport/security_connector.h )
s.files += %w( src/core/lib/security/transport/security_handshaker.h )
s.files += %w( src/core/lib/security/transport/tsi_error.h ) s.files += %w( src/core/lib/security/transport/tsi_error.h )
s.files += %w( src/core/lib/security/util/b64.h ) s.files += %w( src/core/lib/security/util/b64.h )
s.files += %w( src/core/lib/security/util/json_util.h ) s.files += %w( src/core/lib/security/util/json_util.h )
@ -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/ssl_types.h )
s.files += %w( src/core/lib/tsi/transport_security.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/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.h )
s.files += %w( src/core/ext/client_channel/client_channel_factory.h ) s.files += %w( src/core/ext/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/client_channel/connector.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.h )
s.files += %w( src/core/ext/client_channel/subchannel_index.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/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/grpclb.h )
s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.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 ) 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/plugin/plugin_credentials.c )
s.files += %w( src/core/lib/security/credentials/ssl/ssl_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/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/secure_endpoint.c )
s.files += %w( src/core/lib/security/transport/security_connector.c ) s.files += %w( src/core/lib/security/transport/security_connector.c )
s.files += %w( src/core/lib/security/transport/security_handshaker.c )
s.files += %w( src/core/lib/security/transport/server_auth_filter.c ) s.files += %w( src/core/lib/security/transport/server_auth_filter.c )
s.files += %w( src/core/lib/security/transport/tsi_error.c ) s.files += %w( src/core/lib/security/transport/tsi_error.c )
s.files += %w( src/core/lib/security/util/b64.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/fake_transport_security.c )
s.files += %w( src/core/lib/tsi/ssl_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/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/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/channel_connectivity.c )
s.files += %w( src/core/ext/client_channel/client_channel.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.c )
s.files += %w( src/core/ext/client_channel/subchannel_index.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/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.c )
s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.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 ) 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/grpc_library.h>
#include <grpc++/impl/codegen/status.h> #include <grpc++/impl/codegen/status.h>
#include <grpc++/impl/codegen/time.h> #include <grpc++/impl/codegen/time.h>
#include <grpc/impl/codegen/atm.h>
struct grpc_completion_queue; struct grpc_completion_queue;
@ -101,6 +102,7 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// instance. /// instance.
CompletionQueue() { CompletionQueue() {
cq_ = g_core_codegen_interface->grpc_completion_queue_create(nullptr); 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. /// Wrap \a take, taking ownership of the instance.
@ -151,7 +153,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// Request the shutdown of the queue. /// 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 /// will start to return false and \a AsyncNext will return \a
/// NextStatus::SHUTDOWN. Only once either one of these methods does that /// 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 /// (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. /// owership is performed.
grpc_completion_queue* cq() { return cq_; } 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: private:
// Friend synchronous wrappers so that they can access Pluck(), which is // Friend synchronous wrappers so that they can access Pluck(), which is
// a semi-private API geared towards the synchronous implementation. // a semi-private API geared towards the synchronous implementation.
@ -229,6 +247,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
} }
grpc_completion_queue* cq_; // owned grpc_completion_queue* cq_; // owned
gpr_atm avalanches_in_flight_;
}; };
/// A specific type of completion queue used by the processing of notifications /// A specific type of completion queue used by the processing of notifications

@ -140,7 +140,7 @@ class ServerInterface : public CallHook {
ServerAsyncStreamingInterface* stream, ServerAsyncStreamingInterface* stream,
CompletionQueue* call_cq, void* tag, CompletionQueue* call_cq, void* tag,
bool delete_on_finalize); bool delete_on_finalize);
virtual ~BaseAsyncRequest() {} virtual ~BaseAsyncRequest();
bool FinalizeResult(void** tag, bool* status) override; 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/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/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/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/secure_endpoint.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/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/transport/tsi_error.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/b64.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/json_util.h" role="src" />
@ -316,6 +316,7 @@
<file baseinstalldir="/" name="src/core/lib/tsi/ssl_types.h" role="src" /> <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.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.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.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/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/connector.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.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.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/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/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/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" /> <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/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/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/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/secure_endpoint.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/transport/security_connector.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/transport/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/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/transport/tsi_error.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" /> <file baseinstalldir="/" name="src/core/lib/security/util/b64.c" role="src" />
@ -514,6 +516,7 @@
<file baseinstalldir="/" name="src/core/lib/tsi/fake_transport_security.c" role="src" /> <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/ssl_transport_security.c" role="src" />
<file baseinstalldir="/" name="src/core/lib/tsi/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/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/channel_connectivity.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/client_channel.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.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/client_channel/subchannel_index.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/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.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/server/insecure/server_chttp2_posix.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.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() {} 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, bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
const grpc::string& parameter, const grpc::string& parameter,
GeneratorContext* context, GeneratorContext* context,
@ -780,28 +806,15 @@ bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
} }
PrivateGenerator generator(config_, file); PrivateGenerator generator(config_, file);
if (parameter == "grpc_2_0") {
std::unique_ptr<ZeroCopyOutputStream> pb2_output( return GenerateGrpc(context, generator, pb2_grpc_file_name, true);
context->OpenForAppend(pb2_file_name)); } else if (parameter == "") {
std::unique_ptr<ZeroCopyOutputStream> grpc_output( return GenerateGrpc(context, generator, pb2_grpc_file_name, true) &&
context->Open(pb2_grpc_file_name)); GenerateGrpc(context, generator, pb2_file_name, false);
CodedOutputStream pb2_coded_out(pb2_output.get()); } else {
CodedOutputStream grpc_coded_out(grpc_output.get()); *error = "Invalid parameter '" + parameter + "'.";
bool success = false; return 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;
}
} }
return false;
} }
} // namespace grpc_python_generator } // namespace grpc_python_generator

@ -41,10 +41,9 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/uri_parser.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/format_request.h"
#include "src/core/lib/http/parser.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" #include "src/core/lib/support/env.h"
typedef struct http_connect_handshaker { typedef struct http_connect_handshaker {
@ -54,59 +53,105 @@ typedef struct http_connect_handshaker {
char* proxy_server; char* proxy_server;
char* server_name; 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. // State saved while performing the handshake.
grpc_endpoint* endpoint; grpc_handshaker_args* args;
grpc_channel_args* args; grpc_closure* on_handshake_done;
grpc_handshaker_done_cb cb;
void* user_data;
// Objects for processing the HTTP CONNECT request and response. // Objects for processing the HTTP CONNECT request and response.
grpc_slice_buffer write_buffer; grpc_slice_buffer write_buffer;
grpc_slice_buffer* read_buffer; // Ownership passes through this object.
grpc_closure request_done_closure; grpc_closure request_done_closure;
grpc_closure response_read_closure; grpc_closure response_read_closure;
grpc_http_parser http_parser; grpc_http_parser http_parser;
grpc_http_response http_response; grpc_http_response http_response;
grpc_timer timeout_timer;
gpr_refcount refcount;
} http_connect_handshaker; } http_connect_handshaker;
// Unref and clean up handshaker. // Unref and clean up handshaker.
static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx, static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx,
http_connect_handshaker* handshaker) { http_connect_handshaker* handshaker) {
if (gpr_unref(&handshaker->refcount)) { 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->proxy_server);
gpr_free(handshaker->server_name); 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_parser_destroy(&handshaker->http_parser);
grpc_http_response_destroy(&handshaker->http_response); grpc_http_response_destroy(&handshaker->http_response);
gpr_free(handshaker); gpr_free(handshaker);
} }
} }
// Callback invoked when deadline is exceeded. // Set args fields to NULL, saving the endpoint and read buffer for
static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { // later destruction.
http_connect_handshaker* handshaker = arg; static void cleanup_args_for_failure_locked(
if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled. grpc_exec_ctx *exec_ctx, http_connect_handshaker* handshaker) {
grpc_endpoint_shutdown(exec_ctx, handshaker->endpoint); 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. // Callback invoked when finished writing HTTP CONNECT request.
static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg, static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) { grpc_error* error) {
http_connect_handshaker* handshaker = arg; http_connect_handshaker* handshaker = arg;
if (error != GRPC_ERROR_NONE) { gpr_mu_lock(&handshaker->mu);
// If the write failed, invoke the callback immediately with the error. if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args, // If the write failed or we're shutting down, clean up and invoke the
handshaker->read_buffer, handshaker->user_data, // callback with the error.
GRPC_ERROR_REF(error)); handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error));
gpr_mu_unlock(&handshaker->mu);
http_connect_handshaker_unref(exec_ctx, handshaker);
} else { } else {
// Otherwise, read the response. // 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); &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, static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) { grpc_error* error) {
http_connect_handshaker* handshaker = arg; http_connect_handshaker* handshaker = arg;
if (error != GRPC_ERROR_NONE) { gpr_mu_lock(&handshaker->mu);
GRPC_ERROR_REF(error); // Take ref to pass to the handshake-done callback. 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; goto done;
} }
// Add buffer to parser. // Add buffer to parser.
for (size_t i = 0; i < handshaker->read_buffer->count; ++i) { for (size_t i = 0; i < handshaker->args->read_buffer->count; ++i) {
if (GRPC_SLICE_LENGTH(handshaker->read_buffer->slices[i]) > 0) { if (GRPC_SLICE_LENGTH(handshaker->args->read_buffer->slices[i]) > 0) {
size_t body_start_offset = 0; size_t body_start_offset = 0;
error = grpc_http_parser_parse(&handshaker->http_parser, error = grpc_http_parser_parse(&handshaker->http_parser,
handshaker->read_buffer->slices[i], handshaker->args->read_buffer->slices[i],
&body_start_offset); &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) { 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, // Remove the data we've already read from the read buffer,
// leaving only the leftover bytes (if any). // leaving only the leftover bytes (if any).
grpc_slice_buffer tmp_buffer; grpc_slice_buffer tmp_buffer;
grpc_slice_buffer_init(&tmp_buffer); grpc_slice_buffer_init(&tmp_buffer);
if (body_start_offset < 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( grpc_slice_buffer_add(
&tmp_buffer, &tmp_buffer,
grpc_slice_split_tail(&handshaker->read_buffer->slices[i], grpc_slice_split_tail(&handshaker->args->read_buffer->slices[i],
body_start_offset)); body_start_offset));
} }
grpc_slice_buffer_addn(&tmp_buffer, grpc_slice_buffer_addn(&tmp_buffer,
&handshaker->read_buffer->slices[i + 1], &handshaker->args->read_buffer->slices[i + 1],
handshaker->read_buffer->count - i - 1); handshaker->args->read_buffer->count - i - 1);
grpc_slice_buffer_swap(handshaker->read_buffer, &tmp_buffer); grpc_slice_buffer_swap(handshaker->args->read_buffer, &tmp_buffer);
grpc_slice_buffer_destroy_internal(exec_ctx, &tmp_buffer); grpc_slice_buffer_destroy(&tmp_buffer);
break; 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 // complete (e.g., handling chunked transfer encoding or looking
// at the Content-Length: header). // at the Content-Length: header).
if (handshaker->http_parser.state != GRPC_HTTP_BODY) { if (handshaker->http_parser.state != GRPC_HTTP_BODY) {
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, grpc_slice_buffer_reset_and_unref(handshaker->args->read_buffer);
handshaker->read_buffer); grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer, handshaker->args->read_buffer,
&handshaker->response_read_closure); &handshaker->response_read_closure);
gpr_mu_unlock(&handshaker->mu);
return; return;
} }
// Make sure we got a 2xx response. // 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); handshaker->http_response.status);
error = GRPC_ERROR_CREATE(msg); error = GRPC_ERROR_CREATE(msg);
gpr_free(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: done:
// Invoke handshake-done callback. // Set shutdown to true so that subsequent calls to
handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args, // http_connect_handshaker_shutdown() do nothing.
handshaker->read_buffer, handshaker->user_data, error); 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, 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( static void http_connect_handshaker_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in, grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in,
grpc_endpoint* endpoint, grpc_channel_args* args, grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done,
grpc_slice_buffer* read_buffer, gpr_timespec deadline, grpc_handshaker_args* args) {
grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb,
void* user_data) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
gpr_mu_lock(&handshaker->mu);
// Save state in the handshaker object. // Save state in the handshaker object.
handshaker->endpoint = endpoint;
handshaker->args = args; handshaker->args = args;
handshaker->cb = cb; handshaker->on_handshake_done = on_handshake_done;
handshaker->user_data = user_data;
handshaker->read_buffer = read_buffer;
// Send HTTP CONNECT request. // Send HTTP CONNECT request.
gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s",
handshaker->server_name, handshaker->proxy_server); handshaker->server_name, handshaker->proxy_server);
@ -219,16 +280,14 @@ static void http_connect_handshaker_do_handshake(
request.handshaker = &grpc_httpcli_plaintext; request.handshaker = &grpc_httpcli_plaintext;
grpc_slice request_slice = grpc_httpcli_format_connect_request(&request); grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
grpc_slice_buffer_add(&handshaker->write_buffer, request_slice); grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
grpc_endpoint_write(exec_ctx, endpoint, &handshaker->write_buffer, // Take a new ref to be held by the write callback.
&handshaker->request_done_closure);
// Set timeout timer. The timer gets a reference to the handshaker.
gpr_ref(&handshaker->refcount); gpr_ref(&handshaker->refcount);
grpc_timer_init(exec_ctx, &handshaker->timeout_timer, grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), &handshaker->request_done_closure);
on_timeout, handshaker, gpr_now(GPR_CLOCK_MONOTONIC)); 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_destroy, http_connect_handshaker_shutdown,
http_connect_handshaker_do_handshake}; http_connect_handshaker_do_handshake};
@ -236,10 +295,11 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
const char* server_name) { const char* server_name) {
GPR_ASSERT(proxy_server != NULL); GPR_ASSERT(proxy_server != NULL);
GPR_ASSERT(server_name != NULL); GPR_ASSERT(server_name != NULL);
http_connect_handshaker* handshaker = http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker));
gpr_malloc(sizeof(http_connect_handshaker));
memset(handshaker, 0, sizeof(*handshaker)); memset(handshaker, 0, sizeof(*handshaker));
grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base); 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->proxy_server = gpr_strdup(proxy_server);
handshaker->server_name = gpr_strdup(server_name); handshaker->server_name = gpr_strdup(server_name);
grpc_slice_buffer_init(&handshaker->write_buffer); grpc_slice_buffer_init(&handshaker->write_buffer);
@ -249,7 +309,6 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
handshaker); handshaker);
grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE, grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE,
&handshaker->http_response); &handshaker->http_response);
gpr_ref_init(&handshaker->refcount, 1);
return &handshaker->base; return &handshaker->base;
} }

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

@ -124,10 +124,11 @@
#include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/static_metadata.h"
#define BACKOFF_MULTIPLIER 1.6 #define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20
#define BACKOFF_JITTER 0.2 #define GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define BACKOFF_MIN_SECONDS 10 #define GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define BACKOFF_MAX_SECONDS 60 #define GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_GRPCLB_RECONNECT_JITTER 0.2
int grpc_lb_glb_trace = 0; 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, grpc_closure_init(&glb_policy->lb_on_response_received,
lb_on_response_received, glb_policy); lb_on_response_received, glb_policy);
gpr_backoff_init(&glb_policy->lb_call_backoff_state, BACKOFF_MULTIPLIER, gpr_backoff_init(&glb_policy->lb_call_backoff_state,
BACKOFF_JITTER, BACKOFF_MIN_SECONDS * 1000, GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
BACKOFF_MAX_SECONDS * 1000); 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) { 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/backoff.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#define BACKOFF_MULTIPLIER 1.6 #define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1
#define BACKOFF_JITTER 0.2 #define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define BACKOFF_MIN_SECONDS 1 #define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define BACKOFF_MAX_SECONDS 120 #define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct { typedef struct {
/** base class: must be first */ /** 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; server_name_arg.value.string = (char *)path;
r->channel_args = r->channel_args =
grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1); grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER, gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000); 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; 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 <grpc/grpc.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.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/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/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/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/lib/surface/api_trace.h" #include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.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( static void client_channel_factory_ref(
grpc_client_channel_factory *cc_factory) {} grpc_client_channel_factory *cc_factory) {}
@ -174,20 +53,11 @@ static void client_channel_factory_unref(
static grpc_subchannel *client_channel_factory_create_subchannel( static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) { const grpc_subchannel_args *args) {
connector *c = gpr_malloc(sizeof(*c)); grpc_connector *connector = grpc_chttp2_connector_create(
memset(c, 0, sizeof(*c)); exec_ctx, args->server_name, NULL /* create_handshakers */,
c->base.vtable = &connector_vtable; NULL /* user_data */);
gpr_ref_init(&c->refs, 1); grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
c->handshake_mgr = grpc_handshake_manager_create(); grpc_connector_unref(exec_ctx, connector);
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);
return s; return s;
} }
@ -198,16 +68,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel = grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL); grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args); grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args);
if (!resolver) { if (resolver == NULL) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel"); "client_channel_factory_create_channel");
return NULL; return NULL;
} }
grpc_client_channel_finish_initialization( grpc_client_channel_finish_initialization(
exec_ctx, grpc_channel_get_channel_stack(channel), resolver, cc_factory); exec_ctx, grpc_channel_get_channel_stack(channel), resolver, cc_factory);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel"); GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
return channel; return channel;
} }
@ -230,16 +98,13 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
GRPC_API_TRACE( GRPC_API_TRACE(
"grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3, "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
(target, args, reserved)); (target, args, reserved));
GPR_ASSERT(!reserved); GPR_ASSERT(reserved == NULL);
grpc_client_channel_factory *factory = grpc_client_channel_factory *factory =
(grpc_client_channel_factory *)&client_channel_factory; (grpc_client_channel_factory *)&client_channel_factory;
grpc_channel *channel = client_channel_factory_create_channel( grpc_channel *channel = client_channel_factory_create_channel(
&exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args); &exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args);
grpc_client_channel_factory_unref(&exec_ctx, factory); grpc_client_channel_factory_unref(&exec_ctx, factory);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
return channel != NULL ? channel : grpc_lame_client_channel_create( return channel != NULL ? channel : grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL, target, GRPC_STATUS_INTERNAL,
"Failed to create client channel"); "Failed to create client channel");

@ -33,196 +33,19 @@
#include <grpc/grpc.h> #include <grpc/grpc.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.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/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/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/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/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/api_trace.h"
#include "src/core/lib/surface/channel.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 { typedef struct {
grpc_client_channel_factory base; 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( static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory, grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) { const grpc_subchannel_args *args) {
client_channel_factory *f = (client_channel_factory *)cc_factory; client_channel_factory *f = (client_channel_factory *)cc_factory;
connector *c = gpr_malloc(sizeof(*c)); grpc_connector *connector = grpc_chttp2_connector_create(
memset(c, 0, sizeof(*c)); exec_ctx, args->server_name, create_handshakers, f->security_connector);
c->base.vtable = &connector_vtable; grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
c->security_connector = f->security_connector; grpc_connector_unref(exec_ctx, 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);
return s; return s;
} }
@ -277,15 +95,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel = grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL); grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args); grpc_resolver *resolver = grpc_resolver_create(exec_ctx, target, args);
if (resolver != NULL) { 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 {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_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; return channel;
} }
@ -320,8 +137,8 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
grpc_channel_security_connector *security_connector; grpc_channel_security_connector *security_connector;
grpc_channel_args *new_args_from_connector; grpc_channel_args *new_args_from_connector;
if (grpc_channel_credentials_create_security_connector( if (grpc_channel_credentials_create_security_connector(
&exec_ctx, creds, target, args, &security_connector, &exec_ctx, creds, target, args, &security_connector, &new_args_from_connector) !=
&new_args_from_connector) != GRPC_SECURITY_OK) { GRPC_SECURITY_OK) {
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
return grpc_lame_client_channel_create( return grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL, "Failed to create security connector."); 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/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "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/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/api_trace.h"
#include "src/core/lib/surface/server.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) { 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_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, GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr)); (server, addr));
grpc_error *err = grpc_chttp2_server_add_port(
grpc_error **errors = NULL; &exec_ctx, server, addr,
err = grpc_blocking_resolve_address(addr, "https", &resolved); grpc_channel_args_copy(grpc_server_get_channel_args(server)),
if (err != GRPC_ERROR_NONE) { NULL /* handshaker_factory */, &port_num);
goto error;
}
err = grpc_tcp_server_create(&exec_ctx, NULL,
grpc_server_get_channel_args(server), &tcp);
if (err != GRPC_ERROR_NONE) { 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);
const size_t naddrs = resolved->naddrs; GRPC_ERROR_UNREF(err);
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++;
}
} }
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); grpc_exec_ctx_finish(&exec_ctx);
if (errors != NULL) {
for (i = 0; i < naddrs; i++) {
GRPC_ERROR_UNREF(errors[i]);
}
}
gpr_free(errors);
return port_num; return port_num;
} }

@ -38,218 +38,62 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/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/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.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/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.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/api_trace.h"
#include "src/core/lib/surface/server.h" #include "src/core/lib/surface/server.h"
typedef struct server_secure_state { typedef struct {
grpc_server *server; grpc_chttp2_server_handshaker_factory base;
grpc_tcp_server *tcp; grpc_server_security_connector *security_connector;
grpc_server_security_connector *sc; } server_security_handshaker_factory;
grpc_server_credentials *creds;
bool is_shutdown; static void server_security_handshaker_factory_create_handshakers(
gpr_mu mu; grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf,
grpc_closure tcp_server_shutdown_complete; grpc_handshake_manager *handshake_mgr) {
grpc_closure *server_destroy_listener_done; server_security_handshaker_factory *handshaker_factory =
} server_secure_state; (server_security_handshaker_factory *)hf;
grpc_server_security_connector_create_handshakers(
typedef struct server_secure_connect { exec_ctx, handshaker_factory->security_connector, handshake_mgr);
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);
} }
/* Server callback: start listening on our ports */ static void server_security_handshaker_factory_destroy(
static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server, grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf) {
void *statep, grpc_pollset **pollsets, server_security_handshaker_factory *handshaker_factory =
size_t pollset_count) { (server_security_handshaker_factory *)hf;
server_secure_state *server_state = statep; GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &handshaker_factory->security_connector->base,
gpr_mu_lock(&server_state->mu); "server");
server_state->is_shutdown = false; gpr_free(hf);
gpr_mu_unlock(&server_state->mu);
grpc_tcp_server_start(exec_ctx, server_state->tcp, pollsets, pollset_count,
on_accept, server_state);
} }
static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *statep, static const grpc_chttp2_server_handshaker_factory_vtable
grpc_error *error) { server_security_handshaker_factory_vtable = {
server_secure_state *server_state = statep; server_security_handshaker_factory_create_handshakers,
/* ensure all threads have unlocked */ server_security_handshaker_factory_destroy};
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);
}
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_server_credentials *creds) { 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_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE; grpc_error *err = GRPC_ERROR_NONE;
grpc_error **errors = NULL; grpc_server_security_connector *sc = NULL;
int port_num = 0;
GRPC_API_TRACE( GRPC_API_TRACE(
"grpc_server_add_secure_http2_port(" "grpc_server_add_secure_http2_port("
"server=%p, addr=%s, creds=%p)", "server=%p, addr=%s, creds=%p)",
3, (server, addr, creds)); 3, (server, addr, creds));
// Create security context.
/* create security context */
if (creds == NULL) { if (creds == NULL) {
err = GRPC_ERROR_CREATE( err = GRPC_ERROR_CREATE(
"No credentials specified for secure server port (creds==NULL)"); "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); grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
char *msg; 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), err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status); GRPC_ERROR_INT_SECURITY_STATUS, status);
gpr_free(msg); gpr_free(msg);
goto error; goto done;
} }
sc->channel_args = grpc_server_get_channel_args(server); // Create handshaker factory.
server_security_handshaker_factory *handshaker_factory =
/* resolve address */ gpr_malloc(sizeof(*handshaker_factory));
err = grpc_blocking_resolve_address(addr, "https", &resolved); memset(handshaker_factory, 0, sizeof(*handshaker_factory));
if (err != GRPC_ERROR_NONE) { handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable;
goto error; handshaker_factory->security_connector = sc;
} // Create channel args.
server_state = gpr_malloc(sizeof(*server_state)); grpc_arg channel_arg = grpc_server_credentials_to_arg(creds);
memset(server_state, 0, sizeof(*server_state)); grpc_channel_args *args = grpc_channel_args_copy_and_add(
grpc_closure_init(&server_state->tcp_server_shutdown_complete, grpc_server_get_channel_args(server), &channel_arg, 1);
tcp_server_shutdown_complete, server_state); // Add server port.
err = grpc_tcp_server_create(&exec_ctx, err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args,
&server_state->tcp_server_shutdown_complete, &handshaker_factory->base, &port_num);
grpc_server_get_channel_args(server), &tcp); done:
grpc_exec_ctx_finish(&exec_ctx);
if (err != GRPC_ERROR_NONE) { 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; 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, static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
void *byte_stream, void *byte_stream,
grpc_error *error_ignored); 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, static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
grpc_error *error); 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(t->write_state),
write_state_name(st), reason)); write_state_name(st), reason));
t->write_state = st; t->write_state = st;
if (st == GRPC_CHTTP2_WRITE_STATE_IDLE && if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
t->close_transport_on_writes_finished != NULL) { grpc_exec_ctx_enqueue_list(exec_ctx, &t->run_after_write, NULL);
grpc_error *err = t->close_transport_on_writes_finished; if (t->close_transport_on_writes_finished != NULL) {
t->close_transport_on_writes_finished = NULL; grpc_error *err = t->close_transport_on_writes_finished;
close_transport_locked(exec_ctx, t, err); 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) { switch (t->write_state) {
case GRPC_CHTTP2_WRITE_STATE_IDLE: case GRPC_CHTTP2_WRITE_STATE_IDLE:
GPR_UNREACHABLE_CODE(break); GPR_UNREACHABLE_CODE(break);
@ -737,6 +734,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
break; break;
} }
grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing"); GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
GPR_TIMER_END("terminate_writing_with_lock", 0); 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) #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) #define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16)
static grpc_closure *add_closure_barrier(grpc_closure *closure) { static grpc_closure *add_closure_barrier(grpc_closure *closure) {
@ -853,6 +859,16 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
return; return;
} }
closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT; 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 (error != GRPC_ERROR_NONE) {
if (closure->error_data.error == GRPC_ERROR_NONE) { if (closure->error_data.error == GRPC_ERROR_NONE) {
closure->error_data.error = 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); grpc_transport_move_stats(&s->stats, s->collecting_stats);
s->collecting_stats = NULL; 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) { if (op->send_initial_metadata != NULL) {
GPR_ASSERT(s->send_initial_metadata_finished == 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_finished = add_closure_barrier(on_complete);
s->send_initial_metadata = op->send_initial_metadata; s->send_initial_metadata = op->send_initial_metadata;
const size_t metadata_size = 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) { 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); s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
if (s->write_closed) { if (s->write_closed) {
grpc_chttp2_complete_closure_step( 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) { if (op->send_trailing_metadata != NULL) {
GPR_ASSERT(s->send_trailing_metadata_finished == 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_finished = add_closure_barrier(on_complete);
s->send_trailing_metadata = op->send_trailing_metadata; s->send_trailing_metadata = op->send_trailing_metadata;
const size_t metadata_size = const size_t metadata_size =
@ -1538,9 +1563,9 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s,
return error; return error;
} }
static void fail_pending_writes(grpc_exec_ctx *exec_ctx, void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_transport *t,
grpc_error *error) { grpc_chttp2_stream *s, grpc_error *error) {
error = error =
removal_error(error, s, "Pending writes failed due to stream closure"); removal_error(error, s, "Pending writes failed due to stream closure");
s->send_initial_metadata = NULL; 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) { if (close_writes && !s->write_closed) {
s->write_closed_error = GRPC_ERROR_REF(error); s->write_closed_error = GRPC_ERROR_REF(error);
s->write_closed = true; 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); grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
} }
if (s->read_closed && s->write_closed) { if (s->read_closed && s->write_closed) {

@ -327,6 +327,9 @@ struct grpc_chttp2_transport {
*/ */
grpc_error *close_transport_on_writes_finished; 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 */ /* buffer pool state */
/** have we scheduled a benign cleanup? */ /** have we scheduled a benign cleanup? */
bool benign_reclaimer_registered; 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_transport *t,
grpc_chttp2_stream *s); 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 */ #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/channel_args.h"
#include "src/core/lib/channel/handshaker.h" #include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/timer.h"
// //
// grpc_handshaker // grpc_handshaker
// //
void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable, void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
grpc_handshaker* handshaker) { grpc_handshaker* handshaker) {
handshaker->vtable = vtable; handshaker->vtable = vtable;
} }
void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx, static void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) { grpc_handshaker* handshaker) {
handshaker->vtable->destroy(exec_ctx, handshaker); handshaker->vtable->destroy(exec_ctx, handshaker);
} }
void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx, static void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker) { grpc_handshaker* handshaker) {
handshaker->vtable->shutdown(exec_ctx, handshaker); handshaker->vtable->shutdown(exec_ctx, handshaker);
} }
void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx, static void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker, grpc_handshaker* handshaker,
grpc_endpoint* endpoint, grpc_tcp_server_acceptor* acceptor,
grpc_channel_args* args, grpc_closure* on_handshake_done,
grpc_slice_buffer* read_buffer, grpc_handshaker_args* args) {
gpr_timespec deadline, handshaker->vtable->do_handshake(exec_ctx, handshaker, acceptor,
grpc_tcp_server_acceptor* acceptor, on_handshake_done, args);
grpc_handshaker_done_cb cb, void* user_data) {
handshaker->vtable->do_handshake(exec_ctx, handshaker, endpoint, args,
read_buffer, deadline, acceptor, cb,
user_data);
} }
// //
// grpc_handshake_manager // 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 { struct grpc_handshake_manager {
gpr_mu mu;
gpr_refcount refs;
bool shutdown;
// An array of handshakers added via grpc_handshake_manager_add(). // An array of handshakers added via grpc_handshake_manager_add().
size_t count; size_t count;
grpc_handshaker** handshakers; grpc_handshaker** handshakers;
// State used while chaining handshakers. // The index of the handshaker to invoke next and closure to invoke it.
struct grpc_handshaker_state* state; 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* grpc_handshake_manager_create() {
grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager)); grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager));
memset(mgr, 0, sizeof(*mgr)); memset(mgr, 0, sizeof(*mgr));
gpr_mu_init(&mgr->mu);
gpr_ref_init(&mgr->refs, 1);
return mgr; 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, void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
grpc_handshaker* handshaker) { grpc_handshaker* handshaker) {
gpr_mu_lock(&mgr->mu);
// To avoid allocating memory for each handshaker we add, we double // To avoid allocating memory for each handshaker we add, we double
// the number of elements every time we need more. // the number of elements every time we need more.
size_t realloc_count = 0; 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*)); gpr_realloc(mgr->handshakers, realloc_count * sizeof(grpc_handshaker*));
} }
mgr->handshakers[mgr->count++] = 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, void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) { grpc_handshake_manager* mgr) {
for (size_t i = 0; i < mgr->count; ++i) { grpc_handshake_manager_unref(exec_ctx, mgr);
grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
}
gpr_free(mgr->handshakers);
gpr_free(mgr);
} }
void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx, void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) { grpc_handshake_manager* mgr) {
for (size_t i = 0; i < mgr->count; ++i) { gpr_mu_lock(&mgr->mu);
grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[i]); // 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_mu_unlock(&mgr->mu);
gpr_free(mgr->state); }
mgr->state = NULL;
// 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 // A function used as the handshaker-done callback when chaining
// handshakers together. // handshakers together.
static void call_next_handshaker(grpc_exec_ctx* exec_ctx, static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg,
grpc_endpoint* endpoint, grpc_error* error) {
grpc_channel_args* args, grpc_handshake_manager* mgr = arg;
grpc_slice_buffer* read_buffer, gpr_mu_lock(&mgr->mu);
void* user_data, grpc_error* error) { bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_REF(error));
grpc_handshake_manager* mgr = user_data; gpr_mu_unlock(&mgr->mu);
GPR_ASSERT(mgr->state != NULL); // If we're invoked the final callback, we won't be coming back
GPR_ASSERT(mgr->state->index < mgr->count); // to this function, so we can release our reference to the
// If we got an error, skip all remaining handshakers and invoke the // handshake manager.
// caller-supplied callback immediately. if (done) {
if (error != GRPC_ERROR_NONE) { grpc_handshake_manager_unref(exec_ctx, mgr);
mgr->state->final_cb(exec_ctx, endpoint, args, read_buffer,
mgr->state->final_user_data, error);
return;
} }
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. // Callback invoked when deadline is exceeded.
if (mgr->state->index == mgr->count - 1) { static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
cb = mgr->state->final_cb; grpc_handshake_manager* mgr = arg;
user_data = mgr->state->final_user_data; if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
} grpc_handshake_manager_shutdown(exec_ctx, mgr);
// 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;
} }
grpc_handshake_manager_unref(exec_ctx, mgr);
} }
void grpc_handshake_manager_do_handshake( void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr, 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, 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) {
grpc_channel_args* args_copy = grpc_channel_args_copy(args); gpr_mu_lock(&mgr->mu);
grpc_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer)); GPR_ASSERT(mgr->index == 0);
grpc_slice_buffer_init(read_buffer); GPR_ASSERT(!mgr->shutdown);
if (mgr->count == 0) { // Construct handshaker args. These will be passed through all
// No handshakers registered, so we just immediately call the done // handshakers and eventually be freed by the on_handshake_done callback.
// callback with the passed-in endpoint. mgr->args.endpoint = endpoint;
cb(exec_ctx, endpoint, args_copy, read_buffer, user_data, GRPC_ERROR_NONE); mgr->args.args = grpc_channel_args_copy(channel_args);
} else { mgr->args.user_data = user_data;
GPR_ASSERT(mgr->state == NULL); mgr->args.read_buffer = gpr_malloc(sizeof(*mgr->args.read_buffer));
mgr->state = gpr_malloc(sizeof(struct grpc_handshaker_state)); grpc_slice_buffer_init(mgr->args.read_buffer);
memset(mgr->state, 0, sizeof(*mgr->state)); // Initialize state needed for calling handshakers.
mgr->state->deadline = deadline; mgr->acceptor = acceptor;
mgr->state->acceptor = acceptor; grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr);
mgr->state->final_cb = cb; grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args);
mgr->state->final_user_data = user_data; // Start deadline timer, which owns a ref.
call_next_handshaker(exec_ctx, endpoint, args_copy, read_buffer, mgr, gpr_ref(&mgr->refs);
GRPC_ERROR_NONE); 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; typedef struct grpc_handshaker grpc_handshaker;
/// Callback type invoked when a handshaker is done. /// Arguments passed through handshakers and to the on_handshake_done callback.
/// Takes ownership of \a args and \a read_buffer. ///
typedef void (*grpc_handshaker_done_cb)(grpc_exec_ctx* exec_ctx, /// For handshakers, all members are input/output parameters; for
grpc_endpoint* endpoint, /// example, a handshaker may read from or write to \a endpoint and
grpc_channel_args* args, /// then later replace it with a wrapped endpoint. Similarly, a
grpc_slice_buffer* read_buffer, /// handshaker may modify \a args.
void* user_data, grpc_error* error); ///
/// A handshaker takes ownership of the members while a handshake is in
struct grpc_handshaker_vtable { /// 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. /// Destroys the handshaker.
void (*destroy)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker); void (*destroy)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
@ -70,44 +85,26 @@ struct grpc_handshaker_vtable {
/// aborted in the middle). /// aborted in the middle).
void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker); void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
/// Performs handshaking. When finished, calls \a cb with \a user_data. /// Performs handshaking, modifying \a args as needed (e.g., to
/// Takes ownership of \a args. /// replace \a endpoint with a wrapped endpoint).
/// Takes ownership of \a read_buffer, which contains leftover bytes read /// When finished, invokes \a on_handshake_done.
/// from the endpoint by the previous handshaker.
/// \a acceptor will be NULL for client-side handshakers. /// \a acceptor will be NULL for client-side handshakers.
void (*do_handshake)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker, 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_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 /// Base struct. To subclass, make this the first member of the
/// implementation struct. /// implementation struct.
struct grpc_handshaker { struct grpc_handshaker {
const struct grpc_handshaker_vtable* vtable; const grpc_handshaker_vtable* vtable;
}; };
/// Called by concrete implementations to initialize the base struct. /// 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); 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 /// grpc_handshake_manager
/// ///
@ -134,15 +131,21 @@ void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr); grpc_handshake_manager* mgr);
/// Invokes handshakers in the order they were added. /// 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. /// invoking the first handshaker.
/// \a acceptor will be NULL for client-side handshakers. /// \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( void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr, 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, 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 */ #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */

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

@ -144,6 +144,12 @@ struct grpc_resource_quota {
/* Closure around rq_reclamation_done */ /* Closure around rq_reclamation_done */
grpc_closure rq_reclamation_done_closure; 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 */ /* Roots of all resource user lists */
grpc_resource_user *roots[GRPC_RULIST_COUNT]; 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;
resource_user->links[list].prev->links[list].next = resource_user->links[list].prev->links[list].next =
resource_user->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; resource_quota->reclaiming = true;
grpc_resource_quota_ref_internal(resource_quota); grpc_resource_quota_ref_internal(resource_quota);
grpc_closure *c = resource_user->reclaimers[destructive]; 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; resource_user->reclaimers[destructive] = NULL;
grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE); grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE);
return true; return true;
@ -465,6 +475,8 @@ static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
GRPC_ERROR_CANCELLED, NULL); GRPC_ERROR_CANCELLED, NULL);
resource_user->reclaimers[0] = NULL; resource_user->reclaimers[0] = NULL;
resource_user->reclaimers[1] = 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) { 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. */ /* Try listening on IPv6 first. */
addr = &wild6; addr = &wild6;
// TODO(rjshade): Test and propagate the returned grpc_error*: // 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); allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done; 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*: // 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) { if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno)); 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/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.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/secure_endpoint.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/env.h" #include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/fake_transport_security.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; return NULL;
} }
void grpc_server_security_connector_shutdown( void grpc_channel_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) { grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
grpc_security_connector_handshake_list *tmp; grpc_handshake_manager *handshake_mgr) {
gpr_mu_lock(&connector->mu); if (connector != NULL) {
while (connector->handshaking_handshakes) { connector->create_handshakers(exec_ctx, connector, handshake_mgr);
tmp = connector->handshaking_handshakes;
grpc_security_handshake_shutdown(
exec_ctx, connector->handshaking_handshakes->handshake);
connector->handshaking_handshakes = tmp->next;
gpr_free(tmp);
} }
gpr_mu_unlock(&connector->mu);
} }
void grpc_channel_security_connector_do_handshake( void grpc_server_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer, grpc_handshake_manager *handshake_mgr) {
gpr_timespec deadline, grpc_security_handshake_done_cb cb, if (connector != NULL) {
void *user_data) { connector->create_handshakers(exec_ctx, connector, handshake_mgr);
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_security_connector_check_peer(grpc_exec_ctx *exec_ctx, void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_security_connector *sc,
tsi_peer peer, tsi_peer peer,
grpc_security_peer_check_cb cb, grpc_auth_context **auth_context,
void *user_data) { grpc_closure *on_peer_checked) {
if (sc == NULL) { 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); tsi_peer_destruct(&peer);
} else { } 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 #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
grpc_security_connector *sc,
const char *file, int line, const char *file, int line,
const char *reason) { const char *reason) {
if (sc == NULL) return; 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, "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
(int)sc->refcount.count, (int)sc->refcount.count - 1, reason); (int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
#else #else
void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_security_connector *sc) {
if (sc == NULL) return; if (sc == NULL) return;
#endif #endif
if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc); 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. -- */ /* -- Fake implementation. -- */
static void fake_channel_destroy(grpc_exec_ctx *exec_ctx, static void fake_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_security_connector *sc) {
grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_call_credentials_unref(exec_ctx, c->request_metadata_creds); grpc_call_credentials_unref(exec_ctx, c->request_metadata_creds);
gpr_free(sc); gpr_free(sc);
} }
static void fake_server_destroy(grpc_exec_ctx *exec_ctx, static void fake_server_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { gpr_free(sc); }
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_check_peer(grpc_exec_ctx *exec_ctx, static void fake_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer, 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; const char *prop_name;
grpc_security_status status = GRPC_SECURITY_OK; grpc_error *error = GRPC_ERROR_NONE;
grpc_auth_context *auth_context = NULL; *auth_context = NULL;
if (peer.property_count != 1) { if (peer.property_count != 1) {
gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); error = GRPC_ERROR_CREATE("Fake peers should only have 1 property.");
status = GRPC_SECURITY_ERROR;
goto end; goto end;
} }
prop_name = peer.properties[0].name; prop_name = peer.properties[0].name;
if (prop_name == NULL || if (prop_name == NULL ||
strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", char *msg;
prop_name == NULL ? "<EMPTY>" : prop_name); gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
status = GRPC_SECURITY_ERROR; prop_name == NULL ? "<EMPTY>" : prop_name);
error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
goto end; goto end;
} }
if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
peer.properties[0].value.length)) { peer.properties[0].value.length)) {
gpr_log(GPR_ERROR, "Invalid value for cert type property."); error = GRPC_ERROR_CREATE("Invalid value for cert type property.");
status = GRPC_SECURITY_ERROR;
goto end; goto end;
} }
auth_context = grpc_auth_context_create(NULL); *auth_context = grpc_auth_context_create(NULL);
grpc_auth_context_add_cstring_property( 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); GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
end: end:
cb(exec_ctx, user_data, status, auth_context); grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
grpc_auth_context_unref(auth_context);
tsi_peer_destruct(&peer); 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); cb(exec_ctx, user_data, GRPC_SECURITY_OK);
} }
static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx, static void fake_channel_create_handshakers(
grpc_channel_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr) {
grpc_slice_buffer *read_buffer, grpc_security_create_handshakers(
gpr_timespec deadline, exec_ctx, tsi_create_fake_handshaker(true /* is_client */), &sc->base,
grpc_security_handshake_done_cb cb, handshake_mgr);
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_server_do_handshake( static void fake_server_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr) {
grpc_slice_buffer *read_buffer, gpr_timespec deadline, grpc_security_create_handshakers(
grpc_security_handshake_done_cb cb, void *user_data) { exec_ctx, tsi_create_fake_handshaker(false /* is_client */), &sc->base,
grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base, handshake_mgr);
false, nonsecure_endpoint, read_buffer, deadline,
cb, user_data);
} }
static grpc_security_connector_vtable fake_channel_vtable = { 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->base.vtable = &fake_channel_vtable;
c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
c->check_call_host = fake_channel_check_call_host; 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; return c;
} }
@ -366,8 +328,7 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create(
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable; c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->do_handshake = fake_server_do_handshake; c->create_handshakers = fake_server_create_handshakers;
gpr_mu_init(&c->mu);
return c; return c;
} }
@ -385,8 +346,7 @@ typedef struct {
tsi_ssl_handshaker_factory *handshaker_factory; tsi_ssl_handshaker_factory *handshaker_factory;
} grpc_ssl_server_security_connector; } grpc_ssl_server_security_connector;
static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_security_connector *sc) {
grpc_ssl_channel_security_connector *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds); 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); gpr_free(sc);
} }
static void ssl_server_destroy(grpc_exec_ctx *exec_ctx, static void ssl_server_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) {
grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c = grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc; (grpc_ssl_server_security_connector *)sc;
if (c->handshaker_factory != NULL) { if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
} }
gpr_mu_destroy(&c->base.mu);
gpr_free(sc); gpr_free(sc);
} }
@ -425,49 +382,33 @@ static grpc_security_status ssl_create_handshaker(
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }
static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx, static void ssl_channel_create_handshakers(
grpc_channel_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr) {
grpc_slice_buffer *read_buffer,
gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_ssl_channel_security_connector *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
tsi_handshaker *handshaker; // Instantiate TSI handshaker.
grpc_security_status status = ssl_create_handshaker( tsi_handshaker *tsi_hs = NULL;
c->handshaker_factory, true, ssl_create_handshaker(c->handshaker_factory, true /* is_client */,
c->overridden_target_name != NULL ? c->overridden_target_name c->overridden_target_name != NULL
: c->target_name, ? c->overridden_target_name
&handshaker); : c->target_name,
if (status != GRPC_SECURITY_OK) { &tsi_hs);
gpr_free(read_buffer); // Create handshakers.
cb(exec_ctx, user_data, status, NULL, NULL); grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
} else { }
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
nonsecure_endpoint, read_buffer, deadline, cb, static void ssl_server_create_handshakers(
user_data);
}
}
static void ssl_server_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr) {
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data) {
grpc_ssl_server_security_connector *c = grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc; (grpc_ssl_server_security_connector *)sc;
tsi_handshaker *handshaker; // Instantiate TSI handshaker.
grpc_security_status status = tsi_handshaker *tsi_hs = NULL;
ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker); ssl_create_handshaker(c->handshaker_factory, false /* is_client */,
if (status != GRPC_SECURITY_OK) { NULL /* peer_name */, &tsi_hs);
gpr_free(read_buffer); // Create handshakers.
cb(exec_ctx, user_data, status, NULL, NULL); grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
nonsecure_endpoint, read_buffer, deadline, cb,
user_data);
}
} }
static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { 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; return ctx;
} }
static grpc_security_status ssl_check_peer(grpc_security_connector *sc, static grpc_error *ssl_check_peer(grpc_security_connector *sc,
const char *peer_name, const char *peer_name, const tsi_peer *peer,
const tsi_peer *peer, grpc_auth_context **auth_context) {
grpc_auth_context **auth_context) {
/* Check the ALPN. */ /* Check the ALPN. */
const tsi_peer_property *p = const tsi_peer_property *p =
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
if (p == NULL) { if (p == NULL) {
gpr_log(GPR_ERROR, "Missing selected ALPN property."); return GRPC_ERROR_CREATE(
return GRPC_SECURITY_ERROR; "Cannot check peer: missing selected ALPN property.");
} }
if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
gpr_log(GPR_ERROR, "Invalid ALPN value."); return GRPC_ERROR_CREATE("Cannot check peer: invalid ALPN value.");
return GRPC_SECURITY_ERROR;
} }
/* Check the peer name if specified. */ /* Check the peer name if specified. */
if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { 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); char *msg;
return GRPC_SECURITY_ERROR; 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); *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, static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer, grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb, grpc_auth_context **auth_context,
void *user_data) { grpc_closure *on_peer_checked) {
grpc_ssl_channel_security_connector *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
grpc_security_status status; grpc_error *error = ssl_check_peer(sc, c->overridden_target_name != NULL
grpc_auth_context *auth_context = NULL; ? c->overridden_target_name
status = ssl_check_peer(sc, c->overridden_target_name != NULL : c->target_name,
? c->overridden_target_name &peer, auth_context);
: c->target_name, grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
&peer, &auth_context);
cb(exec_ctx, user_data, status, auth_context);
grpc_auth_context_unref(auth_context);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
} }
static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer, grpc_security_connector *sc, tsi_peer peer,
grpc_security_peer_check_cb cb, grpc_auth_context **auth_context,
void *user_data) { grpc_closure *on_peer_checked) {
grpc_auth_context *auth_context = NULL; grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context);
grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
cb(exec_ctx, user_data, status, auth_context); grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
grpc_auth_context_unref(auth_context);
} }
static void add_shallow_auth_property_to_peer(tsi_peer *peer, 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); return GRPC_SLICE_LENGTH(default_pem_root_certs);
} }
grpc_security_status grpc_ssl_channel_security_connector_create( grpc_security_status grpc_ssl_channel_security_connector_create(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds, grpc_call_credentials *request_metadata_creds,
const grpc_ssl_config *config, const char *target_name, const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc) { const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); 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 = c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds); grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host; 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_split_host_port(target_name, &c->target_name, &port);
gpr_free(port); gpr_free(port);
if (overridden_target_name != NULL) { if (overridden_target_name != NULL) {
@ -802,8 +739,7 @@ error:
} }
grpc_security_status grpc_ssl_server_security_connector_create( grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings = const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols); gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@ -847,8 +783,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
*sc = NULL; *sc = NULL;
goto error; goto error;
} }
gpr_mu_init(&c->base.mu); c->base.create_handshakers = ssl_server_create_handshakers;
c->base.do_handshake = ssl_server_do_handshake;
*sc = &c->base; *sc = &c->base;
gpr_free((void *)alpn_protocol_strings); gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths); gpr_free(alpn_protocol_string_lengths);

@ -35,6 +35,8 @@
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
#include <grpc/grpc_security.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/endpoint.h"
#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/tsi/transport_security_interface.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" #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 { typedef struct {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc); void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc);
void (*check_peer)(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, tsi_peer peer, grpc_auth_context **auth_context,
void *user_data); grpc_closure *on_peer_checked);
} grpc_security_connector_vtable; } grpc_security_connector_vtable;
typedef struct grpc_security_connector_handshake_list { typedef struct grpc_security_connector_handshake_list {
@ -109,12 +101,12 @@ void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
#endif #endif
/* Check the peer. Callee takes ownership of the peer object. /* 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, void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_security_connector *sc,
tsi_peer peer, tsi_peer peer,
grpc_security_peer_check_cb cb, grpc_auth_context **auth_context,
void *user_data); grpc_closure *on_peer_checked);
/* Util to encapsulate the connector in a channel arg. */ /* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); 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_channel_security_connector *sc, const char *host,
grpc_auth_context *auth_context, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data); grpc_security_call_host_check_cb cb, void *user_data);
void (*do_handshake)(grpc_exec_ctx *exec_ctx, void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr);
grpc_slice_buffer *read_buffer, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
}; };
/* Checks that the host that will be set for a call is acceptable. */ /* 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, const char *host, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data); grpc_security_call_host_check_cb cb, void *user_data);
/* Handshake. */ /* Registers handshakers with \a handshake_mgr. */
void grpc_channel_security_connector_do_handshake( void grpc_channel_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector, grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer, grpc_handshake_manager *handshake_mgr);
gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
/* --- server_security_connector object. --- /* --- server_security_connector object. ---
@ -172,25 +161,14 @@ typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector { struct grpc_server_security_connector {
grpc_security_connector base; grpc_security_connector base;
gpr_mu mu; void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
grpc_security_connector_handshake_list *handshaking_handshakes; grpc_server_security_connector *sc,
const grpc_channel_args *channel_args; grpc_handshake_manager *handshake_mgr);
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 grpc_server_security_connector_do_handshake( void grpc_server_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, grpc_handshake_manager *handshake_mgr);
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);
/* --- Creation security connectors. --- */ /* --- 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 #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
#include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/security/transport/security_connector.h" #include "src/core/lib/security/transport/security_connector.h"
/* Calls the callback upon completion. Takes owership of handshaker and /// Creates any necessary security handshakers and adds them to
* read_buffer. */ /// \a handshake_mgr.
void grpc_do_security_handshake( void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx,
grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, tsi_handshaker *handshaker,
grpc_security_connector *connector, bool is_client_side, grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint, grpc_slice_buffer *read_buffer, grpc_handshake_manager *handshake_mgr);
gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake); #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H */

@ -35,8 +35,10 @@
#include <grpc/support/useful.h> #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) { int64_t min_timeout_millis, int64_t max_timeout_millis) {
backoff->initial_connect_timeout = initial_connect_timeout;
backoff->multiplier = multiplier; backoff->multiplier = multiplier;
backoff->jitter = jitter; backoff->jitter = jitter;
backoff->min_timeout_millis = min_timeout_millis; 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) { gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) {
backoff->current_timeout_millis = backoff->min_timeout_millis; backoff->current_timeout_millis = backoff->initial_connect_timeout;
return gpr_time_add( const int64_t first_timeout =
now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); 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. */ /* 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) { 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; backoff->multiplier * (double)backoff->current_timeout_millis;
double jitter_range = backoff->jitter * new_timeout_millis; backoff->current_timeout_millis =
double jitter = 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) * (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
jitter_range; jitter_range_width;
backoff->current_timeout_millis = backoff->current_timeout_millis =
GPR_CLAMP((int64_t)(new_timeout_millis + jitter), (int64_t)((double)(backoff->current_timeout_millis) + jitter);
backoff->min_timeout_millis, backoff->max_timeout_millis);
return gpr_time_add( const gpr_timespec current_deadline = gpr_time_add(
now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN)); 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) { void gpr_backoff_reset(gpr_backoff *backoff) {
// forces step() to return a timeout of min_timeout_millis backoff->current_timeout_millis = backoff->initial_connect_timeout;
backoff->current_timeout_millis = 0;
} }

@ -37,7 +37,9 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
typedef struct { 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; double multiplier;
/// const: amount to randomize backoffs /// const: amount to randomize backoffs
double jitter; double jitter;
@ -54,7 +56,8 @@ typedef struct {
} gpr_backoff; } gpr_backoff;
/// Initialize backoff machinery - does not need to be destroyed /// 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); int64_t min_timeout_millis, int64_t max_timeout_millis);
/// Begin retry loop: returns a timespec for the NEXT retry /// 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; error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error; 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->received_initial_metadata = 1;
call->buffered_metadata[0] = op->data.recv_initial_metadata; call->buffered_metadata[0] = op->data.recv_initial_metadata;
grpc_closure_init(&call->receiving_initial_metadata_ready, grpc_closure_init(&call->receiving_initial_metadata_ready,

@ -43,11 +43,21 @@ namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer; 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() { void CompletionQueue::Shutdown() {
g_gli_initializer.summon(); 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( CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(

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

@ -87,7 +87,6 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Grpc.Auth.nuspec" />
<None Include="Grpc.Auth.project.json" /> <None Include="Grpc.Auth.project.json" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </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(); var credentials = new FakeCallCredentials();
Assert.AreSame(credentials, options.WithCredentials(credentials).Credentials); 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. // Check that the original instance is unchanged.
Assert.IsNull(options.Headers); Assert.IsNull(options.Headers);
Assert.IsNull(options.Deadline); Assert.IsNull(options.Deadline);
@ -74,6 +77,7 @@ namespace Grpc.Core.Tests
Assert.IsNull(options.WriteOptions); Assert.IsNull(options.WriteOptions);
Assert.IsNull(options.PropagationToken); Assert.IsNull(options.PropagationToken);
Assert.IsNull(options.Credentials); Assert.IsNull(options.Credentials);
Assert.AreEqual(default(CallFlags), options.Flags);
} }
[Test] [Test]
@ -94,5 +98,16 @@ namespace Grpc.Core.Tests
Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken); Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken);
Assert.Throws(typeof(ArgumentException), () => new CallOptions(cancellationToken: token, propagationToken: propagationToken2).Normalize()); 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"; 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; 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(); throw new NotImplementedException();
} }
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{ {
UnaryResponseClientHandler = callback; 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; ReceivedStatusOnClientHandler = callback;
} }
public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray) public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{ {
ReceivedStatusOnClientHandler = callback; ReceivedStatusOnClientHandler = callback;
} }

@ -50,6 +50,7 @@ namespace Grpc.Core
WriteOptions writeOptions; WriteOptions writeOptions;
ContextPropagationToken propagationToken; ContextPropagationToken propagationToken;
CallCredentials credentials; CallCredentials credentials;
CallFlags flags;
/// <summary> /// <summary>
/// Creates a new instance of <c>CallOptions</c> struct. /// Creates a new instance of <c>CallOptions</c> struct.
@ -69,6 +70,7 @@ namespace Grpc.Core
this.writeOptions = writeOptions; this.writeOptions = writeOptions;
this.propagationToken = propagationToken; this.propagationToken = propagationToken;
this.credentials = credentials; this.credentials = credentials;
this.flags = default(CallFlags);
} }
/// <summary> /// <summary>
@ -125,6 +127,24 @@ namespace Grpc.Core
get { return this.credentials; } 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> /// <summary>
/// Returns new instance of <see cref="CallOptions"/> with /// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved. /// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
@ -197,6 +217,32 @@ namespace Grpc.Core
return newOptions; 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> /// <summary>
/// Returns a new instance of <see cref="CallOptions"/> with /// Returns a new instance of <see cref="CallOptions"/> with
/// all previously unset values set to their defaults and deadline and cancellation /// all previously unset values set to their defaults and deadline and cancellation

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

@ -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 metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
using (var ctx = BatchContextSafeHandle.Create()) 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); var ev = cq.Pluck(ctx.Handle);
@ -150,7 +150,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>(); unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) 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; return unaryResponseTcs.Task;
} }
@ -174,7 +174,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>(); unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{ {
call.StartClientStreaming(HandleUnaryResponse, metadataArray); call.StartClientStreaming(HandleUnaryResponse, metadataArray, details.Options.Flags);
} }
return unaryResponseTcs.Task; return unaryResponseTcs.Task;
@ -200,7 +200,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) 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); call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
} }
@ -222,7 +222,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>(); streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers)) using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{ {
call.StartDuplexStreaming(HandleFinished, metadataArray); call.StartDuplexStreaming(HandleFinished, metadataArray, details.Options.Flags);
} }
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders); 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(); 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()) using (completionQueue.NewScope())
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata())); 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(); .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(); .CheckOk();
} }
public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray) public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{ {
using (completionQueue.NewScope()) using (completionQueue.NewScope())
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata())); 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()) using (completionQueue.NewScope())
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient())); 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()) using (completionQueue.NewScope())
{ {
var ctx = BatchContextSafeHandle.Create(); var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient())); 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 #endregion
using System; using System;
using Grpc.Core;
namespace Grpc.Core.Internal namespace Grpc.Core.Internal
{ {
@ -54,19 +55,19 @@ namespace Grpc.Core.Internal
{ {
void Cancel(); void Cancel();
void CancelWithStatus(Grpc.Core.Status status); void CancelWithStatus(Status status);
string GetPeer(); 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); void StartReceiveMessage(ReceivedMessageHandler callback);
@ -74,11 +75,11 @@ namespace Grpc.Core.Internal
void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray); 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 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); 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_delegate(CallSafeHandle call);
public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description); 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, 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, 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, public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags,
MetadataArraySafeHandle metadataArray, WriteFlags writeFlags); MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call, 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, public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata); BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call, public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -62,13 +62,12 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Grpc.HealthCheck.nuspec" />
<None Include="Grpc.HealthCheck.project.json" /> <None Include="Grpc.HealthCheck.project.json" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> <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> <Name>Grpc.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </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"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -63,13 +63,12 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Grpc.Reflection.nuspec" />
<None Include="Grpc.Reflection.project.json" /> <None Include="Grpc.Reflection.project.json" />
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> <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> <Name>Grpc.Core</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@rem Current package versions @rem Current package versions
set VERSION=1.0.1 set VERSION=1.1.0-dev
set PROTOBUF_VERSION=3.0.0 set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe @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.Core\project.json --output ..\..\artifacts || goto :error
%DOTNET% pack --configuration Release Grpc.Auth\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.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.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version "1.0.1" -OutputDirectory ..\..\artifacts %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory @rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error 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.Core/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Auth/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.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.nuspec -Version "1.1.0-dev" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.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 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx, grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
const char *send_buffer, size_t send_buffer_len, const char *send_buffer, size_t send_buffer_len, uint32_t write_flags,
grpc_metadata_array *initial_metadata, uint32_t write_flags) { grpc_metadata_array *initial_metadata, uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */ /* TODO: don't use magic number */
grpc_op ops[6]; grpc_op ops[6];
memset(ops, 0, sizeof(ops)); 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.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata = ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata; ctx->send_initial_metadata.metadata;
ops[0].flags = 0; ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL; ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE; 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 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_client_streaming(grpc_call *call, grpcsharp_call_start_client_streaming(grpc_call *call,
grpcsharp_batch_context *ctx, 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 */ /* TODO: don't use magic number */
grpc_op ops[4]; grpc_op ops[4];
memset(ops, 0, sizeof(ops)); 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.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata = ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata; ctx->send_initial_metadata.metadata;
ops[0].flags = 0; ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL; ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA; 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( GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, 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 */ /* TODO: don't use magic number */
grpc_op ops[4]; grpc_op ops[4];
memset(ops, 0, sizeof(ops)); 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.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata = ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata; ctx->send_initial_metadata.metadata;
ops[0].flags = 0; ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL; ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE; 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 GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_duplex_streaming(grpc_call *call, grpcsharp_call_start_duplex_streaming(grpc_call *call,
grpcsharp_batch_context *ctx, 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 */ /* TODO: don't use magic number */
grpc_op ops[2]; grpc_op ops[2];
memset(ops, 0, sizeof(ops)); 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.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata = ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata; ctx->send_initial_metadata.metadata;
ops[0].flags = 0; ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL; ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT; ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;

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

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

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

@ -84,9 +84,9 @@ post_install do |installer|
end end
# CocoaPods creates duplicated library targets of gRPC-Core when the test targets include # 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. # 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| target.build_configurations.each do |config|
# TODO(zyc): Remove this setting after the issue is resolved # TODO(zyc): Remove this setting after the issue is resolved
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void # 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', $this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]); ['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$time = new Grpc\Timeval(1000); $time = new Grpc\Timeval(1000);
$state = $this->channel->watchConnectivityState(123, $time); $state = $this->channel->watchConnectivityState(1, $time);
$this->assertTrue($state); $this->assertTrue($state);
unset($time); unset($time);
} }

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

@ -904,6 +904,21 @@ class Server(six.with_metaclass(abc.ABCMeta)):
""" """
raise NotImplementedError() 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 @abc.abstractmethod
def start(self): def start(self):
"""Starts this Server's service of RPCs. """Starts this Server's service of RPCs.
@ -914,7 +929,7 @@ class Server(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod @abc.abstractmethod
def stop(self, grace): def stop(self, grace, shutdown_handler_grace=None):
"""Stops this Server's service of RPCs. """Stops this Server's service of RPCs.
All calls to this method immediately stop service of new RPCs. When existing 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 aborted by this Server's stopping. If None, all RPCs will be aborted
immediately and this method will block until this Server is completely immediately and this method will block until this Server is completely
stopped. stopped.
shutdown_handler_grace: A duration of time in seconds or None. This
value is passed to all shutdown handlers.
Returns: Returns:
A threading.Event that will be set when this Server has completely 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) 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. """Creates a Server with which RPCs can be serviced.
Args: Args:
@ -1244,13 +1262,19 @@ def server(thread_pool, handlers=None, options=None):
returned Server is started. returned Server is started.
options: A sequence of string-value pairs according to which to configure options: A sequence of string-value pairs according to which to configure
the created server. 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: Returns:
A Server with which RPCs can be serviced. A Server with which RPCs can be serviced.
""" """
from grpc import _server from grpc import _server
return _server.Server(thread_pool, () if handlers is None else handlers, 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__ ################################# ################################### __all__ #################################

@ -60,7 +60,8 @@ _CANCELLED = 'cancelled'
_EMPTY_FLAGS = 0 _EMPTY_FLAGS = 0
_EMPTY_METADATA = cygrpc.Metadata(()) _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): def _serialized_request(request_event):
@ -595,14 +596,18 @@ class _ServerStage(enum.Enum):
class _ServerState(object): 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.lock = threading.Lock()
self.completion_queue = completion_queue self.completion_queue = completion_queue
self.server = server self.server = server
self.generic_handlers = list(generic_handlers) self.generic_handlers = list(generic_handlers)
self.thread_pool = thread_pool self.thread_pool = thread_pool
self.exit_grace = exit_grace
self.exit_shutdown_handler_grace = exit_shutdown_handler_grace
self.stage = _ServerStage.STOPPED self.stage = _ServerStage.STOPPED
self.shutdown_events = None self.shutdown_events = None
self.shutdown_handlers = []
# TODO(https://github.com/grpc/grpc/issues/6597): eliminate these fields. # TODO(https://github.com/grpc/grpc/issues/6597): eliminate these fields.
self.rpc_states = set() self.rpc_states = set()
@ -672,41 +677,45 @@ def _serve(state):
return return
def _stop(state, grace): def _stop(state, grace, shutdown_handler_grace):
with state.lock: shutdown_event = threading.Event()
if state.stage is _ServerStage.STOPPED:
shutdown_event = threading.Event() def cancel_all_calls_after_grace():
shutdown_event.set() with state.lock:
return shutdown_event if state.stage is _ServerStage.STOPPED:
else: shutdown_event.set()
if state.stage is _ServerStage.STARTED: return
state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG) elif state.stage is _ServerStage.STARTED:
do_shutdown = True
state.stage = _ServerStage.GRACE state.stage = _ServerStage.GRACE
state.shutdown_events = [] state.shutdown_events = []
state.due.add(_SHUTDOWN_TAG) else:
shutdown_event = threading.Event() do_shutdown = False
state.shutdown_events.append(shutdown_event) 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() state.server.cancel_all_calls()
# TODO(https://github.com/grpc/grpc/issues/6597): delete this loop. # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
for rpc_state in state.rpc_states: for rpc_state in state.rpc_states:
with rpc_state.condition: with rpc_state.condition:
rpc_state.client = _CANCELLED rpc_state.client = _CANCELLED
rpc_state.condition.notify_all() rpc_state.condition.notify_all()
else:
def cancel_all_calls_after_grace(): if grace is None:
shutdown_event.wait(timeout=grace) cancel_all_calls_after_grace()
with state.lock: else:
state.server.cancel_all_calls() threading.Thread(target=cancel_all_calls_after_grace).start()
# 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()
return shutdown_event return shutdown_event
@ -719,9 +728,9 @@ def _start(state):
_request_call(state) _request_call(state)
def cleanup_server(timeout): def cleanup_server(timeout):
if timeout is None: if timeout is None:
_stop(state, _UNEXPECTED_EXIT_SERVER_GRACE).wait() _stop(state, state.exit_grace, state.exit_shutdown_handler_grace).wait()
else: else:
_stop(state, timeout).wait() _stop(state, timeout, 0).wait()
thread = _common.CleanupThread( thread = _common.CleanupThread(
cleanup_server, target=_serve, args=(state,)) cleanup_server, target=_serve, args=(state,))
@ -729,12 +738,16 @@ def _start(state):
class Server(grpc.Server): 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() completion_queue = cygrpc.CompletionQueue()
server = cygrpc.Server(_common.channel_args(options)) server = cygrpc.Server(_common.channel_args(options))
server.register_completion_queue(completion_queue) server.register_completion_queue(completion_queue)
self._state = _ServerState( 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): def add_generic_rpc_handlers(self, generic_rpc_handlers):
_add_generic_handlers(self._state, 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): def add_secure_port(self, address, server_credentials):
return _add_secure_port(self._state, _common.encode(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): def start(self):
_start(self._state) _start(self._state)
def stop(self, grace): def stop(self, grace, shutdown_handler_grace=None):
return _stop(self._state, grace) return _stop(self._state, grace, shutdown_handler_grace)
def __del__(self): 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/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c',
'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c', 'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c', 'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c', 'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c', 'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.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/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c', 'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c', 'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.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.c',
'src/core/ext/client_channel/subchannel_index.c', 'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.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.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.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), '--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_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, same_proto_file,
]) ])
if protoc_result != 0: if protoc_result != 0:
@ -241,7 +241,7 @@ class SplitCommonTest(unittest.TestCase, CommonTestMixin):
'', '',
'--proto_path={}'.format(self.proto_directory), '--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_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, services_proto_file,
messages_proto_file, messages_proto_file,
]) ])
@ -285,7 +285,7 @@ class SplitSeparateTest(unittest.TestCase, SeparateTestMixin):
'', '',
'--proto_path={}'.format(self.proto_directory), '--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_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, services_proto_file,
messages_proto_file, messages_proto_file,
]) ])

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

@ -43,6 +43,8 @@ import threading
import time import time
import unittest import unittest
import grpc
from grpc.framework.foundation import logging_pool
from tests.unit import _exit_scenarios from tests.unit import _exit_scenarios
SCENARIO_FILE = os.path.abspath(os.path.join( 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'] BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt']
INIT_TIME = 1.0 INIT_TIME = 1.0
SHUTDOWN_GRACE = 5.0
processes = [] processes = []
process_lock = threading.Lock() process_lock = threading.Lock()
@ -182,5 +184,24 @@ class ExitTest(unittest.TestCase):
interrupt_and_wait(process) 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__': if __name__ == '__main__':
unittest.main(verbosity=2) unittest.main(verbosity=2)

@ -29,18 +29,17 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE @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 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 @rem Current package versions
set VERSION=${settings.csharp_version} set VERSION=${settings.csharp_version}
set PROTOBUF_VERSION=3.0.0 set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe @rem Adjust the location of nuget.exe
set NUGET=C:\nuget\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 Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this? @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=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86${"\\"}
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64${"\\"} xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64${"\\"}
@rem Fetch all dependencies %%DOTNET% restore . || goto :error
%%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 %%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.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
%%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
%%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 @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 @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');" 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_obsolete.zip ..\..\artifacts${"\\"} xcopy /Y /I csharp_nugets_windows_dotnetcli.zip ..\..\artifacts\ || goto :error
goto :EOF goto :EOF

@ -65,6 +65,7 @@
dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts 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.Auth/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck/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.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.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) # More sanity test dependencies (bazel)
RUN apt-get install -y openjdk-8-jdk RUN apt-get install -y openjdk-8-jdk
# TOOD(jtattermusch): pin the bazel version # Check out Bazel version 0.4.1 since this version allows running
RUN git clone https://github.com/bazelbuild/bazel.git /bazel # ./compile.sh without a local protoc dependency
RUN cd /bazel && ./compile.sh # 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/ RUN ln -s /bazel/output/bazel /bin/
#=================== #===================

@ -64,9 +64,11 @@ typedef struct servers_fixture {
} servers_fixture; } servers_fixture;
typedef struct request_sequences { typedef struct request_sequences {
size_t n; size_t n; /* number of iterations */
int *connections; int *connections; /* indexed by the interation number, value is the index of
int *connectivity_states; 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; } request_sequences;
typedef void (*verifier_fn)(const servers_fixture *, grpc_channel *, 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); gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str);
arg_array[0].type = GRPC_ARG_INTEGER; 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[0].value.integer = RETRY_TIMEOUT;
arg_array[1].type = GRPC_ARG_STRING; arg_array[1].type = GRPC_ARG_STRING;
arg_array[1].key = GRPC_ARG_LB_POLICY_NAME; 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); gpr_asprintf(&client_hostport, "ipv4:%s", servers_hostports_str);
arg_array[0].type = GRPC_ARG_INTEGER; 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[0].value.integer = RETRY_TIMEOUT;
arg_array[1].type = GRPC_ARG_STRING; arg_array[1].type = GRPC_ARG_STRING;
arg_array[1].key = GRPC_ARG_LB_POLICY_NAME; 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++) { for (size_t i = 0; i < sequences->n; i++) {
const grpc_connectivity_state actual = sequences->connectivity_states[i]; const grpc_connectivity_state actual = sequences->connectivity_states[i];
const grpc_connectivity_state expected = GRPC_CHANNEL_TRANSIENT_FAILURE; if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
if (actual != expected) { actual != GRPC_CHANNEL_CONNECTING) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " "CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
"at iteration #%d", "GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
grpc_connectivity_state_name(expected), "'%s' at iteration #%d",
grpc_connectivity_state_name(actual), (int)i); grpc_connectivity_state_name(actual), (int)i);
abort(); 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 /* 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, * servers were available */
* after all servers are gone. */
grpc_connectivity_state actual = sequences->connectivity_states[0]; grpc_connectivity_state actual = sequences->connectivity_states[0];
grpc_connectivity_state expected = GRPC_CHANNEL_READY; grpc_connectivity_state expected = GRPC_CHANNEL_READY;
if (actual != expected) { if (actual != expected) {
@ -842,17 +845,21 @@ static void verify_partial_carnage_round_robin(
abort(); 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]; actual = sequences->connectivity_states[num_iters - 1];
expected = GRPC_CHANNEL_TRANSIENT_FAILURE; for (i = 0; i < sequences->n; i++) {
if (actual != expected) { if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
gpr_log(GPR_ERROR, actual != GRPC_CHANNEL_CONNECTING) {
"CONNECTIVITY STATUS SEQUENCE FAILURE: expected '%s', got '%s' " gpr_log(GPR_ERROR,
"at iteration #%d", "CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
grpc_connectivity_state_name(expected), "GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
grpc_connectivity_state_name(actual), (int)num_iters - 1); "'%s' at iteration #%d",
abort(); grpc_connectivity_state_name(actual), (int)i);
abort();
}
} }
gpr_free(expected_connection_sequence); gpr_free(expected_connection_sequence);
} }
@ -877,68 +884,21 @@ static void verify_rebirth_round_robin(const servers_fixture *f,
grpc_channel *client, grpc_channel *client,
const request_sequences *sequences, const request_sequences *sequences,
const size_t num_iters) { 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); 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 */ /* first iteration succeeds */
GPR_ASSERT(sequences->connections[0] != -1); GPR_ASSERT(sequences->connections[0] != -1);
/* then we fail for a while... */ /* then we fail for a while... */
GPR_ASSERT(sequences->connections[1] == -1); GPR_ASSERT(sequences->connections[1] == -1);
/* ... but should be up at "unique_seq_first_idx" */ /* ... but should be up eventually */
GPR_ASSERT(sequences->connections[unique_seq_first_idx] != -1); size_t first_iter_back_up = ~0ul;
for (size_t i = 2; i < sequences->n; ++i) {
for (j = 0, i = unique_seq_first_idx; i < num_iters; i++) { if (sequences->connections[i] != -1) {
const int actual = sequences->connections[i]; first_iter_back_up = i;
const int expected = break;
expected_connection_sequence[j++ % expected_seq_length];
if (actual != expected) {
print_failed_expectations(expected_connection_sequence,
sequences->connections, expected_seq_length,
num_iters);
abort();
} }
} }
GPR_ASSERT(first_iter_back_up != ~0ul);
/* We can assert that the first client channel state should be READY, when all /* 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 * 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; 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) { if (sequences->connectivity_states[i] == GRPC_CHANNEL_TRANSIENT_FAILURE) {
found_failure_status = true; found_failure_status = true;
break; break;
@ -978,14 +938,11 @@ static void verify_rebirth_round_robin(const servers_fixture *f,
"CONNECTIVITY STATUS SEQUENCE FAILURE: " "CONNECTIVITY STATUS SEQUENCE FAILURE: "
"GRPC_CHANNEL_TRANSIENT_FAILURE status not found. Got the following " "GRPC_CHANNEL_TRANSIENT_FAILURE status not found. Got the following "
"instead:"); "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, gpr_log(GPR_ERROR, "[%d]: %s", (int)i,
grpc_connectivity_state_name(sequences->connectivity_states[i])); grpc_connectivity_state_name(sequences->connectivity_states[i]));
} }
} }
gpr_free(expected_connection_sequence);
gpr_free(seen_elements);
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {

@ -126,8 +126,16 @@ int main(int argc, char **argv) {
char *addr; 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 */ /* 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 */ /* and an initial call to them */
grpc_call *call1 = grpc_channel_create_call( grpc_call *call1 = grpc_channel_create_call(
chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq, "/foo", "127.0.0.1", 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_options thdopt = gpr_thd_options_default();
gpr_thd_id thdid; 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.channel = f.client;
ce.cq = f.cq; 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_raw_byte_buffer_create(&request_payload_slice, 1);
grpc_byte_buffer *response_payload = grpc_byte_buffer *response_payload =
grpc_raw_byte_buffer_create(&response_payload_slice, 1); 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); cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_op ops[6]; grpc_op ops[6];
grpc_op *op; 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) { static void test_simple_delayed_request_short(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f; 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); gpr_log(GPR_INFO, "%s/%s", "test_simple_delayed_request_short", config.name);
f = config.create_fixture(NULL, NULL); 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); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);
} }
static void test_simple_delayed_request_long(grpc_end2end_test_config config) { static void test_simple_delayed_request_long(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f; 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); gpr_log(GPR_INFO, "%s/%s", "test_simple_delayed_request_long", config.name);
f = config.create_fixture(NULL, NULL); f = config.create_fixture(NULL, NULL);
/* This timeout should be longer than a single retry */ /* 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); end_test(&f);
config.tear_down_data(&f); config.tear_down_data(&f);
} }

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

@ -39,61 +39,110 @@
static void test_constant_backoff(void) { static void test_constant_backoff(void) {
gpr_backoff backoff; 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 now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now); 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++) { for (int i = 0; i < 10000; i++) {
next = gpr_backoff_step(&backoff, now); 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; now = next;
} }
} }
static void test_no_jitter_backoff(void) { static void test_min_connect(void) {
gpr_backoff backoff; 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 now = gpr_time_0(GPR_TIMESPAN);
gpr_timespec next = gpr_backoff_begin(&backoff, now); gpr_timespec next = gpr_backoff_begin(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(1, GPR_TIMESPAN), next) == 0); GPR_ASSERT(gpr_time_to_millis(gpr_time_sub(next, now)) == 200);
now = next; }
next = gpr_backoff_step(&backoff, now);
GPR_ASSERT(gpr_time_cmp(gpr_time_from_millis(3, GPR_TIMESPAN), next) == 0); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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; now = next;
next = gpr_backoff_step(&backoff, now); 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) { int main(int argc, char **argv) {
@ -101,7 +150,9 @@ int main(int argc, char **argv) {
gpr_time_init(); gpr_time_init();
test_constant_backoff(); test_constant_backoff();
test_min_connect();
test_no_jitter_backoff(); test_no_jitter_backoff();
test_jitter_backoff();
return 0; return 0;
} }

@ -44,8 +44,11 @@
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
void test_unparsable_target(void) { 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); GPR_ASSERT(port == 0);
grpc_server_destroy(server);
} }
void test_add_same_port_twice() { void test_add_same_port_twice() {

@ -138,7 +138,7 @@ TEST_F(CrashTest, ResponseStream) {
auto server = CreateServerAndClient("response"); auto server = CreateServerAndClient("response");
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), 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(); KillClient();
server->Shutdown(); server->Shutdown();
GPR_ASSERT(HadOneResponseStream()); GPR_ASSERT(HadOneResponseStream());
@ -148,7 +148,7 @@ TEST_F(CrashTest, BidiStream) {
auto server = CreateServerAndClient("bidi"); auto server = CreateServerAndClient("bidi");
gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), 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(); KillClient();
server->Shutdown(); server->Shutdown();
GPR_ASSERT(HadOneBidiStream()); GPR_ASSERT(HadOneBidiStream());

@ -344,7 +344,7 @@ void grpc::testing::interop::RunServer(
} }
std::unique_ptr<Server> server(builder.BuildAndStart()); std::unique_ptr<Server> server(builder.BuildAndStart());
gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str()); 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); sleep(5);
} }
} }

@ -37,10 +37,10 @@
#include "test/cpp/interop/server_helper.h" #include "test/cpp/interop/server_helper.h"
#include "test/cpp/util/test_config.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) { 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) { int main(int argc, char** argv) {

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

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

@ -91,7 +91,7 @@ print yaml.dump({
'boringssl': True, 'boringssl': True,
'defaults': 'boringssl', 'defaults': 'boringssl',
'cpu_cost': guess_cpu(scenario_json, False), 'cpu_cost': guess_cpu(scenario_json, False),
'exclude_configs': ['tsan'], 'exclude_configs': ['tsan', 'asan'],
'timeout_seconds': 6*60 'timeout_seconds': 6*60
} }
for scenario_json in scenario_config.CXXLanguage().scenarios() for scenario_json in scenario_config.CXXLanguage().scenarios()
@ -99,7 +99,7 @@ print yaml.dump({
] + [ ] + [
{ {
'name': 'json_run_localhost', '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)], 'args': ['--scenarios_json', _scenario_json_string(scenario_json, True)],
'ci_platforms': ['linux'], 'ci_platforms': ['linux'],
'platforms': ['linux'], 'platforms': ['linux'],
@ -108,7 +108,7 @@ print yaml.dump({
'boringssl': True, 'boringssl': True,
'defaults': 'boringssl', 'defaults': 'boringssl',
'cpu_cost': guess_cpu(scenario_json, True), '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 'timeout_seconds': 6*60
} }
for scenario_json in scenario_config.CXXLanguage().scenarios() 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) # More sanity test dependencies (bazel)
RUN apt-get install -y openjdk-8-jdk RUN apt-get install -y openjdk-8-jdk
# TOOD(jtattermusch): pin the bazel version # Check out Bazel version 0.4.1 since this version allows running
RUN git clone https://github.com/bazelbuild/bazel.git /bazel # ./compile.sh without a local protoc dependency
RUN cd /bazel && ./compile.sh # 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/ 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/plugin/plugin_credentials.h \
src/core/lib/security/credentials/ssl/ssl_credentials.h \ src/core/lib/security/credentials/ssl/ssl_credentials.h \
src/core/lib/security/transport/auth_filters.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/secure_endpoint.h \
src/core/lib/security/transport/security_connector.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/transport/tsi_error.h \
src/core/lib/security/util/b64.h \ src/core/lib/security/util/b64.h \
src/core/lib/security/util/json_util.h \ src/core/lib/security/util/json_util.h \
@ -931,6 +931,7 @@ src/core/lib/tsi/ssl_transport_security.h \
src/core/lib/tsi/ssl_types.h \ src/core/lib/tsi/ssl_types.h \
src/core/lib/tsi/transport_security.h \ src/core/lib/tsi/transport_security.h \
src/core/lib/tsi/transport_security_interface.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.h \
src/core/ext/client_channel/client_channel_factory.h \ src/core/ext/client_channel/client_channel_factory.h \
src/core/ext/client_channel/connector.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.h \
src/core/ext/client_channel/subchannel_index.h \ src/core/ext/client_channel/subchannel_index.h \
src/core/ext/client_channel/uri_parser.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/grpclb.h \
src/core/ext/lb_policy/grpclb/load_balancer_api.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 \ 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/plugin/plugin_credentials.c \
src/core/lib/security/credentials/ssl/ssl_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/client_auth_filter.c \
src/core/lib/security/transport/handshake.c \
src/core/lib/security/transport/secure_endpoint.c \ src/core/lib/security/transport/secure_endpoint.c \
src/core/lib/security/transport/security_connector.c \ src/core/lib/security/transport/security_connector.c \
src/core/lib/security/transport/security_handshaker.c \
src/core/lib/security/transport/server_auth_filter.c \ src/core/lib/security/transport/server_auth_filter.c \
src/core/lib/security/transport/tsi_error.c \ src/core/lib/security/transport/tsi_error.c \
src/core/lib/security/util/b64.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/fake_transport_security.c \
src/core/lib/tsi/ssl_transport_security.c \ src/core/lib/tsi/ssl_transport_security.c \
src/core/lib/tsi/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/transport/chttp2/client/secure/secure_channel_create.c \
src/core/ext/client_channel/channel_connectivity.c \ src/core/ext/client_channel/channel_connectivity.c \
src/core/ext/client_channel/client_channel.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.c \
src/core/ext/client_channel/subchannel_index.c \ src/core/ext/client_channel/subchannel_index.c \
src/core/ext/client_channel/uri_parser.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.c \
src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
src/core/ext/transport/chttp2/client/insecure/channel_create.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) # Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository. # 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 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. # DOCKERFILE_DIR - Directory in which Dockerfile file is located.
# DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root) # 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. # 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 # $@ - Extra args to pass to docker run
# Use image name based on Dockerfile location checksum # Use image name based on Dockerfile location checksum
DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) 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. if [ "$DOCKERHUB_ORGANIZATION" != "" ]
docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR 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 # Choose random name for docker container
CONTAINER_NAME="build_and_run_docker_$(uuidgen)" 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