aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/csharp_generator.cc8
-rw-r--r--src/compiler/python_generator.cc55
-rw-r--r--src/core/ext/census/census_log.h2
-rw-r--r--src/core/ext/census/grpc_filter.c6
-rw-r--r--src/core/ext/census/mlog.h2
-rw-r--r--src/core/ext/census/trace_context.h2
-rw-r--r--src/core/ext/client_channel/client_channel.c151
-rw-r--r--src/core/ext/client_channel/connector.h2
-rw-r--r--src/core/ext/client_channel/default_initial_connect_string.c4
-rw-r--r--src/core/ext/client_channel/http_connect_handshaker.c206
-rw-r--r--src/core/ext/client_channel/initial_connect_string.c4
-rw-r--r--src/core/ext/client_channel/initial_connect_string.h8
-rw-r--r--src/core/ext/client_channel/lb_policy_registry.c8
-rw-r--r--src/core/ext/client_channel/subchannel.c166
-rw-r--r--src/core/ext/client_channel/subchannel.h4
-rw-r--r--src/core/ext/client_channel/uri_parser.c35
-rw-r--r--src/core/ext/lb_policy/grpclb/grpclb.c291
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.c20
-rw-r--r--src/core/ext/lb_policy/grpclb/load_balancer_api.h8
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c2
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c312
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c1
-rw-r--r--src/core/ext/resolver/dns/native/dns_resolver.c18
-rw-r--r--src/core/ext/resolver/sockaddr/sockaddr_resolver.c17
-rw-r--r--src/core/ext/transport/chttp2/client/chttp2_connector.c261
-rw-r--r--src/core/ext/transport/chttp2/client/chttp2_connector.h52
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create.c153
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c221
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.c354
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.h78
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c172
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c338
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.c55
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_encoder.c47
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_encoder.h15
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c205
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.c33
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h10
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.c26
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.h10
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c16
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.h6
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.c16
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.c28
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.h10
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.c12
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.c65
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_encoder.h6
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c14
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c8
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h2
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h39
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c39
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c26
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c94
-rw-r--r--src/core/lib/channel/channel_args.c6
-rw-r--r--src/core/lib/channel/channel_args.h8
-rw-r--r--src/core/lib/channel/channel_stack.c16
-rw-r--r--src/core/lib/channel/channel_stack.h15
-rw-r--r--src/core/lib/channel/compress_filter.c35
-rw-r--r--src/core/lib/channel/connected_channel.c8
-rw-r--r--src/core/lib/channel/deadline_filter.c6
-rw-r--r--src/core/lib/channel/handshaker.c209
-rw-r--r--src/core/lib/channel/handshaker.h83
-rw-r--r--src/core/lib/channel/http_client_filter.c89
-rw-r--r--src/core/lib/channel/http_server_filter.c42
-rw-r--r--src/core/lib/channel/message_size_filter.c80
-rw-r--r--src/core/lib/compression/message_compress.c50
-rw-r--r--src/core/lib/compression/message_compress.h6
-rw-r--r--src/core/lib/http/format_request.c19
-rw-r--r--src/core/lib/http/format_request.h12
-rw-r--r--src/core/lib/http/httpcli.c24
-rw-r--r--src/core/lib/http/httpcli_security_connector.c90
-rw-r--r--src/core/lib/http/parser.c6
-rw-r--r--src/core/lib/http/parser.h4
-rw-r--r--src/core/lib/iomgr/combiner.c11
-rw-r--r--src/core/lib/iomgr/endpoint.c6
-rw-r--r--src/core/lib/iomgr/endpoint.h17
-rw-r--r--src/core/lib/iomgr/ev_epoll_linux.c33
-rw-r--r--src/core/lib/iomgr/ev_poll_and_epoll_posix.c2076
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c29
-rw-r--r--src/core/lib/iomgr/ev_posix.c2
-rw-r--r--src/core/lib/iomgr/ev_posix.h1
-rw-r--r--src/core/lib/iomgr/iomgr.c1
-rw-r--r--src/core/lib/iomgr/load_file.c6
-rw-r--r--src/core/lib/iomgr/load_file.h4
-rw-r--r--src/core/lib/iomgr/network_status_tracker.c2
-rw-r--r--src/core/lib/iomgr/resource_quota.c251
-rw-r--r--src/core/lib/iomgr/resource_quota.h98
-rw-r--r--src/core/lib/iomgr/socket_mutator.c98
-rw-r--r--src/core/lib/iomgr/socket_mutator.h80
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.c9
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.h5
-rw-r--r--src/core/lib/iomgr/socket_windows.c8
-rw-r--r--src/core/lib/iomgr/socket_windows.h1
-rw-r--r--src/core/lib/iomgr/tcp_client.h1
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.c23
-rw-r--r--src/core/lib/iomgr/tcp_client_windows.c28
-rw-r--r--src/core/lib/iomgr/tcp_posix.c100
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.c45
-rw-r--r--src/core/lib/iomgr/tcp_server_windows.c86
-rw-r--r--src/core/lib/iomgr/tcp_uv.c107
-rw-r--r--src/core/lib/iomgr/tcp_windows.c94
-rw-r--r--src/core/lib/iomgr/udp_server.c6
-rw-r--r--src/core/lib/iomgr/wakeup_fd_pipe.c2
-rw-r--r--src/core/lib/json/json.c6
-rw-r--r--src/core/lib/json/json.h22
-rw-r--r--src/core/lib/security/credentials/credentials.h6
-rw-r--r--src/core/lib/security/credentials/credentials_metadata.c14
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.c9
-rw-r--r--src/core/lib/security/credentials/jwt/json_token.h2
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_credentials.c45
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_verifier.c62
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_verifier.h4
-rw-r--r--src/core/lib/security/credentials/oauth2/oauth2_credentials.c33
-rw-r--r--src/core/lib/security/credentials/plugin/plugin_credentials.c10
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c22
-rw-r--r--src/core/lib/security/transport/handshake.c374
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c132
-rw-r--r--src/core/lib/security/transport/secure_endpoint.h4
-rw-r--r--src/core/lib/security/transport/security_connector.c262
-rw-r--r--src/core/lib/security/transport/security_connector.h60
-rw-r--r--src/core/lib/security/transport/security_handshaker.c450
-rw-r--r--src/core/lib/security/transport/security_handshaker.h (renamed from src/core/lib/security/transport/handshake.h)21
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c19
-rw-r--r--src/core/lib/security/util/b64.c14
-rw-r--r--src/core/lib/security/util/b64.h8
-rw-r--r--src/core/lib/slice/percent_encoding.c (renamed from src/core/lib/support/percent_encoding.c)58
-rw-r--r--src/core/lib/slice/percent_encoding.h (renamed from src/core/lib/support/percent_encoding.h)28
-rw-r--r--src/core/lib/slice/slice.c (renamed from src/core/lib/support/slice.c)104
-rw-r--r--src/core/lib/slice/slice_buffer.c (renamed from src/core/lib/support/slice_buffer.c)122
-rw-r--r--src/core/lib/slice/slice_string_helpers.c89
-rw-r--r--src/core/lib/slice/slice_string_helpers.h58
-rw-r--r--src/core/lib/support/backoff.c37
-rw-r--r--src/core/lib/support/backoff.h7
-rw-r--r--src/core/lib/support/env.h2
-rw-r--r--src/core/lib/support/string.c58
-rw-r--r--src/core/lib/support/string.h14
-rw-r--r--src/core/lib/support/subprocess_posix.c7
-rw-r--r--src/core/lib/support/tmpfile.h2
-rw-r--r--src/core/lib/surface/byte_buffer.c19
-rw-r--r--src/core/lib/surface/byte_buffer_reader.c28
-rw-r--r--src/core/lib/surface/call.c64
-rw-r--r--src/core/lib/surface/channel.c9
-rw-r--r--src/core/lib/surface/lame_client.c5
-rw-r--r--src/core/lib/surface/server.c22
-rw-r--r--src/core/lib/surface/version.c2
-rw-r--r--src/core/lib/transport/byte_stream.c8
-rw-r--r--src/core/lib/transport/byte_stream.h10
-rw-r--r--src/core/lib/transport/connectivity_state.c16
-rw-r--r--src/core/lib/transport/connectivity_state.h5
-rw-r--r--src/core/lib/transport/mdstr_hash_table.c42
-rw-r--r--src/core/lib/transport/mdstr_hash_table.h18
-rw-r--r--src/core/lib/transport/metadata.c67
-rw-r--r--src/core/lib/transport/metadata.h20
-rw-r--r--src/core/lib/transport/metadata_batch.h2
-rw-r--r--src/core/lib/transport/method_config.c340
-rw-r--r--src/core/lib/transport/method_config.h136
-rw-r--r--src/core/lib/transport/pid_controller.c57
-rw-r--r--src/core/lib/transport/pid_controller.h64
-rw-r--r--src/core/lib/transport/service_config.c249
-rw-r--r--src/core/lib/transport/service_config.h70
-rw-r--r--src/core/lib/transport/transport.c22
-rw-r--r--src/core/lib/transport/transport.h13
-rw-r--r--src/core/lib/transport/transport_impl.h3
-rw-r--r--src/core/lib/transport/transport_op_string.c11
-rw-r--r--src/cpp/client/channel_cc.cc32
-rw-r--r--src/cpp/common/channel_arguments.cc30
-rw-r--r--src/cpp/common/channel_filter.cc5
-rw-r--r--src/cpp/common/channel_filter.h14
-rw-r--r--src/cpp/common/core_codegen.cc29
-rw-r--r--src/cpp/common/version_cc.cc (renamed from src/core/lib/iomgr/ev_poll_and_epoll_posix.h)14
-rw-r--r--src/cpp/util/byte_buffer_cc.cc14
-rw-r--r--src/cpp/util/slice_cc.cc8
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj1
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.nuspec28
-rw-r--r--src/csharp/Grpc.Auth/project.json1
-rw-r--r--src/csharp/Grpc.Core.Tests/CallOptionsTest.cs15
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj6
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs3
-rw-r--r--src/csharp/Grpc.Core.Tests/packages.config6
-rw-r--r--src/csharp/Grpc.Core.Tests/project.json2
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs46
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj6
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec35
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs107
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs41
-rw-r--r--src/csharp/Grpc.Core/Internal/CallFlags.cs60
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs25
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs13
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs5
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs22
-rw-r--r--src/csharp/Grpc.Core/Internal/INativeCall.cs17
-rw-r--r--src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs23
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMethods.cs10
-rw-r--r--src/csharp/Grpc.Core/Profiling/Profilers.cs2
-rw-r--r--src/csharp/Grpc.Core/packages.config2
-rw-r--r--src/csharp/Grpc.Core/project.json3
-rw-r--r--src/csharp/Grpc.Dotnet.sln14
-rw-r--r--src/csharp/Grpc.Examples.MathClient/project.json2
-rw-r--r--src/csharp/Grpc.Examples.MathServer/project.json2
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj6
-rw-r--r--src/csharp/Grpc.Examples.Tests/packages.config2
-rw-r--r--src/csharp/Grpc.Examples.Tests/project.json2
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj7
-rw-r--r--src/csharp/Grpc.Examples/Math.cs24
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs8
-rw-r--r--src/csharp/Grpc.Examples/packages.config2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/project.json2
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj12
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec28
-rw-r--r--src/csharp/Grpc.HealthCheck/Health.cs22
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs8
-rw-r--r--src/csharp/Grpc.HealthCheck/packages.config2
-rw-r--r--src/csharp/Grpc.HealthCheck/project.json1
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/project.json2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/project.json2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/project.json2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Control.cs220
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj6
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs28
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs6
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs12
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Stats.cs259
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs18
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/project.json2
-rw-r--r--src/csharp/Grpc.Reflection.Tests/.gitignore2
-rw-r--r--src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj94
-rw-r--r--src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json8
-rw-r--r--src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj18
-rw-r--r--src/csharp/Grpc.Reflection.Tests/NUnitMain.cs59
-rw-r--r--src/csharp/Grpc.Reflection.Tests/Properties/AssemblyInfo.cs44
-rw-r--r--src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs154
-rw-r--r--src/csharp/Grpc.Reflection.Tests/SymbolRegistryTest.cs63
-rw-r--r--src/csharp/Grpc.Reflection.Tests/packages.config7
-rw-r--r--src/csharp/Grpc.Reflection.Tests/project.json65
-rw-r--r--src/csharp/Grpc.Reflection/.gitignore2
-rw-r--r--src/csharp/Grpc.Reflection/Grpc.Reflection.csproj83
-rw-r--r--src/csharp/Grpc.Reflection/Grpc.Reflection.project.json8
-rw-r--r--src/csharp/Grpc.Reflection/Grpc.Reflection.xproj18
-rw-r--r--src/csharp/Grpc.Reflection/Properties/AssemblyInfo.cs44
-rw-r--r--src/csharp/Grpc.Reflection/Reflection.cs1556
-rw-r--r--src/csharp/Grpc.Reflection/ReflectionGrpc.cs132
-rw-r--r--src/csharp/Grpc.Reflection/ReflectionServiceImpl.cs173
-rw-r--r--src/csharp/Grpc.Reflection/Settings.StyleCop10
-rw-r--r--src/csharp/Grpc.Reflection/SymbolRegistry.cs160
-rw-r--r--src/csharp/Grpc.Reflection/packages.config5
-rw-r--r--src/csharp/Grpc.Reflection/project.json40
-rw-r--r--src/csharp/Grpc.sln16
-rwxr-xr-x[-rw-r--r--]src/csharp/build_packages_dotnetcli.bat (renamed from src/csharp/build_packages.bat)41
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.sh1
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c43
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh11
-rw-r--r--src/csharp/tests.json4
-rwxr-xr-xsrc/google_benchmark/gen_build_yaml.py53
-rw-r--r--src/node/ext/byte_buffer.cc16
-rw-r--r--src/node/src/common.js16
-rw-r--r--src/objective-c/GRPCClient/private/NSData+GRPC.m16
-rw-r--r--src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m405
-rw-r--r--src/objective-c/tests/Podfile4
-rw-r--r--src/php/ext/grpc/byte_buffer.c14
-rw-r--r--src/php/lib/Grpc/AbstractCall.php8
-rw-r--r--src/php/lib/Grpc/BaseStub.php2
-rwxr-xr-xsrc/php/tests/interop/interop_client.php8
-rw-r--r--src/php/tests/unit_tests/CallTest.php2
-rw-r--r--src/php/tests/unit_tests/ChannelTest.php2
-rw-r--r--src/php/tests/unit_tests/ServerTest.php4
-rw-r--r--src/proto/grpc/testing/control.proto7
-rw-r--r--src/proto/grpc/testing/stats.proto6
-rw-r--r--src/python/grpcio/grpc/__init__.py42
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi26
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi14
-rw-r--r--src/python/grpcio/grpc/_server.py88
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py16
-rw-r--r--src/python/grpcio_tests/tests/interop/client.py8
-rw-r--r--src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py6
-rw-r--r--src/python/grpcio_tests/tests/stress/client.py26
-rw-r--r--src/python/grpcio_tests/tests/tests.json1
-rw-r--r--src/python/grpcio_tests/tests/unit/_exit_test.py23
-rw-r--r--src/python/grpcio_tests/tests/unit/_rpc_test.py4
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.c14
-rw-r--r--src/ruby/ext/grpc/rb_compression_options.c2
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c120
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h196
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb172
-rw-r--r--src/ruby/spec/generic/rpc_server_pool_spec.rb144
295 files changed, 10035 insertions, 6909 deletions
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 48157033db..a3af258d9c 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -313,7 +313,7 @@ void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
"/// <summary>Base class for server-side implementations of "
"$servicename$</summary>\n",
"servicename", GetServiceClassName(service));
- out->Print("public abstract class $name$\n", "name",
+ out->Print("public abstract partial class $name$\n", "name",
GetServerClassName(service));
out->Print("{\n");
out->Indent();
@@ -344,7 +344,7 @@ void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename",
GetServiceClassName(service));
- out->Print("public class $name$ : ClientBase<$name$>\n", "name",
+ out->Print("public partial class $name$ : ClientBase<$name$>\n", "name",
GetClientClassName(service));
out->Print("{\n");
out->Indent();
@@ -549,8 +549,8 @@ void GenerateService(Printer *out, const ServiceDescriptor *service,
bool generate_client, bool generate_server,
bool internal_access) {
GenerateDocCommentBody(out, service);
- out->Print("$access_level$ static class $classname$\n", "access_level",
- GetAccessLevel(internal_access), "classname",
+ out->Print("$access_level$ static partial class $classname$\n",
+ "access_level", GetAccessLevel(internal_access), "classname",
GetServiceClassName(service));
out->Print("{\n");
out->Indent();
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index febaf135b6..b0a60092ab 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -760,6 +760,32 @@ PythonGrpcGenerator::PythonGrpcGenerator(const GeneratorConfiguration& config)
PythonGrpcGenerator::~PythonGrpcGenerator() {}
+static bool GenerateGrpc(GeneratorContext* context, PrivateGenerator& generator,
+ grpc::string file_name, bool generate_in_pb2_grpc) {
+ bool success;
+ std::unique_ptr<ZeroCopyOutputStream> output;
+ std::unique_ptr<CodedOutputStream> coded_output;
+ grpc::string grpc_code;
+
+ if (generate_in_pb2_grpc) {
+ output.reset(context->Open(file_name));
+ generator.generate_in_pb2_grpc = true;
+ } else {
+ output.reset(context->OpenForInsert(file_name, "module_scope"));
+ generator.generate_in_pb2_grpc = false;
+ }
+
+ coded_output.reset(new CodedOutputStream(output.get()));
+ tie(success, grpc_code) = generator.GetGrpcServices();
+
+ if (success) {
+ coded_output->WriteRaw(grpc_code.data(), grpc_code.size());
+ return true;
+ } else {
+ return false;
+ }
+}
+
bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
const grpc::string& parameter,
GeneratorContext* context,
@@ -780,28 +806,15 @@ bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
}
PrivateGenerator generator(config_, file);
-
- std::unique_ptr<ZeroCopyOutputStream> pb2_output(
- context->OpenForAppend(pb2_file_name));
- std::unique_ptr<ZeroCopyOutputStream> grpc_output(
- context->Open(pb2_grpc_file_name));
- CodedOutputStream pb2_coded_out(pb2_output.get());
- CodedOutputStream grpc_coded_out(grpc_output.get());
- bool success = false;
- grpc::string pb2_code;
- grpc::string grpc_code;
- generator.generate_in_pb2_grpc = false;
- tie(success, pb2_code) = generator.GetGrpcServices();
- if (success) {
- generator.generate_in_pb2_grpc = true;
- tie(success, grpc_code) = generator.GetGrpcServices();
- if (success) {
- pb2_coded_out.WriteRaw(pb2_code.data(), pb2_code.size());
- grpc_coded_out.WriteRaw(grpc_code.data(), grpc_code.size());
- return true;
- }
+ if (parameter == "grpc_2_0") {
+ return GenerateGrpc(context, generator, pb2_grpc_file_name, true);
+ } else if (parameter == "") {
+ return GenerateGrpc(context, generator, pb2_grpc_file_name, true) &&
+ GenerateGrpc(context, generator, pb2_file_name, false);
+ } else {
+ *error = "Invalid parameter '" + parameter + "'.";
+ return false;
}
- return false;
}
} // namespace grpc_python_generator
diff --git a/src/core/ext/census/census_log.h b/src/core/ext/census/census_log.h
index 534ecc5705..1b185a53b9 100644
--- a/src/core/ext/census/census_log.h
+++ b/src/core/ext/census/census_log.h
@@ -84,7 +84,7 @@ const void *census_log_read_next(size_t *bytes_available);
*/
size_t census_log_remaining_space(void);
-/* Returns the number of times gprc_stats_log_start_write() failed due to
+/* Returns the number of times grpc_stats_log_start_write() failed due to
out-of-space. */
int census_log_out_of_space_count(void);
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index a4cf6f37bd..397dbc40a8 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -37,9 +37,9 @@
#include <string.h>
#include <grpc/census.h>
+#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include "src/core/ext/census/census_interface.h"
@@ -69,7 +69,7 @@ static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
for (m = md->list.head; m != NULL; m = m->next) {
if (m->md->key == GRPC_MDSTR_PATH) {
gpr_log(GPR_DEBUG, "%s",
- (const char *)GPR_SLICE_START_PTR(m->md->value->slice));
+ (const char *)GRPC_SLICE_START_PTR(m->md->value->slice));
/* Add method tag here */
}
}
@@ -191,6 +191,7 @@ const grpc_channel_filter grpc_client_census_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"census-client"};
const grpc_channel_filter grpc_server_census_filter = {
@@ -204,4 +205,5 @@ const grpc_channel_filter grpc_server_census_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"census-server"};
diff --git a/src/core/ext/census/mlog.h b/src/core/ext/census/mlog.h
index a256426f91..18805ad994 100644
--- a/src/core/ext/census/mlog.h
+++ b/src/core/ext/census/mlog.h
@@ -88,7 +88,7 @@ const void* census_log_read_next(size_t* bytes_available);
*/
size_t census_log_remaining_space(void);
-/* Returns the number of times gprc_stats_log_start_write() failed due to
+/* Returns the number of times grpc_stats_log_start_write() failed due to
out-of-space. */
int64_t census_log_out_of_space_count(void);
diff --git a/src/core/ext/census/trace_context.h b/src/core/ext/census/trace_context.h
index ee71fef460..1cb5e26ea7 100644
--- a/src/core/ext/census/trace_context.h
+++ b/src/core/ext/census/trace_context.h
@@ -65,4 +65,4 @@ of these do not exist. On success, returns true and false otherwise. */
bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer,
const size_t nbytes);
-#endif
+#endif /* GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H */
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index ff773ac334..1fcff4388a 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -39,6 +39,7 @@
#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>
@@ -55,7 +56,7 @@
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
-#include "src/core/lib/transport/method_config.h"
+#include "src/core/lib/transport/service_config.h"
#include "src/core/lib/transport/static_metadata.h"
/* Client channel implementation */
@@ -81,30 +82,61 @@ static void *method_parameters_copy(void *value) {
return new_value;
}
-static int method_parameters_cmp(void *value1, void *value2) {
- const method_parameters *v1 = value1;
- const method_parameters *v2 = value2;
- const int retval = gpr_time_cmp(v1->timeout, v2->timeout);
- if (retval != 0) return retval;
- if (v1->wait_for_ready > v2->wait_for_ready) return 1;
- if (v1->wait_for_ready < v2->wait_for_ready) return -1;
- return 0;
-}
-
static const grpc_mdstr_hash_table_vtable method_parameters_vtable = {
- gpr_free, method_parameters_copy, method_parameters_cmp};
-
-static void *method_config_convert_value(
- const grpc_method_config *method_config) {
+ gpr_free, method_parameters_copy};
+
+static void *method_parameters_create_from_json(const grpc_json *json) {
+ wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
+ gpr_timespec timeout = {0, 0, GPR_TIMESPAN};
+ for (grpc_json *field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) continue;
+ if (strcmp(field->key, "waitForReady") == 0) {
+ if (wait_for_ready != WAIT_FOR_READY_UNSET) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) {
+ return NULL;
+ }
+ wait_for_ready = field->type == GRPC_JSON_TRUE ? WAIT_FOR_READY_TRUE
+ : WAIT_FOR_READY_FALSE;
+ } else if (strcmp(field->key, "timeout") == 0) {
+ if (timeout.tv_sec > 0 || timeout.tv_nsec > 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ size_t len = strlen(field->value);
+ if (field->value[len - 1] != 's') return NULL;
+ char *buf = gpr_strdup(field->value);
+ buf[len - 1] = '\0'; // Remove trailing 's'.
+ char *decimal_point = strchr(buf, '.');
+ if (decimal_point != NULL) {
+ *decimal_point = '\0';
+ timeout.tv_nsec = gpr_parse_nonnegative_int(decimal_point + 1);
+ if (timeout.tv_nsec == -1) {
+ gpr_free(buf);
+ return NULL;
+ }
+ // There should always be exactly 3, 6, or 9 fractional digits.
+ int multiplier = 1;
+ switch (strlen(decimal_point + 1)) {
+ case 9:
+ break;
+ case 6:
+ multiplier *= 1000;
+ break;
+ case 3:
+ multiplier *= 1000000;
+ break;
+ default: // Unsupported number of digits.
+ gpr_free(buf);
+ return NULL;
+ }
+ timeout.tv_nsec *= multiplier;
+ }
+ timeout.tv_sec = gpr_parse_nonnegative_int(buf);
+ if (timeout.tv_sec == -1) return NULL;
+ gpr_free(buf);
+ }
+ }
method_parameters *value = gpr_malloc(sizeof(method_parameters));
- const gpr_timespec *timeout = grpc_method_config_get_timeout(method_config);
- value->timeout = timeout != NULL ? *timeout : gpr_time_0(GPR_TIMESPAN);
- const bool *wait_for_ready =
- grpc_method_config_get_wait_for_ready(method_config);
- value->wait_for_ready =
- wait_for_ready == NULL
- ? WAIT_FOR_READY_UNSET
- : (wait_for_ready ? WAIT_FOR_READY_TRUE : WAIT_FOR_READY_FALSE);
+ value->timeout = timeout;
+ value->wait_for_ready = wait_for_ready;
return value;
}
@@ -123,7 +155,10 @@ typedef struct client_channel_channel_data {
/** mutex protecting all variables below in this data structure */
gpr_mu mu;
/** currently active load balancer */
+ char *lb_policy_name;
grpc_lb_policy *lb_policy;
+ /** service config in JSON form */
+ char *service_config_json;
/** maps method names to method_parameters structs */
grpc_mdstr_hash_table *method_params_table;
/** incoming resolver result - set by resolver.next() */
@@ -223,22 +258,19 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
channel_data *chand = arg;
+ char *lb_policy_name = NULL;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_mdstr_hash_table *method_params_table = NULL;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
bool exit_idle = false;
grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
+ char *service_config_json = NULL;
if (chand->resolver_result != NULL) {
- grpc_lb_policy_args lb_policy_args;
- lb_policy_args.args = chand->resolver_result;
- lb_policy_args.client_channel_factory = chand->client_channel_factory;
-
// Find LB policy name.
- const char *lb_policy_name = NULL;
const grpc_arg *channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_POLICY_NAME);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
lb_policy_name = channel_arg->value.string;
@@ -247,7 +279,7 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// assume that we should use the grpclb policy, regardless of what the
// resolver actually specified.
channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_ADDRESSES);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_LB_ADDRESSES);
if (channel_arg != NULL) {
GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
grpc_lb_addresses *addresses = channel_arg->value.pointer.p;
@@ -272,7 +304,10 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
// Use pick_first if nothing was specified and we didn't select grpclb
// above.
if (lb_policy_name == NULL) lb_policy_name = "pick_first";
-
+ // Instantiate LB policy.
+ grpc_lb_policy_args lb_policy_args;
+ lb_policy_args.args = chand->resolver_result;
+ lb_policy_args.client_channel_factory = chand->client_channel_factory;
lb_policy =
grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
if (lb_policy != NULL) {
@@ -281,14 +316,25 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
state =
grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
+ // Find service config.
channel_arg =
- grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_SERVICE_CONFIG);
+ grpc_channel_args_find(chand->resolver_result, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
- GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
- method_params_table = grpc_method_config_table_convert(
- (grpc_method_config_table *)channel_arg->value.pointer.p,
- method_config_convert_value, &method_parameters_vtable);
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
+ service_config_json = gpr_strdup(channel_arg->value.string);
+ grpc_service_config *service_config =
+ grpc_service_config_create(service_config_json);
+ if (service_config != NULL) {
+ method_params_table = grpc_service_config_create_method_config_table(
+ service_config, method_parameters_create_from_json,
+ &method_parameters_vtable);
+ grpc_service_config_destroy(service_config);
+ }
}
+ // Before we clean up, save a copy of lb_policy_name, since it might
+ // be pointing to data inside chand->resolver_result.
+ // The copy will be saved in chand->lb_policy_name below.
+ lb_policy_name = gpr_strdup(lb_policy_name);
grpc_channel_args_destroy(chand->resolver_result);
chand->resolver_result = NULL;
}
@@ -299,8 +345,16 @@ static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
gpr_mu_lock(&chand->mu);
+ if (lb_policy_name != NULL) {
+ gpr_free(chand->lb_policy_name);
+ chand->lb_policy_name = lb_policy_name;
+ }
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
+ if (service_config_json != NULL) {
+ gpr_free(chand->service_config_json);
+ chand->service_config_json = service_config_json;
+ }
if (chand->method_params_table != NULL) {
grpc_mdstr_hash_table_unref(chand->method_params_table);
}
@@ -426,6 +480,24 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&chand->mu);
}
+static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *info) {
+ channel_data *chand = elem->channel_data;
+ gpr_mu_lock(&chand->mu);
+ if (info->lb_policy_name != NULL) {
+ *info->lb_policy_name = chand->lb_policy_name == NULL
+ ? NULL
+ : gpr_strdup(chand->lb_policy_name);
+ }
+ if (info->service_config_json != NULL) {
+ *info->service_config_json = chand->service_config_json == NULL
+ ? NULL
+ : gpr_strdup(chand->service_config_json);
+ }
+ gpr_mu_unlock(&chand->mu);
+}
+
/* Constructor for channel_data */
static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
@@ -465,6 +537,8 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
}
+ gpr_free(chand->lb_policy_name);
+ gpr_free(chand->service_config_json);
if (chand->method_params_table != NULL) {
grpc_mdstr_hash_table_unref(chand->method_params_table);
}
@@ -617,7 +691,7 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *new_error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
- calld->deadline, &subchannel_call);
+ calld->call_start_time, calld->deadline, &subchannel_call);
if (new_error != GRPC_ERROR_NONE) {
new_error = grpc_error_add_child(new_error, error);
subchannel_call = CANCELLED_CALL;
@@ -870,7 +944,7 @@ retry:
grpc_subchannel_call *subchannel_call = NULL;
grpc_error *error = grpc_connected_subchannel_create_call(
exec_ctx, calld->connected_subchannel, calld->pollent, calld->path,
- calld->deadline, &subchannel_call);
+ calld->call_start_time, calld->deadline, &subchannel_call);
if (error != GRPC_ERROR_NONE) {
subchannel_call = CANCELLED_CALL;
fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
@@ -1052,6 +1126,7 @@ const grpc_channel_filter grpc_client_channel_filter = {
cc_init_channel_elem,
cc_destroy_channel_elem,
cc_get_peer,
+ cc_get_channel_info,
"client-channel",
};
diff --git a/src/core/ext/client_channel/connector.h b/src/core/ext/client_channel/connector.h
index ed7d5450de..3de061620e 100644
--- a/src/core/ext/client_channel/connector.h
+++ b/src/core/ext/client_channel/connector.h
@@ -52,7 +52,7 @@ typedef struct {
const grpc_resolved_address *addr;
size_t addr_len;
/** initial connect string to send */
- gpr_slice initial_connect_string;
+ grpc_slice initial_connect_string;
/** deadline for connection */
gpr_timespec deadline;
/** channel arguments (to be passed to transport) */
diff --git a/src/core/ext/client_channel/default_initial_connect_string.c b/src/core/ext/client_channel/default_initial_connect_string.c
index 0b251372fd..6db82d84ef 100644
--- a/src/core/ext/client_channel/default_initial_connect_string.c
+++ b/src/core/ext/client_channel/default_initial_connect_string.c
@@ -31,8 +31,8 @@
*
*/
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/lib/iomgr/resolve_address.h"
void grpc_set_default_initial_connect_string(grpc_resolved_address **addr,
- gpr_slice *initial_str) {}
+ grpc_slice *initial_str) {}
diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/client_channel/http_connect_handshaker.c
index ea2cbbdd97..572af52dfd 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.c
+++ b/src/core/ext/client_channel/http_connect_handshaker.c
@@ -35,15 +35,15 @@
#include <string.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
-#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/support/env.h"
typedef struct http_connect_handshaker {
@@ -53,58 +53,105 @@ typedef struct http_connect_handshaker {
char* proxy_server;
char* server_name;
+ gpr_refcount refcount;
+ gpr_mu mu;
+
+ bool shutdown;
+ // Endpoint and read buffer to destroy after a shutdown.
+ grpc_endpoint* endpoint_to_destroy;
+ grpc_slice_buffer* read_buffer_to_destroy;
+
// State saved while performing the handshake.
- grpc_endpoint* endpoint;
- grpc_channel_args* args;
- grpc_handshaker_done_cb cb;
- void* user_data;
+ grpc_handshaker_args* args;
+ grpc_closure* on_handshake_done;
// Objects for processing the HTTP CONNECT request and response.
- gpr_slice_buffer write_buffer;
- gpr_slice_buffer* read_buffer; // Ownership passes through this object.
+ grpc_slice_buffer write_buffer;
grpc_closure request_done_closure;
grpc_closure response_read_closure;
grpc_http_parser http_parser;
grpc_http_response http_response;
- grpc_timer timeout_timer;
-
- gpr_refcount refcount;
} http_connect_handshaker;
// Unref and clean up handshaker.
-static void http_connect_handshaker_unref(http_connect_handshaker* handshaker) {
+static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx,
+ http_connect_handshaker* handshaker) {
if (gpr_unref(&handshaker->refcount)) {
+ gpr_mu_destroy(&handshaker->mu);
+ if (handshaker->endpoint_to_destroy != NULL) {
+ grpc_endpoint_destroy(exec_ctx, handshaker->endpoint_to_destroy);
+ }
+ if (handshaker->read_buffer_to_destroy != NULL) {
+ grpc_slice_buffer_destroy(handshaker->read_buffer_to_destroy);
+ gpr_free(handshaker->read_buffer_to_destroy);
+ }
gpr_free(handshaker->proxy_server);
gpr_free(handshaker->server_name);
- gpr_slice_buffer_destroy(&handshaker->write_buffer);
+ grpc_slice_buffer_destroy(&handshaker->write_buffer);
grpc_http_parser_destroy(&handshaker->http_parser);
grpc_http_response_destroy(&handshaker->http_response);
gpr_free(handshaker);
}
}
-// Callback invoked when deadline is exceeded.
-static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
- http_connect_handshaker* handshaker = arg;
- if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
- grpc_endpoint_shutdown(exec_ctx, handshaker->endpoint);
+// Set args fields to NULL, saving the endpoint and read buffer for
+// later destruction.
+static void cleanup_args_for_failure_locked(
+ http_connect_handshaker* handshaker) {
+ handshaker->endpoint_to_destroy = handshaker->args->endpoint;
+ handshaker->args->endpoint = NULL;
+ handshaker->read_buffer_to_destroy = handshaker->args->read_buffer;
+ handshaker->args->read_buffer = NULL;
+ grpc_channel_args_destroy(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(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(handshaker);
+ // Set shutdown to true so that subsequent calls to
+ // http_connect_handshaker_shutdown() do nothing.
+ handshaker->shutdown = true;
+ }
+ // Invoke callback.
+ grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
}
// Callback invoked when finished writing HTTP CONNECT request.
static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
http_connect_handshaker* handshaker = arg;
- if (error != GRPC_ERROR_NONE) {
- // If the write failed, invoke the callback immediately with the error.
- handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args,
- handshaker->read_buffer, handshaker->user_data,
- GRPC_ERROR_REF(error));
+ gpr_mu_lock(&handshaker->mu);
+ if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
+ // If the write failed or we're shutting down, clean up and invoke the
+ // callback with the error.
+ handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error));
+ gpr_mu_unlock(&handshaker->mu);
+ http_connect_handshaker_unref(exec_ctx, handshaker);
} else {
// Otherwise, read the response.
- grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer,
+ // The read callback inherits our ref to the handshaker.
+ grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
+ handshaker->args->read_buffer,
&handshaker->response_read_closure);
+ gpr_mu_unlock(&handshaker->mu);
}
}
@@ -112,37 +159,41 @@ static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg,
static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
http_connect_handshaker* handshaker = arg;
- if (error != GRPC_ERROR_NONE) {
- GRPC_ERROR_REF(error); // Take ref to pass to the handshake-done callback.
+ gpr_mu_lock(&handshaker->mu);
+ if (error != GRPC_ERROR_NONE || handshaker->shutdown) {
+ // If the read failed or we're shutting down, clean up and invoke the
+ // callback with the error.
+ handshake_failed_locked(exec_ctx, handshaker, GRPC_ERROR_REF(error));
goto done;
}
// Add buffer to parser.
- for (size_t i = 0; i < handshaker->read_buffer->count; ++i) {
- if (GPR_SLICE_LENGTH(handshaker->read_buffer->slices[i]) > 0) {
+ for (size_t i = 0; i < handshaker->args->read_buffer->count; ++i) {
+ if (GRPC_SLICE_LENGTH(handshaker->args->read_buffer->slices[i]) > 0) {
size_t body_start_offset = 0;
error = grpc_http_parser_parse(&handshaker->http_parser,
- handshaker->read_buffer->slices[i],
+ handshaker->args->read_buffer->slices[i],
&body_start_offset);
- if (error != GRPC_ERROR_NONE) goto done;
+ if (error != GRPC_ERROR_NONE) {
+ handshake_failed_locked(exec_ctx, handshaker, error);
+ goto done;
+ }
if (handshaker->http_parser.state == GRPC_HTTP_BODY) {
- // We've gotten back a successul response, so stop the timeout timer.
- grpc_timer_cancel(exec_ctx, &handshaker->timeout_timer);
// Remove the data we've already read from the read buffer,
// leaving only the leftover bytes (if any).
- gpr_slice_buffer tmp_buffer;
- gpr_slice_buffer_init(&tmp_buffer);
+ grpc_slice_buffer tmp_buffer;
+ grpc_slice_buffer_init(&tmp_buffer);
if (body_start_offset <
- GPR_SLICE_LENGTH(handshaker->read_buffer->slices[i])) {
- gpr_slice_buffer_add(
+ GRPC_SLICE_LENGTH(handshaker->args->read_buffer->slices[i])) {
+ grpc_slice_buffer_add(
&tmp_buffer,
- gpr_slice_split_tail(&handshaker->read_buffer->slices[i],
- body_start_offset));
+ grpc_slice_split_tail(&handshaker->args->read_buffer->slices[i],
+ body_start_offset));
}
- gpr_slice_buffer_addn(&tmp_buffer,
- &handshaker->read_buffer->slices[i + 1],
- handshaker->read_buffer->count - i - 1);
- gpr_slice_buffer_swap(handshaker->read_buffer, &tmp_buffer);
- gpr_slice_buffer_destroy(&tmp_buffer);
+ grpc_slice_buffer_addn(&tmp_buffer,
+ &handshaker->args->read_buffer->slices[i + 1],
+ handshaker->args->read_buffer->count - i - 1);
+ grpc_slice_buffer_swap(handshaker->args->read_buffer, &tmp_buffer);
+ grpc_slice_buffer_destroy(&tmp_buffer);
break;
}
}
@@ -159,9 +210,11 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
// complete (e.g., handling chunked transfer encoding or looking
// at the Content-Length: header).
if (handshaker->http_parser.state != GRPC_HTTP_BODY) {
- gpr_slice_buffer_reset_and_unref(handshaker->read_buffer);
- grpc_endpoint_read(exec_ctx, handshaker->endpoint, handshaker->read_buffer,
+ grpc_slice_buffer_reset_and_unref(handshaker->args->read_buffer);
+ grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
+ handshaker->args->read_buffer,
&handshaker->response_read_closure);
+ gpr_mu_unlock(&handshaker->mu);
return;
}
// Make sure we got a 2xx response.
@@ -172,11 +225,17 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg,
handshaker->http_response.status);
error = GRPC_ERROR_CREATE(msg);
gpr_free(msg);
+ handshake_failed_locked(exec_ctx, handshaker, error);
+ goto done;
}
+ // Success. Invoke handshake-done callback.
+ grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
done:
- // Invoke handshake-done callback.
- handshaker->cb(exec_ctx, handshaker->endpoint, handshaker->args,
- handshaker->read_buffer, handshaker->user_data, error);
+ // Set shutdown to true so that subsequent calls to
+ // http_connect_handshaker_shutdown() do nothing.
+ handshaker->shutdown = true;
+ gpr_mu_unlock(&handshaker->mu);
+ http_connect_handshaker_unref(exec_ctx, handshaker);
}
//
@@ -186,25 +245,30 @@ done:
static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshaker* handshaker_in) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
- http_connect_handshaker_unref(handshaker);
+ http_connect_handshaker_unref(exec_ctx, handshaker);
}
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(handshaker);
+ }
+ gpr_mu_unlock(&handshaker->mu);
+}
static void http_connect_handshaker_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker_in,
- grpc_endpoint* endpoint, grpc_channel_args* args,
- gpr_slice_buffer* read_buffer, gpr_timespec deadline,
- grpc_tcp_server_acceptor* acceptor, grpc_handshaker_done_cb cb,
- void* user_data) {
+ grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done,
+ grpc_handshaker_args* args) {
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
+ gpr_mu_lock(&handshaker->mu);
// Save state in the handshaker object.
- handshaker->endpoint = endpoint;
handshaker->args = args;
- handshaker->cb = cb;
- handshaker->user_data = user_data;
- handshaker->read_buffer = read_buffer;
+ handshaker->on_handshake_done = on_handshake_done;
// Send HTTP CONNECT request.
gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s",
handshaker->server_name, handshaker->proxy_server);
@@ -214,18 +278,16 @@ static void http_connect_handshaker_do_handshake(
request.http.method = "CONNECT";
request.http.path = handshaker->server_name;
request.handshaker = &grpc_httpcli_plaintext;
- gpr_slice request_slice = grpc_httpcli_format_connect_request(&request);
- gpr_slice_buffer_add(&handshaker->write_buffer, request_slice);
- grpc_endpoint_write(exec_ctx, endpoint, &handshaker->write_buffer,
- &handshaker->request_done_closure);
- // Set timeout timer. The timer gets a reference to the handshaker.
+ grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
+ grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
+ // Take a new ref to be held by the write callback.
gpr_ref(&handshaker->refcount);
- grpc_timer_init(exec_ctx, &handshaker->timeout_timer,
- gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
- on_timeout, handshaker, gpr_now(GPR_CLOCK_MONOTONIC));
+ grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer,
+ &handshaker->request_done_closure);
+ gpr_mu_unlock(&handshaker->mu);
}
-static const struct grpc_handshaker_vtable http_connect_handshaker_vtable = {
+static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
http_connect_handshaker_destroy, http_connect_handshaker_shutdown,
http_connect_handshaker_do_handshake};
@@ -233,20 +295,20 @@ grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
const char* server_name) {
GPR_ASSERT(proxy_server != NULL);
GPR_ASSERT(server_name != NULL);
- http_connect_handshaker* handshaker =
- gpr_malloc(sizeof(http_connect_handshaker));
+ http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker));
memset(handshaker, 0, sizeof(*handshaker));
grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base);
+ gpr_mu_init(&handshaker->mu);
+ gpr_ref_init(&handshaker->refcount, 1);
handshaker->proxy_server = gpr_strdup(proxy_server);
handshaker->server_name = gpr_strdup(server_name);
- gpr_slice_buffer_init(&handshaker->write_buffer);
+ grpc_slice_buffer_init(&handshaker->write_buffer);
grpc_closure_init(&handshaker->request_done_closure, on_write_done,
handshaker);
grpc_closure_init(&handshaker->response_read_closure, on_read_done,
handshaker);
grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE,
&handshaker->http_response);
- gpr_ref_init(&handshaker->refcount, 1);
return &handshaker->base;
}
diff --git a/src/core/ext/client_channel/initial_connect_string.c b/src/core/ext/client_channel/initial_connect_string.c
index fb1493d77d..8ebd06c458 100644
--- a/src/core/ext/client_channel/initial_connect_string.c
+++ b/src/core/ext/client_channel/initial_connect_string.c
@@ -36,7 +36,7 @@
#include <stddef.h>
extern void grpc_set_default_initial_connect_string(
- grpc_resolved_address **addr, gpr_slice *initial_str);
+ grpc_resolved_address **addr, grpc_slice *initial_str);
static grpc_set_initial_connect_string_func g_set_initial_connect_string_func =
grpc_set_default_initial_connect_string;
@@ -47,6 +47,6 @@ void grpc_test_set_initial_connect_string_function(
}
void grpc_set_initial_connect_string(grpc_resolved_address **addr,
- gpr_slice *initial_str) {
+ grpc_slice *initial_str) {
g_set_initial_connect_string_func(addr, initial_str);
}
diff --git a/src/core/ext/client_channel/initial_connect_string.h b/src/core/ext/client_channel/initial_connect_string.h
index 68adb0373c..876abea40e 100644
--- a/src/core/ext/client_channel/initial_connect_string.h
+++ b/src/core/ext/client_channel/initial_connect_string.h
@@ -34,17 +34,17 @@
#ifndef GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H
#define GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H
-#include <grpc/support/slice.h>
-
+#include <grpc/slice.h>
#include "src/core/lib/iomgr/resolve_address.h"
typedef void (*grpc_set_initial_connect_string_func)(
- grpc_resolved_address **addr, gpr_slice *initial_str);
+ grpc_resolved_address **addr, grpc_slice *initial_str);
+
void grpc_test_set_initial_connect_string_function(
grpc_set_initial_connect_string_func func);
/** Set a string to be sent once connected. Optionally reset addr. */
void grpc_set_initial_connect_string(grpc_resolved_address **addr,
- gpr_slice *connect_string);
+ grpc_slice *connect_string);
#endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_INITIAL_CONNECT_STRING_H */
diff --git a/src/core/ext/client_channel/lb_policy_registry.c b/src/core/ext/client_channel/lb_policy_registry.c
index f46a721f9d..90c149d947 100644
--- a/src/core/ext/client_channel/lb_policy_registry.c
+++ b/src/core/ext/client_channel/lb_policy_registry.c
@@ -35,6 +35,8 @@
#include <string.h>
+#include "src/core/lib/support/string.h"
+
#define MAX_POLICIES 10
static grpc_lb_policy_factory *g_all_of_the_lb_policies[MAX_POLICIES];
@@ -52,8 +54,8 @@ void grpc_lb_policy_registry_shutdown(void) {
void grpc_register_lb_policy(grpc_lb_policy_factory *factory) {
int i;
for (i = 0; i < g_number_of_lb_policies; i++) {
- GPR_ASSERT(0 != strcmp(factory->vtable->name,
- g_all_of_the_lb_policies[i]->vtable->name));
+ GPR_ASSERT(0 != gpr_stricmp(factory->vtable->name,
+ g_all_of_the_lb_policies[i]->vtable->name));
}
GPR_ASSERT(g_number_of_lb_policies != MAX_POLICIES);
grpc_lb_policy_factory_ref(factory);
@@ -66,7 +68,7 @@ static grpc_lb_policy_factory *lookup_factory(const char *name) {
if (name == NULL) return NULL;
for (i = 0; i < g_number_of_lb_policies; i++) {
- if (0 == strcmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
+ if (0 == gpr_stricmp(name, g_all_of_the_lb_policies[i]->vtable->name)) {
return g_all_of_the_lb_policies[i];
}
}
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index 789966cb69..08632079d6 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -100,7 +100,7 @@ struct grpc_subchannel {
grpc_subchannel_key *key;
/** initial string to send to peer */
- gpr_slice initial_connect_string;
+ grpc_slice initial_connect_string;
/** set during connection */
grpc_connect_out_args connecting_result;
@@ -119,9 +119,9 @@ struct grpc_subchannel {
gpr_mu mu;
/** have we seen a disconnection? */
- int disconnected;
+ bool disconnected;
/** are we connecting */
- int connecting;
+ bool connecting;
/** connectivity state tracking */
grpc_connectivity_state_tracker state_tracker;
@@ -132,7 +132,9 @@ struct grpc_subchannel {
/** backoff state */
gpr_backoff backoff_state;
/** do we have an active alarm? */
- int have_alarm;
+ bool have_alarm;
+ /** have we started the backoff loop */
+ bool backoff_begun;
/** our alarm */
grpc_timer alarm;
};
@@ -206,7 +208,7 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args);
gpr_free(c->addr);
- gpr_slice_unref(c->initial_connect_string);
+ grpc_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector);
grpc_pollset_set_destroy(c->pollset_set);
@@ -264,7 +266,7 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_subchannel_index_unregister(exec_ctx, c->key, c);
gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->disconnected);
- c->disconnected = 1;
+ c->disconnected = true;
grpc_connector_shutdown(exec_ctx, c->connector);
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
if (con != NULL) {
@@ -334,16 +336,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
int initial_backoff_ms =
GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS * 1000;
int max_backoff_ms = GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
+ int min_backoff_ms = GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS * 1000;
bool fixed_reconnect_backoff = false;
if (c->args) {
for (size_t i = 0; i < c->args->num_args; i++) {
if (0 == strcmp(c->args->args[i].key,
- "grpc.testing.fixed_reconnect_backoff")) {
+ "grpc.testing.fixed_reconnect_backoff_ms")) {
GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
fixed_reconnect_backoff = true;
- initial_backoff_ms = max_backoff_ms = grpc_channel_arg_get_integer(
- &c->args->args[i],
- (grpc_integer_options){initial_backoff_ms, 100, INT_MAX});
+ initial_backoff_ms = min_backoff_ms = max_backoff_ms =
+ grpc_channel_arg_get_integer(
+ &c->args->args[i],
+ (grpc_integer_options){initial_backoff_ms, 100, INT_MAX});
} else if (0 == strcmp(c->args->args[i].key,
GRPC_ARG_MAX_RECONNECT_BACKOFF_MS)) {
fixed_reconnect_backoff = false;
@@ -360,17 +364,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
}
}
gpr_backoff_init(
- &c->backoff_state,
+ &c->backoff_state, initial_backoff_ms,
fixed_reconnect_backoff ? 1.0
: GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER,
fixed_reconnect_backoff ? 0.0 : GRPC_SUBCHANNEL_RECONNECT_JITTER,
- initial_backoff_ms, max_backoff_ms);
+ min_backoff_ms, max_backoff_ms);
gpr_mu_init(&c->mu);
return grpc_subchannel_index_register(exec_ctx, key, c);
}
-static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
+static void continue_connect_locked(grpc_exec_ctx *exec_ctx,
+ grpc_subchannel *c) {
grpc_connect_in_args args;
args.interested_parties = c->pollset_set;
@@ -386,12 +391,6 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
&c->connected);
}
-static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
- c->next_attempt =
- gpr_backoff_begin(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
- continue_connect(exec_ctx, c);
-}
-
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c,
grpc_error **error) {
grpc_connectivity_state state;
@@ -418,6 +417,73 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
follow_up->cb(exec_ctx, follow_up->cb_arg, error);
}
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+ grpc_subchannel *c = arg;
+ gpr_mu_lock(&c->mu);
+ c->have_alarm = false;
+ if (c->disconnected) {
+ error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
+ } else {
+ GRPC_ERROR_REF(error);
+ }
+ if (error == GRPC_ERROR_NONE) {
+ gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
+ c->next_attempt =
+ gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
+ continue_connect_locked(exec_ctx, c);
+ gpr_mu_unlock(&c->mu);
+ } else {
+ gpr_mu_unlock(&c->mu);
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+ }
+ GRPC_ERROR_UNREF(error);
+}
+
+static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx,
+ grpc_subchannel *c) {
+ if (c->disconnected) {
+ /* Don't try to connect if we're already disconnected */
+ return;
+ }
+
+ if (c->connecting) {
+ /* Already connecting: don't restart */
+ return;
+ }
+
+ if (GET_CONNECTED_SUBCHANNEL(c, no_barrier) != NULL) {
+ /* Already connected: don't restart */
+ return;
+ }
+
+ if (!grpc_connectivity_state_has_watchers(&c->state_tracker)) {
+ /* Nobody is interested in connecting: so don't just yet */
+ return;
+ }
+
+ c->connecting = true;
+ GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
+
+ gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+ if (!c->backoff_begun) {
+ c->backoff_begun = true;
+ c->next_attempt = gpr_backoff_begin(&c->backoff_state, now);
+ continue_connect_locked(exec_ctx, c);
+ } else {
+ GPR_ASSERT(!c->have_alarm);
+ c->have_alarm = true;
+ gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
+ if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
+ 0) {
+ gpr_log(GPR_INFO, "Retry immediately");
+ } else {
+ gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
+ time_til_next.tv_sec, time_til_next.tv_nsec);
+ }
+ grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
+ }
+}
+
void grpc_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
@@ -449,13 +515,9 @@ void grpc_subchannel_notify_on_state_change(
w->next = &c->root_external_state_watcher;
w->prev = w->next->prev;
w->next->prev = w->prev->next = w;
- if (grpc_connectivity_state_notify_on_state_change(
- exec_ctx, &c->state_tracker, state, &w->closure)) {
- c->connecting = 1;
- /* released by connection */
- GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
- start_connect(exec_ctx, c);
- }
+ grpc_connectivity_state_notify_on_state_change(exec_ctx, &c->state_tracker,
+ state, &w->closure);
+ maybe_start_connecting_locked(exec_ctx, c);
gpr_mu_unlock(&c->mu);
}
}
@@ -575,12 +637,9 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
Re-evaluate if we really need this. */
gpr_atm_full_barrier();
GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
- c->connecting = 0;
/* setup subchannel watching connected subchannel for changes; subchannel
- ref
- for connecting is donated
- to the state watcher */
+ ref for connecting is donated to the state watcher */
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
grpc_connected_subchannel_notify_on_state_change(
@@ -592,28 +651,6 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
GRPC_ERROR_NONE, "connected");
}
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
- grpc_subchannel *c = arg;
- gpr_mu_lock(&c->mu);
- c->have_alarm = 0;
- if (c->disconnected) {
- error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
- } else {
- GRPC_ERROR_REF(error);
- }
- if (error == GRPC_ERROR_NONE) {
- gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
- c->next_attempt =
- gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
- continue_connect(exec_ctx, c);
- gpr_mu_unlock(&c->mu);
- } else {
- gpr_mu_unlock(&c->mu);
- GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
- }
- GRPC_ERROR_UNREF(error);
-}
-
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
grpc_subchannel *c = arg;
@@ -621,35 +658,28 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
gpr_mu_lock(&c->mu);
+ c->connecting = false;
if (c->connecting_result.transport != NULL) {
publish_transport_locked(exec_ctx, c);
} else if (c->disconnected) {
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} else {
- gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
- GPR_ASSERT(!c->have_alarm);
- c->have_alarm = 1;
grpc_connectivity_state_set(
exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
grpc_error_set_int(
GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
"connect_failed");
- gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
+
const char *errmsg = grpc_error_string(error);
gpr_log(GPR_INFO, "Connect failed: %s", errmsg);
- if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
- 0) {
- gpr_log(GPR_INFO, "Retry immediately");
- } else {
- gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
- time_til_next.tv_sec, time_til_next.tv_nsec);
- }
- grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
grpc_error_free_string(errmsg);
+
+ maybe_start_connecting_locked(exec_ctx, c);
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
}
gpr_mu_unlock(&c->mu);
- GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connected");
grpc_channel_args_destroy(delete_channel_args);
}
@@ -702,15 +732,15 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
- grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
- grpc_subchannel_call **call) {
+ grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time,
+ gpr_timespec deadline, grpc_subchannel_call **call) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
*call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
(*call)->connection = con; // Ref is added below.
grpc_error *error =
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call,
- NULL, NULL, path, deadline, callstk);
+ NULL, NULL, path, start_time, deadline, callstk);
if (error != GRPC_ERROR_NONE) {
const char *error_string = grpc_error_string(error);
gpr_log(GPR_ERROR, "error: %s", error_string);
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 93bd72d20d..10bae620df 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -111,8 +111,8 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call */
grpc_error *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
- grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec deadline,
- grpc_subchannel_call **subchannel_call);
+ grpc_polling_entity *pollent, grpc_mdstr *path, gpr_timespec start_time,
+ gpr_timespec deadline, grpc_subchannel_call **subchannel_call);
/** process a transport level op */
void grpc_connected_subchannel_process_transport_op(
diff --git a/src/core/ext/client_channel/uri_parser.c b/src/core/ext/client_channel/uri_parser.c
index bcb6a1dee4..0fbc542ef8 100644
--- a/src/core/ext/client_channel/uri_parser.c
+++ b/src/core/ext/client_channel/uri_parser.c
@@ -35,13 +35,14 @@
#include <string.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
/** a size_t default value... maps to all 1's */
@@ -148,38 +149,38 @@ static void parse_query_parts(grpc_uri *uri) {
uri->num_query_parts = 0;
return;
}
- gpr_slice query_slice =
- gpr_slice_new(uri->query, strlen(uri->query), do_nothing);
- gpr_slice_buffer query_parts; /* the &-separated elements of the query */
- gpr_slice_buffer query_param_parts; /* the =-separated subelements */
+ grpc_slice query_slice =
+ grpc_slice_new(uri->query, strlen(uri->query), do_nothing);
+ grpc_slice_buffer query_parts; /* the &-separated elements of the query */
+ grpc_slice_buffer query_param_parts; /* the =-separated subelements */
- gpr_slice_buffer_init(&query_parts);
- gpr_slice_buffer_init(&query_param_parts);
+ grpc_slice_buffer_init(&query_parts);
+ grpc_slice_buffer_init(&query_param_parts);
- gpr_slice_split(query_slice, QUERY_PARTS_SEPARATOR, &query_parts);
+ grpc_slice_split(query_slice, QUERY_PARTS_SEPARATOR, &query_parts);
uri->query_parts = gpr_malloc(query_parts.count * sizeof(char *));
uri->query_parts_values = gpr_malloc(query_parts.count * sizeof(char *));
uri->num_query_parts = query_parts.count;
for (size_t i = 0; i < query_parts.count; i++) {
- gpr_slice_split(query_parts.slices[i], QUERY_PARTS_VALUE_SEPARATOR,
- &query_param_parts);
+ grpc_slice_split(query_parts.slices[i], QUERY_PARTS_VALUE_SEPARATOR,
+ &query_param_parts);
GPR_ASSERT(query_param_parts.count > 0);
uri->query_parts[i] =
- gpr_dump_slice(query_param_parts.slices[0], GPR_DUMP_ASCII);
+ grpc_dump_slice(query_param_parts.slices[0], GPR_DUMP_ASCII);
if (query_param_parts.count > 1) {
/* TODO(dgq): only the first value after the separator is considered.
* Perhaps all chars after the first separator for the query part should
* be included, even if they include the separator. */
uri->query_parts_values[i] =
- gpr_dump_slice(query_param_parts.slices[1], GPR_DUMP_ASCII);
+ grpc_dump_slice(query_param_parts.slices[1], GPR_DUMP_ASCII);
} else {
uri->query_parts_values[i] = NULL;
}
- gpr_slice_buffer_reset_and_unref(&query_param_parts);
+ grpc_slice_buffer_reset_and_unref(&query_param_parts);
}
- gpr_slice_buffer_destroy(&query_parts);
- gpr_slice_buffer_destroy(&query_param_parts);
- gpr_slice_unref(query_slice);
+ grpc_slice_buffer_destroy(&query_parts);
+ grpc_slice_buffer_destroy(&query_param_parts);
+ grpc_slice_unref(query_slice);
}
grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index 30e412e358..df0db61c22 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -116,16 +116,18 @@
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/backoff.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/static_metadata.h"
-#define BACKOFF_MULTIPLIER 1.6
-#define BACKOFF_JITTER 0.2
-#define BACKOFF_MIN_SECONDS 10
-#define BACKOFF_MAX_SECONDS 60
+#define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20
+#define GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS 1
+#define GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS 120
+#define GRPC_GRPCLB_RECONNECT_JITTER 0.2
int grpc_lb_glb_trace = 0;
@@ -181,17 +183,24 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
NULL);
if (wc_arg->rr_policy != NULL) {
- /* if target is NULL, no pick has been made by the RR policy (eg, all
+ /* if *target is NULL, no pick has been made by the RR policy (eg, all
* addresses failed to connect). There won't be any user_data/token
* available */
- if (wc_arg->target != NULL) {
- initial_metadata_add_lb_token(wc_arg->initial_metadata,
- wc_arg->lb_token_mdelem_storage,
- GRPC_MDELEM_REF(wc_arg->lb_token));
+ if (*wc_arg->target != NULL) {
+ if (wc_arg->lb_token != NULL) {
+ initial_metadata_add_lb_token(wc_arg->initial_metadata,
+ wc_arg->lb_token_mdelem_storage,
+ GRPC_MDELEM_REF(wc_arg->lb_token));
+ } else {
+ gpr_log(GPR_ERROR,
+ "No LB token for connected subchannel pick %p (from RR "
+ "instance %p).",
+ (void *)*wc_arg->target, (void *)wc_arg->rr_policy);
+ abort();
+ }
}
if (grpc_lb_glb_trace) {
- gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
- (intptr_t)wc_arg->rr_policy);
+ gpr_log(GPR_INFO, "Unreffing RR %p", (void *)wc_arg->rr_policy);
}
GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure");
}
@@ -409,7 +418,7 @@ static void parse_server(const grpc_grpclb_server *server,
}
/* Returns addresses extracted from \a serverlist. */
-static grpc_lb_addresses *process_serverlist(
+static grpc_lb_addresses *process_serverlist_locked(
const grpc_grpclb_serverlist *serverlist) {
size_t num_valid = 0;
/* first pass: count how many are valid in order to allocate the necessary
@@ -449,10 +458,12 @@ static grpc_lb_addresses *process_serverlist(
user_data = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_LB_TOKEN,
lb_token_mdstr);
} else {
- gpr_log(GPR_ERROR,
+ char *uri = grpc_sockaddr_to_uri(&addr);
+ gpr_log(GPR_INFO,
"Missing LB token for backend address '%s'. The empty token will "
"be used instead",
- grpc_sockaddr_to_uri(&addr));
+ uri);
+ gpr_free(uri);
user_data = GRPC_MDELEM_LB_TOKEN_EMPTY;
}
@@ -465,6 +476,68 @@ static grpc_lb_addresses *process_serverlist(
return lb_addresses;
}
+/* returns true if the new RR policy should replace the current one, if any */
+static bool update_lb_connectivity_status_locked(
+ grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
+ grpc_connectivity_state new_rr_state, grpc_error *new_rr_state_error) {
+ grpc_error *curr_state_error;
+ const grpc_connectivity_state curr_glb_state = grpc_connectivity_state_check(
+ &glb_policy->state_tracker, &curr_state_error);
+
+ /* The new connectivity status is a function of the previous one and the new
+ * input coming from the status of the RR policy.
+ *
+ * current state (grpclb's)
+ * |
+ * v || I | C | R | TF | SD | <- new state (RR's)
+ * ===++====+=====+=====+======+======+
+ * I || I | C | R | [I] | [I] |
+ * ---++----+-----+-----+------+------+
+ * C || I | C | R | [C] | [C] |
+ * ---++----+-----+-----+------+------+
+ * R || I | C | R | [R] | [R] |
+ * ---++----+-----+-----+------+------+
+ * TF || I | C | R | [TF] | [TF] |
+ * ---++----+-----+-----+------+------+
+ * SD || NA | NA | NA | NA | NA | (*)
+ * ---++----+-----+-----+------+------+
+ *
+ * A [STATE] indicates that the old RR policy is kept. In those cases, STATE
+ * is the current state of grpclb, which is left untouched.
+ *
+ * In summary, if the new state is TRANSIENT_FAILURE or SHUTDOWN, stick to
+ * the previous RR instance.
+ *
+ * Note that the status is never updated to SHUTDOWN as a result of calling
+ * this function. Only glb_shutdown() has the power to set that state.
+ *
+ * (*) This function mustn't be called during shutting down. */
+ GPR_ASSERT(curr_glb_state != GRPC_CHANNEL_SHUTDOWN);
+
+ switch (new_rr_state) {
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ case GRPC_CHANNEL_SHUTDOWN:
+ GPR_ASSERT(new_rr_state_error != GRPC_ERROR_NONE);
+ return false; /* don't replace the RR policy */
+ case GRPC_CHANNEL_INIT:
+ case GRPC_CHANNEL_IDLE:
+ case GRPC_CHANNEL_CONNECTING:
+ case GRPC_CHANNEL_READY:
+ GPR_ASSERT(new_rr_state_error == GRPC_ERROR_NONE);
+ }
+
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "Setting grpclb's state to %s from new RR policy %p state.",
+ grpc_connectivity_state_name(new_rr_state),
+ (void *)glb_policy->rr_policy);
+ }
+ grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
+ new_rr_state, GRPC_ERROR_REF(new_rr_state_error),
+ "update_lb_connectivity_status_locked");
+ return true;
+}
+
/* perform a pick over \a rr_policy. Given that a pick can return immediately
* (ignoring its completion callback) we need to perform the cleanups this
* callback would be otherwise resposible for */
@@ -506,7 +579,7 @@ static grpc_lb_policy *create_rr_locked(
grpc_lb_policy_args args;
memset(&args, 0, sizeof(args));
args.client_channel_factory = glb_policy->cc_factory;
- grpc_lb_addresses *addresses = process_serverlist(serverlist);
+ grpc_lb_addresses *addresses = process_serverlist_locked(serverlist);
// Replace the LB addresses in the channel args that we pass down to
// the subchannel.
@@ -527,49 +600,84 @@ static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error);
/* glb_policy->rr_policy may be NULL (initial handover) */
static void rr_handover_locked(grpc_exec_ctx *exec_ctx,
- glb_lb_policy *glb_policy, grpc_error *error) {
+ glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->serverlist != NULL &&
glb_policy->serverlist->num_servers > 0);
+ if (glb_policy->shutting_down) return;
+
+ grpc_lb_policy *new_rr_policy =
+ create_rr_locked(exec_ctx, glb_policy->serverlist, glb_policy);
+ if (new_rr_policy == NULL) {
+ gpr_log(GPR_ERROR,
+ "Failure creating a RoundRobin policy for serverlist update with "
+ "%lu entries. The previous RR instance (%p), if any, will continue "
+ "to be used. Future updates from the LB will attempt to create new "
+ "instances.",
+ (unsigned long)glb_policy->serverlist->num_servers,
+ (void *)glb_policy->rr_policy);
+ return;
+ }
+
+ grpc_error *new_rr_state_error = NULL;
+ const grpc_connectivity_state new_rr_state =
+ grpc_lb_policy_check_connectivity(exec_ctx, new_rr_policy,
+ &new_rr_state_error);
+ /* Connectivity state is a function of the new RR policy just created */
+ const bool replace_old_rr = update_lb_connectivity_status_locked(
+ exec_ctx, glb_policy, new_rr_state, new_rr_state_error);
+
+ if (!replace_old_rr) {
+ /* dispose of the new RR policy that won't be used after all */
+ GRPC_LB_POLICY_UNREF(exec_ctx, new_rr_policy, "rr_handover_no_replace");
+ if (grpc_lb_glb_trace) {
+ gpr_log(GPR_INFO,
+ "Keeping old RR policy (%p) despite new serverlist: new RR "
+ "policy was in %s connectivity state.",
+ (void *)glb_policy->rr_policy,
+ grpc_connectivity_state_name(new_rr_state));
+ }
+ return;
+ }
+
if (grpc_lb_glb_trace) {
- gpr_log(GPR_INFO, "RR handover. Old RR: %p", (void *)glb_policy->rr_policy);
+ gpr_log(GPR_INFO, "Created RR policy (%p) to replace old RR (%p)",
+ (void *)new_rr_policy, (void *)glb_policy->rr_policy);
}
+
if (glb_policy->rr_policy != NULL) {
/* if we are phasing out an existing RR instance, unref it. */
GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "rr_handover");
}
- glb_policy->rr_policy =
- create_rr_locked(exec_ctx, glb_policy->serverlist, glb_policy);
- if (grpc_lb_glb_trace) {
- gpr_log(GPR_INFO, "Created RR policy (%p)", (void *)glb_policy->rr_policy);
- }
+ /* Finally update the RR policy to the newly created one */
+ glb_policy->rr_policy = new_rr_policy;
- GPR_ASSERT(glb_policy->rr_policy != NULL);
+ /* Add the gRPC LB's interested_parties pollset_set to that of the newly
+ * created RR policy. This will make the RR policy progress upon activity on
+ * gRPC LB, which in turn is tied to the application's call */
grpc_pollset_set_add_pollset_set(exec_ctx,
glb_policy->rr_policy->interested_parties,
glb_policy->base.interested_parties);
+ /* Allocate the data for the tracking of the new RR policy's connectivity.
+ * It'll be deallocated in glb_rr_connectivity_changed() */
rr_connectivity_data *rr_connectivity =
gpr_malloc(sizeof(rr_connectivity_data));
memset(rr_connectivity, 0, sizeof(rr_connectivity_data));
grpc_closure_init(&rr_connectivity->on_change, glb_rr_connectivity_changed,
rr_connectivity);
rr_connectivity->glb_policy = glb_policy;
- rr_connectivity->state = grpc_lb_policy_check_connectivity(
- exec_ctx, glb_policy->rr_policy, &error);
+ rr_connectivity->state = new_rr_state;
- grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
- rr_connectivity->state, GRPC_ERROR_REF(error),
- "rr_handover");
- /* subscribe */
+ /* Subscribe to changes to the connectivity of the new RR */
GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "rr_connectivity_cb");
grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy,
&rr_connectivity->state,
&rr_connectivity->on_change);
grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy);
- /* flush pending ops */
+ /* Update picks and pings in wait */
pending_pick *pp;
while ((pp = glb_policy->pending_picks)) {
glb_policy->pending_picks = pp->next;
@@ -600,28 +708,36 @@ static void rr_handover_locked(grpc_exec_ctx *exec_ctx,
static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
- /* If shutdown or error free the arg. Rely on the rest of the code to set the
- * right grpclb status. */
- rr_connectivity_data *rr_conn_data = arg;
- glb_lb_policy *glb_policy = rr_conn_data->glb_policy;
-
- if (rr_conn_data->state != GRPC_CHANNEL_SHUTDOWN &&
- !glb_policy->shutting_down) {
- gpr_mu_lock(&glb_policy->mu);
- /* RR not shutting down. Mimic the RR's policy state */
- grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
- rr_conn_data->state, GRPC_ERROR_REF(error),
- "rr_connectivity_cb");
- /* resubscribe. Reuse the "rr_connectivity_cb" weak ref. */
+ rr_connectivity_data *rr_connectivity = arg;
+ glb_lb_policy *glb_policy = rr_connectivity->glb_policy;
+
+ gpr_mu_lock(&glb_policy->mu);
+ const bool shutting_down = glb_policy->shutting_down;
+ bool unref_needed = false;
+ GRPC_ERROR_REF(error);
+
+ if (rr_connectivity->state == GRPC_CHANNEL_SHUTDOWN || shutting_down) {
+ /* RR policy shutting down. Don't renew subscription and free the arg of
+ * this callback. In addition we need to stash away the current policy to
+ * be UNREF'd after releasing the lock. Otherwise, if the UNREF is the last
+ * one, the policy would be destroyed, alongside the lock, which would
+ * result in a use-after-free */
+ unref_needed = true;
+ gpr_free(rr_connectivity);
+ } else { /* rr state != SHUTDOWN && !shutting down: biz as usual */
+ update_lb_connectivity_status_locked(exec_ctx, glb_policy,
+ rr_connectivity->state, error);
+ /* Resubscribe. Reuse the "rr_connectivity_cb" weak ref. */
grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy,
- &rr_conn_data->state,
- &rr_conn_data->on_change);
- gpr_mu_unlock(&glb_policy->mu);
- } else {
+ &rr_connectivity->state,
+ &rr_connectivity->on_change);
+ }
+ gpr_mu_unlock(&glb_policy->mu);
+ if (unref_needed) {
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"rr_connectivity_cb");
- gpr_free(rr_conn_data);
}
+ GRPC_ERROR_UNREF(error);
}
static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
@@ -756,8 +872,26 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
glb_policy->pending_picks = NULL;
pending_ping *pping = glb_policy->pending_pings;
glb_policy->pending_pings = NULL;
+ if (glb_policy->rr_policy) {
+ GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
+ }
+ grpc_connectivity_state_set(
+ exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
+ /* We need a copy of the lb_call pointer because we can't cancell the call
+ * while holding glb_policy->mu: lb_on_server_status_received, invoked due to
+ * the cancel, needs to acquire that same lock */
+ grpc_call *lb_call = glb_policy->lb_call;
gpr_mu_unlock(&glb_policy->mu);
+ /* glb_policy->lb_call and this local lb_call must be consistent at this point
+ * because glb_policy->lb_call is only assigned in lb_call_init_locked as part
+ * of query_for_backends_locked, which can only be invoked while
+ * glb_policy->shutting_down is false. */
+ if (lb_call != NULL) {
+ grpc_call_cancel(lb_call, NULL);
+ /* lb_on_server_status_received will pick up the cancel and clean up */
+ }
while (pp != NULL) {
pending_pick *next = pp->next;
*pp->target = NULL;
@@ -772,22 +906,6 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
GRPC_ERROR_NONE, NULL);
pping = next;
}
-
- if (glb_policy->rr_policy) {
- GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
- }
-
- if (glb_policy->started_picking) {
- if (glb_policy->lb_call != NULL) {
- grpc_call_cancel(glb_policy->lb_call, NULL);
- /* lb_on_server_status_received will pick up the cancellation and clean up
- */
- }
- }
-
- grpc_connectivity_state_set(
- exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
- GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
}
static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
@@ -957,9 +1075,10 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error);
static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error);
-static void lb_call_init(glb_lb_policy *glb_policy) {
+static void lb_call_init_locked(glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->server_name != NULL);
GPR_ASSERT(glb_policy->server_name[0] != '\0');
+ GPR_ASSERT(!glb_policy->shutting_down);
/* Note the following LB call progresses every time there's activity in \a
* glb_policy->base.interested_parties, which is comprised of the polling
@@ -975,10 +1094,10 @@ static void lb_call_init(glb_lb_policy *glb_policy) {
grpc_grpclb_request *request =
grpc_grpclb_request_create(glb_policy->server_name);
- gpr_slice request_payload_slice = grpc_grpclb_request_encode(request);
+ grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
glb_policy->lb_request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
- gpr_slice_unref(request_payload_slice);
+ grpc_slice_unref(request_payload_slice);
grpc_grpclb_request_destroy(request);
glb_policy->lb_call_status_details = NULL;
@@ -989,12 +1108,15 @@ static void lb_call_init(glb_lb_policy *glb_policy) {
grpc_closure_init(&glb_policy->lb_on_response_received,
lb_on_response_received, glb_policy);
- gpr_backoff_init(&glb_policy->lb_call_backoff_state, BACKOFF_MULTIPLIER,
- BACKOFF_JITTER, BACKOFF_MIN_SECONDS * 1000,
- BACKOFF_MAX_SECONDS * 1000);
+ gpr_backoff_init(&glb_policy->lb_call_backoff_state,
+ GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
+ GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
+ GRPC_GRPCLB_RECONNECT_JITTER,
+ GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+ GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
}
-static void lb_call_destroy(glb_lb_policy *glb_policy) {
+static void lb_call_destroy_locked(glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->lb_call != NULL);
grpc_call_destroy(glb_policy->lb_call);
glb_policy->lb_call = NULL;
@@ -1012,7 +1134,9 @@ static void lb_call_destroy(glb_lb_policy *glb_policy) {
static void query_for_backends_locked(grpc_exec_ctx *exec_ctx,
glb_lb_policy *glb_policy) {
GPR_ASSERT(glb_policy->lb_channel != NULL);
- lb_call_init(glb_policy);
+ if (glb_policy->shutting_down) return;
+
+ lb_call_init_locked(glb_policy);
if (grpc_lb_glb_trace) {
gpr_log(GPR_INFO, "Query for backends (grpclb: %p, lb_call: %p)",
@@ -1084,19 +1208,20 @@ static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
grpc_op ops[2];
memset(ops, 0, sizeof(ops));
grpc_op *op = ops;
+ gpr_mu_lock(&glb_policy->mu);
if (glb_policy->lb_response_payload != NULL) {
gpr_backoff_reset(&glb_policy->lb_call_backoff_state);
/* Received data from the LB server. Look inside
* glb_policy->lb_response_payload, for a serverlist. */
grpc_byte_buffer_reader bbr;
grpc_byte_buffer_reader_init(&bbr, glb_policy->lb_response_payload);
- gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
+ grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
grpc_byte_buffer_destroy(glb_policy->lb_response_payload);
grpc_grpclb_serverlist *serverlist =
grpc_grpclb_response_parse_serverlist(response_slice);
if (serverlist != NULL) {
GPR_ASSERT(glb_policy->lb_call != NULL);
- gpr_slice_unref(response_slice);
+ grpc_slice_unref(response_slice);
if (grpc_lb_glb_trace) {
gpr_log(GPR_INFO, "Serverlist with %lu servers received",
(unsigned long)serverlist->num_servers);
@@ -1112,23 +1237,24 @@ static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
/* update serverlist */
if (serverlist->num_servers > 0) {
- gpr_mu_lock(&glb_policy->mu);
if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, serverlist)) {
if (grpc_lb_glb_trace) {
gpr_log(GPR_INFO,
"Incoming server list identical to current, ignoring.");
}
+ grpc_grpclb_destroy_serverlist(serverlist);
} else { /* new serverlist */
if (glb_policy->serverlist != NULL) {
/* dispose of the old serverlist */
grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
}
- /* and update the copy in the glb_lb_policy instance */
+ /* and update the copy in the glb_lb_policy instance. This serverlist
+ * instance will be destroyed either upon the next update or in
+ * glb_destroy() */
glb_policy->serverlist = serverlist;
- rr_handover_locked(exec_ctx, glb_policy, error);
+ rr_handover_locked(exec_ctx, glb_policy);
}
- gpr_mu_unlock(&glb_policy->mu);
} else {
if (grpc_lb_glb_trace) {
gpr_log(GPR_INFO,
@@ -1138,8 +1264,8 @@ static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
}
} else { /* serverlist == NULL */
gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.",
- gpr_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
- gpr_slice_unref(response_slice);
+ grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
+ grpc_slice_unref(response_slice);
}
if (!glb_policy->shutting_down) {
@@ -1156,9 +1282,11 @@ static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
&glb_policy->lb_on_response_received); /* loop */
GPR_ASSERT(GRPC_CALL_OK == call_error);
}
+ gpr_mu_unlock(&glb_policy->mu);
} else { /* empty payload: call cancelled. */
/* dispose of the "lb_on_response_received" weak ref taken in
* query_for_backends_locked() and reused in every reception loop */
+ gpr_mu_unlock(&glb_policy->mu);
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"lb_on_response_received_empty_payload");
}
@@ -1178,7 +1306,6 @@ static void lb_call_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
query_for_backends_locked(exec_ctx, glb_policy);
}
gpr_mu_unlock(&glb_policy->mu);
-
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
"grpclb_on_retry_timer");
}
@@ -1199,7 +1326,7 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg,
}
/* We need to performe cleanups no matter what. */
- lb_call_destroy(glb_policy);
+ lb_call_destroy_locked(glb_policy);
if (!glb_policy->shutting_down) {
/* if we aren't shutting down, restart the LB client call after some time */
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
index a8881004a0..837e9c1113 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
@@ -90,18 +90,18 @@ grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name) {
return req;
}
-gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) {
+grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request) {
size_t encoded_length;
pb_ostream_t sizestream;
pb_ostream_t outputstream;
- gpr_slice slice;
+ grpc_slice slice;
memset(&sizestream, 0, sizeof(pb_ostream_t));
pb_encode(&sizestream, grpc_lb_v1_LoadBalanceRequest_fields, request);
encoded_length = sizestream.bytes_written;
- slice = gpr_slice_malloc(encoded_length);
+ slice = grpc_slice_malloc(encoded_length);
outputstream =
- pb_ostream_from_buffer(GPR_SLICE_START_PTR(slice), encoded_length);
+ pb_ostream_from_buffer(GRPC_SLICE_START_PTR(slice), encoded_length);
GPR_ASSERT(pb_encode(&outputstream, grpc_lb_v1_LoadBalanceRequest_fields,
request) != 0);
return slice;
@@ -113,10 +113,10 @@ void grpc_grpclb_request_destroy(grpc_grpclb_request *request) {
typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
- gpr_slice encoded_grpc_grpclb_response) {
+ grpc_slice encoded_grpc_grpclb_response) {
pb_istream_t stream =
- pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
- GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
+ pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response),
+ GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response));
grpc_grpclb_response res;
memset(&res, 0, sizeof(grpc_grpclb_response));
if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) {
@@ -132,12 +132,12 @@ grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
}
grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
- gpr_slice encoded_grpc_grpclb_response) {
+ grpc_slice encoded_grpc_grpclb_response) {
bool status;
decode_serverlist_arg arg;
pb_istream_t stream =
- pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
- GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
+ pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_grpc_grpclb_response),
+ GRPC_SLICE_LENGTH(encoded_grpc_grpclb_response));
pb_istream_t stream_at_start = stream;
grpc_grpclb_response res;
memset(&res, 0, sizeof(grpc_grpclb_response));
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
index 079a64a3f3..b4c967e426 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H
-#include <grpc/support/slice_buffer.h>
+#include <grpc/slice_buffer.h>
#include "src/core/ext/client_channel/lb_policy_factory.h"
#include "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
@@ -60,7 +60,7 @@ typedef struct grpc_grpclb_serverlist {
grpc_grpclb_request *grpc_grpclb_request_create(const char *lb_service_name);
/** Protocol Buffers v3-encode \a request */
-gpr_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request);
+grpc_slice grpc_grpclb_request_encode(const grpc_grpclb_request *request);
/** Destroy \a request */
void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
@@ -68,11 +68,11 @@ void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
/** Parse (ie, decode) the bytes in \a encoded_grpc_grpclb_response as a \a
* grpc_grpclb_initial_response */
grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
- gpr_slice encoded_grpc_grpclb_response);
+ grpc_slice encoded_grpc_grpclb_response);
/** Parse the list of servers from an encoded \a grpc_grpclb_response */
grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
- gpr_slice encoded_grpc_grpclb_response);
+ grpc_slice encoded_grpc_grpclb_response);
/** Return a copy of \a sl. The caller is responsible for calling \a
* grpc_grpclb_destroy_serverlist on the returned copy. */
diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c
index ac3c6a305a..c69f773e78 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -292,6 +292,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
} else {
loop:
switch (p->checking_connectivity) {
+ case GRPC_CHANNEL_INIT:
+ GPR_UNREACHABLE_CODE(return );
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 427999aa6b..59f84054c4 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -116,8 +116,13 @@ typedef struct {
grpc_closure connectivity_changed_closure;
/** this subchannels current position in subchannel->ready_list */
ready_list *ready_list_node;
- /** last observed connectivity */
- grpc_connectivity_state connectivity_state;
+ /** last observed connectivity. Not updated by
+ * \a grpc_subchannel_notify_on_state_change. Used to determine the previous
+ * state while processing the new state in \a rr_connectivity_changed */
+ grpc_connectivity_state prev_connectivity_state;
+ /** current connectivity state. Updated by \a
+ * grpc_subchannel_notify_on_state_change */
+ grpc_connectivity_state curr_connectivity_state;
/** the subchannel's target user data */
void *user_data;
/** vtable to operate over \a user_data */
@@ -127,6 +132,7 @@ typedef struct {
struct round_robin_lb_policy {
/** base policy: must be first */
grpc_lb_policy base;
+ gpr_mu mu;
/** total number of addresses received at creation time */
size_t num_addresses;
@@ -135,8 +141,11 @@ struct round_robin_lb_policy {
size_t num_subchannels;
subchannel_data **subchannels;
- /** mutex protecting remaining members */
- gpr_mu mu;
+ /** how many subchannels are in TRANSIENT_FAILURE */
+ size_t num_transient_failures;
+ /** how many subchannels are IDLE */
+ size_t num_idle;
+
/** have we started picking? */
int started_picking;
/** are we shutting down? */
@@ -258,6 +267,10 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
gpr_free(node);
}
+static bool is_ready_list_empty(round_robin_lb_policy *p) {
+ return p->ready_list.prev == NULL;
+}
+
static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
ready_list *elem;
@@ -268,7 +281,7 @@ static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
for (size_t i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
- GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin_destroy");
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy");
if (sd->user_data != NULL) {
GPR_ASSERT(sd->user_data_vtable != NULL);
sd->user_data_vtable->destroy(sd->user_data);
@@ -381,18 +394,18 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
size_t i;
p->started_picking = 1;
- if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, (void *)p,
- p->num_subchannels);
- }
-
for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
- sd->connectivity_state = GRPC_CHANNEL_IDLE;
+ /* use some sentinel value outside of the range of grpc_connectivity_state
+ * to signal an undefined previous state. We won't be referring to this
+ * value again and it'll be overwritten after the first call to
+ * rr_connectivity_changed */
+ sd->prev_connectivity_state = GRPC_CHANNEL_INIT;
+ sd->curr_connectivity_state = GRPC_CHANNEL_IDLE;
+ GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity");
grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, p->base.interested_parties,
- &sd->connectivity_state, &sd->connectivity_changed_closure);
- GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
+ &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
}
}
@@ -422,7 +435,7 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
/* readily available, report right away */
*target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
- "picked");
+ "rr_picked");
if (user_data != NULL) {
*user_data = selected->user_data;
@@ -453,125 +466,184 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
}
}
+static void update_state_counters(subchannel_data *sd) {
+ round_robin_lb_policy *p = sd->policy;
+
+ /* update p->num_transient_failures (resp. p->num_idle): if the previous
+ * state was TRANSIENT_FAILURE (resp. IDLE), decrement
+ * p->num_transient_failures (resp. p->num_idle). */
+ if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+ GPR_ASSERT(p->num_transient_failures > 0);
+ --p->num_transient_failures;
+ } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) {
+ GPR_ASSERT(p->num_idle > 0);
+ --p->num_idle;
+ }
+}
+
+/* sd is the subchannel_data associted with the updated subchannel.
+ * shutdown_error will only be used upon policy transition to TRANSIENT_FAILURE
+ * or SHUTDOWN */
+static grpc_connectivity_state update_lb_connectivity_status(
+ grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) {
+ /* In priority order. The first rule to match terminates the search (ie, if we
+ * are on rule n, all previous rules were unfulfilled).
+ *
+ * 1) RULE: ANY subchannel is READY => policy is READY.
+ * CHECK: At least one subchannel is ready iff p->ready_list is NOT empty.
+ *
+ * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING.
+ * CHECK: sd->curr_connectivity_state == CONNECTING.
+ *
+ * 3) RULE: ALL subchannels are SHUTDOWN => policy is SHUTDOWN.
+ * CHECK: p->num_subchannels = 0.
+ *
+ * 4) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is
+ * TRANSIENT_FAILURE.
+ * CHECK: p->num_transient_failures == p->num_subchannels.
+ *
+ * 5) RULE: ALL subchannels are IDLE => policy is IDLE.
+ * CHECK: p->num_idle == p->num_subchannels.
+ */
+ round_robin_lb_policy *p = sd->policy;
+ if (!is_ready_list_empty(p)) { /* 1) READY */
+ grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY,
+ GRPC_ERROR_NONE, "rr_ready");
+ return GRPC_CHANNEL_READY;
+ } else if (sd->curr_connectivity_state ==
+ GRPC_CHANNEL_CONNECTING) { /* 2) CONNECTING */
+ grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+ GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
+ "rr_connecting");
+ return GRPC_CHANNEL_CONNECTING;
+ } else if (p->num_subchannels == 0) { /* 3) SHUTDOWN */
+ grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+ GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error),
+ "rr_shutdown");
+ return GRPC_CHANNEL_SHUTDOWN;
+ } else if (p->num_transient_failures ==
+ p->num_subchannels) { /* 4) TRANSIENT_FAILURE */
+ grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
+ GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_REF(error), "rr_transient_failure");
+ return GRPC_CHANNEL_TRANSIENT_FAILURE;
+ } else if (p->num_idle == p->num_subchannels) { /* 5) IDLE */
+ grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_IDLE,
+ GRPC_ERROR_NONE, "rr_idle");
+ return GRPC_CHANNEL_IDLE;
+ }
+ /* no change */
+ return sd->curr_connectivity_state;
+}
+
static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
subchannel_data *sd = arg;
round_robin_lb_policy *p = sd->policy;
pending_pick *pp;
- int unref = 0;
-
GRPC_ERROR_REF(error);
gpr_mu_lock(&p->mu);
if (p->shutdown) {
- unref = 1;
- } else {
- switch (sd->connectivity_state) {
- case GRPC_CHANNEL_READY:
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_READY, GRPC_ERROR_REF(error),
- "connecting_ready");
- /* add the newly connected subchannel to the list of connected ones.
- * Note that it goes to the "end of the line". */
- sd->ready_list_node = add_connected_sc_locked(p, sd);
- /* at this point we know there's at least one suitable subchannel. Go
- * ahead and pick one and notify the pending suitors in
- * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
- ready_list *selected = peek_next_connected_locked(p);
- GPR_ASSERT(selected != NULL);
- if (p->pending_picks != NULL) {
- /* if the selected subchannel is going to be used for the pending
- * picks, update the last picked pointer */
- advance_last_picked_locked(p);
+ gpr_mu_unlock(&p->mu);
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ switch (sd->curr_connectivity_state) {
+ case GRPC_CHANNEL_INIT:
+ GPR_UNREACHABLE_CODE(return );
+ case GRPC_CHANNEL_READY:
+ /* add the newly connected subchannel to the list of connected ones.
+ * Note that it goes to the "end of the line". */
+ sd->ready_list_node = add_connected_sc_locked(p, sd);
+ /* at this point we know there's at least one suitable subchannel. Go
+ * ahead and pick one and notify the pending suitors in
+ * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
+ ready_list *selected = peek_next_connected_locked(p);
+ GPR_ASSERT(selected != NULL);
+ if (p->pending_picks != NULL) {
+ /* if the selected subchannel is going to be used for the pending
+ * picks, update the last picked pointer */
+ advance_last_picked_locked(p);
+ }
+ while ((pp = p->pending_picks)) {
+ p->pending_picks = pp->next;
+ *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
+ grpc_subchannel_get_connected_subchannel(selected->subchannel),
+ "rr_picked");
+ if (pp->user_data != NULL) {
+ *pp->user_data = selected->user_data;
}
-
+ if (grpc_lb_round_robin_trace) {
+ gpr_log(GPR_DEBUG,
+ "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
+ (void *)selected->subchannel, (void *)selected);
+ }
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
+ gpr_free(pp);
+ }
+ update_lb_connectivity_status(exec_ctx, sd, error);
+ sd->prev_connectivity_state = sd->curr_connectivity_state;
+ /* renew notification: reuses the "rr_connectivity" weak ref */
+ grpc_subchannel_notify_on_state_change(
+ exec_ctx, sd->subchannel, p->base.interested_parties,
+ &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
+ break;
+ case GRPC_CHANNEL_IDLE:
+ ++p->num_idle;
+ /* fallthrough */
+ case GRPC_CHANNEL_CONNECTING:
+ update_state_counters(sd);
+ update_lb_connectivity_status(exec_ctx, sd, error);
+ sd->prev_connectivity_state = sd->curr_connectivity_state;
+ /* renew notification: reuses the "rr_connectivity" weak ref */
+ grpc_subchannel_notify_on_state_change(
+ exec_ctx, sd->subchannel, p->base.interested_parties,
+ &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
+ break;
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ ++p->num_transient_failures;
+ /* remove from ready list if still present */
+ if (sd->ready_list_node != NULL) {
+ remove_disconnected_sc_locked(p, sd->ready_list_node);
+ sd->ready_list_node = NULL;
+ }
+ update_lb_connectivity_status(exec_ctx, sd, error);
+ sd->prev_connectivity_state = sd->curr_connectivity_state;
+ /* renew notification: reuses the "rr_connectivity" weak ref */
+ grpc_subchannel_notify_on_state_change(
+ exec_ctx, sd->subchannel, p->base.interested_parties,
+ &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
+ break;
+ case GRPC_CHANNEL_SHUTDOWN:
+ update_state_counters(sd);
+ if (sd->ready_list_node != NULL) {
+ remove_disconnected_sc_locked(p, sd->ready_list_node);
+ sd->ready_list_node = NULL;
+ }
+ --p->num_subchannels;
+ GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
+ p->subchannels[p->num_subchannels]);
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown");
+ p->subchannels[sd->index]->index = sd->index;
+ if (update_lb_connectivity_status(exec_ctx, sd, error) ==
+ GRPC_CHANNEL_SHUTDOWN) {
+ /* the policy is shutting down. Flush all the pending picks... */
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
-
- *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
- grpc_subchannel_get_connected_subchannel(selected->subchannel),
- "picked");
- if (pp->user_data != NULL) {
- *pp->user_data = selected->user_data;
- }
- if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG,
- "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
- (void *)selected->subchannel, (void *)selected);
- }
+ *pp->target = NULL;
grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp);
}
- grpc_subchannel_notify_on_state_change(
- exec_ctx, sd->subchannel, p->base.interested_parties,
- &sd->connectivity_state, &sd->connectivity_changed_closure);
- break;
- case GRPC_CHANNEL_CONNECTING:
- case GRPC_CHANNEL_IDLE:
- grpc_connectivity_state_set(
- exec_ctx, &p->state_tracker, sd->connectivity_state,
- GRPC_ERROR_REF(error), "connecting_changed");
- grpc_subchannel_notify_on_state_change(
- exec_ctx, sd->subchannel, p->base.interested_parties,
- &sd->connectivity_state, &sd->connectivity_changed_closure);
- break;
- case GRPC_CHANNEL_TRANSIENT_FAILURE:
- /* renew state notification */
- grpc_subchannel_notify_on_state_change(
- exec_ctx, sd->subchannel, p->base.interested_parties,
- &sd->connectivity_state, &sd->connectivity_changed_closure);
-
- /* remove from ready list if still present */
- if (sd->ready_list_node != NULL) {
- remove_disconnected_sc_locked(p, sd->ready_list_node);
- sd->ready_list_node = NULL;
- }
- grpc_connectivity_state_set(
- exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
- GRPC_ERROR_REF(error), "connecting_transient_failure");
- break;
- case GRPC_CHANNEL_SHUTDOWN:
- if (sd->ready_list_node != NULL) {
- remove_disconnected_sc_locked(p, sd->ready_list_node);
- sd->ready_list_node = NULL;
- }
-
- p->num_subchannels--;
- GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
- p->subchannels[p->num_subchannels]);
- GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
- p->subchannels[sd->index]->index = sd->index;
- gpr_free(sd);
-
- unref = 1;
- if (p->num_subchannels == 0) {
- grpc_connectivity_state_set(
- exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
- GRPC_ERROR_CREATE_REFERENCING("Round Robin Channels Exhausted",
- &error, 1),
- "no_more_channels");
- while ((pp = p->pending_picks)) {
- p->pending_picks = pp->next;
- *pp->target = NULL;
- grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
- NULL);
- gpr_free(pp);
- }
- } else {
- grpc_connectivity_state_set(
- exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
- GRPC_ERROR_REF(error), "subchannel_failed");
- }
- } /* switch */
- } /* !unref */
-
- gpr_mu_unlock(&p->mu);
-
- if (unref) {
- GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
+ }
+ gpr_free(sd);
+ /* unref the "rr_connectivity" weak ref from start_picking */
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
+ break;
}
-
+ gpr_mu_unlock(&p->mu);
GRPC_ERROR_UNREF(error);
}
@@ -607,8 +679,9 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_unlock(&p->mu);
target = GRPC_CONNECTED_SUBCHANNEL_REF(
grpc_subchannel_get_connected_subchannel(selected->subchannel),
- "picked");
+ "rr_picked");
grpc_connected_subchannel_ping(exec_ctx, target, closure);
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked");
} else {
gpr_mu_unlock(&p->mu);
grpc_exec_ctx_sched(exec_ctx, closure,
@@ -704,6 +777,11 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"round_robin");
+
+ if (grpc_lb_round_robin_trace) {
+ gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels",
+ (void *)p, (unsigned long)p->num_subchannels);
+ }
gpr_mu_init(&p->mu);
return &p->base;
}
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index eeae2400fb..b810e20bb9 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -232,4 +232,5 @@ const grpc_channel_filter grpc_load_reporting_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"load_reporting"};
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 958b8af8b2..15476f5792 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -46,10 +46,11 @@
#include "src/core/lib/support/backoff.h"
#include "src/core/lib/support/string.h"
-#define BACKOFF_MULTIPLIER 1.6
-#define BACKOFF_JITTER 0.2
-#define BACKOFF_MIN_SECONDS 1
-#define BACKOFF_MAX_SECONDS 120
+#define GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS 1
+#define GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS 1
+#define GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER 1.6
+#define GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS 120
+#define GRPC_DNS_RECONNECT_JITTER 0.2
typedef struct {
/** base class: must be first */
@@ -190,7 +191,7 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(!r->have_retry_timer);
r->have_retry_timer = true;
GRPC_RESOLVER_REF(&r->base, "retry-timer");
- if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) <= 0) {
+ if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) {
gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
timeout.tv_nsec);
} else {
@@ -269,8 +270,11 @@ static grpc_resolver *dns_create(grpc_resolver_args *args,
server_name_arg.value.string = (char *)path;
r->channel_args =
grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
- gpr_backoff_init(&r->backoff_state, BACKOFF_MULTIPLIER, BACKOFF_JITTER,
- BACKOFF_MIN_SECONDS * 1000, BACKOFF_MAX_SECONDS * 1000);
+ gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
+ GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
+ GRPC_DNS_RECONNECT_JITTER,
+ GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+ GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
return &r->base;
}
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index 5fec03a8e4..26a650aadd 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -47,6 +47,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
typedef struct {
@@ -169,17 +170,17 @@ static grpc_resolver *sockaddr_create(grpc_resolver_args *args,
return NULL;
}
/* Construct addresses. */
- gpr_slice path_slice =
- gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
- gpr_slice_buffer path_parts;
- gpr_slice_buffer_init(&path_parts);
- gpr_slice_split(path_slice, ",", &path_parts);
+ grpc_slice path_slice =
+ grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
+ grpc_slice_buffer path_parts;
+ grpc_slice_buffer_init(&path_parts);
+ grpc_slice_split(path_slice, ",", &path_parts);
grpc_lb_addresses *addresses =
grpc_lb_addresses_create(path_parts.count, NULL /* user_data_vtable */);
bool errors_found = false;
for (size_t i = 0; i < addresses->num_addresses; i++) {
grpc_uri ith_uri = *args->uri;
- char *part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
+ char *part_str = grpc_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
ith_uri.path = part_str;
if (!parse(&ith_uri, &addresses->addresses[i].address)) {
errors_found = true; /* GPR_TRUE */
@@ -187,8 +188,8 @@ static grpc_resolver *sockaddr_create(grpc_resolver_args *args,
gpr_free(part_str);
if (errors_found) break;
}
- gpr_slice_buffer_destroy(&path_parts);
- gpr_slice_unref(path_slice);
+ grpc_slice_buffer_destroy(&path_parts);
+ grpc_slice_unref(path_slice);
if (errors_found) {
grpc_lb_addresses_destroy(addresses);
return NULL;
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.c b/src/core/ext/transport/chttp2/client/chttp2_connector.c
new file mode 100644
index 0000000000..213395c20f
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.c
@@ -0,0 +1,261 @@
+/*
+ *
+ * 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;
+
+ 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->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(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);
+ 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 {
+ 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);
+ 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;
+}
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h
new file mode 100644
index 0000000000..6c34ce1af1
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -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 */
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index 71a06e118b..29f3759d00 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -33,138 +33,17 @@
#include <grpc/grpc.h>
-#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/compress_filter.h"
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/channel/http_client_filter.h"
-#include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
-//
-// connector
-//
-
-typedef struct {
- grpc_connector base;
- gpr_refcount refs;
-
- grpc_closure *notify;
- grpc_connect_in_args args;
- grpc_connect_out_args *result;
- grpc_closure initial_string_sent;
- gpr_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,
- gpr_slice_buffer *read_buffer, void *user_data,
- grpc_error *error) {
- connector *c = user_data;
- if (error != GRPC_ERROR_NONE) {
- grpc_channel_args_destroy(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 (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
- grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
- c);
- gpr_slice_buffer_init(&c->initial_string_buffer);
- gpr_slice_buffer_add(&c->initial_string_buffer,
- c->args.initial_connect_string);
- connector_ref(arg);
- grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
- &c->initial_string_sent);
- } else {
- grpc_handshake_manager_do_handshake(
- exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
- c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
- }
- } else {
- memset(c->result, 0, sizeof(*c->result));
- grpc_closure *notify = c->notify;
- c->notify = NULL;
- grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
- }
-}
-
-static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
-
-static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
- const grpc_connect_in_args *args,
- grpc_connect_out_args *result,
- grpc_closure *notify) {
- connector *c = (connector *)con;
- GPR_ASSERT(c->notify == NULL);
- GPR_ASSERT(notify->cb);
- c->notify = notify;
- c->args = *args;
- c->result = result;
- c->tcp = NULL;
- grpc_closure_init(&c->connected, connected, c);
- grpc_tcp_client_connect(exec_ctx, &c->connected, &c->tcp,
- args->interested_parties, args->channel_args,
- args->addr, args->deadline);
-}
-
-static const grpc_connector_vtable connector_vtable = {
- connector_ref, connector_unref, connector_shutdown, connector_connect};
-
-//
-// client_channel_factory
-//
-
static void client_channel_factory_ref(
grpc_client_channel_factory *cc_factory) {}
@@ -174,20 +53,11 @@ static void client_channel_factory_unref(
static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) {
- connector *c = gpr_malloc(sizeof(*c));
- memset(c, 0, sizeof(*c));
- c->base.vtable = &connector_vtable;
- gpr_ref_init(&c->refs, 1);
- c->handshake_mgr = grpc_handshake_manager_create();
- char *proxy_name = grpc_get_http_proxy_server();
- if (proxy_name != NULL) {
- grpc_handshake_manager_add(
- c->handshake_mgr,
- grpc_http_connect_handshaker_create(proxy_name, args->server_name));
- gpr_free(proxy_name);
- }
- grpc_subchannel *s = grpc_subchannel_create(exec_ctx, &c->base, args);
- grpc_connector_unref(exec_ctx, &c->base);
+ grpc_connector *connector = grpc_chttp2_connector_create(
+ exec_ctx, args->server_name, NULL /* create_handshakers */,
+ NULL /* user_data */);
+ grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
+ grpc_connector_unref(exec_ctx, connector);
return s;
}
@@ -198,16 +68,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(target, args);
- if (!resolver) {
+ if (resolver == NULL) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel");
return NULL;
}
-
grpc_client_channel_finish_initialization(
exec_ctx, grpc_channel_get_channel_stack(channel), resolver, cc_factory);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
-
return channel;
}
@@ -230,16 +98,13 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
GRPC_API_TRACE(
"grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
(target, args, reserved));
- GPR_ASSERT(!reserved);
-
+ GPR_ASSERT(reserved == NULL);
grpc_client_channel_factory *factory =
(grpc_client_channel_factory *)&client_channel_factory;
grpc_channel *channel = client_channel_factory_create_channel(
&exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args);
-
grpc_client_channel_factory_unref(&exec_ctx, factory);
grpc_exec_ctx_finish(&exec_ctx);
-
return channel != NULL ? channel : grpc_lame_client_channel_create(
target, GRPC_STATUS_INTERNAL,
"Failed to create client channel");
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index d0ac72a011..35e1e1f716 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -33,196 +33,19 @@
#include <grpc/grpc.h>
-#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
+#include <grpc/support/string_util.h>
#include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/http_connect_handshaker.h"
#include "src/core/ext/client_channel/resolver_registry.h"
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/iomgr/tcp_client.h"
-#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/auth_filters.h"
+#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/tsi/transport_security_interface.h"
-
-//
-// connector
-//
-
-typedef struct {
- grpc_connector base;
- gpr_refcount refs;
-
- grpc_channel_security_connector *security_connector;
-
- grpc_closure *notify;
- grpc_connect_in_args args;
- grpc_connect_out_args *result;
- grpc_closure initial_string_sent;
- gpr_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(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,
- gpr_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 (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
- grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
- c);
- gpr_slice_buffer_init(&c->initial_string_buffer);
- gpr_slice_buffer_add(&c->initial_string_buffer,
- c->args.initial_connect_string);
- grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
- &c->initial_string_sent);
- } else {
- grpc_handshake_manager_do_handshake(
- exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
- c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
- }
- } else {
- memset(c->result, 0, sizeof(*c->result));
- grpc_closure *notify = c->notify;
- c->notify = NULL;
- grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
- }
-}
-
-static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
- connector *c = (connector *)con;
- grpc_endpoint *ep;
- gpr_mu_lock(&c->mu);
- ep = c->connecting_endpoint;
- c->connecting_endpoint = NULL;
- gpr_mu_unlock(&c->mu);
- if (ep) {
- grpc_endpoint_shutdown(exec_ctx, ep);
- }
-}
-
-static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
- const grpc_connect_in_args *args,
- grpc_connect_out_args *result,
- grpc_closure *notify) {
- connector *c = (connector *)con;
- GPR_ASSERT(c->notify == NULL);
- c->notify = notify;
- c->args = *args;
- c->result = result;
- gpr_mu_lock(&c->mu);
- GPR_ASSERT(c->connecting_endpoint == NULL);
- gpr_mu_unlock(&c->mu);
- grpc_closure_init(&c->connected_closure, connected, c);
- grpc_tcp_client_connect(
- exec_ctx, &c->connected_closure, &c->newly_connecting_endpoint,
- args->interested_parties, args->channel_args, args->addr, args->deadline);
-}
-
-static const grpc_connector_vtable connector_vtable = {
- connector_ref, connector_unref, connector_shutdown, connector_connect};
-
-//
-// client_channel_factory
-//
typedef struct {
grpc_client_channel_factory base;
@@ -246,26 +69,21 @@ static void client_channel_factory_unref(
}
}
+static void create_handshakers(grpc_exec_ctx *exec_ctx,
+ void *security_connector,
+ grpc_handshake_manager *handshake_mgr) {
+ grpc_channel_security_connector_create_handshakers(
+ exec_ctx, security_connector, handshake_mgr);
+}
+
static grpc_subchannel *client_channel_factory_create_subchannel(
grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
const grpc_subchannel_args *args) {
client_channel_factory *f = (client_channel_factory *)cc_factory;
- connector *c = gpr_malloc(sizeof(*c));
- memset(c, 0, sizeof(*c));
- c->base.vtable = &connector_vtable;
- c->security_connector = f->security_connector;
- c->handshake_mgr = grpc_handshake_manager_create();
- char *proxy_name = grpc_get_http_proxy_server();
- if (proxy_name != NULL) {
- grpc_handshake_manager_add(
- c->handshake_mgr,
- grpc_http_connect_handshaker_create(proxy_name, args->server_name));
- gpr_free(proxy_name);
- }
- gpr_mu_init(&c->mu);
- gpr_ref_init(&c->refs, 1);
- grpc_subchannel *s = grpc_subchannel_create(exec_ctx, &c->base, args);
- grpc_connector_unref(exec_ctx, &c->base);
+ grpc_connector *connector = grpc_chttp2_connector_create(
+ exec_ctx, args->server_name, create_handshakers, f->security_connector);
+ grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
+ grpc_connector_unref(exec_ctx, connector);
return s;
}
@@ -277,15 +95,14 @@ static grpc_channel *client_channel_factory_create_channel(
grpc_channel *channel =
grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
grpc_resolver *resolver = grpc_resolver_create(target, args);
- if (resolver != NULL) {
- grpc_client_channel_finish_initialization(
- exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
- GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create");
- } else {
+ if (resolver == NULL) {
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
"client_channel_factory_create_channel");
- channel = NULL;
+ return NULL;
}
+ grpc_client_channel_finish_initialization(
+ exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
+ GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
return channel;
}
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
new file mode 100644
index 0000000000..8ee7e29316
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -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(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(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(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(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;
+}
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h
new file mode 100644
index 0000000000..3073399267
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -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 */
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index d42611b863..7e286d4e46 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -33,180 +33,28 @@
#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/useful.h>
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
-typedef struct server_connect_state {
- grpc_server *server;
- grpc_pollset *accepting_pollset;
- grpc_tcp_server_acceptor *acceptor;
- grpc_handshake_manager *handshake_mgr;
-} server_connect_state;
-
-static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
- grpc_channel_args *args,
- gpr_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(args);
- grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr);
- gpr_free(state);
-}
-
-static void on_accept(grpc_exec_ctx *exec_ctx, void *server, grpc_endpoint *tcp,
- grpc_pollset *accepting_pollset,
- grpc_tcp_server_acceptor *acceptor) {
- server_connect_state *state = gpr_malloc(sizeof(server_connect_state));
- state->server = server;
- state->accepting_pollset = accepting_pollset;
- state->acceptor = acceptor;
- state->handshake_mgr = grpc_handshake_manager_create();
- // TODO(roth): We should really get this timeout value from channel
- // args instead of hard-coding it.
- const gpr_timespec deadline = gpr_time_add(
- gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
- grpc_handshake_manager_do_handshake(
- exec_ctx, state->handshake_mgr, tcp, grpc_server_get_channel_args(server),
- deadline, acceptor, on_handshake_done, state);
-}
-
-/* Server callback: start listening on our ports */
-static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
- grpc_pollset **pollsets, size_t pollset_count) {
- grpc_tcp_server *tcp = tcpp;
- grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, on_accept,
- server);
-}
-
-/* Server callback: destroy the tcp listener (so we don't generate further
- callbacks) */
-static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
- grpc_closure *destroy_done) {
- grpc_tcp_server *tcp = tcpp;
- grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
- grpc_tcp_server_unref(exec_ctx, tcp);
- grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_NONE, NULL);
-}
-
int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
- grpc_resolved_addresses *resolved = NULL;
- grpc_tcp_server *tcp = NULL;
- size_t i;
- size_t count = 0;
- int port_num = -1;
- int port_temp;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_error *err = GRPC_ERROR_NONE;
-
+ int port_num = 0;
GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr));
-
- grpc_error **errors = NULL;
- err = grpc_blocking_resolve_address(addr, "https", &resolved);
- if (err != GRPC_ERROR_NONE) {
- goto error;
- }
-
- err = grpc_tcp_server_create(&exec_ctx, NULL,
- grpc_server_get_channel_args(server), &tcp);
+ grpc_error *err = grpc_chttp2_server_add_port(
+ &exec_ctx, server, addr,
+ grpc_channel_args_copy(grpc_server_get_channel_args(server)),
+ NULL /* handshaker_factory */, &port_num);
if (err != GRPC_ERROR_NONE) {
- goto error;
- }
-
- const size_t naddrs = resolved->naddrs;
- errors = gpr_malloc(sizeof(*errors) * naddrs);
- for (i = 0; i < naddrs; i++) {
- errors[i] = grpc_tcp_server_add_port(tcp, &resolved->addrs[i], &port_temp);
- if (errors[i] == GRPC_ERROR_NONE) {
- if (port_num == -1) {
- port_num = port_temp;
- } else {
- GPR_ASSERT(port_num == port_temp);
- }
- count++;
- }
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(err);
}
- if (count == 0) {
- char *msg;
- gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
- naddrs);
- err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
- gpr_free(msg);
- goto error;
- } else if (count != naddrs) {
- char *msg;
- gpr_asprintf(&msg, "Only %" PRIuPTR
- " addresses added out of total %" PRIuPTR " resolved",
- count, naddrs);
- err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, naddrs);
- gpr_free(msg);
-
- const char *warning_message = grpc_error_string(err);
- gpr_log(GPR_INFO, "WARNING: %s", warning_message);
- grpc_error_free_string(warning_message);
- /* we managed to bind some addresses: continue */
- }
- grpc_resolved_addresses_destroy(resolved);
-
- /* Register with the server only upon success */
- grpc_server_add_listener(&exec_ctx, server, tcp, start, destroy);
- goto done;
-
-/* Error path: cleanup and return */
-error:
- GPR_ASSERT(err != GRPC_ERROR_NONE);
- if (resolved) {
- grpc_resolved_addresses_destroy(resolved);
- }
- if (tcp) {
- grpc_tcp_server_unref(&exec_ctx, tcp);
- }
- port_num = 0;
-
- const char *msg = grpc_error_string(err);
- gpr_log(GPR_ERROR, "%s", msg);
- grpc_error_free_string(msg);
- GRPC_ERROR_UNREF(err);
-
-done:
grpc_exec_ctx_finish(&exec_ctx);
- if (errors != NULL) {
- for (i = 0; i < naddrs; i++) {
- GRPC_ERROR_UNREF(errors[i]);
- }
- }
- gpr_free(errors);
return port_num;
}
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index 7ad687042d..85c21f0ca2 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -38,218 +38,63 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
+
+#include "src/core/ext/transport/chttp2/server/chttp2_server.h"
+
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/iomgr/endpoint.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/auth_filters.h"
-#include "src/core/lib/security/transport/security_connector.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/server.h"
-typedef struct server_secure_state {
- grpc_server *server;
- grpc_tcp_server *tcp;
- grpc_server_security_connector *sc;
- grpc_server_credentials *creds;
- bool is_shutdown;
- gpr_mu mu;
- grpc_closure tcp_server_shutdown_complete;
- grpc_closure *server_destroy_listener_done;
-} server_secure_state;
-
-typedef struct server_secure_connect {
- server_secure_state *server_state;
- grpc_pollset *accepting_pollset;
- grpc_tcp_server_acceptor *acceptor;
- grpc_handshake_manager *handshake_mgr;
- // TODO(roth): Remove the following two fields when we eliminate
- // grpc_server_security_connector_do_handshake().
- gpr_timespec deadline;
- grpc_channel_args *args;
-} server_secure_connect;
-
-static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
- grpc_security_status status,
- grpc_endpoint *secure_endpoint,
- grpc_auth_context *auth_context) {
- server_secure_connect *connection_state = statep;
- if (status == GRPC_SECURITY_OK) {
- if (secure_endpoint) {
- gpr_mu_lock(&connection_state->server_state->mu);
- if (!connection_state->server_state->is_shutdown) {
- grpc_transport *transport = grpc_create_chttp2_transport(
- exec_ctx, grpc_server_get_channel_args(
- connection_state->server_state->server),
- secure_endpoint, 0);
- grpc_arg args_to_add[2];
- args_to_add[0] = grpc_server_credentials_to_arg(
- connection_state->server_state->creds);
- args_to_add[1] = grpc_auth_context_to_arg(auth_context);
- grpc_channel_args *args_copy = grpc_channel_args_copy_and_add(
- connection_state->args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
- grpc_server_setup_transport(
- exec_ctx, connection_state->server_state->server, transport,
- connection_state->accepting_pollset, args_copy);
- grpc_channel_args_destroy(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(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,
- gpr_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(args);
- gpr_free(read_buffer);
- grpc_handshake_manager_shutdown(exec_ctx, connection_state->handshake_mgr);
- grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
- grpc_tcp_server_unref(exec_ctx, connection_state->server_state->tcp);
- gpr_free(connection_state);
- return;
- }
- grpc_handshake_manager_destroy(exec_ctx, connection_state->handshake_mgr);
- connection_state->handshake_mgr = NULL;
- // TODO(roth, jboeuf): Convert security connector handshaking to use new
- // handshake API, and then move the code from on_secure_handshake_done()
- // into this function.
- connection_state->args = args;
- grpc_server_security_connector_do_handshake(
- exec_ctx, connection_state->server_state->sc, connection_state->acceptor,
- endpoint, read_buffer, connection_state->deadline,
- on_secure_handshake_done, connection_state);
-}
-
-static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
- grpc_pollset *accepting_pollset,
- grpc_tcp_server_acceptor *acceptor) {
- server_secure_state *server_state = statep;
- server_secure_connect *connection_state = NULL;
- gpr_mu_lock(&server_state->mu);
- if (server_state->is_shutdown) {
- gpr_mu_unlock(&server_state->mu);
- grpc_endpoint_destroy(exec_ctx, tcp);
- return;
- }
- gpr_mu_unlock(&server_state->mu);
- grpc_tcp_server_ref(server_state->tcp);
- connection_state = gpr_malloc(sizeof(*connection_state));
- connection_state->server_state = server_state;
- connection_state->accepting_pollset = accepting_pollset;
- connection_state->acceptor = acceptor;
- connection_state->handshake_mgr = grpc_handshake_manager_create();
- // TODO(roth): We should really get this timeout value from channel
- // args instead of hard-coding it.
- connection_state->deadline = gpr_time_add(
- gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
- grpc_handshake_manager_do_handshake(
- exec_ctx, connection_state->handshake_mgr, tcp,
- grpc_server_get_channel_args(connection_state->server_state->server),
- connection_state->deadline, acceptor, on_handshake_done,
- connection_state);
+typedef struct {
+ grpc_chttp2_server_handshaker_factory base;
+ grpc_server_security_connector *security_connector;
+} server_security_handshaker_factory;
+
+static void server_security_handshaker_factory_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf,
+ grpc_handshake_manager *handshake_mgr) {
+ server_security_handshaker_factory *handshaker_factory =
+ (server_security_handshaker_factory *)hf;
+ grpc_server_security_connector_create_handshakers(
+ exec_ctx, handshaker_factory->security_connector, handshake_mgr);
}
-/* Server callback: start listening on our ports */
-static void server_start_listener(grpc_exec_ctx *exec_ctx, grpc_server *server,
- void *statep, grpc_pollset **pollsets,
- size_t pollset_count) {
- server_secure_state *server_state = statep;
- gpr_mu_lock(&server_state->mu);
- server_state->is_shutdown = false;
- gpr_mu_unlock(&server_state->mu);
- grpc_tcp_server_start(exec_ctx, server_state->tcp, pollsets, pollset_count,
- on_accept, server_state);
+static void server_security_handshaker_factory_destroy(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf) {
+ server_security_handshaker_factory *handshaker_factory =
+ (server_security_handshaker_factory *)hf;
+ GRPC_SECURITY_CONNECTOR_UNREF(&handshaker_factory->security_connector->base,
+ "server");
+ gpr_free(hf);
}
-static void tcp_server_shutdown_complete(grpc_exec_ctx *exec_ctx, void *statep,
- grpc_error *error) {
- server_secure_state *server_state = statep;
- /* ensure all threads have unlocked */
- gpr_mu_lock(&server_state->mu);
- grpc_closure *destroy_done = server_state->server_destroy_listener_done;
- GPR_ASSERT(server_state->is_shutdown);
- gpr_mu_unlock(&server_state->mu);
- /* clean up */
- grpc_server_security_connector_shutdown(exec_ctx, server_state->sc);
-
- /* Flush queued work before a synchronous unref. */
- grpc_exec_ctx_flush(exec_ctx);
- GRPC_SECURITY_CONNECTOR_UNREF(&server_state->sc->base, "server");
- grpc_server_credentials_unref(server_state->creds);
-
- if (destroy_done != NULL) {
- destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
- grpc_exec_ctx_flush(exec_ctx);
- }
- gpr_free(server_state);
-}
-
-static void server_destroy_listener(grpc_exec_ctx *exec_ctx,
- grpc_server *server, void *statep,
- grpc_closure *callback) {
- server_secure_state *server_state = statep;
- grpc_tcp_server *tcp;
- gpr_mu_lock(&server_state->mu);
- server_state->is_shutdown = true;
- server_state->server_destroy_listener_done = callback;
- tcp = server_state->tcp;
- gpr_mu_unlock(&server_state->mu);
- grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
- grpc_tcp_server_unref(exec_ctx, server_state->tcp);
-}
+static const grpc_chttp2_server_handshaker_factory_vtable
+ server_security_handshaker_factory_vtable = {
+ server_security_handshaker_factory_create_handshakers,
+ server_security_handshaker_factory_destroy};
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_server_credentials *creds) {
- grpc_resolved_addresses *resolved = NULL;
- grpc_tcp_server *tcp = NULL;
- server_secure_state *server_state = NULL;
- size_t i;
- size_t count = 0;
- int port_num = -1;
- int port_temp;
- grpc_security_status status = GRPC_SECURITY_ERROR;
- grpc_server_security_connector *sc = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_error *err = GRPC_ERROR_NONE;
- grpc_error **errors = NULL;
-
+ grpc_server_security_connector *sc = NULL;
+ int port_num = 0;
GRPC_API_TRACE(
"grpc_server_add_secure_http2_port("
"server=%p, addr=%s, creds=%p)",
3, (server, addr, creds));
-
- /* create security context */
+ // Create security context.
if (creds == NULL) {
err = GRPC_ERROR_CREATE(
"No credentials specified for secure server port (creds==NULL)");
- goto error;
+ goto done;
}
- status = grpc_server_credentials_create_security_connector(creds, &sc);
+ grpc_security_status status =
+ grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) {
char *msg;
gpr_asprintf(&msg,
@@ -258,107 +103,28 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_INT_SECURITY_STATUS, status);
gpr_free(msg);
- goto error;
+ goto done;
}
- sc->channel_args = grpc_server_get_channel_args(server);
-
- /* resolve address */
- err = grpc_blocking_resolve_address(addr, "https", &resolved);
- if (err != GRPC_ERROR_NONE) {
- goto error;
- }
- server_state = gpr_malloc(sizeof(*server_state));
- memset(server_state, 0, sizeof(*server_state));
- grpc_closure_init(&server_state->tcp_server_shutdown_complete,
- tcp_server_shutdown_complete, server_state);
- err = grpc_tcp_server_create(&exec_ctx,
- &server_state->tcp_server_shutdown_complete,
- grpc_server_get_channel_args(server), &tcp);
+ // Create handshaker factory.
+ server_security_handshaker_factory *handshaker_factory =
+ gpr_malloc(sizeof(*handshaker_factory));
+ memset(handshaker_factory, 0, sizeof(*handshaker_factory));
+ handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable;
+ handshaker_factory->security_connector = sc;
+ // Create channel args.
+ grpc_arg channel_arg = grpc_server_credentials_to_arg(creds);
+ grpc_channel_args *args = grpc_channel_args_copy_and_add(
+ grpc_server_get_channel_args(server), &channel_arg, 1);
+ // Add server port.
+ err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args,
+ &handshaker_factory->base, &port_num);
+done:
+ grpc_exec_ctx_finish(&exec_ctx);
if (err != GRPC_ERROR_NONE) {
- goto error;
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(err);
}
-
- server_state->server = server;
- server_state->tcp = tcp;
- server_state->sc = sc;
- server_state->creds = grpc_server_credentials_ref(creds);
- server_state->is_shutdown = true;
- gpr_mu_init(&server_state->mu);
-
- errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
- for (i = 0; i < resolved->naddrs; i++) {
- errors[i] = grpc_tcp_server_add_port(tcp, &resolved->addrs[i], &port_temp);
- if (errors[i] == GRPC_ERROR_NONE) {
- if (port_num == -1) {
- port_num = port_temp;
- } else {
- GPR_ASSERT(port_num == port_temp);
- }
- count++;
- }
- }
- if (count == 0) {
- char *msg;
- gpr_asprintf(&msg, "No address added out of total %" PRIuPTR " resolved",
- resolved->naddrs);
- err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
- gpr_free(msg);
- goto error;
- } else if (count != resolved->naddrs) {
- char *msg;
- gpr_asprintf(&msg, "Only %" PRIuPTR
- " addresses added out of total %" PRIuPTR " resolved",
- count, resolved->naddrs);
- err = GRPC_ERROR_CREATE_REFERENCING(msg, errors, resolved->naddrs);
- gpr_free(msg);
-
- const char *warning_message = grpc_error_string(err);
- gpr_log(GPR_INFO, "WARNING: %s", warning_message);
- grpc_error_free_string(warning_message);
- /* we managed to bind some addresses: continue */
- } else {
- for (i = 0; i < resolved->naddrs; i++) {
- GRPC_ERROR_UNREF(errors[i]);
- }
- }
- gpr_free(errors);
- errors = NULL;
- grpc_resolved_addresses_destroy(resolved);
-
- /* Register with the server only upon success */
- grpc_server_add_listener(&exec_ctx, server, server_state,
- server_start_listener, server_destroy_listener);
-
- grpc_exec_ctx_finish(&exec_ctx);
return port_num;
-
-/* Error path: cleanup and return */
-error:
- GPR_ASSERT(err != GRPC_ERROR_NONE);
- if (errors != NULL) {
- for (i = 0; i < resolved->naddrs; i++) {
- GRPC_ERROR_UNREF(errors[i]);
- }
- gpr_free(errors);
- }
- if (resolved) {
- grpc_resolved_addresses_destroy(resolved);
- }
- if (tcp) {
- grpc_tcp_server_unref(&exec_ctx, tcp);
- } else {
- if (sc) {
- grpc_exec_ctx_flush(&exec_ctx);
- GRPC_SECURITY_CONNECTOR_UNREF(&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;
}
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.c b/src/core/ext/transport/chttp2/transport/bin_decoder.c
index 2d90b01cd8..3eef80b557 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.c
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -34,6 +34,7 @@
#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
static uint8_t decode_table[] = {
@@ -142,11 +143,11 @@ bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) {
return true;
}
-gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
- size_t input_length = GPR_SLICE_LENGTH(input);
+grpc_slice grpc_chttp2_base64_decode(grpc_slice input) {
+ size_t input_length = GRPC_SLICE_LENGTH(input);
size_t output_length = input_length / 4 * 3;
struct grpc_base64_decode_context ctx;
- gpr_slice output;
+ grpc_slice output;
if (input_length % 4 != 0) {
gpr_log(GPR_ERROR,
@@ -158,7 +159,7 @@ gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
}
if (input_length > 0) {
- uint8_t *input_end = GPR_SLICE_END_PTR(input);
+ uint8_t *input_end = GRPC_SLICE_END_PTR(input);
if (*(--input_end) == '=') {
output_length--;
if (*(--input_end) == '=') {
@@ -166,30 +167,30 @@ gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
}
}
}
- output = gpr_slice_malloc(output_length);
+ output = grpc_slice_malloc(output_length);
- ctx.input_cur = GPR_SLICE_START_PTR(input);
- ctx.input_end = GPR_SLICE_END_PTR(input);
- ctx.output_cur = GPR_SLICE_START_PTR(output);
- ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.input_cur = GRPC_SLICE_START_PTR(input);
+ ctx.input_end = GRPC_SLICE_END_PTR(input);
+ ctx.output_cur = GRPC_SLICE_START_PTR(output);
+ ctx.output_end = GRPC_SLICE_END_PTR(output);
ctx.contains_tail = false;
if (!grpc_base64_decode_partial(&ctx)) {
- char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
- gpr_slice_unref(output);
+ grpc_slice_unref(output);
return gpr_empty_slice();
}
- GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
- GPR_ASSERT(ctx.input_cur == GPR_SLICE_END_PTR(input));
+ GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input));
return output;
}
-gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
- size_t output_length) {
- size_t input_length = GPR_SLICE_LENGTH(input);
- gpr_slice output = gpr_slice_malloc(output_length);
+grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
+ size_t output_length) {
+ size_t input_length = GRPC_SLICE_LENGTH(input);
+ grpc_slice output = grpc_slice_malloc(output_length);
struct grpc_base64_decode_context ctx;
// The length of a base64 string cannot be 4 * n + 1
@@ -199,7 +200,7 @@ gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
"grpc_chttp2_base64_decode_with_length has a length of %d, which "
"has a tail of 1 byte.\n",
(int)input_length);
- gpr_slice_unref(output);
+ grpc_slice_unref(output);
return gpr_empty_slice();
}
@@ -209,24 +210,24 @@ gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
"than the max possible output length %d.\n",
(int)output_length,
(int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
- gpr_slice_unref(output);
+ grpc_slice_unref(output);
return gpr_empty_slice();
}
- ctx.input_cur = GPR_SLICE_START_PTR(input);
- ctx.input_end = GPR_SLICE_END_PTR(input);
- ctx.output_cur = GPR_SLICE_START_PTR(output);
- ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.input_cur = GRPC_SLICE_START_PTR(input);
+ ctx.input_end = GRPC_SLICE_END_PTR(input);
+ ctx.output_cur = GRPC_SLICE_START_PTR(output);
+ ctx.output_end = GRPC_SLICE_END_PTR(output);
ctx.contains_tail = true;
if (!grpc_base64_decode_partial(&ctx)) {
- char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
gpr_free(s);
- gpr_slice_unref(output);
+ grpc_slice_unref(output);
return gpr_empty_slice();
}
- GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
- GPR_ASSERT(ctx.input_cur <= GPR_SLICE_END_PTR(input));
+ GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input));
return output;
}
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
index b9d40c9b74..83a90be519 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include <stdbool.h>
struct grpc_base64_decode_context {
@@ -55,12 +55,12 @@ bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx);
/* base64 decode a slice with pad chars. Returns a new slice, does not take
ownership of the input. Returns an empty slice if decoding is failed. */
-gpr_slice grpc_chttp2_base64_decode(gpr_slice input);
+grpc_slice grpc_chttp2_base64_decode(grpc_slice input);
/* base64 decode a slice without pad chars, data length is needed. Returns a new
slice, does not take ownership of the input. Returns an empty slice if
decoding is failed. */
-gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
- size_t output_length);
+grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
+ size_t output_length);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.c b/src/core/ext/transport/chttp2/transport/bin_encoder.c
index 1b43c28be1..af25a4352a 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.c
@@ -61,14 +61,14 @@ static const b64_huff_sym huff_alphabet[64] = {
static const uint8_t tail_xtra[3] = {0, 2, 3};
-gpr_slice grpc_chttp2_base64_encode(gpr_slice input) {
- size_t input_length = GPR_SLICE_LENGTH(input);
+grpc_slice grpc_chttp2_base64_encode(grpc_slice input) {
+ size_t input_length = GRPC_SLICE_LENGTH(input);
size_t input_triplets = input_length / 3;
size_t tail_case = input_length % 3;
size_t output_length = input_triplets * 4 + tail_xtra[tail_case];
- gpr_slice output = gpr_slice_malloc(output_length);
- uint8_t *in = GPR_SLICE_START_PTR(input);
- char *out = (char *)GPR_SLICE_START_PTR(output);
+ grpc_slice output = grpc_slice_malloc(output_length);
+ uint8_t *in = GRPC_SLICE_START_PTR(input);
+ char *out = (char *)GRPC_SLICE_START_PTR(output);
size_t i;
/* encode full triplets */
@@ -100,27 +100,29 @@ gpr_slice grpc_chttp2_base64_encode(gpr_slice input) {
break;
}
- GPR_ASSERT(out == (char *)GPR_SLICE_END_PTR(output));
- GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
+ GPR_ASSERT(out == (char *)GRPC_SLICE_END_PTR(output));
+ GPR_ASSERT(in == GRPC_SLICE_END_PTR(input));
return output;
}
-gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) {
+grpc_slice grpc_chttp2_huffman_compress(grpc_slice input) {
size_t nbits;
uint8_t *in;
uint8_t *out;
- gpr_slice output;
+ grpc_slice output;
uint32_t temp = 0;
uint32_t temp_length = 0;
nbits = 0;
- for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
+ for (in = GRPC_SLICE_START_PTR(input); in != GRPC_SLICE_END_PTR(input);
+ ++in) {
nbits += grpc_chttp2_huffsyms[*in].length;
}
- output = gpr_slice_malloc(nbits / 8 + (nbits % 8 != 0));
- out = GPR_SLICE_START_PTR(output);
- for (in = GPR_SLICE_START_PTR(input); in != GPR_SLICE_END_PTR(input); ++in) {
+ output = grpc_slice_malloc(nbits / 8 + (nbits % 8 != 0));
+ out = GRPC_SLICE_START_PTR(output);
+ for (in = GRPC_SLICE_START_PTR(input); in != GRPC_SLICE_END_PTR(input);
+ ++in) {
int sym = *in;
temp <<= grpc_chttp2_huffsyms[sym].length;
temp |= grpc_chttp2_huffsyms[sym].bits;
@@ -141,7 +143,7 @@ gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) {
(uint8_t)(0xffu >> temp_length));
}
- GPR_ASSERT(out == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(out == GRPC_SLICE_END_PTR(output));
return output;
}
@@ -175,16 +177,17 @@ static void enc_add1(huff_out *out, uint8_t a) {
enc_flush_some(out);
}
-gpr_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(gpr_slice input) {
- size_t input_length = GPR_SLICE_LENGTH(input);
+grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(
+ grpc_slice input) {
+ size_t input_length = GRPC_SLICE_LENGTH(input);
size_t input_triplets = input_length / 3;
size_t tail_case = input_length % 3;
size_t output_syms = input_triplets * 4 + tail_xtra[tail_case];
size_t max_output_bits = 11 * output_syms;
size_t max_output_length = max_output_bits / 8 + (max_output_bits % 8 != 0);
- gpr_slice output = gpr_slice_malloc(max_output_length);
- uint8_t *in = GPR_SLICE_START_PTR(input);
- uint8_t *start_out = GPR_SLICE_START_PTR(output);
+ grpc_slice output = grpc_slice_malloc(max_output_length);
+ uint8_t *in = GRPC_SLICE_START_PTR(input);
+ uint8_t *start_out = GRPC_SLICE_START_PTR(output);
huff_out out;
size_t i;
@@ -231,9 +234,9 @@ gpr_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(gpr_slice input) {
(uint8_t)(0xffu >> out.temp_length));
}
- GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output));
- GPR_SLICE_SET_LENGTH(output, out.out - start_out);
+ GPR_ASSERT(out.out <= GRPC_SLICE_END_PTR(output));
+ GRPC_SLICE_SET_LENGTH(output, out.out - start_out);
- GPR_ASSERT(in == GPR_SLICE_END_PTR(input));
+ GPR_ASSERT(in == GRPC_SLICE_END_PTR(input));
return output;
}
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
index 61ebbafa9a..9e143b46e2 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -34,21 +34,22 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
/* base64 encode a slice. Returns a new slice, does not take ownership of the
input */
-gpr_slice grpc_chttp2_base64_encode(gpr_slice input);
+grpc_slice grpc_chttp2_base64_encode(grpc_slice input);
/* Compress a slice with the static huffman encoder detailed in the hpack
standard. Returns a new slice, does not take ownership of the input */
-gpr_slice grpc_chttp2_huffman_compress(gpr_slice input);
+grpc_slice grpc_chttp2_huffman_compress(grpc_slice input);
/* equivalent to:
- gpr_slice x = grpc_chttp2_base64_encode(input);
- gpr_slice y = grpc_chttp2_huffman_compress(x);
- gpr_slice_unref(x);
+ grpc_slice x = grpc_chttp2_base64_encode(input);
+ grpc_slice y = grpc_chttp2_huffman_compress(x);
+ grpc_slice_unref(x);
return y; */
-gpr_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(gpr_slice input);
+grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(
+ grpc_slice input);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 4a9f806354..3e7c078d3c 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -38,9 +38,9 @@
#include <stdio.h>
#include <string.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
@@ -51,6 +51,7 @@
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/workqueue.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
@@ -110,9 +111,6 @@ static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
void *byte_stream,
grpc_error *error_ignored);
-static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- grpc_error *error);
static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
grpc_error *error);
@@ -143,12 +141,12 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
grpc_endpoint_destroy(exec_ctx, t->ep);
- gpr_slice_buffer_destroy(&t->qbuf);
+ grpc_slice_buffer_destroy(&t->qbuf);
- gpr_slice_buffer_destroy(&t->outbuf);
+ grpc_slice_buffer_destroy(&t->outbuf);
grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
- gpr_slice_buffer_destroy(&t->read_buffer);
+ grpc_slice_buffer_destroy(&t->read_buffer);
grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
@@ -243,9 +241,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
&t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
is_client ? "client_transport" : "server_transport");
- gpr_slice_buffer_init(&t->qbuf);
+ grpc_slice_buffer_init(&t->qbuf);
- gpr_slice_buffer_init(&t->outbuf);
+ grpc_slice_buffer_init(&t->outbuf);
grpc_chttp2_hpack_compressor_init(&t->hpack_compressor);
grpc_closure_init(&t->write_action_begin_locked, write_action_begin_locked,
@@ -264,7 +262,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_goaway_parser_init(&t->goaway_parser);
grpc_chttp2_hpack_parser_init(&t->hpack_parser);
- gpr_slice_buffer_init(&t->read_buffer);
+ grpc_slice_buffer_init(&t->read_buffer);
/* 8 is a random stab in the dark as to a good initial size: it's small enough
that it shouldn't waste memory for infrequently used connections, yet
@@ -286,8 +284,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->sent_local_settings = 0;
if (is_client) {
- gpr_slice_buffer_add(&t->outbuf, gpr_slice_from_copied_string(
- GRPC_CHTTP2_CLIENT_CONNECT_STRING));
+ grpc_slice_buffer_add(&t->outbuf, grpc_slice_from_copied_string(
+ GRPC_CHTTP2_CLIENT_CONNECT_STRING));
grpc_chttp2_initiate_write(exec_ctx, t, false, "initial_write");
}
@@ -427,6 +425,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
/* flush writable stream list to avoid dangling references */
grpc_chttp2_stream *s;
while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
+ grpc_chttp2_leave_writing_lists(exec_ctx, t, s);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
}
end_all_the_calls(exec_ctx, t, GRPC_ERROR_REF(error));
@@ -471,7 +470,7 @@ static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]);
grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]);
grpc_chttp2_data_parser_init(&s->data_parser);
- gpr_slice_buffer_init(&s->flow_controlled_buffer);
+ grpc_slice_buffer_init(&s->flow_controlled_buffer);
s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
grpc_closure_init(&s->complete_fetch, complete_fetch, s);
grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s);
@@ -522,6 +521,10 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
}
}
+ if (s->fail_pending_writes_on_writes_finished_error != NULL) {
+ GRPC_ERROR_UNREF(s->fail_pending_writes_on_writes_finished_error);
+ }
+
GPR_ASSERT(s->send_initial_metadata_finished == NULL);
GPR_ASSERT(s->fetching_send_message == NULL);
GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
@@ -531,7 +534,7 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
grpc_chttp2_data_parser_destroy(exec_ctx, &s->data_parser);
grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]);
grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]);
- gpr_slice_buffer_destroy(&s->flow_controlled_buffer);
+ grpc_slice_buffer_destroy(&s->flow_controlled_buffer);
GRPC_ERROR_UNREF(s->read_closed_error);
GRPC_ERROR_UNREF(s->write_closed_error);
@@ -703,8 +706,6 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
}
}
- grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
-
switch (t->write_state) {
case GRPC_CHTTP2_WRITE_STATE_IDLE:
GPR_UNREACHABLE_CODE(break);
@@ -733,6 +734,8 @@ static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
break;
}
+ grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
+
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
GPR_TIMER_END("terminate_writing_with_lock", 0);
}
@@ -756,11 +759,11 @@ static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
uint32_t goaway_error,
- gpr_slice goaway_text) {
- char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ grpc_slice goaway_text) {
+ char *msg = grpc_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
- gpr_slice_unref(goaway_text);
+ grpc_slice_unref(goaway_text);
t->seen_goaway = 1;
/* lie: use transient failure from the transport to indicate goaway has been
* received */
@@ -884,8 +887,8 @@ static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
s->fetched_send_message_length +=
- (uint32_t)GPR_SLICE_LENGTH(s->fetching_slice);
- gpr_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
+ (uint32_t)GRPC_SLICE_LENGTH(s->fetching_slice);
+ grpc_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
if (s->id != 0) {
grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
}
@@ -953,6 +956,16 @@ static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs,
static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id,
+ bool is_client, bool is_initial) {
+ for (grpc_linked_mdelem *md = md_batch->list.head; md != md_batch->list.tail;
+ md = md->next) {
+ gpr_log(GPR_INFO, "HTTP:%d:%s:%s: %s: %s", id, is_initial ? "HDR" : "TRL",
+ is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->md->key),
+ grpc_mdstr_as_c_string(md->md->value));
+ }
+}
+
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
grpc_error *error_ignored) {
GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
@@ -966,6 +979,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str,
op->on_complete);
gpr_free(str);
+ if (op->send_initial_metadata) {
+ log_metadata(op->send_initial_metadata, s->id, t->is_client, true);
+ }
+ if (op->send_trailing_metadata) {
+ log_metadata(op->send_trailing_metadata, s->id, t->is_client, false);
+ }
}
grpc_closure *on_complete = op->on_complete;
@@ -1036,7 +1055,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
"op.send_initial_metadata");
}
} else {
- s->send_trailing_metadata = NULL;
+ s->send_initial_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->send_initial_metadata_finished,
GRPC_ERROR_CREATE(
@@ -1056,7 +1075,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
} else {
GPR_ASSERT(s->fetching_send_message == NULL);
uint8_t *frame_hdr =
- gpr_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5);
+ grpc_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5);
uint32_t flags = op->send_message->flags;
frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
size_t len = op->send_message->length;
@@ -1196,7 +1215,7 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
p->id[7] = (uint8_t)(t->ping_counter & 0xff);
t->ping_counter++;
p->on_recv = on_recv;
- gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
+ grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping");
}
@@ -1220,7 +1239,7 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- grpc_chttp2_error_code error, gpr_slice data) {
+ grpc_chttp2_error_code error, grpc_slice data) {
t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data,
&t->qbuf);
@@ -1243,7 +1262,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
if (op->send_goaway) {
send_goaway(exec_ctx, t,
grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
- gpr_slice_ref(*op->goaway_message));
+ grpc_slice_ref(*op->goaway_message));
}
if (op->set_accept_stream) {
@@ -1387,6 +1406,7 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
}
if (grpc_chttp2_list_remove_writable_stream(t, s)) {
+ grpc_chttp2_leave_writing_lists(exec_ctx, t, s);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:remove_stream");
}
@@ -1432,7 +1452,7 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
&grpc_status);
if (s->id != 0) {
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
&s->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream");
@@ -1445,7 +1465,7 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
free_msg = true;
msg = grpc_error_string(due_to_error);
}
- gpr_slice msg_slice = gpr_slice_from_copied_string(msg);
+ grpc_slice msg_slice = grpc_slice_from_copied_string(msg);
grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
if (free_msg) grpc_error_free_string(msg);
}
@@ -1458,7 +1478,7 @@ void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_status_code status,
- gpr_slice *slice) {
+ grpc_slice *slice) {
if (status != GRPC_STATUS_OK) {
s->seen_error = true;
}
@@ -1481,13 +1501,13 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
&s->metadata_buffer[1],
grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_GRPC_MESSAGE,
- grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
+ grpc_mdstr_from_slice(grpc_slice_ref(*slice))));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
if (slice) {
- gpr_slice_unref(*slice);
+ grpc_slice_unref(*slice);
}
}
@@ -1517,18 +1537,54 @@ static grpc_error *removal_error(grpc_error *extra_error, grpc_chttp2_stream *s,
return error;
}
-static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- grpc_error *error) {
+void grpc_chttp2_leave_writing_lists(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s) {
+ if (s->need_fail_pending_writes_on_writes_finished) {
+ grpc_error *error = s->fail_pending_writes_on_writes_finished_error;
+ s->fail_pending_writes_on_writes_finished_error = NULL;
+ s->need_fail_pending_writes_on_writes_finished = false;
+ grpc_chttp2_fail_pending_writes(exec_ctx, t, s, error);
+ }
+}
+
+void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, grpc_error *error) {
+ if (s->need_fail_pending_writes_on_writes_finished ||
+ (t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE &&
+ (s->included[GRPC_CHTTP2_LIST_WRITABLE] ||
+ s->included[GRPC_CHTTP2_LIST_WRITING]))) {
+ /* If a write is in progress, and it involves this stream, wait for the
+ * write to complete before cancelling things out. If we don't do this, then
+ * our combiner lock might think that some operation on its queue might be
+ * covering a completion even though there is none, in which case we might
+ * offload to another thread, which isn't guarateed to exist */
+ if (error != GRPC_ERROR_NONE) {
+ if (s->fail_pending_writes_on_writes_finished_error == GRPC_ERROR_NONE) {
+ s->fail_pending_writes_on_writes_finished_error = GRPC_ERROR_CREATE(
+ "Post-poned fail writes due to in-progress write");
+ }
+ s->fail_pending_writes_on_writes_finished_error = grpc_error_add_child(
+ s->fail_pending_writes_on_writes_finished_error, error);
+ }
+ s->need_fail_pending_writes_on_writes_finished = true;
+ return; /* early out */
+ }
+
error =
removal_error(error, s, "Pending writes failed due to stream closure");
- s->fetching_send_message = NULL;
+ s->send_initial_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->send_initial_metadata_finished, GRPC_ERROR_REF(error),
"send_initial_metadata_finished");
+
+ s->send_trailing_metadata = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->send_trailing_metadata_finished,
GRPC_ERROR_REF(error), "send_trailing_metadata_finished");
+
+ s->fetching_send_message = NULL;
grpc_chttp2_complete_closure_step(
exec_ctx, t, s, &s->fetching_send_message_finished, GRPC_ERROR_REF(error),
"fetching_send_message_finished");
@@ -1569,7 +1625,7 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
if (close_writes && !s->write_closed) {
s->write_closed_error = GRPC_ERROR_REF(error);
s->write_closed = true;
- fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
+ grpc_chttp2_fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
}
if (s->read_closed && s->write_closed) {
@@ -1584,9 +1640,9 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_error *error) {
- gpr_slice hdr;
- gpr_slice status_hdr;
- gpr_slice message_pfx;
+ grpc_slice hdr;
+ grpc_slice status_hdr;
+ grpc_slice message_pfx;
uint8_t *p;
uint32_t len = 0;
grpc_status_code grpc_status;
@@ -1605,8 +1661,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
time we got around to sending this, so instead we ignore HPACK
compression
and just write the uncompressed bytes onto the wire. */
- status_hdr = gpr_slice_malloc(15 + (grpc_status >= 10));
- p = GPR_SLICE_START_PTR(status_hdr);
+ status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
+ p = GRPC_SLICE_START_PTR(status_hdr);
*p++ = 0x40; /* literal header */
*p++ = 11; /* len(grpc-status) */
*p++ = 'g';
@@ -1628,8 +1684,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
*p++ = (uint8_t)('0' + (grpc_status / 10));
*p++ = (uint8_t)('0' + (grpc_status % 10));
}
- GPR_ASSERT(p == GPR_SLICE_END_PTR(status_hdr));
- len += (uint32_t)GPR_SLICE_LENGTH(status_hdr);
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
+ len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
const char *optional_message =
grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
@@ -1637,8 +1693,8 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (optional_message != NULL) {
size_t msg_len = strlen(optional_message);
GPR_ASSERT(msg_len < 127);
- message_pfx = gpr_slice_malloc(15);
- p = GPR_SLICE_START_PTR(message_pfx);
+ message_pfx = grpc_slice_malloc(15);
+ p = GRPC_SLICE_START_PTR(message_pfx);
*p++ = 0x40;
*p++ = 12; /* len(grpc-message) */
*p++ = 'g';
@@ -1654,13 +1710,13 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
*p++ = 'g';
*p++ = 'e';
*p++ = (uint8_t)msg_len;
- GPR_ASSERT(p == GPR_SLICE_END_PTR(message_pfx));
- len += (uint32_t)GPR_SLICE_LENGTH(message_pfx);
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
+ len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
len += (uint32_t)msg_len;
}
- hdr = gpr_slice_malloc(9);
- p = GPR_SLICE_START_PTR(hdr);
+ hdr = grpc_slice_malloc(9);
+ p = GRPC_SLICE_START_PTR(hdr);
*p++ = (uint8_t)(len >> 16);
*p++ = (uint8_t)(len >> 8);
*p++ = (uint8_t)(len);
@@ -1670,16 +1726,16 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
*p++ = (uint8_t)(s->id >> 16);
*p++ = (uint8_t)(s->id >> 8);
*p++ = (uint8_t)(s->id);
- GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
- gpr_slice_buffer_add(&t->qbuf, hdr);
- gpr_slice_buffer_add(&t->qbuf, status_hdr);
+ grpc_slice_buffer_add(&t->qbuf, hdr);
+ grpc_slice_buffer_add(&t->qbuf, status_hdr);
if (optional_message) {
- gpr_slice_buffer_add(&t->qbuf, message_pfx);
- gpr_slice_buffer_add(&t->qbuf,
- gpr_slice_from_copied_string(optional_message));
+ grpc_slice_buffer_add(&t->qbuf, message_pfx);
+ grpc_slice_buffer_add(&t->qbuf,
+ grpc_slice_from_copied_string(optional_message));
}
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
&s->stats.outgoing));
}
@@ -1690,7 +1746,7 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
free_msg = true;
msg = grpc_error_string(error);
}
- gpr_slice msg_slice = gpr_slice_from_copied_string(msg);
+ grpc_slice msg_slice = grpc_slice_from_copied_string(msg);
grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
if (free_msg) grpc_error_free_string(msg);
@@ -1861,7 +1917,7 @@ static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
keep_reading = true;
GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
}
- gpr_slice_buffer_reset_and_unref(&t->read_buffer);
+ grpc_slice_buffer_reset_and_unref(&t->read_buffer);
if (keep_reading) {
grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_begin);
@@ -1915,7 +1971,7 @@ static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs) {
if (gpr_unref(&bs->refs)) {
GRPC_ERROR_UNREF(bs->error);
- gpr_slice_buffer_destroy(&bs->slices);
+ grpc_slice_buffer_destroy(&bs->slices);
gpr_mu_destroy(&bs->slice_mu);
gpr_free(bs);
}
@@ -1977,7 +2033,7 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
}
gpr_mu_lock(&bs->slice_mu);
if (bs->slices.count > 0) {
- *bs->next_action.slice = gpr_slice_buffer_take_first(&bs->slices);
+ *bs->next_action.slice = grpc_slice_buffer_take_first(&bs->slices);
grpc_closure_run(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE);
} else if (bs->error != GRPC_ERROR_NONE) {
grpc_closure_run(exec_ctx, bs->next_action.on_complete,
@@ -1992,7 +2048,7 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
- gpr_slice *slice, size_t max_size_hint,
+ grpc_slice *slice, size_t max_size_hint,
grpc_closure *on_complete) {
GPR_TIMER_BEGIN("incoming_byte_stream_next", 0);
grpc_chttp2_incoming_byte_stream *bs =
@@ -2045,19 +2101,19 @@ static void incoming_byte_stream_publish_error(
void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs,
- gpr_slice slice) {
+ grpc_slice slice) {
gpr_mu_lock(&bs->slice_mu);
- if (bs->remaining_bytes < GPR_SLICE_LENGTH(slice)) {
+ if (bs->remaining_bytes < GRPC_SLICE_LENGTH(slice)) {
incoming_byte_stream_publish_error(
exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream"));
} else {
- bs->remaining_bytes -= (uint32_t)GPR_SLICE_LENGTH(slice);
+ bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
if (bs->on_next != NULL) {
*bs->next = slice;
grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
bs->on_next = NULL;
} else {
- gpr_slice_buffer_add(&bs->slices, slice);
+ grpc_slice_buffer_add(&bs->slices, slice);
}
}
gpr_mu_unlock(&bs->slice_mu);
@@ -2095,7 +2151,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
incoming_byte_stream->transport = t;
incoming_byte_stream->stream = s;
gpr_ref(&incoming_byte_stream->stream->active_streams);
- gpr_slice_buffer_init(&incoming_byte_stream->slices);
+ grpc_slice_buffer_init(&incoming_byte_stream->slices);
incoming_byte_stream->on_next = NULL;
incoming_byte_stream->is_tail = 1;
incoming_byte_stream->error = GRPC_ERROR_NONE;
@@ -2163,7 +2219,7 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
t->peer_string);
}
send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM,
- gpr_slice_from_static_string("Buffers full"));
+ grpc_slice_from_static_string("Buffers full"));
} else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
gpr_log(GPR_DEBUG,
"HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
@@ -2293,6 +2349,14 @@ static char *chttp2_get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
}
+/*******************************************************************************
+ * MONITORING
+ */
+static grpc_endpoint *chttp2_get_endpoint(grpc_exec_ctx *exec_ctx,
+ grpc_transport *t) {
+ return ((grpc_chttp2_transport *)t)->ep;
+}
+
static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
"chttp2",
init_stream,
@@ -2302,7 +2366,8 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
perform_transport_op,
destroy_stream,
destroy_transport,
- chttp2_get_peer};
+ chttp2_get_peer,
+ chttp2_get_endpoint};
grpc_transport *grpc_create_chttp2_transport(
grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
@@ -2314,12 +2379,12 @@ grpc_transport *grpc_create_chttp2_transport(
void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- gpr_slice_buffer *read_buffer) {
+ grpc_slice_buffer *read_buffer) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
GRPC_CHTTP2_REF_TRANSPORT(
t, "reading_action"); /* matches unref inside reading_action */
if (read_buffer != NULL) {
- gpr_slice_buffer_move_into(read_buffer, &t->read_buffer);
+ grpc_slice_buffer_move_into(read_buffer, &t->read_buffer);
gpr_free(read_buffer);
}
read_action_begin(exec_ctx, t, GRPC_ERROR_NONE);
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index 4e2d0954bf..c372174f2d 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -48,6 +48,6 @@ grpc_transport *grpc_create_chttp2_transport(
/// leftover bytes previously read from the endpoint (e.g., by handshakers).
void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_transport *transport,
- gpr_slice_buffer *read_buffer);
+ grpc_slice_buffer *read_buffer);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index 1e444a91fd..ffd4d9669b 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -34,8 +34,8 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H
+#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
#include "src/core/lib/iomgr/error.h"
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
index 8668816930..f9b9e1b309 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.c
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -40,6 +40,7 @@
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport.h"
@@ -112,16 +113,16 @@ grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
return out;
}
-void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
+void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf,
uint32_t write_bytes, int is_eof,
grpc_transport_one_way_stats *stats,
- gpr_slice_buffer *outbuf) {
- gpr_slice hdr;
+ grpc_slice_buffer *outbuf) {
+ grpc_slice hdr;
uint8_t *p;
static const size_t header_size = 9;
- hdr = gpr_slice_malloc(header_size);
- p = GPR_SLICE_START_PTR(hdr);
+ hdr = grpc_slice_malloc(header_size);
+ p = GRPC_SLICE_START_PTR(hdr);
GPR_ASSERT(write_bytes < (1 << 24));
*p++ = (uint8_t)(write_bytes >> 16);
*p++ = (uint8_t)(write_bytes >> 8);
@@ -132,9 +133,9 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
*p++ = (uint8_t)(id >> 16);
*p++ = (uint8_t)(id >> 8);
*p++ = (uint8_t)(id);
- gpr_slice_buffer_add(outbuf, hdr);
+ grpc_slice_buffer_add(outbuf, hdr);
- gpr_slice_buffer_move_first(inbuf, write_bytes, outbuf);
+ grpc_slice_buffer_move_first(inbuf, write_bytes, outbuf);
stats->framing_bytes += header_size;
stats->data_bytes += write_bytes;
@@ -143,9 +144,9 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *p,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- gpr_slice slice) {
- uint8_t *const beg = GPR_SLICE_START_PTR(slice);
- uint8_t *const end = GPR_SLICE_END_PTR(slice);
+ grpc_slice slice) {
+ uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *const end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
uint32_t message_flags;
grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
@@ -176,7 +177,7 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
(intptr_t)s->id);
gpr_free(msg);
- msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
p->error =
grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
gpr_free(msg);
@@ -236,7 +237,7 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
s->stats.incoming.data_bytes += p->frame_size;
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
- gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+ grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
GRPC_ERROR_NONE);
p->parsing_frame = NULL;
@@ -246,8 +247,8 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
s->stats.incoming.data_bytes += p->frame_size;
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
- gpr_slice_sub(slice, (size_t)(cur - beg),
- (size_t)(cur + p->frame_size - beg)));
+ grpc_slice_sub(slice, (size_t)(cur - beg),
+ (size_t)(cur + p->frame_size - beg)));
grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
GRPC_ERROR_NONE);
p->parsing_frame = NULL;
@@ -257,7 +258,7 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(remaining <= p->frame_size);
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
- gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
+ grpc_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
p->frame_size -= remaining;
s->stats.incoming.data_bytes += remaining;
return GRPC_ERROR_NONE;
@@ -270,7 +271,7 @@ static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
+ grpc_slice slice, int is_last) {
grpc_chttp2_data_parser *p = parser;
grpc_error *error = parse_inner(exec_ctx, p, t, s, slice);
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index eb2d97d898..264ad14608 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -36,8 +36,8 @@
/* Parser for GRPC streams embedded in DATA frames */
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/byte_stream.h"
@@ -94,11 +94,11 @@ grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
-void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
+void grpc_chttp2_encode_data(uint32_t id, grpc_slice_buffer *inbuf,
uint32_t write_bytes, int is_eof,
grpc_transport_one_way_stats *stats,
- gpr_slice_buffer *outbuf);
+ grpc_slice_buffer *outbuf);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c
index 33d2269169..d99d486c1b 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.c
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c
@@ -71,9 +71,9 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
- uint8_t *const beg = GPR_SLICE_START_PTR(slice);
- uint8_t *const end = GPR_SLICE_END_PTR(slice);
+ grpc_slice slice, int is_last) {
+ uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *const end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
grpc_chttp2_goaway_parser *p = parser;
@@ -151,7 +151,7 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
if (is_last) {
grpc_chttp2_add_incoming_goaway(
exec_ctx, t, (uint32_t)p->error_code,
- gpr_slice_new(p->debug_data, p->debug_length, gpr_free));
+ grpc_slice_new(p->debug_data, p->debug_length, gpr_free));
p->debug_data = NULL;
}
return GRPC_ERROR_NONE;
@@ -160,13 +160,13 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
}
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
- gpr_slice debug_data,
- gpr_slice_buffer *slice_buffer) {
- gpr_slice header = gpr_slice_malloc(9 + 4 + 4);
- uint8_t *p = GPR_SLICE_START_PTR(header);
+ grpc_slice debug_data,
+ grpc_slice_buffer *slice_buffer) {
+ grpc_slice header = grpc_slice_malloc(9 + 4 + 4);
+ uint8_t *p = GRPC_SLICE_START_PTR(header);
uint32_t frame_length;
- GPR_ASSERT(GPR_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
- frame_length = 4 + 4 + (uint32_t)GPR_SLICE_LENGTH(debug_data);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(debug_data) < UINT32_MAX - 4 - 4);
+ frame_length = 4 + 4 + (uint32_t)GRPC_SLICE_LENGTH(debug_data);
/* frame header: length */
*p++ = (uint8_t)(frame_length >> 16);
@@ -191,7 +191,7 @@ void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
*p++ = (uint8_t)(error_code >> 16);
*p++ = (uint8_t)(error_code >> 8);
*p++ = (uint8_t)(error_code);
- GPR_ASSERT(p == GPR_SLICE_END_PTR(header));
- gpr_slice_buffer_add(slice_buffer, header);
- gpr_slice_buffer_add(slice_buffer, debug_data);
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(header));
+ grpc_slice_buffer_add(slice_buffer, header);
+ grpc_slice_buffer_add(slice_buffer, debug_data);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index 355104a5a7..21fe819488 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -34,9 +34,9 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@@ -69,10 +69,10 @@ grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
- gpr_slice debug_data,
- gpr_slice_buffer *slice_buffer);
+ grpc_slice debug_data,
+ grpc_slice_buffer *slice_buffer);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 624f42649d..7de5f6362d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -40,9 +40,9 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
- gpr_slice slice = gpr_slice_malloc(9 + 8);
- uint8_t *p = GPR_SLICE_START_PTR(slice);
+grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
+ grpc_slice slice = grpc_slice_malloc(9 + 8);
+ uint8_t *p = GRPC_SLICE_START_PTR(slice);
*p++ = 0;
*p++ = 0;
@@ -76,9 +76,9 @@ grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
- uint8_t *const beg = GPR_SLICE_START_PTR(slice);
- uint8_t *const end = GPR_SLICE_END_PTR(slice);
+ grpc_slice slice, int is_last) {
+ uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *const end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
grpc_chttp2_ping_parser *p = parser;
@@ -93,8 +93,8 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
if (p->is_ack) {
grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
} else {
- gpr_slice_buffer_add(&t->qbuf,
- grpc_chttp2_ping_create(1, p->opaque_8bytes));
+ grpc_slice_buffer_add(&t->qbuf,
+ grpc_chttp2_ping_create(1, p->opaque_8bytes));
grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
}
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 2071f647fb..b9889e2d11 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@@ -44,13 +44,13 @@ typedef struct {
uint8_t opaque_8bytes[8];
} grpc_chttp2_ping_parser;
-gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
+grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
uint32_t length, uint8_t flags);
grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index 9eac050797..b4c5ed769b 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -42,12 +42,12 @@
#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
-gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
- grpc_transport_one_way_stats *stats) {
+grpc_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
+ grpc_transport_one_way_stats *stats) {
static const size_t frame_size = 13;
- gpr_slice slice = gpr_slice_malloc(frame_size);
+ grpc_slice slice = grpc_slice_malloc(frame_size);
stats->framing_bytes += frame_size;
- uint8_t *p = GPR_SLICE_START_PTR(slice);
+ uint8_t *p = GRPC_SLICE_START_PTR(slice);
// Frame size.
*p++ = 0;
@@ -89,9 +89,9 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
- uint8_t *const beg = GPR_SLICE_START_PTR(slice);
- uint8_t *const end = GPR_SLICE_END_PTR(slice);
+ grpc_slice slice, int is_last) {
+ uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *const end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
grpc_chttp2_rst_stream_parser *p = parser;
@@ -117,7 +117,7 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
char *status_details;
gpr_asprintf(&status_details, "Received RST_STREAM with error code %d",
reason);
- gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
+ grpc_slice slice_details = grpc_slice_from_copied_string(status_details);
gpr_free(status_details);
grpc_chttp2_fake_status(exec_ctx, t, s, status_code, &slice_details);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
index 5a1f578a29..779507a617 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/transport.h"
@@ -44,8 +44,8 @@ typedef struct {
uint8_t reason_bytes[4];
} grpc_chttp2_rst_stream_parser;
-gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code,
- grpc_transport_one_way_stats *stats);
+grpc_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code,
+ grpc_transport_one_way_stats *stats);
grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
@@ -53,6 +53,6 @@ grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index 92022f90c9..98facae87f 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -82,19 +82,19 @@ static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) {
return out;
}
-gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
- uint32_t force_mask, size_t count) {
+grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
+ uint32_t force_mask, size_t count) {
size_t i;
uint32_t n = 0;
- gpr_slice output;
+ grpc_slice output;
uint8_t *p;
for (i = 0; i < count; i++) {
n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
}
- output = gpr_slice_malloc(9 + 6 * n);
- p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
+ output = grpc_slice_malloc(9 + 6 * n);
+ p = fill_header(GRPC_SLICE_START_PTR(output), 6 * n, 0);
for (i = 0; i < count; i++) {
if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
@@ -109,14 +109,14 @@ gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
}
}
- GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(p == GRPC_SLICE_END_PTR(output));
return output;
}
-gpr_slice grpc_chttp2_settings_ack_create(void) {
- gpr_slice output = gpr_slice_malloc(9);
- fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
+grpc_slice grpc_chttp2_settings_ack_create(void) {
+ grpc_slice output = grpc_slice_malloc(9);
+ fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
return output;
}
@@ -146,10 +146,10 @@ grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
+ grpc_slice slice, int is_last) {
grpc_chttp2_settings_parser *parser = p;
- const uint8_t *cur = GPR_SLICE_START_PTR(slice);
- const uint8_t *end = GPR_SLICE_END_PTR(slice);
+ const uint8_t *cur = GRPC_SLICE_START_PTR(slice);
+ const uint8_t *end = GRPC_SLICE_END_PTR(slice);
char *msg;
if (parser->is_ack) {
@@ -164,7 +164,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
if (is_last) {
memcpy(parser->target_settings, parser->incoming_settings,
GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
- gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
+ grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
}
return GRPC_ERROR_NONE;
}
@@ -225,7 +225,7 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
grpc_chttp2_goaway_append(
t->last_new_stream_id, sp->error_value,
- gpr_slice_from_static_string("HTTP2 settings error"),
+ grpc_slice_from_static_string("HTTP2 settings error"),
&t->qbuf);
gpr_asprintf(&msg, "invalid value %u passed for %s",
parser->value, sp->name);
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index 4bfa944cf1..a29dc82106 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -34,8 +34,8 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H
+#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@@ -87,10 +87,10 @@ extern const grpc_chttp2_setting_parameters
grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
/* Create a settings frame by diffing old & new, and updating old to be new */
-gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
- uint32_t force_mask, size_t count);
+grpc_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
+ uint32_t force_mask, size_t count);
/* Create an ack settings frame */
-gpr_slice grpc_chttp2_settings_ack_create(void);
+grpc_slice grpc_chttp2_settings_ack_create(void);
grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
@@ -99,6 +99,6 @@ grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx,
void *parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c
index 418166a6df..31a31c2871 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.c
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -38,12 +38,12 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-gpr_slice grpc_chttp2_window_update_create(
+grpc_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) {
static const size_t frame_size = 13;
- gpr_slice slice = gpr_slice_malloc(frame_size);
+ grpc_slice slice = grpc_slice_malloc(frame_size);
stats->header_bytes += frame_size;
- uint8_t *p = GPR_SLICE_START_PTR(slice);
+ uint8_t *p = GRPC_SLICE_START_PTR(slice);
GPR_ASSERT(window_update);
@@ -81,9 +81,9 @@ grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, gpr_slice slice, int is_last) {
- uint8_t *const beg = GPR_SLICE_START_PTR(slice);
- uint8_t *const end = GPR_SLICE_END_PTR(slice);
+ grpc_chttp2_stream *s, grpc_slice slice, int is_last) {
+ uint8_t *const beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *const end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
grpc_chttp2_window_update_parser *p = parser;
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h
index 6e62f31872..f75dfb3d87 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/transport.h"
@@ -45,13 +45,13 @@ typedef struct {
uint32_t amount;
} grpc_chttp2_window_update_parser;
-gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta,
- grpc_transport_one_way_stats *stats);
+grpc_slice grpc_chttp2_window_update_create(
+ uint32_t id, uint32_t window_delta, grpc_transport_one_way_stats *stats);
grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t,
- grpc_chttp2_stream *s, gpr_slice slice, int is_last);
+ grpc_chttp2_stream *s, grpc_slice slice, int is_last);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index 581471ba02..eb68fe3138 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -76,7 +76,7 @@ typedef struct {
uint8_t seen_regular_header;
/* output stream id */
uint32_t stream_id;
- gpr_slice_buffer *output;
+ grpc_slice_buffer *output;
grpc_transport_one_way_stats *stats;
/* maximum size of a frame */
size_t max_frame_size;
@@ -104,7 +104,7 @@ static void finish_frame(framer_state *st, int is_header_boundary,
type = st->is_first_frame ? GRPC_CHTTP2_FRAME_HEADER
: GRPC_CHTTP2_FRAME_CONTINUATION;
fill_header(
- GPR_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
+ GRPC_SLICE_START_PTR(st->output->slices[st->header_idx]), type,
st->stream_id, st->output->length - st->output_length_at_start_of_frame,
(uint8_t)((is_last_in_stream ? GRPC_CHTTP2_DATA_FLAG_END_STREAM : 0) |
(is_header_boundary ? GRPC_CHTTP2_DATA_FLAG_END_HEADERS : 0)));
@@ -116,7 +116,7 @@ static void finish_frame(framer_state *st, int is_header_boundary,
output before beginning */
static void begin_frame(framer_state *st) {
st->header_idx =
- gpr_slice_buffer_add_indexed(st->output, gpr_slice_malloc(9));
+ grpc_slice_buffer_add_indexed(st->output, grpc_slice_malloc(9));
st->output_length_at_start_of_frame = st->output->length;
}
@@ -147,18 +147,18 @@ static void inc_filter(uint8_t idx, uint32_t *sum, uint8_t *elems) {
}
}
-static void add_header_data(framer_state *st, gpr_slice slice) {
- size_t len = GPR_SLICE_LENGTH(slice);
+static void add_header_data(framer_state *st, grpc_slice slice) {
+ size_t len = GRPC_SLICE_LENGTH(slice);
size_t remaining;
if (len == 0) return;
remaining = st->max_frame_size + st->output_length_at_start_of_frame -
st->output->length;
if (len <= remaining) {
st->stats->header_bytes += len;
- gpr_slice_buffer_add(st->output, slice);
+ grpc_slice_buffer_add(st->output, slice);
} else {
st->stats->header_bytes += remaining;
- gpr_slice_buffer_add(st->output, gpr_slice_split_head(&slice, remaining));
+ grpc_slice_buffer_add(st->output, grpc_slice_split_head(&slice, remaining));
finish_frame(st, 0, 0);
begin_frame(st);
add_header_data(st, slice);
@@ -167,7 +167,7 @@ static void add_header_data(framer_state *st, gpr_slice slice) {
static uint8_t *add_tiny_header_data(framer_state *st, size_t len) {
ensure_space(st, len);
- return gpr_slice_buffer_tiny_add(st->output, len);
+ return grpc_slice_buffer_tiny_add(st->output, len);
}
static void evict_entry(grpc_chttp2_hpack_compressor *c) {
@@ -268,9 +268,10 @@ static void emit_indexed(grpc_chttp2_hpack_compressor *c, uint32_t elem_index,
len);
}
-static gpr_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
- if (grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice))) {
+static grpc_slice get_wire_value(grpc_mdelem *elem, uint8_t *huffman_prefix) {
+ if (grpc_is_binary_header(
+ (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
+ GRPC_SLICE_LENGTH(elem->key->slice))) {
*huffman_prefix = 0x80;
return grpc_mdstr_as_base64_encoded_and_huffman_compressed(elem->value);
}
@@ -284,8 +285,8 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
framer_state *st) {
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 2);
uint8_t huffman_prefix;
- gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
- size_t len_val = GPR_SLICE_LENGTH(value_slice);
+ grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
+ size_t len_val = GRPC_SLICE_LENGTH(value_slice);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
@@ -293,7 +294,7 @@ static void emit_lithdr_incidx(grpc_chttp2_hpack_compressor *c,
add_tiny_header_data(st, len_pfx), len_pfx);
GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, gpr_slice_ref(value_slice));
+ add_header_data(st, grpc_slice_ref(value_slice));
}
static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
@@ -301,8 +302,8 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
framer_state *st) {
uint32_t len_pfx = GRPC_CHTTP2_VARINT_LENGTH(key_index, 4);
uint8_t huffman_prefix;
- gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
- size_t len_val = GPR_SLICE_LENGTH(value_slice);
+ grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
+ size_t len_val = GRPC_SLICE_LENGTH(value_slice);
uint32_t len_val_len;
GPR_ASSERT(len_val <= UINT32_MAX);
len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
@@ -310,45 +311,45 @@ static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
add_tiny_header_data(st, len_pfx), len_pfx);
GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, gpr_slice_ref(value_slice));
+ add_header_data(st, grpc_slice_ref(value_slice));
}
static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
grpc_mdelem *elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice);
uint8_t huffman_prefix;
- gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
- uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
+ grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
+ uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
GPR_ASSERT(len_key <= UINT32_MAX);
- GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
*add_tiny_header_data(st, 1) = 0x40;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, gpr_slice_ref(elem->key->slice));
+ add_header_data(st, grpc_slice_ref(elem->key->slice));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, gpr_slice_ref(value_slice));
+ add_header_data(st, grpc_slice_ref(value_slice));
}
static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
grpc_mdelem *elem, framer_state *st) {
- uint32_t len_key = (uint32_t)GPR_SLICE_LENGTH(elem->key->slice);
+ uint32_t len_key = (uint32_t)GRPC_SLICE_LENGTH(elem->key->slice);
uint8_t huffman_prefix;
- gpr_slice value_slice = get_wire_value(elem, &huffman_prefix);
- uint32_t len_val = (uint32_t)GPR_SLICE_LENGTH(value_slice);
+ grpc_slice value_slice = get_wire_value(elem, &huffman_prefix);
+ uint32_t len_val = (uint32_t)GRPC_SLICE_LENGTH(value_slice);
uint32_t len_key_len = GRPC_CHTTP2_VARINT_LENGTH(len_key, 1);
uint32_t len_val_len = GRPC_CHTTP2_VARINT_LENGTH(len_val, 1);
GPR_ASSERT(len_key <= UINT32_MAX);
- GPR_ASSERT(GPR_SLICE_LENGTH(value_slice) <= UINT32_MAX);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(value_slice) <= UINT32_MAX);
*add_tiny_header_data(st, 1) = 0x00;
GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
add_tiny_header_data(st, len_key_len), len_key_len);
- add_header_data(st, gpr_slice_ref(elem->key->slice));
+ add_header_data(st, grpc_slice_ref(elem->key->slice));
GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
add_tiny_header_data(st, len_val_len), len_val_len);
- add_header_data(st, gpr_slice_ref(value_slice));
+ add_header_data(st, grpc_slice_ref(value_slice));
}
static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
@@ -373,8 +374,8 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
uint32_t indices_key;
int should_add_elem;
- GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0);
- if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
+ GPR_ASSERT(GRPC_SLICE_LENGTH(elem->key->slice) > 0);
+ if (GRPC_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
st->seen_regular_header = 1;
} else {
GPR_ASSERT(
@@ -546,7 +547,7 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
grpc_metadata_batch *metadata, int is_eof,
size_t max_frame_size,
grpc_transport_one_way_stats *stats,
- gpr_slice_buffer *outbuf) {
+ grpc_slice_buffer *outbuf) {
framer_state st;
grpc_linked_mdelem *l;
gpr_timespec deadline;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index 4c3a931549..bcbd675ca2 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -34,9 +34,9 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
@@ -93,6 +93,6 @@ void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id,
grpc_metadata_batch *metadata, int is_eof,
size_t max_frame_size,
grpc_transport_one_way_stats *stats,
- gpr_slice_buffer *outbuf);
+ grpc_slice_buffer *outbuf);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 9702cb2c81..6a9200b8db 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -1502,9 +1502,9 @@ static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
- *is =
- grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice));
+ *is = grpc_is_binary_header(
+ (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
+ GRPC_SLICE_LENGTH(elem->key->slice));
return GRPC_ERROR_NONE;
}
@@ -1584,7 +1584,7 @@ static void force_client_rst_stream(grpc_exec_ctx *exec_ctx, void *sp,
grpc_chttp2_stream *s = sp;
grpc_chttp2_transport *t = s->t;
if (!s->write_closed) {
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
&s->stats.outgoing));
grpc_chttp2_initiate_write(exec_ctx, t, false, "force_rst_stream");
@@ -1597,14 +1597,14 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
void *hpack_parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
+ grpc_slice slice, int is_last) {
grpc_chttp2_hpack_parser *parser = hpack_parser;
GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0);
if (s != NULL) {
- s->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
+ s->stats.incoming.header_bytes += GRPC_SLICE_LENGTH(slice);
}
grpc_error *error = grpc_chttp2_hpack_parser_parse(
- exec_ctx, parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
+ exec_ctx, parser, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_END_PTR(slice));
if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return error;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 0290c78d5a..a39bf466cd 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -116,6 +116,6 @@ grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
void *hpack_parser,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 2b73ec969e..2dc793d304 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -226,8 +226,8 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
/* Evict one element from the table */
static void evict1(grpc_chttp2_hptbl *tbl) {
grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
- size_t elem_bytes = GPR_SLICE_LENGTH(first_ent->key->slice) +
- GPR_SLICE_LENGTH(first_ent->value->slice) +
+ size_t elem_bytes = GRPC_SLICE_LENGTH(first_ent->key->slice) +
+ GRPC_SLICE_LENGTH(first_ent->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
tbl->mem_used -= (uint32_t)elem_bytes;
@@ -298,8 +298,8 @@ grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
- size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
- GPR_SLICE_LENGTH(md->value->slice) +
+ size_t elem_bytes = GRPC_SLICE_LENGTH(md->key->slice) +
+ GRPC_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 45bd9255bf..2ca130e64b 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -34,8 +34,8 @@
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H
+#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h"
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index e0c4a1e925..6cba1e7fd2 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -170,14 +170,14 @@ struct grpc_chttp2_incoming_byte_stream {
bool is_tail;
gpr_mu slice_mu; // protects slices, on_next
- gpr_slice_buffer slices;
+ grpc_slice_buffer slices;
grpc_closure *on_next;
- gpr_slice *next;
+ grpc_slice *next;
uint32_t remaining_bytes;
struct {
grpc_closure closure;
- gpr_slice *slice;
+ grpc_slice *slice;
size_t max_size_hint;
grpc_closure *on_complete;
} next_action;
@@ -219,7 +219,7 @@ struct grpc_chttp2_transport {
grpc_closure read_action_locked;
/** incoming read bytes */
- gpr_slice_buffer read_buffer;
+ grpc_slice_buffer read_buffer;
/** address to place a newly accepted stream - set and unset by
grpc_chttp2_parsing_accept_stream; used by init_stream to
@@ -237,7 +237,7 @@ struct grpc_chttp2_transport {
} channel_callback;
/** data to write now */
- gpr_slice_buffer outbuf;
+ grpc_slice_buffer outbuf;
/** hpack encoding */
grpc_chttp2_hpack_compressor hpack_compressor;
int64_t outgoing_window;
@@ -245,7 +245,7 @@ struct grpc_chttp2_transport {
uint8_t is_client;
/** data to write next write */
- gpr_slice_buffer qbuf;
+ grpc_slice_buffer qbuf;
/** window available to announce to peer */
int64_t announce_incoming_window;
@@ -314,12 +314,12 @@ struct grpc_chttp2_transport {
grpc_chttp2_stream *incoming_stream;
grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- gpr_slice slice, int is_last);
+ grpc_slice slice, int is_last);
/* goaway data */
grpc_status_code goaway_error;
uint32_t goaway_last_stream_index;
- gpr_slice goaway_text;
+ grpc_slice goaway_text;
grpc_chttp2_write_cb *write_cb_pool;
@@ -374,7 +374,7 @@ struct grpc_chttp2_stream {
grpc_byte_stream *fetching_send_message;
uint32_t fetched_send_message_length;
- gpr_slice fetching_slice;
+ grpc_slice fetching_slice;
int64_t next_message_end_offset;
int64_t flow_controlled_bytes_written;
bool complete_fetch_covered_by_poller;
@@ -409,6 +409,9 @@ struct grpc_chttp2_stream {
grpc_error *read_closed_error;
/** the error that resulted in this stream being write-closed */
grpc_error *write_closed_error;
+ /** should any writes be cleared once this stream becomes non-writable */
+ bool need_fail_pending_writes_on_writes_finished;
+ grpc_error *fail_pending_writes_on_writes_finished_error;
grpc_published_metadata_method published_metadata[2];
bool final_metadata_requested;
@@ -434,7 +437,7 @@ struct grpc_chttp2_stream {
bool sent_trailing_metadata;
/** how much window should we announce? */
uint32_t announce_window;
- gpr_slice_buffer flow_controlled_buffer;
+ grpc_slice_buffer flow_controlled_buffer;
grpc_chttp2_write_cb *on_write_finished_cbs;
grpc_chttp2_write_cb *finish_after_write;
@@ -466,7 +469,8 @@ void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/** Process one slice of incoming data; return 1 if the connection is still
viable after reading, or 0 if the connection should be torn down */
grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t, gpr_slice slice);
+ grpc_chttp2_transport *t,
+ grpc_slice slice);
bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
@@ -509,7 +513,7 @@ grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
uint32_t goaway_error,
- gpr_slice goaway_text);
+ grpc_slice goaway_text);
void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t);
@@ -611,7 +615,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *stream,
- grpc_status_code status, gpr_slice *details);
+ grpc_status_code status, grpc_slice *details);
void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s, int close_reads,
@@ -659,7 +663,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
uint32_t frame_size, uint32_t flags);
void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs,
- gpr_slice slice);
+ grpc_slice slice);
void grpc_chttp2_incoming_byte_stream_finished(
grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
grpc_error *error);
@@ -688,4 +692,11 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s);
+void grpc_chttp2_leave_writing_lists(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s);
+void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t,
+ grpc_chttp2_stream *s, grpc_error *error);
+
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 8005350ae7..5efb49751c 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -67,14 +67,14 @@ static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx,
int is_header);
static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t, gpr_slice slice,
+ grpc_chttp2_transport *t, grpc_slice slice,
int is_last);
grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- gpr_slice slice) {
- uint8_t *beg = GPR_SLICE_START_PTR(slice);
- uint8_t *end = GPR_SLICE_END_PTR(slice);
+ grpc_slice slice) {
+ uint8_t *beg = GRPC_SLICE_START_PTR(slice);
+ uint8_t *end = GRPC_SLICE_END_PTR(slice);
uint8_t *cur = beg;
grpc_error *err;
@@ -229,10 +229,10 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
case GRPC_DTS_FRAME:
GPR_ASSERT(cur < end);
if ((uint32_t)(end - cur) == t->incoming_frame_size) {
- err = parse_frame_slice(exec_ctx, t,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 1);
+ err = parse_frame_slice(
+ exec_ctx, t, grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 1);
if (err != GRPC_ERROR_NONE) {
return err;
}
@@ -243,8 +243,8 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
size_t cur_offset = (size_t)(cur - beg);
err = parse_frame_slice(
exec_ctx, t,
- gpr_slice_sub_no_ref(slice, cur_offset,
- cur_offset + t->incoming_frame_size),
+ grpc_slice_sub_no_ref(slice, cur_offset,
+ cur_offset + t->incoming_frame_size),
1);
if (err != GRPC_ERROR_NONE) {
return err;
@@ -253,10 +253,10 @@ grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
t->incoming_stream = NULL;
goto dts_fh_0; /* loop */
} else {
- err = parse_frame_slice(exec_ctx, t,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 0);
+ err = parse_frame_slice(
+ exec_ctx, t, grpc_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 0);
if (err != GRPC_ERROR_NONE) {
return err;
}
@@ -331,7 +331,7 @@ static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport *t, grpc_chttp2_stream *s,
- gpr_slice slice, int is_last) {
+ grpc_slice slice, int is_last) {
return GRPC_ERROR_NONE;
}
@@ -430,7 +430,7 @@ error_handler:
if (s != NULL) {
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, err);
}
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR,
&s->stats.outgoing));
@@ -471,7 +471,8 @@ static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
grpc_mdstr_as_c_string(md->value));
*cached_timeout = gpr_inf_future(GPR_TIMESPAN);
}
- grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
+ cached_timeout =
+ grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&s->metadata_buffer[0],
@@ -722,7 +723,7 @@ static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx,
}
static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport *t, gpr_slice slice,
+ grpc_chttp2_transport *t, grpc_slice slice,
int is_last) {
grpc_chttp2_stream *s = t->incoming_stream;
grpc_error *err = t->parser(exec_ctx, t->parser_data, t, s, slice, is_last);
@@ -737,7 +738,7 @@ static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
if (s) {
s->forced_close_error = err;
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
GRPC_CHTTP2_PROTOCOL_ERROR,
&s->stats.outgoing));
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index b39695a1a5..769b229a0d 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -80,7 +80,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 0);
if (t->dirtied_local_settings && !t->sent_local_settings) {
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->outbuf,
grpc_chttp2_settings_create(
t->settings[GRPC_SENT_SETTINGS], t->settings[GRPC_LOCAL_SETTINGS],
@@ -91,7 +91,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
}
/* simple writes are queued to qbuf, and flushed here */
- gpr_slice_buffer_move_into(&t->qbuf, &t->outbuf);
+ grpc_slice_buffer_move_into(&t->qbuf, &t->outbuf);
GPR_ASSERT(t->qbuf.count == 0);
grpc_chttp2_hpack_compressor_set_max_table_size(
@@ -130,9 +130,9 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
/* send any window updates */
if (s->announce_window > 0) {
uint32_t announce = s->announce_window;
- gpr_slice_buffer_add(&t->outbuf,
- grpc_chttp2_window_update_create(
- s->id, s->announce_window, &s->stats.outgoing));
+ grpc_slice_buffer_add(&t->outbuf,
+ grpc_chttp2_window_update_create(
+ s->id, s->announce_window, &s->stats.outgoing));
GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce);
}
if (sent_initial_metadata) {
@@ -162,9 +162,9 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
s->send_trailing_metadata = NULL;
s->sent_trailing_metadata = true;
if (!t->is_client && !s->read_closed) {
- gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(
- s->id, GRPC_CHTTP2_NO_ERROR,
- &s->stats.outgoing));
+ grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(
+ s->id, GRPC_CHTTP2_NO_ERROR,
+ &s->stats.outgoing));
}
}
s->sending_bytes += send_bytes;
@@ -194,7 +194,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
s->send_trailing_metadata = NULL;
s->sent_trailing_metadata = true;
if (!t->is_client && !s->read_closed) {
- gpr_slice_buffer_add(
+ grpc_slice_buffer_add(
&t->outbuf, grpc_chttp2_rst_stream_create(
s->id, GRPC_CHTTP2_NO_ERROR, &s->stats.outgoing));
}
@@ -208,6 +208,7 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:already_writing");
}
} else {
+ grpc_chttp2_leave_writing_lists(exec_ctx, t, s);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:no_write");
}
}
@@ -220,8 +221,8 @@ bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window,
announced);
grpc_transport_one_way_stats throwaway_stats;
- gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create(
- 0, announced, &throwaway_stats));
+ grpc_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create(
+ 0, announced, &throwaway_stats));
}
GPR_TIMER_END("grpc_chttp2_begin_write", 0);
@@ -252,9 +253,10 @@ void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1,
GRPC_ERROR_REF(error));
}
+ grpc_chttp2_leave_writing_lists(exec_ctx, t, s);
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end");
}
- gpr_slice_buffer_reset_and_unref(&t->outbuf);
+ grpc_slice_buffer_reset_and_unref(&t->outbuf);
GRPC_ERROR_UNREF(error);
GPR_TIMER_END("grpc_chttp2_end_write", 0);
}
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 25ad40b935..a4c110101e 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -34,14 +34,15 @@
#include <string.h>
#include <grpc/impl/codegen/port_platform.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
+#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/channel.h"
@@ -130,7 +131,7 @@ struct read_state {
/* vars for holding data destined for the application */
struct grpc_slice_buffer_stream sbs;
- gpr_slice_buffer read_slice_buffer;
+ grpc_slice_buffer read_slice_buffer;
/* vars for trailing metadata */
grpc_chttp2_incoming_metadata_buffer trailing_metadata;
@@ -517,11 +518,11 @@ static void on_response_trailers_received(
Utility function that takes the data from s->write_slice_buffer and assembles
into a contiguous byte stream with 5 byte gRPC header prepended.
*/
-static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer,
+static void create_grpc_frame(grpc_slice_buffer *write_slice_buffer,
char **pp_write_buffer,
size_t *p_write_buffer_size) {
- gpr_slice slice = gpr_slice_buffer_take_first(write_slice_buffer);
- size_t length = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = grpc_slice_buffer_take_first(write_slice_buffer);
+ size_t length = GRPC_SLICE_LENGTH(slice);
*p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
/* This is freed in the on_write_completed callback */
char *write_buffer = gpr_malloc(length + GRPC_HEADER_SIZE_IN_BYTES);
@@ -534,7 +535,7 @@ static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer,
*p++ = (uint8_t)(length >> 8);
*p++ = (uint8_t)(length);
/* append actual data */
- memcpy(p, GPR_SLICE_START_PTR(slice), length);
+ memcpy(p, GRPC_SLICE_START_PTR(slice), length);
}
/*
@@ -610,6 +611,16 @@ static int parse_grpc_header(const uint8_t *data) {
return length;
}
+static bool header_has_authority(grpc_linked_mdelem *head) {
+ while (head != NULL) {
+ if (head->md->key == GRPC_MDSTR_AUTHORITY) {
+ return true;
+ }
+ head = head->next;
+ }
+ return false;
+}
+
/*
Op Execution: Decide if one of the actions contained in the stream op can be
executed. This is the heart of the state machine.
@@ -817,9 +828,9 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
result = NO_ACTION_POSSIBLE;
CRONET_LOG(GPR_DEBUG, "Stream is either cancelled or failed.");
} else {
- gpr_slice_buffer write_slice_buffer;
- gpr_slice slice;
- gpr_slice_buffer_init(&write_slice_buffer);
+ grpc_slice_buffer write_slice_buffer;
+ grpc_slice slice;
+ grpc_slice_buffer_init(&write_slice_buffer);
grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
stream_op->send_message->length, NULL);
/* Check that compression flag is OFF. We don't support compression yet.
@@ -828,7 +839,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
gpr_log(GPR_ERROR, "Compression is not supported");
GPR_ASSERT(stream_op->send_message->flags == 0);
}
- gpr_slice_buffer_add(&write_slice_buffer, slice);
+ grpc_slice_buffer_add(&write_slice_buffer, slice);
if (write_slice_buffer.count != 1) {
/* Empty request not handled yet */
gpr_log(GPR_ERROR, "Empty request is not supported");
@@ -891,7 +902,7 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
} else {
stream_state->rs.remaining_bytes = 0;
CRONET_LOG(GPR_DEBUG, "read operation complete. Empty response.");
- gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+ grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
&stream_state->rs.read_slice_buffer, 0);
*((grpc_byte_buffer **)stream_op->recv_message) =
@@ -918,15 +929,15 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
}
} else if (stream_state->rs.remaining_bytes == 0) {
CRONET_LOG(GPR_DEBUG, "read operation complete");
- gpr_slice read_data_slice =
- gpr_slice_malloc((uint32_t)stream_state->rs.length_field);
- uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
+ grpc_slice read_data_slice =
+ grpc_slice_malloc((uint32_t)stream_state->rs.length_field);
+ uint8_t *dst_p = GRPC_SLICE_START_PTR(read_data_slice);
memcpy(dst_p, stream_state->rs.read_buffer,
(size_t)stream_state->rs.length_field);
free_read_buffer(s);
- gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
- gpr_slice_buffer_add(&stream_state->rs.read_slice_buffer,
- read_data_slice);
+ grpc_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+ grpc_slice_buffer_add(&stream_state->rs.read_slice_buffer,
+ read_data_slice);
grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
&stream_state->rs.read_slice_buffer, 0);
*((grpc_byte_buffer **)stream_op->recv_message) =
@@ -981,11 +992,18 @@ static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
} else if (stream_op->on_complete &&
op_can_be_run(stream_op, stream_state, &oas->state,
OP_ON_COMPLETE)) {
- /* All actions in this stream_op are complete. Call the on_complete callback
- */
CRONET_LOG(GPR_DEBUG, "running: %p OP_ON_COMPLETE", oas);
- grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE,
- NULL);
+ if (stream_state->state_op_done[OP_CANCEL_ERROR] ||
+ stream_state->state_callback_received[OP_FAILED]) {
+ grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete,
+ GRPC_ERROR_CANCELLED, NULL);
+ } else {
+ /* All actions in this stream_op are complete. Call the on_complete
+ * callback
+ */
+ grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE,
+ NULL);
+ }
oas->state.state_op_done[OP_ON_COMPLETE] = true;
oas->done = true;
/* reset any send message state, only if this ON_COMPLETE is about a send.
@@ -1042,7 +1060,31 @@ static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
s->curr_gs = gs;
memcpy(&s->curr_ct, gt, sizeof(grpc_cronet_transport));
add_to_storage(s, op);
- execute_from_storage(s);
+ if (op->send_initial_metadata &&
+ header_has_authority(op->send_initial_metadata->list.head)) {
+ /* Cronet does not support :authority header field. We cancel the call when
+ this field is present in metadata */
+ cronet_bidirectional_stream_header_array header_array;
+ cronet_bidirectional_stream_header *header;
+ cronet_bidirectional_stream cbs;
+ CRONET_LOG(GPR_DEBUG,
+ ":authority header is provided but not supported;"
+ " cancel operations");
+ /* Notify application that operation is cancelled by forging trailers */
+ header_array.count = 1;
+ header_array.capacity = 1;
+ header_array.headers =
+ gpr_malloc(sizeof(cronet_bidirectional_stream_header));
+ header = (cronet_bidirectional_stream_header *)header_array.headers;
+ header->key = "grpc-status";
+ header->value = "1"; /* Return status GRPC_STATUS_CANCELLED */
+ cbs.annotation = (void *)s;
+ s->state.state_op_done[OP_CANCEL_ERROR] = true;
+ on_response_trailers_received(&cbs, &header_array);
+ gpr_free(header_array.headers);
+ } else {
+ execute_from_storage(s);
+ }
}
static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
@@ -1054,6 +1096,11 @@ static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
return NULL;
}
+static grpc_endpoint *get_endpoint(grpc_exec_ctx *exec_ctx,
+ grpc_transport *gt) {
+ return NULL;
+}
+
static void perform_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_transport_op *op) {}
@@ -1066,4 +1113,5 @@ const grpc_transport_vtable grpc_cronet_vtable = {sizeof(stream_obj),
perform_op,
destroy_stream,
destroy_transport,
- get_peer};
+ get_peer,
+ get_endpoint};
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index cfc072c0b5..401a2ad4fe 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -298,6 +298,12 @@ uint32_t grpc_channel_args_compression_algorithm_get_states(
}
}
+grpc_channel_args *grpc_channel_args_set_socket_mutator(
+ grpc_channel_args *a, grpc_socket_mutator *mutator) {
+ grpc_arg tmp = grpc_socket_mutator_to_arg(mutator);
+ return grpc_channel_args_copy_and_add(a, &tmp, 1);
+}
+
int grpc_channel_args_compare(const grpc_channel_args *a,
const grpc_channel_args *b) {
int c = GPR_ICMP(a->num_args, b->num_args);
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 1e05303471..88fc0e37a3 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -36,6 +36,7 @@
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include "src/core/lib/iomgr/socket_mutator.h"
// Channel args are intentionally immutable, to avoid the need for locking.
@@ -100,6 +101,13 @@ uint32_t grpc_channel_args_compression_algorithm_get_states(
int grpc_channel_args_compare(const grpc_channel_args *a,
const grpc_channel_args *b);
+/** Returns a channel arg instance with socket mutator added. The socket mutator
+ * will perform its mutate_fd method on all file descriptors used by the
+ * channel.
+ * If \a a is non-MULL, its args are copied. */
+grpc_channel_args *grpc_channel_args_set_socket_mutator(
+ grpc_channel_args *a, grpc_socket_mutator *mutator);
+
/** Returns the value of argument \a name from \a args, or NULL if not found. */
const grpc_arg *grpc_channel_args_find(const grpc_channel_args *args,
const char *name);
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 2c5367901d..999ad5f507 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -162,7 +162,8 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack) {
+ grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline,
+ grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
grpc_call_element_args args;
size_t count = channel_stack->count;
@@ -179,7 +180,7 @@ grpc_error *grpc_call_stack_init(
/* init per-filter data */
grpc_error *first_error = GRPC_ERROR_NONE;
- args.start_time = gpr_now(GPR_CLOCK_MONOTONIC);
+ args.start_time = start_time;
for (i = 0; i < count; i++) {
args.call_stack = call_stack;
args.server_transport_data = transport_server_data;
@@ -255,6 +256,13 @@ char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx,
return next_elem->filter->get_peer(exec_ctx, next_elem);
}
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {
+ grpc_channel_element *next_elem = elem + 1;
+ next_elem->filter->get_channel_info(exec_ctx, next_elem, channel_info);
+}
+
void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
grpc_transport_op *op) {
grpc_channel_element *next_elem = elem + 1;
@@ -288,7 +296,7 @@ void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_status_code status,
- gpr_slice *optional_message) {
+ grpc_slice *optional_message) {
grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
memset(op, 0, sizeof(*op));
op->on_complete = grpc_closure_create(destroy_op, op);
@@ -300,7 +308,7 @@ void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_status_code status,
- gpr_slice *optional_message) {
+ grpc_slice *optional_message) {
grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
memset(op, 0, sizeof(*op));
op->on_complete = grpc_closure_create(destroy_op, op);
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 27f3be7b29..004643d45f 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -156,6 +156,10 @@ typedef struct {
/* Implement grpc_call_get_peer() */
char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+ /* Implement grpc_channel_get_info() */
+ void (*get_channel_info)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ const grpc_channel_info *channel_info);
+
/* The name of this filter */
const char *name;
} grpc_channel_filter;
@@ -227,7 +231,8 @@ grpc_error *grpc_call_stack_init(
grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
int initial_refs, grpc_iomgr_cb_func destroy, void *destroy_arg,
grpc_call_context_element *context, const void *transport_server_data,
- grpc_mdstr *path, gpr_timespec deadline, grpc_call_stack *call_stack);
+ grpc_mdstr *path, gpr_timespec start_time, gpr_timespec deadline,
+ grpc_call_stack *call_stack);
/* Set a pollset or a pollset_set for a call stack: must occur before the first
* op is started */
void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -273,6 +278,10 @@ void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
grpc_transport_op *op);
/* Pass through a request to get_peer to the next child element */
char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+/* Pass through a request to get_channel_info() to the next child element */
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *channel_info);
/* Given the top element of a channel stack, get the channel stack itself */
grpc_channel_stack *grpc_channel_stack_from_top_element(
@@ -289,12 +298,12 @@ void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *cur_elem,
grpc_status_code status,
- gpr_slice *optional_message);
+ grpc_slice *optional_message);
void grpc_call_element_send_close_with_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *cur_elem,
grpc_status_code status,
- gpr_slice *optional_message);
+ grpc_slice *optional_message);
extern int grpc_trace_channel;
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 0981d59f63..2874d63fc7 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -35,9 +35,9 @@
#include <string.h>
#include <grpc/compression.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/compress_filter.h"
@@ -50,7 +50,7 @@
int grpc_compression_trace = 0;
typedef struct call_data {
- gpr_slice_buffer slices; /**< Buffers up input slices to be compressed */
+ grpc_slice_buffer slices; /**< Buffers up input slices to be compressed */
grpc_linked_mdelem compression_algorithm_storage;
grpc_linked_mdelem accept_encoding_storage;
uint32_t remaining_slice_bytes;
@@ -63,7 +63,7 @@ typedef struct call_data {
grpc_transport_stream_op *send_op;
uint32_t send_length;
uint32_t send_flags;
- gpr_slice incoming_slice;
+ grpc_slice incoming_slice;
grpc_slice_buffer_stream replacement_stream;
grpc_closure *post_send;
grpc_closure send_done;
@@ -111,9 +111,13 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
return md;
}
-static int skip_compression(grpc_call_element *elem) {
+static int skip_compression(grpc_call_element *elem, uint32_t flags) {
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
+
+ if (flags & (GRPC_WRITE_NO_COMPRESS | GRPC_WRITE_INTERNAL_COMPRESS)) {
+ return 1;
+ }
if (calld->has_compression_algorithm) {
if (calld->compression_algorithm == GRPC_COMPRESS_NONE) {
return 1;
@@ -157,7 +161,7 @@ static void continue_send_message(grpc_exec_ctx *exec_ctx,
static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
- gpr_slice_buffer_reset_and_unref(&calld->slices);
+ grpc_slice_buffer_reset_and_unref(&calld->slices);
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
}
@@ -165,8 +169,8 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {
call_data *calld = elem->call_data;
int did_compress;
- gpr_slice_buffer tmp;
- gpr_slice_buffer_init(&tmp);
+ grpc_slice_buffer tmp;
+ grpc_slice_buffer_init(&tmp);
did_compress =
grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp);
if (did_compress) {
@@ -181,7 +185,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
" bytes (%.2f%% savings)",
algo_name, before_size, after_size, 100 * savings_ratio);
}
- gpr_slice_buffer_swap(&calld->slices, &tmp);
+ grpc_slice_buffer_swap(&calld->slices, &tmp);
calld->send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
} else {
if (grpc_compression_trace) {
@@ -195,7 +199,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
}
}
- gpr_slice_buffer_destroy(&tmp);
+ grpc_slice_buffer_destroy(&tmp);
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
calld->send_flags);
@@ -209,7 +213,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
- gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
finish_send_message(exec_ctx, elem);
} else {
@@ -223,7 +227,7 @@ static void continue_send_message(grpc_exec_ctx *exec_ctx,
while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message,
&calld->incoming_slice, ~(size_t)0,
&calld->got_slice)) {
- gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
finish_send_message(exec_ctx, elem);
break;
@@ -241,8 +245,8 @@ static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
if (op->send_initial_metadata) {
process_send_initial_metadata(elem, op->send_initial_metadata);
}
- if (op->send_message != NULL && !skip_compression(elem) &&
- 0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
+ if (op->send_message != NULL &&
+ !skip_compression(elem, op->send_message->flags)) {
calld->send_op = op;
calld->send_length = op->send_message->length;
calld->send_flags = op->send_message->flags;
@@ -263,7 +267,7 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
call_data *calld = elem->call_data;
/* initialize members */
- gpr_slice_buffer_init(&calld->slices);
+ grpc_slice_buffer_init(&calld->slices);
calld->has_compression_algorithm = 0;
grpc_closure_init(&calld->got_slice, got_slice, elem);
grpc_closure_init(&calld->send_done, send_done, elem);
@@ -277,7 +281,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
void *ignored) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
- gpr_slice_buffer_destroy(&calld->slices);
+ grpc_slice_buffer_destroy(&calld->slices);
}
/* Constructor for channel_data */
@@ -328,4 +332,5 @@ const grpc_channel_filter grpc_compress_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"compress"};
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 918379c845..038e819f72 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -38,9 +38,9 @@
#include <string.h>
#include <grpc/byte_buffer.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport.h"
@@ -134,6 +134,11 @@ static char *con_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
return grpc_transport_get_peer(exec_ctx, chand->transport);
}
+/* No-op. */
+static void con_get_channel_info(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {}
+
static const grpc_channel_filter connected_channel_filter = {
con_start_transport_stream_op,
con_start_transport_op,
@@ -145,6 +150,7 @@ static const grpc_channel_filter connected_channel_filter = {
init_channel_elem,
destroy_channel_elem,
con_get_peer,
+ con_get_channel_info,
"connected",
};
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index d2ea5250f6..0e703d8d27 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -55,10 +55,10 @@ static void timer_callback(grpc_exec_ctx* exec_ctx, void* arg,
deadline_state->timer_pending = false;
gpr_mu_unlock(&deadline_state->timer_mu);
if (error != GRPC_ERROR_CANCELLED) {
- gpr_slice msg = gpr_slice_from_static_string("Deadline Exceeded");
+ grpc_slice msg = grpc_slice_from_static_string("Deadline Exceeded");
grpc_call_element_send_cancel_with_message(
exec_ctx, elem, GRPC_STATUS_DEADLINE_EXCEEDED, &msg);
- gpr_slice_unref(msg);
+ grpc_slice_unref(msg);
}
GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer");
}
@@ -316,6 +316,7 @@ const grpc_channel_filter grpc_client_deadline_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"deadline",
};
@@ -330,5 +331,6 @@ const grpc_channel_filter grpc_server_deadline_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"deadline",
};
diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c
index 0d759887bc..90626dc2d1 100644
--- a/src/core/lib/channel/handshaker.c
+++ b/src/core/lib/channel/handshaker.c
@@ -38,67 +38,66 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/iomgr/timer.h"
//
// grpc_handshaker
//
-void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
+void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
grpc_handshaker* handshaker) {
handshaker->vtable = vtable;
}
-void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker) {
+static void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
+ grpc_handshaker* handshaker) {
handshaker->vtable->destroy(exec_ctx, handshaker);
}
-void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker) {
+static void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
+ grpc_handshaker* handshaker) {
handshaker->vtable->shutdown(exec_ctx, handshaker);
}
-void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker,
- grpc_endpoint* endpoint,
- grpc_channel_args* args,
- gpr_slice_buffer* read_buffer,
- gpr_timespec deadline,
- grpc_tcp_server_acceptor* acceptor,
- grpc_handshaker_done_cb cb, void* user_data) {
- handshaker->vtable->do_handshake(exec_ctx, handshaker, endpoint, args,
- read_buffer, deadline, acceptor, cb,
- user_data);
+static void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
+ grpc_handshaker* handshaker,
+ grpc_tcp_server_acceptor* acceptor,
+ grpc_closure* on_handshake_done,
+ grpc_handshaker_args* args) {
+ handshaker->vtable->do_handshake(exec_ctx, handshaker, acceptor,
+ on_handshake_done, args);
}
//
// grpc_handshake_manager
//
-// State used while chaining handshakers.
-struct grpc_handshaker_state {
- // The index of the handshaker to invoke next.
- size_t index;
- // The deadline for all handshakers.
- gpr_timespec deadline;
- // The acceptor to call the handshakers with.
- grpc_tcp_server_acceptor* acceptor;
- // The final callback and user_data to invoke after the last handshaker.
- grpc_handshaker_done_cb final_cb;
- void* final_user_data;
-};
-
struct grpc_handshake_manager {
+ gpr_mu mu;
+ gpr_refcount refs;
+ bool shutdown;
// An array of handshakers added via grpc_handshake_manager_add().
size_t count;
grpc_handshaker** handshakers;
- // State used while chaining handshakers.
- struct grpc_handshaker_state* state;
+ // The index of the handshaker to invoke next and closure to invoke it.
+ size_t index;
+ grpc_closure call_next_handshaker;
+ // The acceptor to call the handshakers with.
+ grpc_tcp_server_acceptor* acceptor;
+ // Deadline timer across all handshakers.
+ grpc_timer deadline_timer;
+ // The final callback and user_data to invoke after the last handshaker.
+ grpc_closure on_handshake_done;
+ void* user_data;
+ // Handshaker args.
+ grpc_handshaker_args args;
};
grpc_handshake_manager* grpc_handshake_manager_create() {
grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager));
memset(mgr, 0, sizeof(*mgr));
+ gpr_mu_init(&mgr->mu);
+ gpr_ref_init(&mgr->refs, 1);
return mgr;
}
@@ -106,6 +105,7 @@ static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; }
void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
grpc_handshaker* handshaker) {
+ gpr_mu_lock(&mgr->mu);
// To avoid allocating memory for each handshaker we add, we double
// the number of elements every time we need more.
size_t realloc_count = 0;
@@ -119,85 +119,116 @@ void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
gpr_realloc(mgr->handshakers, realloc_count * sizeof(grpc_handshaker*));
}
mgr->handshakers[mgr->count++] = handshaker;
+ gpr_mu_unlock(&mgr->mu);
+}
+
+static void grpc_handshake_manager_unref(grpc_exec_ctx* exec_ctx,
+ grpc_handshake_manager* mgr) {
+ if (gpr_unref(&mgr->refs)) {
+ for (size_t i = 0; i < mgr->count; ++i) {
+ grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
+ }
+ gpr_free(mgr->handshakers);
+ gpr_mu_destroy(&mgr->mu);
+ gpr_free(mgr);
+ }
}
void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) {
- for (size_t i = 0; i < mgr->count; ++i) {
- grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
- }
- gpr_free(mgr->handshakers);
- gpr_free(mgr);
+ grpc_handshake_manager_unref(exec_ctx, mgr);
}
void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr) {
- for (size_t i = 0; i < mgr->count; ++i) {
- grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[i]);
+ gpr_mu_lock(&mgr->mu);
+ // Shutdown the handshaker that's currently in progress, if any.
+ if (!mgr->shutdown && mgr->index > 0) {
+ mgr->shutdown = true;
+ grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[mgr->index - 1]);
}
- if (mgr->state != NULL) {
- gpr_free(mgr->state);
- mgr->state = NULL;
+ gpr_mu_unlock(&mgr->mu);
+}
+
+// Helper function to call either the next handshaker or the
+// on_handshake_done callback.
+// Returns true if we've scheduled the on_handshake_done callback.
+static bool call_next_handshaker_locked(grpc_exec_ctx* exec_ctx,
+ grpc_handshake_manager* mgr,
+ grpc_error* error) {
+ GPR_ASSERT(mgr->index <= mgr->count);
+ // If we got an error or we've been shut down or we've finished the last
+ // handshaker, invoke the on_handshake_done callback. Otherwise, call the
+ // next handshaker.
+ if (error != GRPC_ERROR_NONE || mgr->shutdown || mgr->index == mgr->count) {
+ // Cancel deadline timer, since we're invoking the on_handshake_done
+ // callback now.
+ grpc_timer_cancel(exec_ctx, &mgr->deadline_timer);
+ grpc_exec_ctx_sched(exec_ctx, &mgr->on_handshake_done, error, NULL);
+ mgr->shutdown = true;
+ } else {
+ grpc_handshaker_do_handshake(exec_ctx, mgr->handshakers[mgr->index],
+ mgr->acceptor, &mgr->call_next_handshaker,
+ &mgr->args);
}
+ ++mgr->index;
+ return mgr->shutdown;
}
// A function used as the handshaker-done callback when chaining
// handshakers together.
-static void call_next_handshaker(grpc_exec_ctx* exec_ctx,
- grpc_endpoint* endpoint,
- grpc_channel_args* args,
- gpr_slice_buffer* read_buffer, void* user_data,
+static void call_next_handshaker(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
- grpc_handshake_manager* mgr = user_data;
- GPR_ASSERT(mgr->state != NULL);
- GPR_ASSERT(mgr->state->index < mgr->count);
- // If we got an error, skip all remaining handshakers and invoke the
- // caller-supplied callback immediately.
- if (error != GRPC_ERROR_NONE) {
- mgr->state->final_cb(exec_ctx, endpoint, args, read_buffer,
- mgr->state->final_user_data, error);
- return;
+ grpc_handshake_manager* mgr = arg;
+ gpr_mu_lock(&mgr->mu);
+ bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_REF(error));
+ gpr_mu_unlock(&mgr->mu);
+ // If we're invoked the final callback, we won't be coming back
+ // to this function, so we can release our reference to the
+ // handshake manager.
+ if (done) {
+ grpc_handshake_manager_unref(exec_ctx, mgr);
}
- grpc_handshaker_done_cb cb = call_next_handshaker;
- // If this is the last handshaker, use the caller-supplied callback
- // and user_data instead of chaining back to this function again.
- if (mgr->state->index == mgr->count - 1) {
- cb = mgr->state->final_cb;
- user_data = mgr->state->final_user_data;
- }
- // Invoke handshaker.
- grpc_handshaker_do_handshake(
- exec_ctx, mgr->handshakers[mgr->state->index], endpoint, args,
- read_buffer, mgr->state->deadline, mgr->state->acceptor, cb, user_data);
- ++mgr->state->index;
- // If this is the last handshaker, clean up state.
- if (mgr->state->index == mgr->count) {
- gpr_free(mgr->state);
- mgr->state = NULL;
+}
+
+// Callback invoked when deadline is exceeded.
+static void on_timeout(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) {
+ grpc_handshake_manager* mgr = arg;
+ if (error == GRPC_ERROR_NONE) { // Timer fired, rather than being cancelled.
+ grpc_handshake_manager_shutdown(exec_ctx, mgr);
}
+ grpc_handshake_manager_unref(exec_ctx, mgr);
}
void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
- grpc_endpoint* endpoint, const grpc_channel_args* args,
+ grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
- grpc_handshaker_done_cb cb, void* user_data) {
- grpc_channel_args* args_copy = grpc_channel_args_copy(args);
- gpr_slice_buffer* read_buffer = gpr_malloc(sizeof(*read_buffer));
- gpr_slice_buffer_init(read_buffer);
- if (mgr->count == 0) {
- // No handshakers registered, so we just immediately call the done
- // callback with the passed-in endpoint.
- cb(exec_ctx, endpoint, args_copy, read_buffer, user_data, GRPC_ERROR_NONE);
- } else {
- GPR_ASSERT(mgr->state == NULL);
- mgr->state = gpr_malloc(sizeof(struct grpc_handshaker_state));
- memset(mgr->state, 0, sizeof(*mgr->state));
- mgr->state->deadline = deadline;
- mgr->state->acceptor = acceptor;
- mgr->state->final_cb = cb;
- mgr->state->final_user_data = user_data;
- call_next_handshaker(exec_ctx, endpoint, args_copy, read_buffer, mgr,
- GRPC_ERROR_NONE);
+ grpc_iomgr_cb_func on_handshake_done, void* user_data) {
+ gpr_mu_lock(&mgr->mu);
+ GPR_ASSERT(mgr->index == 0);
+ GPR_ASSERT(!mgr->shutdown);
+ // Construct handshaker args. These will be passed through all
+ // handshakers and eventually be freed by the on_handshake_done callback.
+ mgr->args.endpoint = endpoint;
+ mgr->args.args = grpc_channel_args_copy(channel_args);
+ mgr->args.user_data = user_data;
+ mgr->args.read_buffer = gpr_malloc(sizeof(*mgr->args.read_buffer));
+ grpc_slice_buffer_init(mgr->args.read_buffer);
+ // Initialize state needed for calling handshakers.
+ mgr->acceptor = acceptor;
+ grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr);
+ grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args);
+ // Start deadline timer, which owns a ref.
+ gpr_ref(&mgr->refs);
+ grpc_timer_init(exec_ctx, &mgr->deadline_timer,
+ gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+ on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC));
+ // Start first handshaker, which also owns a ref.
+ gpr_ref(&mgr->refs);
+ bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);
+ gpr_mu_unlock(&mgr->mu);
+ if (done) {
+ grpc_handshake_manager_unref(exec_ctx, mgr);
}
}
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index d574b46242..ebbc1ff7f3 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -54,15 +54,30 @@
typedef struct grpc_handshaker grpc_handshaker;
-/// Callback type invoked when a handshaker is done.
-/// Takes ownership of \a args and \a read_buffer.
-typedef void (*grpc_handshaker_done_cb)(grpc_exec_ctx* exec_ctx,
- grpc_endpoint* endpoint,
- grpc_channel_args* args,
- gpr_slice_buffer* read_buffer,
- void* user_data, grpc_error* error);
-
-struct grpc_handshaker_vtable {
+/// Arguments passed through handshakers and to the on_handshake_done callback.
+///
+/// For handshakers, all members are input/output parameters; for
+/// example, a handshaker may read from or write to \a endpoint and
+/// then later replace it with a wrapped endpoint. Similarly, a
+/// handshaker may modify \a args.
+///
+/// A handshaker takes ownership of the members while a handshake is in
+/// progress. Upon failure or shutdown of an in-progress handshaker,
+/// the handshaker is responsible for destroying the members and setting
+/// them to NULL before invoking the on_handshake_done callback.
+///
+/// For the on_handshake_done callback, all members are input arguments,
+/// which the callback takes ownership of.
+typedef struct {
+ grpc_endpoint* endpoint;
+ grpc_channel_args* args;
+ grpc_slice_buffer* read_buffer;
+ // User data passed through the handshake manager. Not used by
+ // individual handshakers.
+ void* user_data;
+} grpc_handshaker_args;
+
+typedef struct {
/// Destroys the handshaker.
void (*destroy)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
@@ -70,44 +85,26 @@ struct grpc_handshaker_vtable {
/// aborted in the middle).
void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
- /// Performs handshaking. When finished, calls \a cb with \a user_data.
- /// Takes ownership of \a args.
- /// Takes ownership of \a read_buffer, which contains leftover bytes read
- /// from the endpoint by the previous handshaker.
+ /// Performs handshaking, modifying \a args as needed (e.g., to
+ /// replace \a endpoint with a wrapped endpoint).
+ /// When finished, invokes \a on_handshake_done.
/// \a acceptor will be NULL for client-side handshakers.
void (*do_handshake)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker,
- grpc_endpoint* endpoint, grpc_channel_args* args,
- gpr_slice_buffer* read_buffer, gpr_timespec deadline,
grpc_tcp_server_acceptor* acceptor,
- grpc_handshaker_done_cb cb, void* user_data);
-};
+ grpc_closure* on_handshake_done,
+ grpc_handshaker_args* args);
+} grpc_handshaker_vtable;
/// Base struct. To subclass, make this the first member of the
/// implementation struct.
struct grpc_handshaker {
- const struct grpc_handshaker_vtable* vtable;
+ const grpc_handshaker_vtable* vtable;
};
/// Called by concrete implementations to initialize the base struct.
-void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
+void grpc_handshaker_init(const grpc_handshaker_vtable* vtable,
grpc_handshaker* handshaker);
-/// Convenient wrappers for invoking methods via the vtable.
-/// These probably do not need to be called from anywhere but
-/// grpc_handshake_manager.
-void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker);
-void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker);
-void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
- grpc_handshaker* handshaker,
- grpc_endpoint* endpoint,
- grpc_channel_args* args,
- gpr_slice_buffer* read_buffer,
- gpr_timespec deadline,
- grpc_tcp_server_acceptor* acceptor,
- grpc_handshaker_done_cb cb, void* user_data);
-
///
/// grpc_handshake_manager
///
@@ -134,15 +131,21 @@ void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
grpc_handshake_manager* mgr);
/// Invokes handshakers in the order they were added.
-/// Does NOT take ownership of \a args. Instead, makes a copy before
+/// Takes ownership of \a endpoint, and then passes that ownership to
+/// the \a on_handshake_done callback.
+/// Does NOT take ownership of \a channel_args. Instead, makes a copy before
/// invoking the first handshaker.
/// \a acceptor will be NULL for client-side handshakers.
-/// Invokes \a cb with \a user_data after either a handshaker fails or
-/// all handshakers have completed successfully.
+///
+/// When done, invokes \a on_handshake_done with a grpc_handshaker_args
+/// object as its argument. If the callback is invoked with error !=
+/// GRPC_ERROR_NONE, then handshaking failed and the handshaker has done
+/// the necessary clean-up. Otherwise, the callback takes ownership of
+/// the arguments.
void grpc_handshake_manager_do_handshake(
grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
- grpc_endpoint* endpoint, const grpc_channel_args* args,
+ grpc_endpoint* endpoint, const grpc_channel_args* channel_args,
gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
- grpc_handshaker_done_cb cb, void* user_data);
+ grpc_iomgr_cb_func on_handshake_done, void* user_data);
#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 1dc05fb20d..fd8b46afcb 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -36,6 +36,7 @@
#include <grpc/support/string_util.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/transport_impl.h"
@@ -56,27 +57,30 @@ typedef struct call_data {
grpc_linked_mdelem payload_bin;
grpc_metadata_batch *recv_initial_metadata;
+ grpc_metadata_batch *recv_trailing_metadata;
uint8_t *payload_bytes;
/* Vars to read data off of send_message */
grpc_transport_stream_op send_op;
uint32_t send_length;
uint32_t send_flags;
- gpr_slice incoming_slice;
+ grpc_slice incoming_slice;
grpc_slice_buffer_stream replacement_stream;
- gpr_slice_buffer slices;
+ grpc_slice_buffer slices;
/* flag that indicates that all slices of send_messages aren't availble */
bool send_message_blocked;
/** Closure to call when finished with the hc_on_recv hook */
- grpc_closure *on_done_recv;
+ grpc_closure *on_done_recv_initial_metadata;
+ grpc_closure *on_done_recv_trailing_metadata;
grpc_closure *on_complete;
grpc_closure *post_send;
/** Receive closures are chained: we inject this closure as the on_done_recv
up-call on transport_op, and remember to call our on_done_recv member
after handling it. */
- grpc_closure hc_on_recv;
+ grpc_closure hc_on_recv_initial_metadata;
+ grpc_closure hc_on_recv_trailing_metadata;
grpc_closure hc_on_complete;
grpc_closure got_slice;
grpc_closure send_done;
@@ -101,11 +105,21 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
char *message_string;
gpr_asprintf(&message_string, "Received http2 header with status: %s",
grpc_mdstr_as_c_string(md->value));
- gpr_slice message = gpr_slice_from_copied_string(message_string);
+ grpc_slice message = grpc_slice_from_copied_string(message_string);
gpr_free(message_string);
grpc_call_element_send_close_with_message(a->exec_ctx, a->elem,
GRPC_STATUS_CANCELLED, &message);
return NULL;
+ } else if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
+ grpc_slice pct_decoded_msg =
+ grpc_permissive_percent_decode_slice(md->value->slice);
+ if (grpc_slice_is_equivalent(pct_decoded_msg, md->value->slice)) {
+ grpc_slice_unref(pct_decoded_msg);
+ return md;
+ } else {
+ return grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_decoded_msg));
+ }
} else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
return NULL;
} else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
@@ -129,8 +143,8 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
return md;
}
-static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
- grpc_error *error) {
+static void hc_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
+ void *user_data, grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
client_recv_filter_args a;
@@ -138,7 +152,21 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
a.exec_ctx = exec_ctx;
grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
&a);
- calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
+ grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata,
+ GRPC_ERROR_REF(error));
+}
+
+static void hc_on_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
+ void *user_data, grpc_error *error) {
+ grpc_call_element *elem = user_data;
+ call_data *calld = elem->call_data;
+ client_recv_filter_args a;
+ a.elem = elem;
+ a.exec_ctx = exec_ctx;
+ grpc_metadata_batch_filter(calld->recv_trailing_metadata, client_recv_filter,
+ &a);
+ grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata,
+ GRPC_ERROR_REF(error));
}
static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -155,7 +183,7 @@ static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
- gpr_slice_buffer_reset_and_unref(&calld->slices);
+ grpc_slice_buffer_reset_and_unref(&calld->slices);
calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
}
@@ -176,10 +204,10 @@ static void continue_send_message(grpc_exec_ctx *exec_ctx,
while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
&calld->incoming_slice, ~(size_t)0,
&calld->got_slice)) {
- memcpy(wrptr, GPR_SLICE_START_PTR(calld->incoming_slice),
- GPR_SLICE_LENGTH(calld->incoming_slice));
- wrptr += GPR_SLICE_LENGTH(calld->incoming_slice);
- gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ memcpy(wrptr, GRPC_SLICE_START_PTR(calld->incoming_slice),
+ GRPC_SLICE_LENGTH(calld->incoming_slice));
+ wrptr += GRPC_SLICE_LENGTH(calld->incoming_slice);
+ grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
calld->send_message_blocked = false;
break;
@@ -191,7 +219,7 @@ static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
calld->send_message_blocked = false;
- gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+ grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
if (calld->send_length == calld->slices.length) {
/* Pass down the original send_message op that was blocked.*/
grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
@@ -217,12 +245,15 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
message, and the payload is below the size threshold, and all the data
for this request is immediately available. */
grpc_mdelem *method = GRPC_MDELEM_METHOD_POST;
- calld->send_message_blocked = false;
if ((op->send_initial_metadata_flags &
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
op->send_message != NULL &&
op->send_message->length < channeld->max_payload_size_for_get) {
method = GRPC_MDELEM_METHOD_GET;
+ /* The following write to calld->send_message_blocked isn't racy with
+ reads in hc_start_transport_op (which deals with SEND_MESSAGE ops) because
+ being here means ops->send_message is not NULL, which is primarily
+ guarding the read there. */
calld->send_message_blocked = true;
} else if (op->send_initial_metadata_flags &
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
@@ -281,8 +312,15 @@ static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
if (op->recv_initial_metadata != NULL) {
/* substitute our callback for the higher callback */
calld->recv_initial_metadata = op->recv_initial_metadata;
- calld->on_done_recv = op->recv_initial_metadata_ready;
- op->recv_initial_metadata_ready = &calld->hc_on_recv;
+ calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
+ op->recv_initial_metadata_ready = &calld->hc_on_recv_initial_metadata;
+ }
+
+ if (op->recv_trailing_metadata != NULL) {
+ /* substitute our callback for the higher callback */
+ calld->recv_trailing_metadata = op->recv_trailing_metadata;
+ calld->on_done_recv_trailing_metadata = op->on_complete;
+ op->on_complete = &calld->hc_on_recv_trailing_metadata;
}
}
@@ -296,8 +334,7 @@ static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
call_data *calld = elem->call_data;
if (op->send_message != NULL && calld->send_message_blocked) {
/* Don't forward the op. send_message contains slices that aren't ready
- yet. The call will be forwarded by the op_complete of slice read call.
- */
+ yet. The call will be forwarded by the op_complete of slice read call. */
} else {
grpc_call_next_op(exec_ctx, elem, op);
}
@@ -308,11 +345,16 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_call_element_args *args) {
call_data *calld = elem->call_data;
- calld->on_done_recv = NULL;
+ calld->on_done_recv_initial_metadata = NULL;
+ calld->on_done_recv_trailing_metadata = NULL;
calld->on_complete = NULL;
calld->payload_bytes = NULL;
- gpr_slice_buffer_init(&calld->slices);
- grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
+ calld->send_message_blocked = false;
+ grpc_slice_buffer_init(&calld->slices);
+ grpc_closure_init(&calld->hc_on_recv_initial_metadata,
+ hc_on_recv_initial_metadata, elem);
+ grpc_closure_init(&calld->hc_on_recv_trailing_metadata,
+ hc_on_recv_trailing_metadata, elem);
grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem);
grpc_closure_init(&calld->got_slice, got_slice, elem);
grpc_closure_init(&calld->send_done, send_done, elem);
@@ -324,7 +366,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
void *ignored) {
call_data *calld = elem->call_data;
- gpr_slice_buffer_destroy(&calld->slices);
+ grpc_slice_buffer_destroy(&calld->slices);
}
static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
@@ -448,4 +490,5 @@ const grpc_channel_filter grpc_http_client_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"http-client"};
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index f2221fb0fb..b42ff06039 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -37,6 +37,7 @@
#include <grpc/support/log.h>
#include <string.h>
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/percent_encoding.h"
#include "src/core/lib/transport/static_metadata.h"
#define EXPECTED_CONTENT_TYPE "application/grpc"
@@ -68,7 +69,7 @@ typedef struct call_data {
grpc_closure *recv_message_ready;
grpc_closure *on_complete;
grpc_byte_stream **pp_recv_message;
- gpr_slice_buffer read_slice_buffer;
+ grpc_slice_buffer read_slice_buffer;
grpc_slice_buffer_stream read_stream;
/** Receive closures are chained: we inject this closure as the on_done_recv
@@ -86,6 +87,23 @@ typedef struct {
grpc_exec_ctx *exec_ctx;
} server_filter_args;
+static grpc_mdelem *server_filter_outgoing_metadata(void *user_data,
+ grpc_mdelem *md) {
+ if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
+ grpc_slice pct_encoded_msg = grpc_percent_encode_slice(
+ md->value->slice, grpc_compatible_percent_encoding_unreserved_bytes);
+ if (grpc_slice_is_equivalent(pct_encoded_msg, md->value->slice)) {
+ grpc_slice_unref(pct_encoded_msg);
+ return md;
+ } else {
+ return grpc_mdelem_from_metadata_strings(
+ GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_encoded_msg));
+ }
+ } else {
+ return md;
+ }
+}
+
static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
server_filter_args *a = user_data;
grpc_call_element *elem = a->elem;
@@ -162,9 +180,8 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
/* Retrieve the payload from the value of the 'grpc-internal-payload-bin'
header field */
calld->seen_payload_bin = 1;
- gpr_slice_buffer_init(&calld->read_slice_buffer);
- gpr_slice_buffer_add(&calld->read_slice_buffer,
- gpr_slice_ref(md->value->slice));
+ grpc_slice_buffer_add(&calld->read_slice_buffer,
+ grpc_slice_ref(md->value->slice));
grpc_slice_buffer_stream_init(&calld->read_stream,
&calld->read_slice_buffer, 0);
return NULL;
@@ -255,7 +272,7 @@ static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
}
}
-static void hs_mutate_op(grpc_call_element *elem,
+static void hs_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_transport_stream_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
@@ -291,6 +308,12 @@ static void hs_mutate_op(grpc_call_element *elem,
op->on_complete = &calld->hs_on_complete;
}
}
+
+ if (op->send_trailing_metadata) {
+ server_filter_args a = {elem, exec_ctx};
+ grpc_metadata_batch_filter(op->send_trailing_metadata,
+ server_filter_outgoing_metadata, &a);
+ }
}
static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -298,7 +321,7 @@ static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
GPR_TIMER_BEGIN("hs_start_transport_op", 0);
- hs_mutate_op(elem, op);
+ hs_mutate_op(exec_ctx, elem, op);
grpc_call_next_op(exec_ctx, elem, op);
GPR_TIMER_END("hs_start_transport_op", 0);
}
@@ -314,13 +337,17 @@ static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem);
grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem);
+ grpc_slice_buffer_init(&calld->read_slice_buffer);
return GRPC_ERROR_NONE;
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_final_info *final_info,
- void *ignored) {}
+ void *ignored) {
+ call_data *calld = elem->call_data;
+ grpc_slice_buffer_destroy(&calld->read_slice_buffer);
+}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
@@ -344,4 +371,5 @@ const grpc_channel_filter grpc_http_server_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"http-server"};
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 7dc5ae0df1..1cf68d790d 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -34,16 +34,14 @@
#include <limits.h>
#include <string.h>
+#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/transport/method_config.h"
-
-#define DEFAULT_MAX_SEND_MESSAGE_LENGTH -1 // Unlimited.
-// The protobuf library will (by default) start warning at 100 megs.
-#define DEFAULT_MAX_RECV_MESSAGE_LENGTH (4 * 1024 * 1024)
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/service_config.h"
typedef struct message_size_limits {
int max_send_size;
@@ -56,30 +54,29 @@ static void* message_size_limits_copy(void* value) {
return new_value;
}
-static int message_size_limits_cmp(void* value1, void* value2) {
- const message_size_limits* v1 = value1;
- const message_size_limits* v2 = value2;
- if (v1->max_send_size > v2->max_send_size) return 1;
- if (v1->max_send_size < v2->max_send_size) return -1;
- if (v1->max_recv_size > v2->max_recv_size) return 1;
- if (v1->max_recv_size < v2->max_recv_size) return -1;
- return 0;
-}
-
static const grpc_mdstr_hash_table_vtable message_size_limits_vtable = {
- gpr_free, message_size_limits_copy, message_size_limits_cmp};
-
-static void* method_config_convert_value(
- const grpc_method_config* method_config) {
+ gpr_free, message_size_limits_copy};
+
+static void* message_size_limits_create_from_json(const grpc_json* json) {
+ int max_request_message_bytes = -1;
+ int max_response_message_bytes = -1;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) continue;
+ if (strcmp(field->key, "maxRequestMessageBytes") == 0) {
+ if (max_request_message_bytes >= 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ max_request_message_bytes = gpr_parse_nonnegative_int(field->value);
+ if (max_request_message_bytes == -1) return NULL;
+ } else if (strcmp(field->key, "maxResponseMessageBytes") == 0) {
+ if (max_response_message_bytes >= 0) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ max_response_message_bytes = gpr_parse_nonnegative_int(field->value);
+ if (max_response_message_bytes == -1) return NULL;
+ }
+ }
message_size_limits* value = gpr_malloc(sizeof(message_size_limits));
- const int32_t* max_request_message_bytes =
- grpc_method_config_get_max_request_message_bytes(method_config);
- value->max_send_size =
- max_request_message_bytes != NULL ? *max_request_message_bytes : -1;
- const int32_t* max_response_message_bytes =
- grpc_method_config_get_max_response_message_bytes(method_config);
- value->max_recv_size =
- max_response_message_bytes != NULL ? *max_response_message_bytes : -1;
+ value->max_send_size = max_request_message_bytes;
+ value->max_recv_size = max_response_message_bytes;
return value;
}
@@ -141,7 +138,7 @@ static void start_transport_stream_op(grpc_exec_ctx* exec_ctx,
char* message_string;
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %d)",
op->send_message->length, calld->max_send_size);
- gpr_slice message = gpr_slice_from_copied_string(message_string);
+ grpc_slice message = grpc_slice_from_copied_string(message_string);
gpr_free(message_string);
grpc_call_element_send_close_with_message(
exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message);
@@ -201,20 +198,20 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
GPR_ASSERT(!args->is_last);
channel_data* chand = elem->channel_data;
memset(chand, 0, sizeof(*chand));
- chand->max_send_size = DEFAULT_MAX_SEND_MESSAGE_LENGTH;
- chand->max_recv_size = DEFAULT_MAX_RECV_MESSAGE_LENGTH;
+ chand->max_send_size = GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH;
+ chand->max_recv_size = GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH;
for (size_t i = 0; i < args->channel_args->num_args; ++i) {
if (strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) {
- const grpc_integer_options options = {DEFAULT_MAX_SEND_MESSAGE_LENGTH, 0,
- INT_MAX};
+ const grpc_integer_options options = {
+ GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH, 0, INT_MAX};
chand->max_send_size =
grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
}
if (strcmp(args->channel_args->args[i].key,
GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) {
- const grpc_integer_options options = {DEFAULT_MAX_RECV_MESSAGE_LENGTH, 0,
- INT_MAX};
+ const grpc_integer_options options = {
+ GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH, 0, INT_MAX};
chand->max_recv_size =
grpc_channel_arg_get_integer(&args->channel_args->args[i], options);
}
@@ -223,10 +220,16 @@ static void init_channel_elem(grpc_exec_ctx* exec_ctx,
const grpc_arg* channel_arg =
grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG);
if (channel_arg != NULL) {
- GPR_ASSERT(channel_arg->type == GRPC_ARG_POINTER);
- chand->method_limit_table = grpc_method_config_table_convert(
- (grpc_method_config_table*)channel_arg->value.pointer.p,
- method_config_convert_value, &message_size_limits_vtable);
+ GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
+ grpc_service_config* service_config =
+ grpc_service_config_create(channel_arg->value.string);
+ if (service_config != NULL) {
+ chand->method_limit_table =
+ grpc_service_config_create_method_config_table(
+ service_config, message_size_limits_create_from_json,
+ &message_size_limits_vtable);
+ grpc_service_config_destroy(service_config);
+ }
}
}
@@ -248,4 +251,5 @@ const grpc_channel_filter grpc_message_size_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"message_size"};
diff --git a/src/core/lib/compression/message_compress.c b/src/core/lib/compression/message_compress.c
index cbe0b5a285..6c245acf61 100644
--- a/src/core/lib/compression/message_compress.c
+++ b/src/core/lib/compression/message_compress.c
@@ -42,31 +42,31 @@
#define OUTPUT_BLOCK_SIZE 1024
-static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
- gpr_slice_buffer* output,
+static int zlib_body(z_stream* zs, grpc_slice_buffer* input,
+ grpc_slice_buffer* output,
int (*flate)(z_stream* zs, int flush)) {
int r;
int flush;
size_t i;
- gpr_slice outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
+ grpc_slice outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE);
const uInt uint_max = ~(uInt)0;
- GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
- zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
- zs->next_out = GPR_SLICE_START_PTR(outbuf);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
+ zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
+ zs->next_out = GRPC_SLICE_START_PTR(outbuf);
flush = Z_NO_FLUSH;
for (i = 0; i < input->count; i++) {
if (i == input->count - 1) flush = Z_FINISH;
- GPR_ASSERT(GPR_SLICE_LENGTH(input->slices[i]) <= uint_max);
- zs->avail_in = (uInt)GPR_SLICE_LENGTH(input->slices[i]);
- zs->next_in = GPR_SLICE_START_PTR(input->slices[i]);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(input->slices[i]) <= uint_max);
+ zs->avail_in = (uInt)GRPC_SLICE_LENGTH(input->slices[i]);
+ zs->next_in = GRPC_SLICE_START_PTR(input->slices[i]);
do {
if (zs->avail_out == 0) {
- gpr_slice_buffer_add_indexed(output, outbuf);
- outbuf = gpr_slice_malloc(OUTPUT_BLOCK_SIZE);
- GPR_ASSERT(GPR_SLICE_LENGTH(outbuf) <= uint_max);
- zs->avail_out = (uInt)GPR_SLICE_LENGTH(outbuf);
- zs->next_out = GPR_SLICE_START_PTR(outbuf);
+ grpc_slice_buffer_add_indexed(output, outbuf);
+ outbuf = grpc_slice_malloc(OUTPUT_BLOCK_SIZE);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(outbuf) <= uint_max);
+ zs->avail_out = (uInt)GRPC_SLICE_LENGTH(outbuf);
+ zs->next_out = GRPC_SLICE_START_PTR(outbuf);
}
r = flate(zs, flush);
if (r < 0 && r != Z_BUF_ERROR /* not fatal */) {
@@ -82,12 +82,12 @@ static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
GPR_ASSERT(outbuf.refcount);
outbuf.data.refcounted.length -= zs->avail_out;
- gpr_slice_buffer_add_indexed(output, outbuf);
+ grpc_slice_buffer_add_indexed(output, outbuf);
return 1;
error:
- gpr_slice_unref(outbuf);
+ grpc_slice_unref(outbuf);
return 0;
}
@@ -97,7 +97,7 @@ static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
-static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
+static int zlib_compress(grpc_slice_buffer* input, grpc_slice_buffer* output,
int gzip) {
z_stream zs;
int r;
@@ -113,7 +113,7 @@ static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
if (!r) {
for (i = count_before; i < output->count; i++) {
- gpr_slice_unref(output->slices[i]);
+ grpc_slice_unref(output->slices[i]);
}
output->count = count_before;
output->length = length_before;
@@ -122,7 +122,7 @@ static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
return r;
}
-static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
+static int zlib_decompress(grpc_slice_buffer* input, grpc_slice_buffer* output,
int gzip) {
z_stream zs;
int r;
@@ -137,7 +137,7 @@ static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
r = zlib_body(&zs, input, output, inflate);
if (!r) {
for (i = count_before; i < output->count; i++) {
- gpr_slice_unref(output->slices[i]);
+ grpc_slice_unref(output->slices[i]);
}
output->count = count_before;
output->length = length_before;
@@ -146,16 +146,16 @@ static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
return r;
}
-static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
+static int copy(grpc_slice_buffer* input, grpc_slice_buffer* output) {
size_t i;
for (i = 0; i < input->count; i++) {
- gpr_slice_buffer_add(output, gpr_slice_ref(input->slices[i]));
+ grpc_slice_buffer_add(output, grpc_slice_ref(input->slices[i]));
}
return 1;
}
static int compress_inner(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output) {
+ grpc_slice_buffer* input, grpc_slice_buffer* output) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
/* the fallback path always needs to be send uncompressed: we simply
@@ -173,7 +173,7 @@ static int compress_inner(grpc_compression_algorithm algorithm,
}
int grpc_msg_compress(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output) {
+ grpc_slice_buffer* input, grpc_slice_buffer* output) {
if (!compress_inner(algorithm, input, output)) {
copy(input, output);
return 0;
@@ -182,7 +182,7 @@ int grpc_msg_compress(grpc_compression_algorithm algorithm,
}
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output) {
+ grpc_slice_buffer* input, grpc_slice_buffer* output) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
return copy(input, output);
diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h
index c69eaaf006..448d36a863 100644
--- a/src/core/lib/compression/message_compress.h
+++ b/src/core/lib/compression/message_compress.h
@@ -35,18 +35,18 @@
#define GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H
#include <grpc/compression.h>
-#include <grpc/support/slice_buffer.h>
+#include <grpc/slice_buffer.h>
/* compress 'input' to 'output' using 'algorithm'.
On success, appends compressed slices to output and returns 1.
On failure, appends uncompressed slices to output and returns 0. */
int grpc_msg_compress(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output);
+ grpc_slice_buffer* input, grpc_slice_buffer* output);
/* decompress 'input' to 'output' using 'algorithm'.
On success, appends slices to output and returns 1.
On failure, output is unchanged, and returns 0. */
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output);
+ grpc_slice_buffer* input, grpc_slice_buffer* output);
#endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/lib/http/format_request.c b/src/core/lib/http/format_request.c
index e818b70113..024664b6ee 100644
--- a/src/core/lib/http/format_request.c
+++ b/src/core/lib/http/format_request.c
@@ -37,8 +37,8 @@
#include <stdio.h>
#include <string.h>
+#include <grpc/slice.h>
#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/lib/support/string.h"
@@ -65,7 +65,8 @@ static void fill_common_header(const grpc_httpcli_request *request,
}
}
-gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
+grpc_slice grpc_httpcli_format_get_request(
+ const grpc_httpcli_request *request) {
gpr_strvec out;
char *flat;
size_t flat_len;
@@ -78,12 +79,12 @@ gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request) {
flat = gpr_strvec_flatten(&out, &flat_len);
gpr_strvec_destroy(&out);
- return gpr_slice_new(flat, flat_len, gpr_free);
+ return grpc_slice_new(flat, flat_len, gpr_free);
}
-gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
- const char *body_bytes,
- size_t body_size) {
+grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+ const char *body_bytes,
+ size_t body_size) {
gpr_strvec out;
char *tmp;
size_t out_len;
@@ -117,10 +118,10 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
out_len += body_size;
}
- return gpr_slice_new(tmp, out_len, gpr_free);
+ return grpc_slice_new(tmp, out_len, gpr_free);
}
-gpr_slice grpc_httpcli_format_connect_request(
+grpc_slice grpc_httpcli_format_connect_request(
const grpc_httpcli_request *request) {
gpr_strvec out;
gpr_strvec_init(&out);
@@ -130,5 +131,5 @@ gpr_slice grpc_httpcli_format_connect_request(
size_t flat_len;
char *flat = gpr_strvec_flatten(&out, &flat_len);
gpr_strvec_destroy(&out);
- return gpr_slice_new(flat, flat_len, gpr_free);
+ return grpc_slice_new(flat, flat_len, gpr_free);
}
diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h
index 7abd55f2f7..1c8e3f68c5 100644
--- a/src/core/lib/http/format_request.h
+++ b/src/core/lib/http/format_request.h
@@ -34,14 +34,14 @@
#ifndef GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
#define GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/lib/http/httpcli.h"
-gpr_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
-gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
- const char *body_bytes,
- size_t body_size);
-gpr_slice grpc_httpcli_format_connect_request(
+grpc_slice grpc_httpcli_format_get_request(const grpc_httpcli_request *request);
+grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
+ const char *body_bytes,
+ size_t body_size);
+grpc_slice grpc_httpcli_format_connect_request(
const grpc_httpcli_request *request);
#endif /* GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H */
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index 411e669b53..fdb8abaa2d 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -50,7 +50,7 @@
#include "src/core/lib/support/string.h"
typedef struct {
- gpr_slice request_text;
+ grpc_slice request_text;
grpc_http_parser parser;
grpc_resolved_addresses *addresses;
size_t next_address;
@@ -64,8 +64,8 @@ typedef struct {
grpc_httpcli_context *context;
grpc_polling_entity *pollent;
grpc_iomgr_object iomgr_obj;
- gpr_slice_buffer incoming;
- gpr_slice_buffer outgoing;
+ grpc_slice_buffer incoming;
+ grpc_slice_buffer outgoing;
grpc_closure on_read;
grpc_closure done_write;
grpc_closure connected;
@@ -111,12 +111,12 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
if (req->ep != NULL) {
grpc_endpoint_destroy(exec_ctx, req->ep);
}
- gpr_slice_unref(req->request_text);
+ grpc_slice_unref(req->request_text);
gpr_free(req->host);
gpr_free(req->ssl_host_override);
grpc_iomgr_unregister_object(&req->iomgr_obj);
- gpr_slice_buffer_destroy(&req->incoming);
- gpr_slice_buffer_destroy(&req->outgoing);
+ grpc_slice_buffer_destroy(&req->incoming);
+ grpc_slice_buffer_destroy(&req->outgoing);
GRPC_ERROR_UNREF(req->overall_error);
grpc_resource_quota_internal_unref(exec_ctx, req->resource_quota);
gpr_free(req);
@@ -144,7 +144,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
size_t i;
for (i = 0; i < req->incoming.count; i++) {
- if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
+ if (GRPC_SLICE_LENGTH(req->incoming.slices[i])) {
req->have_read_byte = 1;
grpc_error *err =
grpc_http_parser_parse(&req->parser, req->incoming.slices[i], NULL);
@@ -178,8 +178,8 @@ static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
}
static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) {
- gpr_slice_ref(req->request_text);
- gpr_slice_buffer_add(&req->outgoing, req->request_text);
+ grpc_slice_ref(req->request_text);
+ grpc_slice_buffer_add(&req->outgoing, req->request_text);
grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write);
}
@@ -253,7 +253,7 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx,
const grpc_httpcli_request *request,
gpr_timespec deadline, grpc_closure *on_done,
grpc_httpcli_response *response,
- const char *name, gpr_slice request_text) {
+ const char *name, grpc_slice request_text) {
internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req));
req->request_text = request_text;
@@ -268,8 +268,8 @@ static void internal_request_begin(grpc_exec_ctx *exec_ctx,
req->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
grpc_closure_init(&req->on_read, on_read, req);
grpc_closure_init(&req->done_write, done_write, req);
- gpr_slice_buffer_init(&req->incoming);
- gpr_slice_buffer_init(&req->outgoing);
+ grpc_slice_buffer_init(&req->incoming);
+ grpc_slice_buffer_init(&req->outgoing);
grpc_iomgr_register_object(&req->iomgr_obj, name);
req->host = gpr_strdup(request->host);
req->ssl_host_override = gpr_strdup(request->ssl_host_override);
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 0006e809a6..0ab34d00e4 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -38,7 +38,9 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include "src/core/lib/security/transport/handshake.h"
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/ssl_transport_security.h"
@@ -58,52 +60,42 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
gpr_free(sc);
}
-static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
- grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer,
- gpr_timespec deadline,
- grpc_security_handshake_done_cb cb,
- void *user_data) {
+static void httpcli_ssl_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+ grpc_handshake_manager *handshake_mgr) {
grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc;
- tsi_result result = TSI_OK;
- tsi_handshaker *handshaker;
- if (c->handshaker_factory == NULL) {
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
- return;
- }
- result = tsi_ssl_handshaker_factory_create_handshaker(
- c->handshaker_factory, c->secure_peer_name, &handshaker);
- if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
- tsi_result_to_string(result));
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
- } else {
- grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
- nonsecure_endpoint, read_buffer, deadline, cb,
- user_data);
+ tsi_handshaker *handshaker = NULL;
+ if (c->handshaker_factory != NULL) {
+ tsi_result result = tsi_ssl_handshaker_factory_create_handshaker(
+ c->handshaker_factory, c->secure_peer_name, &handshaker);
+ if (result != TSI_OK) {
+ gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+ tsi_result_to_string(result));
+ }
}
+ grpc_security_create_handshakers(exec_ctx, handshaker, &sc->base,
+ handshake_mgr);
}
static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
- grpc_security_peer_check_cb cb,
- void *user_data) {
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_connector *)sc;
- grpc_security_status status = GRPC_SECURITY_OK;
+ grpc_error *error = GRPC_ERROR_NONE;
/* Check the peer name. */
if (c->secure_peer_name != NULL &&
!tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
- gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate",
- c->secure_peer_name);
- status = GRPC_SECURITY_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
+ c->secure_peer_name);
+ error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
}
- cb(exec_ctx, user_data, status, NULL);
+ grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
@@ -140,7 +132,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
*sc = NULL;
return GRPC_SECURITY_ERROR;
}
- c->base.do_handshake = httpcli_ssl_do_handshake;
+ c->base.create_handshakers = httpcli_ssl_create_handshakers;
*sc = &c->base;
return GRPC_SECURITY_OK;
}
@@ -150,19 +142,25 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
typedef struct {
void (*func)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint);
void *arg;
+ grpc_handshake_manager *handshake_mgr;
} on_done_closure;
-static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
- grpc_security_status status,
- grpc_endpoint *secure_endpoint,
- grpc_auth_context *auth_context) {
- on_done_closure *c = rp;
- if (status != GRPC_SECURITY_OK) {
- gpr_log(GPR_ERROR, "Secure transport setup failed with error %d.", status);
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_handshaker_args *args = arg;
+ on_done_closure *c = args->user_data;
+ if (error != GRPC_ERROR_NONE) {
+ const char *msg = grpc_error_string(error);
+ gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
+ grpc_error_free_string(msg);
c->func(exec_ctx, c->arg, NULL);
} else {
- c->func(exec_ctx, c->arg, secure_endpoint);
+ grpc_channel_args_destroy(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);
}
@@ -183,11 +181,15 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
}
c->func = on_done;
c->arg = arg;
+ c->handshake_mgr = grpc_handshake_manager_create();
GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK);
- grpc_channel_security_connector_do_handshake(
- exec_ctx, sc, tcp, NULL, deadline, on_secure_transport_setup_done, c);
+ grpc_channel_security_connector_create_handshakers(exec_ctx, sc,
+ c->handshake_mgr);
+ grpc_handshake_manager_do_handshake(
+ exec_ctx, c->handshake_mgr, tcp, NULL /* channel_args */, deadline,
+ NULL /* acceptor */, on_handshake_done, c /* user_data */);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
}
diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c
index be9e9b6b63..2f84adc187 100644
--- a/src/core/lib/http/parser.c
+++ b/src/core/lib/http/parser.c
@@ -333,12 +333,12 @@ void grpc_http_response_destroy(grpc_http_response *response) {
gpr_free(response->hdrs);
}
-grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice,
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, grpc_slice slice,
size_t *start_of_body) {
- for (size_t i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
+ for (size_t i = 0; i < GRPC_SLICE_LENGTH(slice); i++) {
bool found_body_start = false;
grpc_error *err =
- addbyte(parser, GPR_SLICE_START_PTR(slice)[i], &found_body_start);
+ addbyte(parser, GRPC_SLICE_START_PTR(slice)[i], &found_body_start);
if (err != GRPC_ERROR_NONE) return err;
if (found_body_start && start_of_body != NULL) *start_of_body = i + 1;
}
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
index fab42979cd..a68011dd43 100644
--- a/src/core/lib/http/parser.h
+++ b/src/core/lib/http/parser.h
@@ -34,8 +34,8 @@
#ifndef GRPC_CORE_LIB_HTTP_PARSER_H
#define GRPC_CORE_LIB_HTTP_PARSER_H
+#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
#include "src/core/lib/iomgr/error.h"
/* Maximum length of a header string of the form 'Key: Value\r\n' */
@@ -114,7 +114,7 @@ void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
void grpc_http_parser_destroy(grpc_http_parser *parser);
/* Sets \a start_of_body to the offset in \a slice of the start of the body. */
-grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice,
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, grpc_slice slice,
size_t *start_of_body);
grpc_error *grpc_http_parser_eof(grpc_http_parser *parser);
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
index 60ee14eb23..cfc67020ae 100644
--- a/src/core/lib/iomgr/combiner.c
+++ b/src/core/lib/iomgr/combiner.c
@@ -90,6 +90,12 @@ static bool is_covered_by_poller(grpc_combiner *lock) {
gpr_atm_acq_load(&lock->elements_covered_by_poller) > 0;
}
+#define IS_COVERED_BY_POLLER_FMT "(final=%d elems=%" PRIdPTR ")->%d"
+#define IS_COVERED_BY_POLLER_ARGS(lock) \
+ (lock)->final_list_covered_by_poller, \
+ gpr_atm_acq_load(&(lock)->elements_covered_by_poller), \
+ is_covered_by_poller((lock))
+
grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) {
grpc_combiner *lock = gpr_malloc(sizeof(*lock));
lock->next_combiner_on_this_exec_ctx = NULL;
@@ -197,9 +203,10 @@ bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) {
GRPC_COMBINER_TRACE(
gpr_log(GPR_DEBUG,
"C:%p grpc_combiner_continue_exec_ctx workqueue=%p "
- "is_covered_by_poller=%d exec_ctx_ready_to_finish=%d "
+ "is_covered_by_poller=" IS_COVERED_BY_POLLER_FMT
+ " exec_ctx_ready_to_finish=%d "
"time_to_execute_final_list=%d",
- lock, lock->optional_workqueue, is_covered_by_poller(lock),
+ lock, lock->optional_workqueue, IS_COVERED_BY_POLLER_ARGS(lock),
grpc_exec_ctx_ready_to_finish(exec_ctx),
lock->time_to_execute_final_list));
diff --git a/src/core/lib/iomgr/endpoint.c b/src/core/lib/iomgr/endpoint.c
index 74fa9c45df..2d300f4560 100644
--- a/src/core/lib/iomgr/endpoint.c
+++ b/src/core/lib/iomgr/endpoint.c
@@ -34,12 +34,12 @@
#include "src/core/lib/iomgr/endpoint.h"
void grpc_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
- gpr_slice_buffer* slices, grpc_closure* cb) {
+ grpc_slice_buffer* slices, grpc_closure* cb) {
ep->vtable->read(exec_ctx, ep, slices, cb);
}
void grpc_endpoint_write(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
- gpr_slice_buffer* slices, grpc_closure* cb) {
+ grpc_slice_buffer* slices, grpc_closure* cb) {
ep->vtable->write(exec_ctx, ep, slices, cb);
}
@@ -66,6 +66,8 @@ char* grpc_endpoint_get_peer(grpc_endpoint* ep) {
return ep->vtable->get_peer(ep);
}
+int grpc_endpoint_get_fd(grpc_endpoint* ep) { return ep->vtable->get_fd(ep); }
+
grpc_workqueue* grpc_endpoint_get_workqueue(grpc_endpoint* ep) {
return ep->vtable->get_workqueue(ep);
}
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 0ac5486ff5..1609b64f2b 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -34,8 +34,8 @@
#ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_H
#define GRPC_CORE_LIB_IOMGR_ENDPOINT_H
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
@@ -49,9 +49,9 @@ typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
struct grpc_endpoint_vtable {
void (*read)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *slices, grpc_closure *cb);
+ grpc_slice_buffer *slices, grpc_closure *cb);
void (*write)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *slices, grpc_closure *cb);
+ grpc_slice_buffer *slices, grpc_closure *cb);
grpc_workqueue *(*get_workqueue)(grpc_endpoint *ep);
void (*add_to_pollset)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_pollset *pollset);
@@ -61,6 +61,7 @@ struct grpc_endpoint_vtable {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
grpc_resource_user *(*get_resource_user)(grpc_endpoint *ep);
char *(*get_peer)(grpc_endpoint *ep);
+ int (*get_fd)(grpc_endpoint *ep);
};
/* When data is available on the connection, calls the callback with slices.
@@ -69,10 +70,14 @@ struct grpc_endpoint_vtable {
Valid slices may be placed into \a slices even when the callback is
invoked with error != GRPC_ERROR_NONE. */
void grpc_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *slices, grpc_closure *cb);
+ grpc_slice_buffer *slices, grpc_closure *cb);
char *grpc_endpoint_get_peer(grpc_endpoint *ep);
+/* Get the file descriptor used by \a ep. Return -1 if \a ep is not using an fd.
+ */
+int grpc_endpoint_get_fd(grpc_endpoint *ep);
+
/* Retrieve a reference to the workqueue associated with this endpoint */
grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep);
@@ -87,7 +92,7 @@ grpc_workqueue *grpc_endpoint_get_workqueue(grpc_endpoint *ep);
it is a valid slice buffer.
*/
void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *slices, grpc_closure *cb);
+ grpc_slice_buffer *slices, grpc_closure *cb);
/* Causes any pending and future read/write callbacks to run immediately with
success==0 */
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index db51ec4939..07fbfd849e 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -72,6 +72,11 @@ static int grpc_polling_trace = 0; /* Disabled by default */
static int grpc_wakeup_signal = -1;
static bool is_grpc_wakeup_signal_initialized = false;
+/* TODO: sreek: Right now, this wakes up all pollers. In future we should make
+ * sure to wake up one polling thread (which can wake up other threads if
+ * needed) */
+static grpc_wakeup_fd global_wakeup_fd;
+
/* Implements the function defined in grpc_posix.h. This function might be
* called before even calling grpc_init() to set either a different signal to
* use. If signum == -1, then the use of signals is disabled */
@@ -163,7 +168,7 @@ static void fd_global_shutdown(void);
#define PI_ADD_REF(p, r) pi_add_ref((p))
#define PI_UNREF(exec_ctx, p, r) pi_unref((exec_ctx), (p))
-#endif /* !defined(GPRC_PI_REF_COUNT_DEBUG) */
+#endif /* !defined(GRPC_PI_REF_COUNT_DEBUG) */
/* This is also used as grpc_workqueue (by directly casing it) */
typedef struct polling_island {
@@ -437,9 +442,8 @@ static void polling_island_add_wakeup_fd_locked(polling_island *pi,
gpr_asprintf(&err_msg,
"epoll_ctl (epoll_fd: %d) add wakeup fd: %d failed with "
"error: %d (%s)",
- pi->epoll_fd,
- GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), errno,
- strerror(errno));
+ pi->epoll_fd, GRPC_WAKEUP_FD_GET_READ_FD(&global_wakeup_fd),
+ errno, strerror(errno));
append_error(error, GRPC_OS_ERROR(errno, err_msg), err_desc);
gpr_free(err_msg);
}
@@ -541,7 +545,7 @@ static polling_island *polling_island_create(grpc_exec_ctx *exec_ctx,
goto done;
}
- polling_island_add_wakeup_fd_locked(pi, &grpc_global_wakeup_fd, error);
+ polling_island_add_wakeup_fd_locked(pi, &global_wakeup_fd, error);
polling_island_add_wakeup_fd_locked(pi, &pi->workqueue_wakeup_fd, error);
if (initial_fd != NULL) {
@@ -843,11 +847,6 @@ static void polling_island_global_shutdown() {
* alarm 'epoch'). This wakeup_fd gives us something to alert on when such a
* case occurs. */
-/* TODO: sreek: Right now, this wakes up all pollers. In future we should make
- * sure to wake up one polling thread (which can wake up other threads if
- * needed) */
-grpc_wakeup_fd grpc_global_wakeup_fd;
-
static grpc_fd *fd_freelist = NULL;
static gpr_mu fd_freelist_mu;
@@ -1163,11 +1162,11 @@ static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_pollset);
gpr_tls_init(&g_current_thread_worker);
poller_kick_init();
- return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_init(&global_wakeup_fd);
}
static void pollset_global_shutdown(void) {
- grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd);
+ grpc_wakeup_fd_destroy(&global_wakeup_fd);
gpr_tls_destroy(&g_current_thread_pollset);
gpr_tls_destroy(&g_current_thread_worker);
}
@@ -1274,7 +1273,7 @@ static grpc_error *pollset_kick(grpc_pollset *p,
}
static grpc_error *kick_poller(void) {
- return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
}
static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
@@ -1501,13 +1500,11 @@ static void pollset_work_and_unlock(grpc_exec_ctx *exec_ctx,
for (int i = 0; i < ep_rv; ++i) {
void *data_ptr = ep_ev[i].data.ptr;
- if (data_ptr == &grpc_global_wakeup_fd) {
- append_error(error,
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd),
+ if (data_ptr == &global_wakeup_fd) {
+ append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
err_desc);
} else if (data_ptr == &pi->workqueue_wakeup_fd) {
- append_error(error,
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd),
+ append_error(error, grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd),
err_desc);
maybe_do_workqueue_work(exec_ctx, pi);
} else if (data_ptr == &polling_island_wakeup_fd) {
diff --git a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c b/src/core/lib/iomgr/ev_poll_and_epoll_posix.c
deleted file mode 100644
index bf51404203..0000000000
--- a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c
+++ /dev/null
@@ -1,2076 +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.
- *
- */
-
-/* This file will be removed shortly: it's here to keep refactoring
- * steps simple and auditable.
- * It's the combination of the old files:
- * - fd_posix.{h,c}
- * - pollset_posix.{h,c}
- * - pullset_multipoller_with_{poll,epoll}.{h,c}
- * The new version will be split into:
- * - ev_poll_posix.{h,c}
- * - ev_epoll_posix.{h,c}
- */
-
-#include "src/core/lib/iomgr/port.h"
-
-#ifdef GRPC_POSIX_SOCKET
-
-#include "src/core/lib/iomgr/ev_poll_and_epoll_posix.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <poll.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/tls.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/lib/iomgr/iomgr_internal.h"
-#include "src/core/lib/iomgr/wakeup_fd_posix.h"
-#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
-
-/*******************************************************************************
- * FD declarations
- */
-
-typedef struct grpc_fd_watcher {
- struct grpc_fd_watcher *next;
- struct grpc_fd_watcher *prev;
- grpc_pollset *pollset;
- grpc_pollset_worker *worker;
- grpc_fd *fd;
-} grpc_fd_watcher;
-
-struct grpc_fd {
- int fd;
- /* refst format:
- bit0: 1=active/0=orphaned
- bit1-n: refcount
- meaning that mostly we ref by two to avoid altering the orphaned bit,
- and just unref by 1 when we're ready to flag the object as orphaned */
- gpr_atm refst;
-
- gpr_mu mu;
- int shutdown;
- int closed;
- int released;
-
- /* The watcher list.
-
- The following watcher related fields are protected by watcher_mu.
-
- An fd_watcher is an ephemeral object created when an fd wants to
- begin polling, and destroyed after the poll.
-
- It denotes the fd's interest in whether to read poll or write poll
- or both or neither on this fd.
-
- If a watcher is asked to poll for reads or writes, the read_watcher
- or write_watcher fields are set respectively. A watcher may be asked
- to poll for both, in which case both fields will be set.
-
- read_watcher and write_watcher may be NULL if no watcher has been
- asked to poll for reads or writes.
-
- If an fd_watcher is not asked to poll for reads or writes, it's added
- to a linked list of inactive watchers, rooted at inactive_watcher_root.
- If at a later time there becomes need of a poller to poll, one of
- the inactive pollers may be kicked out of their poll loops to take
- that responsibility. */
- grpc_fd_watcher inactive_watcher_root;
- grpc_fd_watcher *read_watcher;
- grpc_fd_watcher *write_watcher;
-
- grpc_closure *read_closure;
- grpc_closure *write_closure;
-
- struct grpc_fd *freelist_next;
-
- grpc_closure *on_done_closure;
-
- grpc_iomgr_object iomgr_object;
-
- /* The pollset that last noticed and notified that the fd is readable */
- grpc_pollset *read_notifier_pollset;
-};
-
-/* Begin polling on an fd.
- Registers that the given pollset is interested in this fd - so that if read
- or writability interest changes, the pollset can be kicked to pick up that
- new interest.
- Return value is:
- (fd_needs_read? read_mask : 0) | (fd_needs_write? write_mask : 0)
- i.e. a combination of read_mask and write_mask determined by the fd's current
- interest in said events.
- Polling strategies that do not need to alter their behavior depending on the
- fd's current interest (such as epoll) do not need to call this function.
- MUST NOT be called with a pollset lock taken */
-static uint32_t fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
- grpc_pollset_worker *worker, uint32_t read_mask,
- uint32_t write_mask, grpc_fd_watcher *rec);
-/* Complete polling previously started with fd_begin_poll
- MUST NOT be called with a pollset lock taken
- if got_read or got_write are 1, also does the become_{readable,writable} as
- appropriate. */
-static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec,
- int got_read, int got_write,
- grpc_pollset *read_notifier_pollset);
-
-/* Return 1 if this fd is orphaned, 0 otherwise */
-static bool fd_is_orphaned(grpc_fd *fd);
-
-/* Reference counting for fds */
-/*#define GRPC_FD_REF_COUNT_DEBUG*/
-#ifdef GRPC_FD_REF_COUNT_DEBUG
-static void fd_ref(grpc_fd *fd, const char *reason, const char *file, int line);
-static void fd_unref(grpc_fd *fd, const char *reason, const char *file,
- int line);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd, reason, __FILE__, __LINE__)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd, reason, __FILE__, __LINE__)
-#else
-static void fd_ref(grpc_fd *fd);
-static void fd_unref(grpc_fd *fd);
-#define GRPC_FD_REF(fd, reason) fd_ref(fd)
-#define GRPC_FD_UNREF(fd, reason) fd_unref(fd)
-#endif
-
-static void fd_global_init(void);
-static void fd_global_shutdown(void);
-
-#define CLOSURE_NOT_READY ((grpc_closure *)0)
-#define CLOSURE_READY ((grpc_closure *)1)
-
-/*******************************************************************************
- * pollset declarations
- */
-
-typedef struct grpc_pollset_vtable grpc_pollset_vtable;
-
-typedef struct grpc_cached_wakeup_fd {
- grpc_wakeup_fd fd;
- struct grpc_cached_wakeup_fd *next;
-} grpc_cached_wakeup_fd;
-
-struct grpc_pollset_worker {
- grpc_cached_wakeup_fd *wakeup_fd;
- int reevaluate_polling_on_wakeup;
- int kicked_specifically;
- struct grpc_pollset_worker *next;
- struct grpc_pollset_worker *prev;
-};
-
-struct grpc_pollset {
- /* pollsets under posix can mutate representation as fds are added and
- removed.
- For example, we may choose a poll() based implementation on linux for
- few fds, and an epoll() based implementation for many fds */
- const grpc_pollset_vtable *vtable;
- gpr_mu mu;
- grpc_pollset_worker root_worker;
- int in_flight_cbs;
- int shutting_down;
- int called_shutdown;
- int kicked_without_pollers;
- grpc_closure *shutdown_done;
- grpc_closure_list idle_jobs;
- union {
- int fd;
- void *ptr;
- } data;
- /* Local cache of eventfds for workers */
- grpc_cached_wakeup_fd *local_wakeup_cache;
-};
-
-struct grpc_pollset_vtable {
- void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- struct grpc_fd *fd, int and_unlock_pollset);
- grpc_error *(*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_pollset_worker *worker,
- gpr_timespec deadline, gpr_timespec now);
- void (*finish_shutdown)(grpc_pollset *pollset);
- void (*destroy)(grpc_pollset *pollset);
-};
-
-/* Add an fd to a pollset */
-static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- struct grpc_fd *fd);
-
-static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *pollset_set, grpc_fd *fd);
-
-/* Convert a timespec to milliseconds:
- - very small or negative poll times are clamped to zero to do a
- non-blocking poll (which becomes spin polling)
- - other small values are rounded up to one millisecond
- - longer than a millisecond polls are rounded up to the next nearest
- millisecond to avoid spinning
- - infinite timeouts are converted to -1 */
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
- gpr_timespec now);
-
-/* Allow kick to wakeup the currently polling worker */
-#define GRPC_POLLSET_CAN_KICK_SELF 1
-/* Force the wakee to repoll when awoken */
-#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
-/* As per pollset_kick, with an extended set of flags (defined above)
- -- mostly for fd_posix's use. */
-static grpc_error *pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags) GRPC_MUST_USE_RESULT;
-
-/* turn a pollset into a multipoller: platform specific */
-typedef void (*platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- struct grpc_fd **fds,
- size_t fd_count);
-static platform_become_multipoller_type platform_become_multipoller;
-
-/* Return 1 if the pollset has active threads in pollset_work (pollset must
- * be locked) */
-static int pollset_has_workers(grpc_pollset *pollset);
-
-static void remove_fd_from_all_epoll_sets(int fd);
-
-/*******************************************************************************
- * pollset_set definitions
- */
-
-struct grpc_pollset_set {
- gpr_mu mu;
-
- size_t pollset_count;
- size_t pollset_capacity;
- grpc_pollset **pollsets;
-
- size_t pollset_set_count;
- size_t pollset_set_capacity;
- struct grpc_pollset_set **pollset_sets;
-
- size_t fd_count;
- size_t fd_capacity;
- grpc_fd **fds;
-};
-
-/*******************************************************************************
- * fd_posix.c
- */
-
-/* We need to keep a freelist not because of any concerns of malloc performance
- * but instead so that implementations with multiple threads in (for example)
- * epoll_wait deal with the race between pollset removal and incoming poll
- * notifications.
- *
- * The problem is that the poller ultimately holds a reference to this
- * object, so it is very difficult to know when is safe to free it, at least
- * without some expensive synchronization.
- *
- * If we keep the object freelisted, in the worst case losing this race just
- * becomes a spurious read notification on a reused fd.
- */
-/* TODO(klempner): We could use some form of polling generation count to know
- * when these are safe to free. */
-/* TODO(klempner): Consider disabling freelisting if we don't have multiple
- * threads in poll on the same fd */
-/* TODO(klempner): Batch these allocations to reduce fragmentation */
-static grpc_fd *fd_freelist = NULL;
-static gpr_mu fd_freelist_mu;
-
-static void freelist_fd(grpc_fd *fd) {
- gpr_mu_lock(&fd_freelist_mu);
- fd->freelist_next = fd_freelist;
- fd_freelist = fd;
- grpc_iomgr_unregister_object(&fd->iomgr_object);
- gpr_mu_unlock(&fd_freelist_mu);
-}
-
-static grpc_fd *alloc_fd(int fd) {
- grpc_fd *r = NULL;
- gpr_mu_lock(&fd_freelist_mu);
- if (fd_freelist != NULL) {
- r = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- }
- gpr_mu_unlock(&fd_freelist_mu);
- if (r == NULL) {
- r = gpr_malloc(sizeof(grpc_fd));
- gpr_mu_init(&r->mu);
- }
-
- gpr_mu_lock(&r->mu);
- gpr_atm_rel_store(&r->refst, 1);
- r->shutdown = 0;
- r->read_closure = CLOSURE_NOT_READY;
- r->write_closure = CLOSURE_NOT_READY;
- r->fd = fd;
- r->inactive_watcher_root.next = r->inactive_watcher_root.prev =
- &r->inactive_watcher_root;
- r->freelist_next = NULL;
- r->read_watcher = r->write_watcher = NULL;
- r->on_done_closure = NULL;
- r->closed = 0;
- r->released = 0;
- r->read_notifier_pollset = NULL;
- gpr_mu_unlock(&r->mu);
- return r;
-}
-
-static void destroy(grpc_fd *fd) {
- gpr_mu_destroy(&fd->mu);
- gpr_free(fd);
-}
-
-#ifdef GRPC_FD_REF_COUNT_DEBUG
-#define REF_BY(fd, n, reason) ref_by(fd, n, reason, __FILE__, __LINE__)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
-static void ref_by(grpc_fd *fd, int n, const char *reason, const char *file,
- int line) {
- gpr_log(GPR_DEBUG, "FD %d %p ref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
- gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) + n, reason, file, line);
-#else
-#define REF_BY(fd, n, reason) ref_by(fd, n)
-#define UNREF_BY(fd, n, reason) unref_by(fd, n)
-static void ref_by(grpc_fd *fd, int n) {
-#endif
- GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&fd->refst, n) > 0);
-}
-
-#ifdef GRPC_FD_REF_COUNT_DEBUG
-static void unref_by(grpc_fd *fd, int n, const char *reason, const char *file,
- int line) {
- gpr_atm old;
- gpr_log(GPR_DEBUG, "FD %d %p unref %d %d -> %d [%s; %s:%d]", fd->fd, fd, n,
- gpr_atm_no_barrier_load(&fd->refst),
- gpr_atm_no_barrier_load(&fd->refst) - n, reason, file, line);
-#else
-static void unref_by(grpc_fd *fd, int n) {
- gpr_atm old;
-#endif
- old = gpr_atm_full_fetch_add(&fd->refst, -n);
- if (old == n) {
- freelist_fd(fd);
- } else {
- GPR_ASSERT(old > n);
- }
-}
-
-static void fd_global_init(void) { gpr_mu_init(&fd_freelist_mu); }
-
-static void fd_global_shutdown(void) {
- gpr_mu_lock(&fd_freelist_mu);
- gpr_mu_unlock(&fd_freelist_mu);
- while (fd_freelist != NULL) {
- grpc_fd *fd = fd_freelist;
- fd_freelist = fd_freelist->freelist_next;
- destroy(fd);
- }
- gpr_mu_destroy(&fd_freelist_mu);
-}
-
-static grpc_fd *fd_create(int fd, const char *name) {
- grpc_fd *r = alloc_fd(fd);
- char *name2;
- gpr_asprintf(&name2, "%s fd=%d", name, fd);
- grpc_iomgr_register_object(&r->iomgr_object, name2);
- gpr_free(name2);
-#ifdef GRPC_FD_REF_COUNT_DEBUG
- gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name);
-#endif
- return r;
-}
-
-static bool fd_is_orphaned(grpc_fd *fd) {
- return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
-}
-
-static grpc_error *pollset_kick_locked(grpc_fd_watcher *watcher) {
- gpr_mu_lock(&watcher->pollset->mu);
- GPR_ASSERT(watcher->worker);
- grpc_error *err = pollset_kick_ext(watcher->pollset, watcher->worker,
- GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
- gpr_mu_unlock(&watcher->pollset->mu);
- return err;
-}
-
-static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
- if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) {
- pollset_kick_locked(fd->inactive_watcher_root.next);
- } else if (fd->read_watcher) {
- pollset_kick_locked(fd->read_watcher);
- } else if (fd->write_watcher) {
- pollset_kick_locked(fd->write_watcher);
- }
-}
-
-static void wake_all_watchers_locked(grpc_fd *fd) {
- grpc_fd_watcher *watcher;
- for (watcher = fd->inactive_watcher_root.next;
- watcher != &fd->inactive_watcher_root; watcher = watcher->next) {
- pollset_kick_locked(watcher);
- }
- if (fd->read_watcher) {
- pollset_kick_locked(fd->read_watcher);
- }
- if (fd->write_watcher && fd->write_watcher != fd->read_watcher) {
- pollset_kick_locked(fd->write_watcher);
- }
-}
-
-static int has_watchers(grpc_fd *fd) {
- return fd->read_watcher != NULL || fd->write_watcher != NULL ||
- fd->inactive_watcher_root.next != &fd->inactive_watcher_root;
-}
-
-static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- fd->closed = 1;
- if (!fd->released) {
- close(fd->fd);
- } else {
- remove_fd_from_all_epoll_sets(fd->fd);
- }
- grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
-}
-
-static int fd_wrapped_fd(grpc_fd *fd) {
- if (fd->released || fd->closed) {
- return -1;
- } else {
- return fd->fd;
- }
-}
-
-static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_closure *on_done, int *release_fd,
- const char *reason) {
- fd->on_done_closure = on_done;
- fd->released = release_fd != NULL;
- if (!fd->released) {
- shutdown(fd->fd, SHUT_RDWR);
- } else {
- *release_fd = fd->fd;
- }
- gpr_mu_lock(&fd->mu);
- REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
- if (!has_watchers(fd)) {
- close_fd_locked(exec_ctx, fd);
- } else {
- wake_all_watchers_locked(fd);
- }
- gpr_mu_unlock(&fd->mu);
- UNREF_BY(fd, 2, reason); /* drop the reference */
-}
-
-/* increment refcount by two to avoid changing the orphan bit */
-#ifdef GRPC_FD_REF_COUNT_DEBUG
-static void fd_ref(grpc_fd *fd, const char *reason, const char *file,
- int line) {
- ref_by(fd, 2, reason, file, line);
-}
-
-static void fd_unref(grpc_fd *fd, const char *reason, const char *file,
- int line) {
- unref_by(fd, 2, reason, file, line);
-}
-#else
-static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
-
-static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
-#endif
-
-static grpc_error *fd_shutdown_error(bool shutdown) {
- if (!shutdown) {
- return GRPC_ERROR_NONE;
- } else {
- return GRPC_ERROR_CREATE("FD shutdown");
- }
-}
-
-static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_closure **st, grpc_closure *closure) {
- if (fd->shutdown) {
- grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
- NULL);
- } else if (*st == CLOSURE_NOT_READY) {
- /* not ready ==> switch to a waiting state by setting the closure */
- *st = closure;
- } else if (*st == CLOSURE_READY) {
- /* already ready ==> queue the closure to run immediately */
- *st = CLOSURE_NOT_READY;
- grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
- NULL);
- maybe_wake_one_watcher_locked(fd);
- } else {
- /* upcallptr was set to a different closure. This is an error! */
- gpr_log(GPR_ERROR,
- "User called a notify_on function with a previous callback still "
- "pending");
- abort();
- }
-}
-
-/* returns 1 if state becomes not ready */
-static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_closure **st) {
- if (*st == CLOSURE_READY) {
- /* duplicate ready ==> ignore */
- return 0;
- } else if (*st == CLOSURE_NOT_READY) {
- /* not ready, and not waiting ==> flag ready */
- *st = CLOSURE_READY;
- return 0;
- } else {
- /* waiting ==> queue closure */
- grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
- *st = CLOSURE_NOT_READY;
- return 1;
- }
-}
-
-static void set_read_notifier_pollset_locked(
- grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_pollset *read_notifier_pollset) {
- fd->read_notifier_pollset = read_notifier_pollset;
-}
-
-static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- gpr_mu_lock(&fd->mu);
- /* only shutdown once */
- if (!fd->shutdown) {
- fd->shutdown = 1;
- /* signal read/write closed to OS so that future operations fail */
- shutdown(fd->fd, SHUT_RDWR);
- set_ready_locked(exec_ctx, fd, &fd->read_closure);
- set_ready_locked(exec_ctx, fd, &fd->write_closure);
- }
- gpr_mu_unlock(&fd->mu);
-}
-
-static bool fd_is_shutdown(grpc_fd *fd) {
- gpr_mu_lock(&fd->mu);
- bool r = fd->shutdown;
- gpr_mu_unlock(&fd->mu);
- return r;
-}
-
-static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_closure *closure) {
- gpr_mu_lock(&fd->mu);
- notify_on_locked(exec_ctx, fd, &fd->read_closure, closure);
- gpr_mu_unlock(&fd->mu);
-}
-
-static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_closure *closure) {
- gpr_mu_lock(&fd->mu);
- notify_on_locked(exec_ctx, fd, &fd->write_closure, closure);
- gpr_mu_unlock(&fd->mu);
-}
-
-/* Return the read-notifier pollset */
-static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
- grpc_fd *fd) {
- grpc_pollset *notifier = NULL;
-
- gpr_mu_lock(&fd->mu);
- notifier = fd->read_notifier_pollset;
- gpr_mu_unlock(&fd->mu);
-
- return notifier;
-}
-
-static uint32_t fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
- grpc_pollset_worker *worker, uint32_t read_mask,
- uint32_t write_mask, grpc_fd_watcher *watcher) {
- uint32_t mask = 0;
- grpc_closure *cur;
- int requested;
- /* keep track of pollers that have requested our events, in case they change
- */
- GRPC_FD_REF(fd, "poll");
-
- gpr_mu_lock(&fd->mu);
-
- /* if we are shutdown, then don't add to the watcher set */
- if (fd->shutdown) {
- watcher->fd = NULL;
- watcher->pollset = NULL;
- watcher->worker = NULL;
- gpr_mu_unlock(&fd->mu);
- GRPC_FD_UNREF(fd, "poll");
- return 0;
- }
-
- /* if there is nobody polling for read, but we need to, then start doing so */
- cur = fd->read_closure;
- requested = cur != CLOSURE_READY;
- if (read_mask && fd->read_watcher == NULL && requested) {
- fd->read_watcher = watcher;
- mask |= read_mask;
- }
- /* if there is nobody polling for write, but we need to, then start doing so
- */
- cur = fd->write_closure;
- requested = cur != CLOSURE_READY;
- if (write_mask && fd->write_watcher == NULL && requested) {
- fd->write_watcher = watcher;
- mask |= write_mask;
- }
- /* if not polling, remember this watcher in case we need someone to later */
- if (mask == 0 && worker != NULL) {
- watcher->next = &fd->inactive_watcher_root;
- watcher->prev = watcher->next->prev;
- watcher->next->prev = watcher->prev->next = watcher;
- }
- watcher->pollset = pollset;
- watcher->worker = worker;
- watcher->fd = fd;
- gpr_mu_unlock(&fd->mu);
-
- return mask;
-}
-
-static void fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
- int got_read, int got_write,
- grpc_pollset *read_notifier_pollset) {
- int was_polling = 0;
- int kick = 0;
- grpc_fd *fd = watcher->fd;
-
- if (fd == NULL) {
- return;
- }
-
- gpr_mu_lock(&fd->mu);
-
- if (watcher == fd->read_watcher) {
- /* remove read watcher, kick if we still need a read */
- was_polling = 1;
- if (!got_read) {
- kick = 1;
- }
- fd->read_watcher = NULL;
- }
- if (watcher == fd->write_watcher) {
- /* remove write watcher, kick if we still need a write */
- was_polling = 1;
- if (!got_write) {
- kick = 1;
- }
- fd->write_watcher = NULL;
- }
- if (!was_polling && watcher->worker != NULL) {
- /* remove from inactive list */
- watcher->next->prev = watcher->prev;
- watcher->prev->next = watcher->next;
- }
- if (got_read) {
- if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) {
- kick = 1;
- }
-
- if (read_notifier_pollset != NULL) {
- set_read_notifier_pollset_locked(exec_ctx, fd, read_notifier_pollset);
- }
- }
- if (got_write) {
- if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) {
- kick = 1;
- }
- }
- if (kick) {
- maybe_wake_one_watcher_locked(fd);
- }
- if (fd_is_orphaned(fd) && !has_watchers(fd) && !fd->closed) {
- close_fd_locked(exec_ctx, fd);
- }
- gpr_mu_unlock(&fd->mu);
-
- GRPC_FD_UNREF(fd, "poll");
-}
-
-static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) { return NULL; }
-
-/*******************************************************************************
- * pollset_posix.c
- */
-
-GPR_TLS_DECL(g_current_thread_poller);
-GPR_TLS_DECL(g_current_thread_worker);
-
-/** The alarm system needs to be able to wakeup 'some poller' sometimes
- * (specifically when a new alarm needs to be triggered earlier than the next
- * alarm 'epoch').
- * This wakeup_fd gives us something to alert on when such a case occurs. */
-grpc_wakeup_fd grpc_global_wakeup_fd;
-
-static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
- worker->prev->next = worker->next;
- worker->next->prev = worker->prev;
-}
-
-static int pollset_has_workers(grpc_pollset *p) {
- return p->root_worker.next != &p->root_worker;
-}
-
-static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) {
- if (pollset_has_workers(p)) {
- grpc_pollset_worker *w = p->root_worker.next;
- remove_worker(p, w);
- return w;
- } else {
- return NULL;
- }
-}
-
-static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
- worker->next = &p->root_worker;
- worker->prev = worker->next->prev;
- worker->prev->next = worker->next->prev = worker;
-}
-
-static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
- worker->prev = &p->root_worker;
- worker->next = worker->prev->next;
- worker->prev->next = worker->next->prev = worker;
-}
-
-static void kick_append_error(grpc_error **composite, grpc_error *error) {
- if (error == GRPC_ERROR_NONE) return;
- if (*composite == GRPC_ERROR_NONE) {
- *composite = GRPC_ERROR_CREATE("Kick Failure");
- }
- *composite = grpc_error_add_child(*composite, error);
-}
-
-static grpc_error *pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags) {
- GPR_TIMER_BEGIN("pollset_kick_ext", 0);
- grpc_error *error = GRPC_ERROR_NONE;
-
- /* pollset->mu already held */
- if (specific_worker != NULL) {
- if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
- GPR_TIMER_BEGIN("pollset_kick_ext.broadcast", 0);
- GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
- for (specific_worker = p->root_worker.next;
- specific_worker != &p->root_worker;
- specific_worker = specific_worker->next) {
- kick_append_error(
- &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
- }
- p->kicked_without_pollers = true;
- GPR_TIMER_END("pollset_kick_ext.broadcast", 0);
- } else if (gpr_tls_get(&g_current_thread_worker) !=
- (intptr_t)specific_worker) {
- GPR_TIMER_MARK("different_thread_worker", 0);
- if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
- specific_worker->reevaluate_polling_on_wakeup = true;
- }
- specific_worker->kicked_specifically = true;
- kick_append_error(&error,
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
- } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
- GPR_TIMER_MARK("kick_yoself", 0);
- if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
- specific_worker->reevaluate_polling_on_wakeup = true;
- }
- specific_worker->kicked_specifically = true;
- kick_append_error(&error,
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
- }
- } else if (gpr_tls_get(&g_current_thread_poller) != (intptr_t)p) {
- GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
- GPR_TIMER_MARK("kick_anonymous", 0);
- specific_worker = pop_front_worker(p);
- if (specific_worker != NULL) {
- if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
- GPR_TIMER_MARK("kick_anonymous_not_self", 0);
- push_back_worker(p, specific_worker);
- specific_worker = pop_front_worker(p);
- if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
- gpr_tls_get(&g_current_thread_worker) ==
- (intptr_t)specific_worker) {
- push_back_worker(p, specific_worker);
- specific_worker = NULL;
- }
- }
- if (specific_worker != NULL) {
- GPR_TIMER_MARK("finally_kick", 0);
- push_back_worker(p, specific_worker);
- kick_append_error(
- &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
- }
- } else {
- GPR_TIMER_MARK("kicked_no_pollers", 0);
- p->kicked_without_pollers = true;
- }
- }
-
- GPR_TIMER_END("pollset_kick_ext", 0);
- return error;
-}
-
-static grpc_error *pollset_kick(grpc_pollset *p,
- grpc_pollset_worker *specific_worker) {
- return pollset_kick_ext(p, specific_worker, 0);
-}
-
-/* global state management */
-
-static grpc_error *pollset_global_init(void) {
- gpr_tls_init(&g_current_thread_poller);
- gpr_tls_init(&g_current_thread_worker);
- return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
-}
-
-static void pollset_global_shutdown(void) {
- grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd);
- gpr_tls_destroy(&g_current_thread_poller);
- gpr_tls_destroy(&g_current_thread_worker);
-}
-
-static grpc_error *kick_poller(void) {
- return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
-}
-
-/* main interface */
-
-static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
-
-static void pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
- gpr_mu_init(&pollset->mu);
- *mu = &pollset->mu;
- pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
- pollset->in_flight_cbs = 0;
- pollset->shutting_down = 0;
- pollset->called_shutdown = 0;
- pollset->kicked_without_pollers = 0;
- pollset->idle_jobs.head = pollset->idle_jobs.tail = NULL;
- pollset->local_wakeup_cache = NULL;
- pollset->kicked_without_pollers = 0;
- become_basic_pollset(pollset, NULL);
-}
-
-static void pollset_destroy(grpc_pollset *pollset) {
- GPR_ASSERT(pollset->in_flight_cbs == 0);
- GPR_ASSERT(!pollset_has_workers(pollset));
- GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
- pollset->vtable->destroy(pollset);
- while (pollset->local_wakeup_cache) {
- grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next;
- grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd);
- gpr_free(pollset->local_wakeup_cache);
- pollset->local_wakeup_cache = next;
- }
- gpr_mu_destroy(&pollset->mu);
-}
-
-static void pollset_reset(grpc_pollset *pollset) {
- GPR_ASSERT(pollset->shutting_down);
- GPR_ASSERT(pollset->in_flight_cbs == 0);
- GPR_ASSERT(!pollset_has_workers(pollset));
- GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
- pollset->vtable->destroy(pollset);
- pollset->shutting_down = 0;
- pollset->called_shutdown = 0;
- pollset->kicked_without_pollers = 0;
- become_basic_pollset(pollset, NULL);
-}
-
-static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_fd *fd) {
- gpr_mu_lock(&pollset->mu);
- pollset->vtable->add_fd(exec_ctx, pollset, fd, 1);
-/* the following (enabled only in debug) will reacquire and then release
- our lock - meaning that if the unlocking flag passed to add_fd above is
- not respected, the code will deadlock (in a way that we have a chance of
- debugging) */
-#ifndef NDEBUG
- gpr_mu_lock(&pollset->mu);
- gpr_mu_unlock(&pollset->mu);
-#endif
-}
-
-static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
- GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
- pollset->vtable->finish_shutdown(pollset);
- grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
-}
-
-static void work_combine_error(grpc_error **composite, grpc_error *error) {
- if (error == GRPC_ERROR_NONE) return;
- if (*composite == GRPC_ERROR_NONE) {
- *composite = GRPC_ERROR_CREATE("pollset_work");
- }
- *composite = grpc_error_add_child(*composite, error);
-}
-
-static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker_hdl,
- gpr_timespec now, gpr_timespec deadline) {
- grpc_pollset_worker worker;
- *worker_hdl = &worker;
- grpc_error *error = GRPC_ERROR_NONE;
-
- /* pollset->mu already held */
- int added_worker = 0;
- int locked = 1;
- int queued_work = 0;
- int keep_polling = 0;
- GPR_TIMER_BEGIN("pollset_work", 0);
- /* this must happen before we (potentially) drop pollset->mu */
- worker.next = worker.prev = NULL;
- worker.reevaluate_polling_on_wakeup = 0;
- if (pollset->local_wakeup_cache != NULL) {
- worker.wakeup_fd = pollset->local_wakeup_cache;
- pollset->local_wakeup_cache = worker.wakeup_fd->next;
- } else {
- worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
- error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
- if (error != GRPC_ERROR_NONE) {
- return error;
- }
- }
- worker.kicked_specifically = 0;
- /* If there's work waiting for the pollset to be idle, and the
- pollset is idle, then do that work */
- if (!pollset_has_workers(pollset) &&
- !grpc_closure_list_empty(pollset->idle_jobs)) {
- GPR_TIMER_MARK("pollset_work.idle_jobs", 0);
- grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
- goto done;
- }
- /* If we're shutting down then we don't execute any extended work */
- if (pollset->shutting_down) {
- GPR_TIMER_MARK("pollset_work.shutting_down", 0);
- goto done;
- }
- /* Give do_promote priority so we don't starve it out */
- if (pollset->in_flight_cbs) {
- GPR_TIMER_MARK("pollset_work.in_flight_cbs", 0);
- gpr_mu_unlock(&pollset->mu);
- locked = 0;
- goto done;
- }
- /* Start polling, and keep doing so while we're being asked to
- re-evaluate our pollers (this allows poll() based pollers to
- ensure they don't miss wakeups) */
- keep_polling = 1;
- while (keep_polling) {
- keep_polling = 0;
- if (!pollset->kicked_without_pollers) {
- if (!added_worker) {
- push_front_worker(pollset, &worker);
- added_worker = 1;
- gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
- }
- gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
- GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
- work_combine_error(&error,
- pollset->vtable->maybe_work_and_unlock(
- exec_ctx, pollset, &worker, deadline, now));
- GPR_TIMER_END("maybe_work_and_unlock", 0);
- locked = 0;
- gpr_tls_set(&g_current_thread_poller, 0);
- } else {
- GPR_TIMER_MARK("pollset_work.kicked_without_pollers", 0);
- pollset->kicked_without_pollers = 0;
- }
- /* Finished execution - start cleaning up.
- Note that we may arrive here from outside the enclosing while() loop.
- In that case we won't loop though as we haven't added worker to the
- worker list, which means nobody could ask us to re-evaluate polling). */
- done:
- if (!locked) {
- queued_work |= grpc_exec_ctx_flush(exec_ctx);
- gpr_mu_lock(&pollset->mu);
- locked = 1;
- }
- /* If we're forced to re-evaluate polling (via pollset_kick with
- GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
- a loop */
- if (worker.reevaluate_polling_on_wakeup) {
- worker.reevaluate_polling_on_wakeup = 0;
- pollset->kicked_without_pollers = 0;
- if (queued_work || worker.kicked_specifically) {
- /* If there's queued work on the list, then set the deadline to be
- immediate so we get back out of the polling loop quickly */
- deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
- }
- keep_polling = 1;
- }
- }
- if (added_worker) {
- remove_worker(pollset, &worker);
- gpr_tls_set(&g_current_thread_worker, 0);
- }
- /* release wakeup fd to the local pool */
- worker.wakeup_fd->next = pollset->local_wakeup_cache;
- pollset->local_wakeup_cache = worker.wakeup_fd;
- /* check shutdown conditions */
- if (pollset->shutting_down) {
- if (pollset_has_workers(pollset)) {
- pollset_kick(pollset, NULL);
- } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
- pollset->called_shutdown = 1;
- gpr_mu_unlock(&pollset->mu);
- finish_shutdown(exec_ctx, pollset);
- grpc_exec_ctx_flush(exec_ctx);
- /* Continuing to access pollset here is safe -- it is the caller's
- * responsibility to not destroy when it has outstanding calls to
- * pollset_work.
- * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
- gpr_mu_lock(&pollset->mu);
- } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
- grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
- gpr_mu_unlock(&pollset->mu);
- grpc_exec_ctx_flush(exec_ctx);
- gpr_mu_lock(&pollset->mu);
- }
- }
- *worker_hdl = NULL;
- GPR_TIMER_END("pollset_work", 0);
- return error;
-}
-
-static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_closure *closure) {
- GPR_ASSERT(!pollset->shutting_down);
- pollset->shutting_down = 1;
- pollset->shutdown_done = closure;
- pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
- if (!pollset_has_workers(pollset)) {
- grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
- }
- if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
- !pollset_has_workers(pollset)) {
- pollset->called_shutdown = 1;
- finish_shutdown(exec_ctx, pollset);
- }
-}
-
-static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
- gpr_timespec now) {
- gpr_timespec timeout;
- static const int64_t max_spin_polling_us = 10;
- if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
- return -1;
- }
- if (gpr_time_cmp(deadline, gpr_time_add(now, gpr_time_from_micros(
- max_spin_polling_us,
- GPR_TIMESPAN))) <= 0) {
- return 0;
- }
- timeout = gpr_time_sub(deadline, now);
- return gpr_time_to_millis(gpr_time_add(
- timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
-}
-
-/*
- * basic_pollset - a vtable that provides polling for zero or one file
- * descriptor via poll()
- */
-
-typedef struct grpc_unary_promote_args {
- const grpc_pollset_vtable *original_vtable;
- grpc_pollset *pollset;
- grpc_fd *fd;
- grpc_closure promotion_closure;
-} grpc_unary_promote_args;
-
-static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
- grpc_error *error) {
- grpc_unary_promote_args *up_args = args;
- const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
- grpc_pollset *pollset = up_args->pollset;
- grpc_fd *fd = up_args->fd;
-
- /*
- * This is quite tricky. There are a number of cases to keep in mind here:
- * 1. fd may have been orphaned
- * 2. The pollset may no longer be a unary poller (and we can't let case #1
- * leak to other pollset types!)
- * 3. pollset's fd (which may have changed) may have been orphaned
- * 4. The pollset may be shutting down.
- */
-
- gpr_mu_lock(&pollset->mu);
- /* First we need to ensure that nobody is polling concurrently */
- GPR_ASSERT(!pollset_has_workers(pollset));
-
- gpr_free(up_args);
- /* At this point the pollset may no longer be a unary poller. In that case
- * we should just call the right add function and be done. */
- /* TODO(klempner): If we're not careful this could cause infinite recursion.
- * That's not a problem for now because empty_pollset has a trivial poller
- * and we don't have any mechanism to unbecome multipoller. */
- pollset->in_flight_cbs--;
- if (pollset->shutting_down) {
- /* We don't care about this pollset anymore. */
- if (pollset->in_flight_cbs == 0 && !pollset->called_shutdown) {
- pollset->called_shutdown = 1;
- finish_shutdown(exec_ctx, pollset);
- }
- } else if (fd_is_orphaned(fd)) {
- /* Don't try to add it to anything, we'll drop our ref on it below */
- } else if (pollset->vtable != original_vtable) {
- pollset->vtable->add_fd(exec_ctx, pollset, fd, 0);
- } else if (fd != pollset->data.ptr) {
- grpc_fd *fds[2];
- fds[0] = pollset->data.ptr;
- fds[1] = fd;
-
- if (fds[0] && !fd_is_orphaned(fds[0])) {
- platform_become_multipoller(exec_ctx, pollset, fds, GPR_ARRAY_SIZE(fds));
- GRPC_FD_UNREF(fds[0], "basicpoll");
- } else {
- /* old fd is orphaned and we haven't cleaned it up until now, so remain a
- * unary poller */
- /* Note that it is possible that fds[1] is also orphaned at this point.
- * That's okay, we'll correct it at the next add or poll. */
- if (fds[0]) GRPC_FD_UNREF(fds[0], "basicpoll");
- pollset->data.ptr = fd;
- GRPC_FD_REF(fd, "basicpoll");
- }
- }
-
- gpr_mu_unlock(&pollset->mu);
-
- /* Matching ref in basic_pollset_add_fd */
- GRPC_FD_UNREF(fd, "basicpoll_add");
-}
-
-static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_fd *fd, int and_unlock_pollset) {
- grpc_unary_promote_args *up_args;
- GPR_ASSERT(fd);
- if (fd == pollset->data.ptr) goto exit;
-
- if (!pollset_has_workers(pollset)) {
- /* Fast path -- no in flight cbs */
- /* TODO(klempner): Comment this out and fix any test failures or establish
- * they are due to timing issues */
- grpc_fd *fds[2];
- fds[0] = pollset->data.ptr;
- fds[1] = fd;
-
- if (fds[0] == NULL) {
- pollset->data.ptr = fd;
- GRPC_FD_REF(fd, "basicpoll");
- } else if (!fd_is_orphaned(fds[0])) {
- platform_become_multipoller(exec_ctx, pollset, fds, GPR_ARRAY_SIZE(fds));
- GRPC_FD_UNREF(fds[0], "basicpoll");
- } else {
- /* old fd is orphaned and we haven't cleaned it up until now, so remain a
- * unary poller */
- GRPC_FD_UNREF(fds[0], "basicpoll");
- pollset->data.ptr = fd;
- GRPC_FD_REF(fd, "basicpoll");
- }
- goto exit;
- }
-
- /* Now we need to promote. This needs to happen when we're not polling. Since
- * this may be called from poll, the wait needs to happen asynchronously. */
- GRPC_FD_REF(fd, "basicpoll_add");
- pollset->in_flight_cbs++;
- up_args = gpr_malloc(sizeof(*up_args));
- up_args->fd = fd;
- up_args->original_vtable = pollset->vtable;
- up_args->pollset = pollset;
- up_args->promotion_closure.cb = basic_do_promote;
- up_args->promotion_closure.cb_arg = up_args;
-
- grpc_closure_list_append(&pollset->idle_jobs, &up_args->promotion_closure,
- GRPC_ERROR_NONE);
- pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
-
-exit:
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- }
-}
-
-static grpc_error *basic_pollset_maybe_work_and_unlock(
- grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
- gpr_timespec deadline, gpr_timespec now) {
-#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
-#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
-
- struct pollfd pfd[3];
- grpc_fd *fd;
- grpc_fd_watcher fd_watcher;
- int timeout;
- int r;
- nfds_t nfds;
- grpc_error *error = GRPC_ERROR_NONE;
-
- fd = pollset->data.ptr;
- if (fd && fd_is_orphaned(fd)) {
- GRPC_FD_UNREF(fd, "basicpoll");
- fd = pollset->data.ptr = NULL;
- }
- timeout = poll_deadline_to_millis_timeout(deadline, now);
- pfd[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
- pfd[0].events = POLLIN;
- pfd[0].revents = 0;
- pfd[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
- pfd[1].events = POLLIN;
- pfd[1].revents = 0;
- nfds = 2;
- if (fd) {
- pfd[2].fd = fd->fd;
- pfd[2].revents = 0;
- GRPC_FD_REF(fd, "basicpoll_begin");
- gpr_mu_unlock(&pollset->mu);
- pfd[2].events =
- (short)fd_begin_poll(fd, pollset, worker, POLLIN, POLLOUT, &fd_watcher);
- if (pfd[2].events != 0) {
- nfds++;
- }
- } else {
- gpr_mu_unlock(&pollset->mu);
- }
-
- /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
- even going into the blocking annotation if possible */
- /* poll fd count (argument 2) is shortened by one if we have no events
- to poll on - such that it only includes the kicker */
- GPR_TIMER_BEGIN("poll", 0);
- GRPC_SCHEDULING_START_BLOCKING_REGION;
- r = grpc_poll_function(pfd, nfds, timeout);
- GRPC_SCHEDULING_END_BLOCKING_REGION;
- GPR_TIMER_END("poll", 0);
-
- if (r < 0) {
- if (errno != EINTR) {
- work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
- }
- if (fd) {
- fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL);
- }
- } else if (r == 0) {
- if (fd) {
- fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL);
- }
- } else {
- if (pfd[0].revents & POLLIN_CHECK) {
- work_combine_error(&error,
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
- }
- if (pfd[1].revents & POLLIN_CHECK) {
- work_combine_error(&error,
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
- }
- if (nfds > 2) {
- fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
- pfd[2].revents & POLLOUT_CHECK, pollset);
- } else if (fd) {
- fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL);
- }
- }
-
- if (fd) {
- GRPC_FD_UNREF(fd, "basicpoll_begin");
- }
-
- return error;
-}
-
-static void basic_pollset_destroy(grpc_pollset *pollset) {
- if (pollset->data.ptr != NULL) {
- GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
- pollset->data.ptr = NULL;
- }
-}
-
-static const grpc_pollset_vtable basic_pollset = {
- basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock,
- basic_pollset_destroy, basic_pollset_destroy};
-
-static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
- pollset->vtable = &basic_pollset;
- pollset->data.ptr = fd_or_null;
- if (fd_or_null != NULL) {
- GRPC_FD_REF(fd_or_null, "basicpoll");
- }
-}
-
-/*******************************************************************************
- * pollset_multipoller_with_poll_posix.c
- */
-
-#ifndef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
-
-typedef struct {
- /* all polled fds */
- size_t fd_count;
- size_t fd_capacity;
- grpc_fd **fds;
- /* fds that have been removed from the pollset explicitly */
- size_t del_count;
- size_t del_capacity;
- grpc_fd **dels;
-} poll_hdr;
-
-static void multipoll_with_poll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_fd *fd,
- int and_unlock_pollset) {
- size_t i;
- poll_hdr *h = pollset->data.ptr;
- /* TODO(ctiller): this is O(num_fds^2); maybe switch to a hash set here */
- for (i = 0; i < h->fd_count; i++) {
- if (h->fds[i] == fd) goto exit;
- }
- if (h->fd_count == h->fd_capacity) {
- h->fd_capacity = GPR_MAX(h->fd_capacity + 8, h->fd_count * 3 / 2);
- h->fds = gpr_realloc(h->fds, sizeof(grpc_fd *) * h->fd_capacity);
- }
- h->fds[h->fd_count++] = fd;
- GRPC_FD_REF(fd, "multipoller");
-exit:
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- }
-}
-
-static grpc_error *multipoll_with_poll_pollset_maybe_work_and_unlock(
- grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
- gpr_timespec deadline, gpr_timespec now) {
-#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
-#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
-
- int timeout;
- int r;
- size_t i, j, fd_count;
- nfds_t pfd_count;
- poll_hdr *h;
- /* TODO(ctiller): inline some elements to avoid an allocation */
- grpc_fd_watcher *watchers;
- struct pollfd *pfds;
- grpc_error *error = GRPC_ERROR_NONE;
-
- h = pollset->data.ptr;
- timeout = poll_deadline_to_millis_timeout(deadline, now);
- /* TODO(ctiller): perform just one malloc here if we exceed the inline case */
- pfds = gpr_malloc(sizeof(*pfds) * (h->fd_count + 2));
- watchers = gpr_malloc(sizeof(*watchers) * (h->fd_count + 2));
- fd_count = 0;
- pfd_count = 2;
- pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
- pfds[0].events = POLLIN;
- pfds[0].revents = 0;
- pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
- pfds[1].events = POLLIN;
- pfds[1].revents = 0;
- for (i = 0; i < h->fd_count; i++) {
- int remove = fd_is_orphaned(h->fds[i]);
- for (j = 0; !remove && j < h->del_count; j++) {
- if (h->fds[i] == h->dels[j]) remove = 1;
- }
- if (remove) {
- GRPC_FD_UNREF(h->fds[i], "multipoller");
- } else {
- h->fds[fd_count++] = h->fds[i];
- watchers[pfd_count].fd = h->fds[i];
- GRPC_FD_REF(watchers[pfd_count].fd, "multipoller_start");
- pfds[pfd_count].fd = h->fds[i]->fd;
- pfds[pfd_count].revents = 0;
- pfd_count++;
- }
- }
- for (j = 0; j < h->del_count; j++) {
- GRPC_FD_UNREF(h->dels[j], "multipoller_del");
- }
- h->del_count = 0;
- h->fd_count = fd_count;
- gpr_mu_unlock(&pollset->mu);
-
- for (i = 2; i < pfd_count; i++) {
- grpc_fd *fd = watchers[i].fd;
- pfds[i].events = (short)fd_begin_poll(fd, pollset, worker, POLLIN, POLLOUT,
- &watchers[i]);
- GRPC_FD_UNREF(fd, "multipoller_start");
- }
-
- /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
- even going into the blocking annotation if possible */
- GRPC_SCHEDULING_START_BLOCKING_REGION;
- r = grpc_poll_function(pfds, pfd_count, timeout);
- GRPC_SCHEDULING_END_BLOCKING_REGION;
-
- if (r < 0) {
- if (errno != EINTR) {
- work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
- }
- for (i = 2; i < pfd_count; i++) {
- fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
- }
- } else if (r == 0) {
- for (i = 2; i < pfd_count; i++) {
- fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
- }
- } else {
- if (pfds[0].revents & POLLIN_CHECK) {
- work_combine_error(&error,
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
- }
- if (pfds[1].revents & POLLIN_CHECK) {
- work_combine_error(&error,
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
- }
- for (i = 2; i < pfd_count; i++) {
- if (watchers[i].fd == NULL) {
- fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
- continue;
- }
- fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK,
- pfds[i].revents & POLLOUT_CHECK, pollset);
- }
- }
-
- gpr_free(pfds);
- gpr_free(watchers);
-
- return error;
-}
-
-static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
- size_t i;
- poll_hdr *h = pollset->data.ptr;
- for (i = 0; i < h->fd_count; i++) {
- GRPC_FD_UNREF(h->fds[i], "multipoller");
- }
- for (i = 0; i < h->del_count; i++) {
- GRPC_FD_UNREF(h->dels[i], "multipoller_del");
- }
- h->fd_count = 0;
- h->del_count = 0;
-}
-
-static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
- poll_hdr *h = pollset->data.ptr;
- multipoll_with_poll_pollset_finish_shutdown(pollset);
- gpr_free(h->fds);
- gpr_free(h->dels);
- gpr_free(h);
-}
-
-static const grpc_pollset_vtable multipoll_with_poll_pollset = {
- multipoll_with_poll_pollset_add_fd,
- multipoll_with_poll_pollset_maybe_work_and_unlock,
- multipoll_with_poll_pollset_finish_shutdown,
- multipoll_with_poll_pollset_destroy};
-
-static void poll_become_multipoller(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset, grpc_fd **fds,
- size_t nfds) {
- size_t i;
- poll_hdr *h = gpr_malloc(sizeof(poll_hdr));
- pollset->vtable = &multipoll_with_poll_pollset;
- pollset->data.ptr = h;
- h->fd_count = nfds;
- h->fd_capacity = nfds;
- h->fds = gpr_malloc(nfds * sizeof(grpc_fd *));
- h->del_count = 0;
- h->del_capacity = 0;
- h->dels = NULL;
- for (i = 0; i < nfds; i++) {
- h->fds[i] = fds[i];
- GRPC_FD_REF(fds[i], "multipoller");
- }
-}
-
-#endif /* !GRPC_LINUX_MULTIPOLL_WITH_EPOLL */
-
-/*******************************************************************************
- * pollset_multipoller_with_epoll_posix.c
- */
-
-#ifdef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
-
-#include <errno.h>
-#include <poll.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <unistd.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include "src/core/lib/iomgr/ev_posix.h"
-#include "src/core/lib/profiling/timers.h"
-#include "src/core/lib/support/block_annotate.h"
-
-static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st,
- grpc_pollset *read_notifier_pollset) {
- /* only one set_ready can be active at once (but there may be a racing
- notify_on) */
- gpr_mu_lock(&fd->mu);
- set_ready_locked(exec_ctx, fd, st);
-
- /* A non-NULL read_notifier_pollset means that the fd is readable. */
- if (read_notifier_pollset != NULL) {
- /* Note: Since the fd might be a part of multiple pollsets, this might be
- * called multiple times (for each time the fd becomes readable) and it is
- * okay to set the fd's read-notifier pollset to anyone of these pollsets */
- set_read_notifier_pollset_locked(exec_ctx, fd, read_notifier_pollset);
- }
-
- gpr_mu_unlock(&fd->mu);
-}
-
-static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- grpc_pollset *notifier_pollset) {
- set_ready(exec_ctx, fd, &fd->read_closure, notifier_pollset);
-}
-
-static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- set_ready(exec_ctx, fd, &fd->write_closure, NULL);
-}
-
-struct epoll_fd_list {
- int *epoll_fds;
- size_t count;
- size_t capacity;
-};
-
-static struct epoll_fd_list epoll_fd_global_list;
-static gpr_once init_epoll_fd_list_mu = GPR_ONCE_INIT;
-static gpr_mu epoll_fd_list_mu;
-
-static void init_mu(void) { gpr_mu_init(&epoll_fd_list_mu); }
-
-static void add_epoll_fd_to_global_list(int epoll_fd) {
- gpr_once_init(&init_epoll_fd_list_mu, init_mu);
-
- gpr_mu_lock(&epoll_fd_list_mu);
- if (epoll_fd_global_list.count == epoll_fd_global_list.capacity) {
- epoll_fd_global_list.capacity =
- GPR_MAX((size_t)8, epoll_fd_global_list.capacity * 2);
- epoll_fd_global_list.epoll_fds =
- gpr_realloc(epoll_fd_global_list.epoll_fds,
- epoll_fd_global_list.capacity * sizeof(int));
- }
- epoll_fd_global_list.epoll_fds[epoll_fd_global_list.count++] = epoll_fd;
- gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-static void remove_epoll_fd_from_global_list(int epoll_fd) {
- gpr_mu_lock(&epoll_fd_list_mu);
- GPR_ASSERT(epoll_fd_global_list.count > 0);
- for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
- if (epoll_fd == epoll_fd_global_list.epoll_fds[i]) {
- epoll_fd_global_list.epoll_fds[i] =
- epoll_fd_global_list.epoll_fds[--(epoll_fd_global_list.count)];
- break;
- }
- }
- gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-static void remove_fd_from_all_epoll_sets(int fd) {
- int err;
- gpr_once_init(&init_epoll_fd_list_mu, init_mu);
- gpr_mu_lock(&epoll_fd_list_mu);
- if (epoll_fd_global_list.count == 0) {
- gpr_mu_unlock(&epoll_fd_list_mu);
- return;
- }
- for (size_t i = 0; i < epoll_fd_global_list.count; i++) {
- err = epoll_ctl(epoll_fd_global_list.epoll_fds[i], EPOLL_CTL_DEL, fd, NULL);
- if (err < 0 && errno != ENOENT) {
- gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd,
- strerror(errno));
- }
- }
- gpr_mu_unlock(&epoll_fd_list_mu);
-}
-
-typedef struct {
- grpc_pollset *pollset;
- grpc_fd *fd;
- grpc_closure closure;
-} delayed_add;
-
-typedef struct { int epoll_fd; } epoll_hdr;
-
-static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_fd *fd) {
- epoll_hdr *h = pollset->data.ptr;
- struct epoll_event ev;
- int err;
- grpc_fd_watcher watcher;
-
- /* We pretend to be polling whilst adding an fd to keep the fd from being
- closed during the add. This may result in a spurious wakeup being assigned
- to this pollset whilst adding, but that should be benign. */
- GPR_ASSERT(fd_begin_poll(fd, pollset, NULL, 0, 0, &watcher) == 0);
- if (watcher.fd != NULL) {
- ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
- ev.data.ptr = fd;
- err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD, fd->fd, &ev);
- if (err < 0) {
- /* FDs may be added to a pollset multiple times, so EEXIST is normal. */
- if (errno != EEXIST) {
- gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s", fd->fd,
- strerror(errno));
- }
- }
- }
- fd_end_poll(exec_ctx, &watcher, 0, 0, NULL);
-}
-
-static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- delayed_add *da = arg;
-
- if (!fd_is_orphaned(da->fd)) {
- finally_add_fd(exec_ctx, da->pollset, da->fd);
- }
-
- gpr_mu_lock(&da->pollset->mu);
- da->pollset->in_flight_cbs--;
- if (da->pollset->shutting_down) {
- /* We don't care about this pollset anymore. */
- if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
- da->pollset->called_shutdown = 1;
- grpc_exec_ctx_sched(exec_ctx, da->pollset->shutdown_done, GRPC_ERROR_NONE,
- NULL);
- }
- }
- gpr_mu_unlock(&da->pollset->mu);
-
- GRPC_FD_UNREF(da->fd, "delayed_add");
-
- gpr_free(da);
-}
-
-static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_fd *fd,
- int and_unlock_pollset) {
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- finally_add_fd(exec_ctx, pollset, fd);
- } else {
- delayed_add *da = gpr_malloc(sizeof(*da));
- da->pollset = pollset;
- da->fd = fd;
- GRPC_FD_REF(fd, "delayed_add");
- grpc_closure_init(&da->closure, perform_delayed_add, da);
- pollset->in_flight_cbs++;
- grpc_exec_ctx_sched(exec_ctx, &da->closure, GRPC_ERROR_NONE, NULL);
- }
-}
-
-/* TODO(klempner): We probably want to turn this down a bit */
-#define GRPC_EPOLL_MAX_EVENTS 1000
-
-static grpc_error *multipoll_with_epoll_pollset_maybe_work_and_unlock(
- grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
- gpr_timespec deadline, gpr_timespec now) {
- struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
- int ep_rv;
- int poll_rv;
- epoll_hdr *h = pollset->data.ptr;
- int timeout_ms;
- struct pollfd pfds[2];
- grpc_error *error = GRPC_ERROR_NONE;
-
- /* If you want to ignore epoll's ability to sanely handle parallel pollers,
- * for a more apples-to-apples performance comparison with poll, add a
- * if (pollset->counter != 0) { return 0; }
- * here.
- */
-
- gpr_mu_unlock(&pollset->mu);
-
- timeout_ms = poll_deadline_to_millis_timeout(deadline, now);
-
- pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker->wakeup_fd->fd);
- pfds[0].events = POLLIN;
- pfds[0].revents = 0;
- pfds[1].fd = h->epoll_fd;
- pfds[1].events = POLLIN;
- pfds[1].revents = 0;
-
- /* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
- even going into the blocking annotation if possible */
- GPR_TIMER_BEGIN("poll", 0);
- GRPC_SCHEDULING_START_BLOCKING_REGION;
- poll_rv = grpc_poll_function(pfds, 2, timeout_ms);
- GRPC_SCHEDULING_END_BLOCKING_REGION;
- GPR_TIMER_END("poll", 0);
-
- if (poll_rv < 0) {
- if (errno != EINTR) {
- work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
- }
- } else if (poll_rv == 0) {
- /* do nothing */
- } else {
- if (pfds[0].revents) {
- work_combine_error(&error,
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
- }
- if (pfds[1].revents) {
- do {
- /* The following epoll_wait never blocks; it has a timeout of 0 */
- ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
- if (ep_rv < 0) {
- if (errno != EINTR) {
- work_combine_error(&error, GRPC_OS_ERROR(errno, "epoll_wait"));
- }
- } else {
- int i;
- for (i = 0; i < ep_rv; ++i) {
- grpc_fd *fd = ep_ev[i].data.ptr;
- /* TODO(klempner): We might want to consider making err and pri
- * separate events */
- int cancel = ep_ev[i].events & (EPOLLERR | EPOLLHUP);
- int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
- int write_ev = ep_ev[i].events & EPOLLOUT;
- if (fd == NULL) {
- work_combine_error(&error, grpc_wakeup_fd_consume_wakeup(
- &grpc_global_wakeup_fd));
- } else {
- if (read_ev || cancel) {
- fd_become_readable(exec_ctx, fd, pollset);
- }
- if (write_ev || cancel) {
- fd_become_writable(exec_ctx, fd);
- }
- }
- }
- }
- } while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
- }
- }
- return error;
-}
-
-static void multipoll_with_epoll_pollset_finish_shutdown(
- grpc_pollset *pollset) {}
-
-static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
- epoll_hdr *h = pollset->data.ptr;
- close(h->epoll_fd);
- remove_epoll_fd_from_global_list(h->epoll_fd);
- gpr_free(h);
-}
-
-static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
- multipoll_with_epoll_pollset_add_fd,
- multipoll_with_epoll_pollset_maybe_work_and_unlock,
- multipoll_with_epoll_pollset_finish_shutdown,
- multipoll_with_epoll_pollset_destroy};
-
-static void epoll_become_multipoller(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset, grpc_fd **fds,
- size_t nfds) {
- size_t i;
- epoll_hdr *h = gpr_malloc(sizeof(epoll_hdr));
- struct epoll_event ev;
- int err;
-
- pollset->vtable = &multipoll_with_epoll_pollset;
- pollset->data.ptr = h;
- h->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- if (h->epoll_fd < 0) {
- /* TODO(klempner): Fall back to poll here, especially on ENOSYS */
- gpr_log(GPR_ERROR, "epoll_create1 failed: %s", strerror(errno));
- abort();
- }
- add_epoll_fd_to_global_list(h->epoll_fd);
-
- ev.events = (uint32_t)(EPOLLIN | EPOLLET);
- ev.data.ptr = NULL;
- err = epoll_ctl(h->epoll_fd, EPOLL_CTL_ADD,
- GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd), &ev);
- if (err < 0) {
- gpr_log(GPR_ERROR, "epoll_ctl add for %d failed: %s",
- GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd),
- strerror(errno));
- }
-
- for (i = 0; i < nfds; i++) {
- multipoll_with_epoll_pollset_add_fd(exec_ctx, pollset, fds[i], 0);
- }
-}
-
-#else /* GRPC_LINUX_MULTIPOLL_WITH_EPOLL */
-
-static void remove_fd_from_all_epoll_sets(int fd) {}
-
-#endif /* GRPC_LINUX_MULTIPOLL_WITH_EPOLL */
-
-/*******************************************************************************
- * pollset_set_posix.c
- */
-
-static grpc_pollset_set *pollset_set_create(void) {
- grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set));
- memset(pollset_set, 0, sizeof(*pollset_set));
- gpr_mu_init(&pollset_set->mu);
- return pollset_set;
-}
-
-static void pollset_set_destroy(grpc_pollset_set *pollset_set) {
- size_t i;
- gpr_mu_destroy(&pollset_set->mu);
- for (i = 0; i < pollset_set->fd_count; i++) {
- GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
- }
- gpr_free(pollset_set->pollsets);
- gpr_free(pollset_set->pollset_sets);
- gpr_free(pollset_set->fds);
- gpr_free(pollset_set);
-}
-
-static void pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *pollset_set,
- grpc_pollset *pollset) {
- size_t i, j;
- gpr_mu_lock(&pollset_set->mu);
- if (pollset_set->pollset_count == pollset_set->pollset_capacity) {
- pollset_set->pollset_capacity =
- GPR_MAX(8, 2 * pollset_set->pollset_capacity);
- pollset_set->pollsets =
- gpr_realloc(pollset_set->pollsets, pollset_set->pollset_capacity *
- sizeof(*pollset_set->pollsets));
- }
- pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
- for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
- if (fd_is_orphaned(pollset_set->fds[i])) {
- GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
- } else {
- pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
- pollset_set->fds[j++] = pollset_set->fds[i];
- }
- }
- pollset_set->fd_count = j;
- gpr_mu_unlock(&pollset_set->mu);
-}
-
-static void pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *pollset_set,
- grpc_pollset *pollset) {
- size_t i;
- gpr_mu_lock(&pollset_set->mu);
- for (i = 0; i < pollset_set->pollset_count; i++) {
- if (pollset_set->pollsets[i] == pollset) {
- pollset_set->pollset_count--;
- GPR_SWAP(grpc_pollset *, pollset_set->pollsets[i],
- pollset_set->pollsets[pollset_set->pollset_count]);
- break;
- }
- }
- gpr_mu_unlock(&pollset_set->mu);
-}
-
-static void pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *bag,
- grpc_pollset_set *item) {
- size_t i, j;
- gpr_mu_lock(&bag->mu);
- if (bag->pollset_set_count == bag->pollset_set_capacity) {
- bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
- bag->pollset_sets =
- gpr_realloc(bag->pollset_sets,
- bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
- }
- bag->pollset_sets[bag->pollset_set_count++] = item;
- for (i = 0, j = 0; i < bag->fd_count; i++) {
- if (fd_is_orphaned(bag->fds[i])) {
- GRPC_FD_UNREF(bag->fds[i], "pollset_set");
- } else {
- pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
- bag->fds[j++] = bag->fds[i];
- }
- }
- bag->fd_count = j;
- gpr_mu_unlock(&bag->mu);
-}
-
-static void pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *bag,
- grpc_pollset_set *item) {
- size_t i;
- gpr_mu_lock(&bag->mu);
- for (i = 0; i < bag->pollset_set_count; i++) {
- if (bag->pollset_sets[i] == item) {
- bag->pollset_set_count--;
- GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
- bag->pollset_sets[bag->pollset_set_count]);
- break;
- }
- }
- gpr_mu_unlock(&bag->mu);
-}
-
-static void pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *pollset_set, grpc_fd *fd) {
- size_t i;
- gpr_mu_lock(&pollset_set->mu);
- if (pollset_set->fd_count == pollset_set->fd_capacity) {
- pollset_set->fd_capacity = GPR_MAX(8, 2 * pollset_set->fd_capacity);
- pollset_set->fds = gpr_realloc(
- pollset_set->fds, pollset_set->fd_capacity * sizeof(*pollset_set->fds));
- }
- GRPC_FD_REF(fd, "pollset_set");
- pollset_set->fds[pollset_set->fd_count++] = fd;
- for (i = 0; i < pollset_set->pollset_count; i++) {
- pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd);
- }
- for (i = 0; i < pollset_set->pollset_set_count; i++) {
- pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
- }
- gpr_mu_unlock(&pollset_set->mu);
-}
-
-static void pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset_set *pollset_set, grpc_fd *fd) {
- size_t i;
- gpr_mu_lock(&pollset_set->mu);
- for (i = 0; i < pollset_set->fd_count; i++) {
- if (pollset_set->fds[i] == fd) {
- pollset_set->fd_count--;
- GPR_SWAP(grpc_fd *, pollset_set->fds[i],
- pollset_set->fds[pollset_set->fd_count]);
- GRPC_FD_UNREF(fd, "pollset_set");
- break;
- }
- }
- for (i = 0; i < pollset_set->pollset_set_count; i++) {
- pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
- }
- gpr_mu_unlock(&pollset_set->mu);
-}
-
-/*******************************************************************************
- * workqueue stubs
- */
-
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue,
- const char *file, int line,
- const char *reason) {
- return workqueue;
-}
-static void workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
- const char *file, int line, const char *reason) {}
-#else
-static grpc_workqueue *workqueue_ref(grpc_workqueue *workqueue) {
- return workqueue;
-}
-static void workqueue_unref(grpc_exec_ctx *exec_ctx,
- grpc_workqueue *workqueue) {}
-#endif
-
-static void workqueue_enqueue(grpc_exec_ctx *exec_ctx,
- grpc_workqueue *workqueue, grpc_closure *closure,
- grpc_error *error) {
- grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
-}
-
-/*******************************************************************************
- * event engine binding
- */
-
-static void shutdown_engine(void) {
- fd_global_shutdown();
- pollset_global_shutdown();
-}
-
-static const grpc_event_engine_vtable vtable = {
- .pollset_size = sizeof(grpc_pollset),
-
- .fd_create = fd_create,
- .fd_wrapped_fd = fd_wrapped_fd,
- .fd_orphan = fd_orphan,
- .fd_shutdown = fd_shutdown,
- .fd_is_shutdown = fd_is_shutdown,
- .fd_notify_on_read = fd_notify_on_read,
- .fd_notify_on_write = fd_notify_on_write,
- .fd_get_read_notifier_pollset = fd_get_read_notifier_pollset,
- .fd_get_workqueue = fd_get_workqueue,
-
- .pollset_init = pollset_init,
- .pollset_shutdown = pollset_shutdown,
- .pollset_reset = pollset_reset,
- .pollset_destroy = pollset_destroy,
- .pollset_work = pollset_work,
- .pollset_kick = pollset_kick,
- .pollset_add_fd = pollset_add_fd,
-
- .pollset_set_create = pollset_set_create,
- .pollset_set_destroy = pollset_set_destroy,
- .pollset_set_add_pollset = pollset_set_add_pollset,
- .pollset_set_del_pollset = pollset_set_del_pollset,
- .pollset_set_add_pollset_set = pollset_set_add_pollset_set,
- .pollset_set_del_pollset_set = pollset_set_del_pollset_set,
- .pollset_set_add_fd = pollset_set_add_fd,
- .pollset_set_del_fd = pollset_set_del_fd,
-
- .kick_poller = kick_poller,
-
- .workqueue_ref = workqueue_ref,
- .workqueue_unref = workqueue_unref,
- .workqueue_enqueue = workqueue_enqueue,
-
- .shutdown_engine = shutdown_engine,
-};
-
-const grpc_event_engine_vtable *grpc_init_poll_and_epoll_posix(void) {
-#ifdef GRPC_LINUX_MULTIPOLL_WITH_EPOLL
- platform_become_multipoller = epoll_become_multipoller;
-#else
- platform_become_multipoller = poll_become_multipoller;
-#endif
- fd_global_init();
- pollset_global_init();
- return &vtable;
-}
-
-#endif
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index e1d620cfff..21b28e5554 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -120,6 +120,8 @@ struct grpc_fd {
grpc_pollset *read_notifier_pollset;
};
+static grpc_wakeup_fd global_wakeup_fd;
+
/* Begin polling on an fd.
Registers that the given pollset is interested in this fd - so that if read
or writability interest changes, the pollset can be kicked to pick up that
@@ -769,17 +771,17 @@ static grpc_error *pollset_kick(grpc_pollset *p,
static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker);
- return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_init(&global_wakeup_fd);
}
static void pollset_global_shutdown(void) {
- grpc_wakeup_fd_destroy(&grpc_global_wakeup_fd);
+ grpc_wakeup_fd_destroy(&global_wakeup_fd);
gpr_tls_destroy(&g_current_thread_poller);
gpr_tls_destroy(&g_current_thread_worker);
}
static grpc_error *kick_poller(void) {
- return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_wakeup(&global_wakeup_fd);
}
/* main interface */
@@ -947,7 +949,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
fd_count = 0;
pfd_count = 2;
- pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
+ pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&global_wakeup_fd);
pfds[0].events = POLLIN;
pfds[0].revents = 0;
pfds[1].fd = GRPC_WAKEUP_FD_GET_READ_FD(&worker.wakeup_fd->fd);
@@ -1001,8 +1003,8 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
} else {
if (pfds[0].revents & POLLIN_CHECK) {
- work_combine_error(
- &error, grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&global_wakeup_fd));
}
if (pfds[1].revents & POLLIN_CHECK) {
work_combine_error(
@@ -1343,6 +1345,7 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
int res, idx;
gpr_cv *pollcv;
cv_node *cvn, *prev;
+ int skip_poll = 0;
nfds_t nsockfds = 0;
gpr_thd_id t_id;
gpr_thd_options opt;
@@ -1358,17 +1361,17 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
cvn->cv = pollcv;
cvn->next = g_cvfds.cvfds[idx].cvs;
g_cvfds.cvfds[idx].cvs = cvn;
- // We should return immediately if there are pending events,
- // but we still need to call poll() to check for socket events
+ // Don't bother polling if a wakeup fd is ready
if (g_cvfds.cvfds[idx].is_set) {
- timeout = 0;
+ skip_poll = 1;
}
} else if (fds[i].fd >= 0) {
nsockfds++;
}
}
- if (nsockfds > 0) {
+ res = 0;
+ if (!skip_poll && nsockfds > 0) {
pargs = gpr_malloc(sizeof(struct poll_args));
// Both the main thread and calling thread get a reference
gpr_ref_init(&pargs->refcount, 2);
@@ -1398,16 +1401,14 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
res = pargs->retval;
errno = pargs->err;
} else {
- res = 0;
errno = 0;
gpr_atm_no_barrier_store(&pargs->status, CANCELLED);
}
- } else {
+ } else if (!skip_poll) {
gpr_timespec deadline = gpr_now(GPR_CLOCK_REALTIME);
deadline =
gpr_time_add(deadline, gpr_time_from_millis(timeout, GPR_TIMESPAN));
gpr_cv_wait(pollcv, &g_cvfds.mu, deadline);
- res = 0;
}
idx = 0;
@@ -1431,7 +1432,7 @@ static int cvfd_poll(struct pollfd *fds, nfds_t nfds, int timeout) {
fds[i].revents = POLLIN;
if (res >= 0) res++;
}
- } else if (fds[i].fd >= 0 &&
+ } else if (!skip_poll && fds[i].fd >= 0 &&
gpr_atm_no_barrier_load(&pargs->status) == COMPLETED) {
fds[i].revents = pargs->fds[idx].revents;
idx++;
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index ef36ba89b2..ab139895fd 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -45,7 +45,6 @@
#include <grpc/support/useful.h>
#include "src/core/lib/iomgr/ev_epoll_linux.h"
-#include "src/core/lib/iomgr/ev_poll_and_epoll_posix.h"
#include "src/core/lib/iomgr/ev_poll_posix.h"
#include "src/core/lib/support/env.h"
@@ -67,7 +66,6 @@ static const event_engine_factory g_factories[] = {
{"epoll", grpc_init_epoll_linux},
{"poll", grpc_init_poll_posix},
{"poll-cv", grpc_init_poll_cv_posix},
- {"legacy", grpc_init_poll_and_epoll_posix},
};
static void add(const char *beg, const char *end, char ***ss, size_t *ns) {
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 2fdef06838..cb5832539d 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -183,6 +183,5 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
/* override to allow tests to hook poll() usage */
typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
extern grpc_poll_function_type grpc_poll_function;
-extern grpc_wakeup_fd grpc_global_wakeup_fd;
#endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 4fd83e0b22..3470b5ac81 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -108,6 +108,7 @@ void grpc_iomgr_shutdown(void) {
NULL)) {
gpr_mu_unlock(&g_mu);
grpc_exec_ctx_flush(&exec_ctx);
+ grpc_iomgr_platform_flush();
gpr_mu_lock(&g_mu);
continue;
}
diff --git a/src/core/lib/iomgr/load_file.c b/src/core/lib/iomgr/load_file.c
index b62ecbc534..217bc5da59 100644
--- a/src/core/lib/iomgr/load_file.c
+++ b/src/core/lib/iomgr/load_file.c
@@ -44,10 +44,10 @@
#include "src/core/lib/support/string.h"
grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
- gpr_slice *output) {
+ grpc_slice *output) {
unsigned char *contents = NULL;
size_t contents_size = 0;
- gpr_slice result = gpr_empty_slice();
+ grpc_slice result = gpr_empty_slice();
FILE *file;
size_t bytes_read = 0;
grpc_error *error = GRPC_ERROR_NONE;
@@ -72,7 +72,7 @@ grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
if (add_null_terminator) {
contents[contents_size++] = 0;
}
- result = gpr_slice_new(contents, contents_size, gpr_free);
+ result = grpc_slice_new(contents, contents_size, gpr_free);
end:
*output = result;
diff --git a/src/core/lib/iomgr/load_file.h b/src/core/lib/iomgr/load_file.h
index 9aac2225d1..73ee8c3abf 100644
--- a/src/core/lib/iomgr/load_file.h
+++ b/src/core/lib/iomgr/load_file.h
@@ -36,7 +36,7 @@
#include <stdio.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/lib/iomgr/error.h"
@@ -47,7 +47,7 @@ extern "C" {
/* Loads the content of a file into a slice. add_null_terminator will add
a NULL terminator if non-zero. */
grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
- gpr_slice *slice);
+ grpc_slice *slice);
#ifdef __cplusplus
}
diff --git a/src/core/lib/iomgr/network_status_tracker.c b/src/core/lib/iomgr/network_status_tracker.c
index b4bb7e3cf7..a5ca9ed2c3 100644
--- a/src/core/lib/iomgr/network_status_tracker.c
+++ b/src/core/lib/iomgr/network_status_tracker.c
@@ -46,7 +46,7 @@ static gpr_mu g_endpoint_mutex;
void grpc_network_status_shutdown(void) {
if (head != NULL) {
gpr_log(GPR_ERROR,
- "Memory leaked as all network endpoints were not shut down");
+ "Memory leaked as not all network endpoints were shut down");
}
gpr_mu_destroy(&g_endpoint_mutex);
}
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 8a06443d58..213d29600c 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -44,6 +44,84 @@
int grpc_resource_quota_trace = 0;
+/* Internal linked list pointers for a resource user */
+typedef struct {
+ grpc_resource_user *next;
+ grpc_resource_user *prev;
+} grpc_resource_user_link;
+
+/* Resource users are kept in (potentially) several intrusive linked lists
+ at once. These are the list names. */
+typedef enum {
+ /* Resource users that are waiting for an allocation */
+ GRPC_RULIST_AWAITING_ALLOCATION,
+ /* Resource users that have free memory available for internal reclamation */
+ GRPC_RULIST_NON_EMPTY_FREE_POOL,
+ /* Resource users that have published a benign reclamation is available */
+ GRPC_RULIST_RECLAIMER_BENIGN,
+ /* Resource users that have published a destructive reclamation is
+ available */
+ GRPC_RULIST_RECLAIMER_DESTRUCTIVE,
+ /* Number of lists: must be last */
+ GRPC_RULIST_COUNT
+} grpc_rulist;
+
+struct grpc_resource_user {
+ /* The quota this resource user consumes from */
+ grpc_resource_quota *resource_quota;
+
+ /* Closure to schedule an allocation under the resource quota combiner lock */
+ grpc_closure allocate_closure;
+ /* Closure to publish a non empty free pool under the resource quota combiner
+ lock */
+ grpc_closure add_to_free_pool_closure;
+
+ /* one ref for each ref call (released by grpc_resource_user_unref), and one
+ ref for each byte allocated (released by grpc_resource_user_free) */
+ gpr_atm refs;
+ /* is this resource user unlocked? starts at 0, increases for each shutdown
+ call */
+ gpr_atm shutdown;
+
+ gpr_mu mu;
+ /* The amount of memory (in bytes) this user has cached for its own use: to
+ avoid quota contention, each resource user can keep some memory in
+ addition to what it is immediately using (e.g., for caching), and the quota
+ can pull it back under memory pressure.
+ This value can become negative if more memory has been requested than
+ existed in the free pool, at which point the quota is consulted to bring
+ this value non-negative (asynchronously). */
+ int64_t free_pool;
+ /* A list of closures to call once free_pool becomes non-negative - ie when
+ all outstanding allocations have been granted. */
+ grpc_closure_list on_allocated;
+ /* True if we are currently trying to allocate from the quota, false if not */
+ bool allocating;
+ /* True if we are currently trying to add ourselves to the non-free quota
+ list, false otherwise */
+ bool added_to_free_pool;
+
+ /* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
+ */
+ grpc_closure *reclaimers[2];
+ /* Reclaimers just posted: once we're in the combiner lock, we'll move them
+ to the array above */
+ grpc_closure *new_reclaimers[2];
+ /* Trampoline closures to finish reclamation and re-enter the quota combiner
+ lock */
+ grpc_closure post_reclaimer_closure[2];
+
+ /* Closure to execute under the quota combiner to de-register and shutdown the
+ resource user */
+ grpc_closure destroy_closure;
+
+ /* Links in the various grpc_rulist lists */
+ grpc_resource_user_link links[GRPC_RULIST_COUNT];
+
+ /* The name of this resource user, for debugging/tracing */
+ char *name;
+};
+
struct grpc_resource_quota {
/* refcount */
gpr_refcount refs;
@@ -66,6 +144,12 @@ struct grpc_resource_quota {
/* Closure around rq_reclamation_done */
grpc_closure rq_reclamation_done_closure;
+ /* This is only really usable for debugging: it's always a stale pointer, but
+ a stale pointer that might just be fresh enough to guide us to where the
+ reclamation system is stuck */
+ grpc_closure *debug_only_last_initiated_reclaimer;
+ grpc_resource_user *debug_only_last_reclaimer_resource_user;
+
/* Roots of all resource user lists */
grpc_resource_user *roots[GRPC_RULIST_COUNT];
@@ -147,6 +231,7 @@ static void rulist_remove(grpc_resource_user *resource_user, grpc_rulist list) {
resource_user->links[list].prev;
resource_user->links[list].prev->links[list].next =
resource_user->links[list].next;
+ resource_user->links[list].next = resource_user->links[list].prev = NULL;
}
/*******************************************************************************
@@ -262,6 +347,9 @@ static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
resource_quota->reclaiming = true;
grpc_resource_quota_internal_ref(resource_quota);
grpc_closure *c = resource_user->reclaimers[destructive];
+ GPR_ASSERT(c);
+ resource_quota->debug_only_last_reclaimer_resource_user = resource_user;
+ resource_quota->debug_only_last_initiated_reclaimer = c;
resource_user->reclaimers[destructive] = NULL;
grpc_closure_run(exec_ctx, c, GRPC_ERROR_NONE);
return true;
@@ -272,7 +360,7 @@ static bool rq_reclaim(grpc_exec_ctx *exec_ctx,
*/
typedef struct {
- gpr_slice_refcount base;
+ grpc_slice_refcount base;
gpr_refcount refs;
grpc_resource_user *resource_user;
size_t size;
@@ -289,7 +377,7 @@ static void ru_slice_unref(void *p) {
/* TODO(ctiller): this is dangerous, but I think safe for now:
we have no guarantee here that we're at a safe point for creating an
execution context, but we have no way of writing this code otherwise.
- In the future: consider lifting gpr_slice to grpc, and offering an
+ In the future: consider lifting grpc_slice to grpc, and offering an
internal_{ref,unref} pair that is execution context aware.
Alternatively,
make exec_ctx be thread local and 'do the right thing' (whatever that
@@ -302,15 +390,15 @@ static void ru_slice_unref(void *p) {
}
}
-static gpr_slice ru_slice_create(grpc_resource_user *resource_user,
- size_t size) {
+static grpc_slice ru_slice_create(grpc_resource_user *resource_user,
+ size_t size) {
ru_slice_refcount *rc = gpr_malloc(sizeof(ru_slice_refcount) + size);
rc->base.ref = ru_slice_ref;
rc->base.unref = ru_slice_unref;
gpr_ref_init(&rc->refs, 1);
rc->resource_user = resource_user;
rc->size = size;
- gpr_slice slice;
+ grpc_slice slice;
slice.refcount = &rc->base;
slice.data.refcounted.bytes = (uint8_t *)(rc + 1);
slice.data.refcounted.length = size;
@@ -343,9 +431,25 @@ static void ru_add_to_free_pool(grpc_exec_ctx *exec_ctx, void *ru,
rulist_add_tail(resource_user, GRPC_RULIST_NON_EMPTY_FREE_POOL);
}
+static bool ru_post_reclaimer(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ bool destructive) {
+ grpc_closure *closure = resource_user->new_reclaimers[destructive];
+ GPR_ASSERT(closure != NULL);
+ resource_user->new_reclaimers[destructive] = NULL;
+ GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
+ if (gpr_atm_acq_load(&resource_user->shutdown) > 0) {
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL);
+ return false;
+ }
+ resource_user->reclaimers[destructive] = closure;
+ return true;
+}
+
static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
grpc_error *error) {
grpc_resource_user *resource_user = ru;
+ if (!ru_post_reclaimer(exec_ctx, resource_user, false)) return;
if (!rulist_empty(resource_user->resource_quota,
GRPC_RULIST_AWAITING_ALLOCATION) &&
rulist_empty(resource_user->resource_quota,
@@ -360,6 +464,7 @@ static void ru_post_benign_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
grpc_error *error) {
grpc_resource_user *resource_user = ru;
+ if (!ru_post_reclaimer(exec_ctx, resource_user, true)) return;
if (!rulist_empty(resource_user->resource_quota,
GRPC_RULIST_AWAITING_ALLOCATION) &&
rulist_empty(resource_user->resource_quota,
@@ -373,9 +478,21 @@ static void ru_post_destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *ru,
rulist_add_tail(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
}
+static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
+ grpc_resource_user *resource_user = ru;
+ grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0],
+ GRPC_ERROR_CANCELLED, NULL);
+ grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
+ GRPC_ERROR_CANCELLED, NULL);
+ resource_user->reclaimers[0] = NULL;
+ resource_user->reclaimers[1] = NULL;
+ rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
+ rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_DESTRUCTIVE);
+}
+
static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
grpc_resource_user *resource_user = ru;
- GPR_ASSERT(resource_user->allocated == 0);
+ GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->refs) == 0);
for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
rulist_remove(resource_user, (grpc_rulist)i);
}
@@ -383,13 +500,14 @@ static void ru_destroy(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
GRPC_ERROR_CANCELLED, NULL);
grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
GRPC_ERROR_CANCELLED, NULL);
- grpc_exec_ctx_sched(exec_ctx, (grpc_closure *)gpr_atm_no_barrier_load(
- &resource_user->on_done_destroy_closure),
- GRPC_ERROR_NONE, NULL);
if (resource_user->free_pool != 0) {
resource_user->resource_quota->free_pool += resource_user->free_pool;
rq_step_sched(exec_ctx, resource_user->resource_quota);
}
+ grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
+ gpr_mu_destroy(&resource_user->mu);
+ gpr_free(resource_user->name);
+ gpr_free(resource_user);
}
static void ru_allocated_slices(grpc_exec_ctx *exec_ctx, void *arg,
@@ -397,7 +515,7 @@ static void ru_allocated_slices(grpc_exec_ctx *exec_ctx, void *arg,
grpc_resource_user_slice_allocator *slice_allocator = arg;
if (error == GRPC_ERROR_NONE) {
for (size_t i = 0; i < slice_allocator->count; i++) {
- gpr_slice_buffer_add_indexed(
+ grpc_slice_buffer_add_indexed(
slice_allocator->dest, ru_slice_create(slice_allocator->resource_user,
slice_allocator->length));
}
@@ -539,9 +657,9 @@ const grpc_arg_pointer_vtable *grpc_resource_quota_arg_vtable(void) {
* grpc_resource_user api
*/
-void grpc_resource_user_init(grpc_resource_user *resource_user,
- grpc_resource_quota *resource_quota,
- const char *name) {
+grpc_resource_user *grpc_resource_user_create(
+ grpc_resource_quota *resource_quota, const char *name) {
+ grpc_resource_user *resource_user = gpr_malloc(sizeof(*resource_user));
resource_user->resource_quota =
grpc_resource_quota_internal_ref(resource_quota);
grpc_closure_init(&resource_user->allocate_closure, &ru_allocate,
@@ -555,14 +673,16 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
grpc_closure_init(&resource_user->destroy_closure, &ru_destroy,
resource_user);
gpr_mu_init(&resource_user->mu);
- resource_user->allocated = 0;
+ gpr_atm_rel_store(&resource_user->refs, 1);
+ gpr_atm_rel_store(&resource_user->shutdown, 0);
resource_user->free_pool = 0;
grpc_closure_list_init(&resource_user->on_allocated);
resource_user->allocating = false;
resource_user->added_to_free_pool = false;
- gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure, 0);
resource_user->reclaimers[0] = NULL;
resource_user->reclaimers[1] = NULL;
+ resource_user->new_reclaimers[0] = NULL;
+ resource_user->new_reclaimers[1] = NULL;
for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
resource_user->links[i].next = resource_user->links[i].prev = NULL;
}
@@ -572,56 +692,54 @@ void grpc_resource_user_init(grpc_resource_user *resource_user,
gpr_asprintf(&resource_user->name, "anonymous_resource_user_%" PRIxPTR,
(intptr_t)resource_user);
}
+ return resource_user;
}
-void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user,
- grpc_closure *on_done) {
- gpr_mu_lock(&resource_user->mu);
- GPR_ASSERT(gpr_atm_no_barrier_load(&resource_user->on_done_destroy_closure) ==
- 0);
- gpr_atm_no_barrier_store(&resource_user->on_done_destroy_closure,
- (gpr_atm)on_done);
- if (resource_user->allocated == 0) {
+static void ru_ref_by(grpc_resource_user *resource_user, gpr_atm amount) {
+ GPR_ASSERT(amount > 0);
+ GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&resource_user->refs, amount) != 0);
+}
+
+static void ru_unref_by(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user, gpr_atm amount) {
+ GPR_ASSERT(amount > 0);
+ gpr_atm old = gpr_atm_full_fetch_add(&resource_user->refs, -amount);
+ GPR_ASSERT(old >= amount);
+ if (old == amount) {
grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
&resource_user->destroy_closure, GRPC_ERROR_NONE,
false);
}
- gpr_mu_unlock(&resource_user->mu);
}
-void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user) {
- grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
- gpr_mu_destroy(&resource_user->mu);
- gpr_free(resource_user->name);
+void grpc_resource_user_ref(grpc_resource_user *resource_user) {
+ ru_ref_by(resource_user, 1);
+}
+
+void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user) {
+ ru_unref_by(exec_ctx, resource_user, 1);
+}
+
+void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user) {
+ if (gpr_atm_full_fetch_add(&resource_user->shutdown, 1) == 0) {
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ grpc_closure_create(ru_shutdown, resource_user),
+ GRPC_ERROR_NONE, false);
+ }
}
void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user, size_t size,
grpc_closure *optional_on_done) {
gpr_mu_lock(&resource_user->mu);
- grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
- &resource_user->on_done_destroy_closure);
- if (on_done_destroy != NULL) {
- /* already shutdown */
- if (grpc_resource_quota_trace) {
- gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR " after shutdown",
- resource_user->resource_quota->name, resource_user->name, size);
- }
- grpc_exec_ctx_sched(
- exec_ctx, optional_on_done,
- GRPC_ERROR_CREATE("Buffer pool user is already shutdown"), NULL);
- gpr_mu_unlock(&resource_user->mu);
- return;
- }
- resource_user->allocated += (int64_t)size;
+ ru_ref_by(resource_user, (gpr_atm)size);
resource_user->free_pool -= (int64_t)size;
if (grpc_resource_quota_trace) {
- gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; allocated -> %" PRId64
- ", free_pool -> %" PRId64,
+ gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
resource_user->resource_quota->name, resource_user->name, size,
- resource_user->allocated, resource_user->free_pool);
+ resource_user->free_pool);
}
if (resource_user->free_pool < 0) {
grpc_closure_list_append(&resource_user->on_allocated, optional_on_done,
@@ -641,15 +759,12 @@ void grpc_resource_user_alloc(grpc_exec_ctx *exec_ctx,
void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user, size_t size) {
gpr_mu_lock(&resource_user->mu);
- GPR_ASSERT(resource_user->allocated >= (int64_t)size);
bool was_zero_or_negative = resource_user->free_pool <= 0;
resource_user->free_pool += (int64_t)size;
- resource_user->allocated -= (int64_t)size;
if (grpc_resource_quota_trace) {
- gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; allocated -> %" PRId64
- ", free_pool -> %" PRId64,
+ gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64,
resource_user->resource_quota->name, resource_user->name, size,
- resource_user->allocated, resource_user->free_pool);
+ resource_user->free_pool);
}
bool is_bigger_than_zero = resource_user->free_pool > 0;
if (is_bigger_than_zero && was_zero_or_negative &&
@@ -659,29 +774,19 @@ void grpc_resource_user_free(grpc_exec_ctx *exec_ctx,
&resource_user->add_to_free_pool_closure,
GRPC_ERROR_NONE, false);
}
- grpc_closure *on_done_destroy = (grpc_closure *)gpr_atm_no_barrier_load(
- &resource_user->on_done_destroy_closure);
- if (on_done_destroy != NULL && resource_user->allocated == 0) {
- grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
- &resource_user->destroy_closure, GRPC_ERROR_NONE,
- false);
- }
gpr_mu_unlock(&resource_user->mu);
+ ru_unref_by(exec_ctx, resource_user, (gpr_atm)size);
}
void grpc_resource_user_post_reclaimer(grpc_exec_ctx *exec_ctx,
grpc_resource_user *resource_user,
bool destructive,
grpc_closure *closure) {
- if (gpr_atm_acq_load(&resource_user->on_done_destroy_closure) == 0) {
- GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
- resource_user->reclaimers[destructive] = closure;
- grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
- &resource_user->post_reclaimer_closure[destructive],
- GRPC_ERROR_NONE, false);
- } else {
- grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL);
- }
+ GPR_ASSERT(resource_user->new_reclaimers[destructive] == NULL);
+ resource_user->new_reclaimers[destructive] = closure;
+ grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
+ &resource_user->post_reclaimer_closure[destructive],
+ GRPC_ERROR_NONE, false);
}
void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx,
@@ -708,7 +813,7 @@ void grpc_resource_user_slice_allocator_init(
void grpc_resource_user_alloc_slices(
grpc_exec_ctx *exec_ctx,
grpc_resource_user_slice_allocator *slice_allocator, size_t length,
- size_t count, gpr_slice_buffer *dest) {
+ size_t count, grpc_slice_buffer *dest) {
slice_allocator->length = length;
slice_allocator->count = count;
slice_allocator->dest = dest;
@@ -716,9 +821,9 @@ void grpc_resource_user_alloc_slices(
count * length, &slice_allocator->on_allocated);
}
-gpr_slice grpc_resource_user_slice_malloc(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user,
- size_t size) {
+grpc_slice grpc_resource_user_slice_malloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ size_t size) {
grpc_resource_user_alloc(exec_ctx, resource_user, size, NULL);
return ru_slice_create(resource_user, size);
}
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index da68f21a2c..0181fd978b 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -84,91 +84,15 @@ void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_resource_quota *grpc_resource_quota_from_channel_args(
const grpc_channel_args *channel_args);
-/* Resource users are kept in (potentially) several intrusive linked lists
- at once. These are the list names. */
-typedef enum {
- /* Resource users that are waiting for an allocation */
- GRPC_RULIST_AWAITING_ALLOCATION,
- /* Resource users that have free memory available for internal reclamation */
- GRPC_RULIST_NON_EMPTY_FREE_POOL,
- /* Resource users that have published a benign reclamation is available */
- GRPC_RULIST_RECLAIMER_BENIGN,
- /* Resource users that have published a destructive reclamation is
- available */
- GRPC_RULIST_RECLAIMER_DESTRUCTIVE,
- /* Number of lists: must be last */
- GRPC_RULIST_COUNT
-} grpc_rulist;
-
typedef struct grpc_resource_user grpc_resource_user;
-/* Internal linked list pointers for a resource user */
-typedef struct {
- grpc_resource_user *next;
- grpc_resource_user *prev;
-} grpc_resource_user_link;
-
-struct grpc_resource_user {
- /* The quota this resource user consumes from */
- grpc_resource_quota *resource_quota;
-
- /* Closure to schedule an allocation under the resource quota combiner lock */
- grpc_closure allocate_closure;
- /* Closure to publish a non empty free pool under the resource quota combiner
- lock */
- grpc_closure add_to_free_pool_closure;
-
- gpr_mu mu;
- /* Total allocated memory outstanding by this resource user in bytes;
- always positive */
- int64_t allocated;
- /* The amount of memory (in bytes) this user has cached for its own use: to
- avoid quota contention, each resource user can keep some memory in
- addition to what it is immediately using (e.g., for caching), and the quota
- can pull it back under memory pressure.
- This value can become negative if more memory has been requested than
- existed in the free pool, at which point the quota is consulted to bring
- this value non-negative (asynchronously). */
- int64_t free_pool;
- /* A list of closures to call once free_pool becomes non-negative - ie when
- all outstanding allocations have been granted. */
- grpc_closure_list on_allocated;
- /* True if we are currently trying to allocate from the quota, false if not */
- bool allocating;
- /* True if we are currently trying to add ourselves to the non-free quota
- list, false otherwise */
- bool added_to_free_pool;
-
- /* Reclaimers: index 0 is the benign reclaimer, 1 is the destructive reclaimer
- */
- grpc_closure *reclaimers[2];
- /* Trampoline closures to finish reclamation and re-enter the quota combiner
- lock */
- grpc_closure post_reclaimer_closure[2];
-
- /* Closure to execute under the quota combiner to de-register and shutdown the
- resource user */
- grpc_closure destroy_closure;
- /* User supplied closure to call once the user has finished shutting down AND
- all outstanding allocations have been freed. Real type is grpc_closure*,
- but it's stored as an atomic to avoid a mutex on some fast paths. */
- gpr_atm on_done_destroy_closure;
-
- /* Links in the various grpc_rulist lists */
- grpc_resource_user_link links[GRPC_RULIST_COUNT];
-
- /* The name of this resource user, for debugging/tracing */
- char *name;
-};
-
-void grpc_resource_user_init(grpc_resource_user *resource_user,
- grpc_resource_quota *resource_quota,
- const char *name);
+grpc_resource_user *grpc_resource_user_create(
+ grpc_resource_quota *resource_quota, const char *name);
+void grpc_resource_user_ref(grpc_resource_user *resource_user);
+void grpc_resource_user_unref(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user);
void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user,
- grpc_closure *on_done);
-void grpc_resource_user_destroy(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user);
+ grpc_resource_user *resource_user);
/* Allocate from the resource user (and its quota).
If optional_on_done is NULL, then allocate immediately. This may push the
@@ -203,7 +127,7 @@ typedef struct grpc_resource_user_slice_allocator {
/* Number of slices to allocate on the current request */
size_t count;
/* Destination for slices to allocate on the current request */
- gpr_slice_buffer *dest;
+ grpc_slice_buffer *dest;
/* Parent resource user */
grpc_resource_user *resource_user;
} grpc_resource_user_slice_allocator;
@@ -219,11 +143,11 @@ void grpc_resource_user_slice_allocator_init(
void grpc_resource_user_alloc_slices(
grpc_exec_ctx *exec_ctx,
grpc_resource_user_slice_allocator *slice_allocator, size_t length,
- size_t count, gpr_slice_buffer *dest);
+ size_t count, grpc_slice_buffer *dest);
/* Allocate one slice of length \a size synchronously. */
-gpr_slice grpc_resource_user_slice_malloc(grpc_exec_ctx *exec_ctx,
- grpc_resource_user *resource_user,
- size_t size);
+grpc_slice grpc_resource_user_slice_malloc(grpc_exec_ctx *exec_ctx,
+ grpc_resource_user *resource_user,
+ size_t size);
#endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */
diff --git a/src/core/lib/iomgr/socket_mutator.c b/src/core/lib/iomgr/socket_mutator.c
new file mode 100644
index 0000000000..8b1efb6bab
--- /dev/null
+++ b/src/core/lib/iomgr/socket_mutator.c
@@ -0,0 +1,98 @@
+/*
+ *
+ * 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/iomgr/socket_mutator.h"
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
+void grpc_socket_mutator_init(grpc_socket_mutator *mutator,
+ const grpc_socket_mutator_vtable *vtable) {
+ mutator->vtable = vtable;
+ gpr_ref_init(&mutator->refcount, 1);
+}
+
+grpc_socket_mutator *grpc_socket_mutator_ref(grpc_socket_mutator *mutator) {
+ gpr_ref(&mutator->refcount);
+ return mutator;
+}
+
+bool grpc_socket_mutator_mutate_fd(grpc_socket_mutator *mutator, int fd) {
+ return mutator->vtable->mutate_fd(fd, mutator);
+}
+
+int grpc_socket_mutator_compare(grpc_socket_mutator *a,
+ grpc_socket_mutator *b) {
+ int c = GPR_ICMP(a, b);
+ if (c != 0) {
+ grpc_socket_mutator *sma = a;
+ grpc_socket_mutator *smb = b;
+ c = GPR_ICMP(sma->vtable, smb->vtable);
+ if (c == 0) {
+ c = sma->vtable->compare(sma, smb);
+ }
+ }
+ return c;
+}
+
+void grpc_socket_mutator_unref(grpc_socket_mutator *mutator) {
+ if (gpr_unref(&mutator->refcount)) {
+ mutator->vtable->destory(mutator);
+ }
+}
+
+static void *socket_mutator_arg_copy(void *p) {
+ return grpc_socket_mutator_ref(p);
+}
+
+static void socket_mutator_arg_destroy(void *p) {
+ grpc_socket_mutator_unref(p);
+}
+
+static int socket_mutator_cmp(void *a, void *b) {
+ return grpc_socket_mutator_compare((grpc_socket_mutator *)a,
+ (grpc_socket_mutator *)b);
+}
+
+static const grpc_arg_pointer_vtable socket_mutator_arg_vtable = {
+ socket_mutator_arg_copy, socket_mutator_arg_destroy, socket_mutator_cmp};
+
+grpc_arg grpc_socket_mutator_to_arg(grpc_socket_mutator *mutator) {
+ grpc_arg arg;
+ arg.type = GRPC_ARG_POINTER;
+ arg.key = GRPC_ARG_SOCKET_MUTATOR;
+ arg.value.pointer.vtable = &socket_mutator_arg_vtable;
+ arg.value.pointer.p = mutator;
+ return arg;
+}
diff --git a/src/core/lib/iomgr/socket_mutator.h b/src/core/lib/iomgr/socket_mutator.h
new file mode 100644
index 0000000000..2f5b6c248e
--- /dev/null
+++ b/src/core/lib/iomgr/socket_mutator.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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_LIB_IOMGR_SOCKET_MUTATOR_H
+#define GRPC_CORE_LIB_IOMGR_SOCKET_MUTATOR_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/sync.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The virtual table of grpc_socket_mutator */
+typedef struct {
+ /** Mutates the socket opitons of \a fd */
+ bool (*mutate_fd)(int fd, grpc_socket_mutator *mutator);
+ /** Compare socket mutator \a a and \a b */
+ int (*compare)(grpc_socket_mutator *a, grpc_socket_mutator *b);
+ /** Destroys the socket mutator instance */
+ void (*destory)(grpc_socket_mutator *mutator);
+} grpc_socket_mutator_vtable;
+
+/** The Socket Mutator interface allows changes on socket options */
+struct grpc_socket_mutator {
+ const grpc_socket_mutator_vtable *vtable;
+ gpr_refcount refcount;
+};
+
+/** called by concrete implementations to initialize the base struct */
+void grpc_socket_mutator_init(grpc_socket_mutator *mutator,
+ const grpc_socket_mutator_vtable *vtable);
+
+/** Wrap \a mutator as a grpc_arg */
+grpc_arg grpc_socket_mutator_to_arg(grpc_socket_mutator *mutator);
+
+/** Perform the file descriptor mutation operation of \a mutator on \a fd */
+bool grpc_socket_mutator_mutate_fd(grpc_socket_mutator *mutator, int fd);
+
+/** Compare if \a a and \a b are the same mutator or have same settings */
+int grpc_socket_mutator_compare(grpc_socket_mutator *a, grpc_socket_mutator *b);
+
+grpc_socket_mutator *grpc_socket_mutator_ref(grpc_socket_mutator *mutator);
+void grpc_socket_mutator_unref(grpc_socket_mutator *mutator);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_MUTATOR_H */
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.c b/src/core/lib/iomgr/socket_utils_common_posix.c
index bc28bbe316..88e9ade253 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.c
+++ b/src/core/lib/iomgr/socket_utils_common_posix.c
@@ -209,6 +209,15 @@ grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) {
return GRPC_ERROR_NONE;
}
+/* set a socket using a grpc_socket_mutator */
+grpc_error *grpc_set_socket_with_mutator(int fd, grpc_socket_mutator *mutator) {
+ GPR_ASSERT(mutator);
+ if (!grpc_socket_mutator_mutate_fd(mutator, fd)) {
+ return GRPC_ERROR_CREATE("grpc_socket_mutator failed.");
+ }
+ return GRPC_ERROR_NONE;
+}
+
static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
static int g_ipv6_loopback_available;
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index 175fb2b717..e84d3781a1 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -39,7 +39,9 @@
#include <sys/socket.h>
#include <unistd.h>
+#include <grpc/impl/codegen/grpc_types.h>
#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/iomgr/socket_mutator.h"
/* a wrapper for accept or accept4 */
int grpc_accept4(int sockfd, grpc_resolved_address *resolved_addr, int nonblock,
@@ -88,6 +90,9 @@ grpc_error *grpc_set_socket_sndbuf(int fd, int buffer_size_bytes);
/* Tries to set the socket's receive buffer to given size. */
grpc_error *grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes);
+/* Tries to set the socket using a grpc_socket_mutator */
+grpc_error *grpc_set_socket_with_mutator(int fd, grpc_socket_mutator *mutator);
+
/* An enum to keep track of IPv4/IPv6 socket modes.
Currently, this information is only used when a socket is first created, but
diff --git a/src/core/lib/iomgr/socket_windows.c b/src/core/lib/iomgr/socket_windows.c
index 35f23300dc..54911e0e31 100644
--- a/src/core/lib/iomgr/socket_windows.c
+++ b/src/core/lib/iomgr/socket_windows.c
@@ -76,6 +76,14 @@ void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
LPFN_DISCONNECTEX DisconnectEx;
DWORD ioctl_num_bytes;
+ gpr_mu_lock(&winsocket->state_mu);
+ if (winsocket->shutdown_called) {
+ gpr_mu_unlock(&winsocket->state_mu);
+ return;
+ }
+ winsocket->shutdown_called = true;
+ gpr_mu_unlock(&winsocket->state_mu);
+
status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
&ioctl_num_bytes, NULL, NULL);
diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h
index 490d0e0a06..a3875ce16c 100644
--- a/src/core/lib/iomgr/socket_windows.h
+++ b/src/core/lib/iomgr/socket_windows.h
@@ -87,6 +87,7 @@ typedef struct grpc_winsocket {
grpc_winsocket_callback_info read_info;
gpr_mu state_mu;
+ bool shutdown_called;
/* You can't add the same socket twice to the same IO Completion Port.
This prevents that. */
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 18e6e60ebc..0485661316 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -34,6 +34,7 @@
#ifndef GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
#define GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H
+#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/time.h>
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/pollset_set.h"
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index bc08c94ee0..a3a70a8ed7 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -51,6 +51,7 @@
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_posix.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/iomgr/socket_mutator.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/timer.h"
@@ -73,7 +74,8 @@ typedef struct {
grpc_channel_args *channel_args;
} async_connect;
-static grpc_error *prepare_socket(const grpc_resolved_address *addr, int fd) {
+static grpc_error *prepare_socket(const grpc_resolved_address *addr, int fd,
+ const grpc_channel_args *channel_args) {
grpc_error *err = GRPC_ERROR_NONE;
GPR_ASSERT(fd >= 0);
@@ -88,6 +90,16 @@ static grpc_error *prepare_socket(const grpc_resolved_address *addr, int fd) {
}
err = grpc_set_socket_no_sigpipe_if_possible(fd);
if (err != GRPC_ERROR_NONE) goto error;
+ if (channel_args) {
+ for (size_t i = 0; i < channel_args->num_args; i++) {
+ if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_SOCKET_MUTATOR)) {
+ GPR_ASSERT(channel_args->args[i].type == GRPC_ARG_POINTER);
+ grpc_socket_mutator *mutator = channel_args->args[i].value.pointer.p;
+ err = grpc_set_socket_with_mutator(fd, mutator);
+ if (err != GRPC_ERROR_NONE) goto error;
+ }
+ }
+ }
goto done;
error:
@@ -239,8 +251,11 @@ finish:
done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (error != GRPC_ERROR_NONE) {
- error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION,
- "Failed to connect to remote host");
+ char *error_descr;
+ gpr_asprintf(&error_descr, "Failed to connect to remote host: %s",
+ grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION));
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_DESCRIPTION, error_descr);
+ gpr_free(error_descr);
error =
grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, ac->addr_str);
}
@@ -287,7 +302,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
addr = &addr4_copy;
}
- if ((error = prepare_socket(addr, fd)) != GRPC_ERROR_NONE) {
+ if ((error = prepare_socket(addr, fd, channel_args)) != GRPC_ERROR_NONE) {
grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
return;
}
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index 30f7c66f15..1127588ebc 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -37,10 +37,10 @@
#include "src/core/lib/iomgr/sockaddr_windows.h"
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/log_windows.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/useful.h>
#include "src/core/lib/channel/channel_args.h"
@@ -107,18 +107,22 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
gpr_mu_lock(&ac->mu);
- if (error == GRPC_ERROR_NONE && socket != NULL) {
- DWORD transfered_bytes = 0;
- DWORD flags;
- BOOL wsa_success =
- WSAGetOverlappedResult(socket->socket, &socket->write_info.overlapped,
- &transfered_bytes, FALSE, &flags);
- GPR_ASSERT(transfered_bytes == 0);
- if (!wsa_success) {
- error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
+ if (error == GRPC_ERROR_NONE) {
+ if (socket != NULL) {
+ DWORD transfered_bytes = 0;
+ DWORD flags;
+ BOOL wsa_success =
+ WSAGetOverlappedResult(socket->socket, &socket->write_info.overlapped,
+ &transfered_bytes, FALSE, &flags);
+ GPR_ASSERT(transfered_bytes == 0);
+ if (!wsa_success) {
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
+ } else {
+ *ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name);
+ socket = NULL;
+ }
} else {
- *ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name);
- socket = NULL;
+ error = GRPC_ERROR_CREATE("socket is null");
}
}
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 880af93ee1..12a4797e6f 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -46,9 +46,9 @@
#include <sys/types.h>
#include <unistd.h>
+#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
@@ -56,6 +56,7 @@
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#ifdef GRPC_HAVE_MSG_NOSIGNAL
@@ -83,10 +84,10 @@ typedef struct {
gpr_atm shutdown_count;
/* garbage after the last read */
- gpr_slice_buffer last_read_buffer;
+ grpc_slice_buffer last_read_buffer;
- gpr_slice_buffer *incoming_buffer;
- gpr_slice_buffer *outgoing_buffer;
+ grpc_slice_buffer *incoming_buffer;
+ grpc_slice_buffer *outgoing_buffer;
/** slice within outgoing_buffer to write next */
size_t outgoing_slice_idx;
/** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */
@@ -102,7 +103,7 @@ typedef struct {
char *peer_string;
- grpc_resource_user resource_user;
+ grpc_resource_user *resource_user;
grpc_resource_user_slice_allocator slice_allocator;
} grpc_tcp;
@@ -110,28 +111,18 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error);
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
grpc_error *error);
-static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- grpc_error *error);
-
-static void tcp_maybe_shutdown_resource_user(grpc_exec_ctx *exec_ctx,
- grpc_tcp *tcp) {
- if (gpr_atm_full_fetch_add(&tcp->shutdown_count, 1) == 0) {
- grpc_resource_user_shutdown(exec_ctx, &tcp->resource_user,
- grpc_closure_create(tcp_unref_closure, tcp));
- }
-}
static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
grpc_fd_shutdown(exec_ctx, tcp->em_fd);
+ grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
}
static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
"tcp_unref_orphan");
- gpr_slice_buffer_destroy(&tcp->last_read_buffer);
- grpc_resource_user_destroy(exec_ctx, &tcp->resource_user);
+ grpc_slice_buffer_destroy(&tcp->last_read_buffer);
+ grpc_resource_user_unref(exec_ctx, tcp->resource_user);
gpr_free(tcp->peer_string);
gpr_free(tcp);
}
@@ -168,16 +159,10 @@ static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
#endif
-static void tcp_unref_closure(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- TCP_UNREF(exec_ctx, arg, "resource_user");
-}
-
static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp *tcp = (grpc_tcp *)ep;
- tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
- gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+ grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
TCP_UNREF(exec_ctx, tcp, "destroy");
}
@@ -191,8 +176,8 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
gpr_log(GPR_DEBUG, "read: error=%s", str);
grpc_error_free_string(str);
for (i = 0; i < tcp->incoming_buffer->count; i++) {
- char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *dump = grpc_dump_slice(tcp->incoming_buffer->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
gpr_free(dump);
}
@@ -216,8 +201,8 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GPR_TIMER_BEGIN("tcp_continue_read", 0);
for (i = 0; i < tcp->incoming_buffer->count; i++) {
- iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
- iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
+ iov[i].iov_base = GRPC_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
+ iov[i].iov_len = GRPC_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
}
msg.msg_name = NULL;
@@ -244,19 +229,19 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
/* We've consumed the edge, request a new one */
grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
} else {
- gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
call_read_cb(exec_ctx, tcp, GRPC_OS_ERROR(errno, "recvmsg"));
TCP_UNREF(exec_ctx, tcp, "read");
}
} else if (read_bytes == 0) {
/* 0 read size ==> end of stream */
- gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
call_read_cb(exec_ctx, tcp, GRPC_ERROR_CREATE("Socket closed"));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
if ((size_t)read_bytes < tcp->incoming_buffer->length) {
- gpr_slice_buffer_trim_end(
+ grpc_slice_buffer_trim_end(
tcp->incoming_buffer,
tcp->incoming_buffer->length - (size_t)read_bytes,
&tcp->last_read_buffer);
@@ -275,8 +260,8 @@ static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp,
grpc_error *error) {
grpc_tcp *tcp = tcpp;
if (error != GRPC_ERROR_NONE) {
- gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
- gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+ grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
@@ -301,8 +286,8 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
GPR_ASSERT(!tcp->finished_edge);
if (error != GRPC_ERROR_NONE) {
- gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
- gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+ grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
@@ -311,13 +296,13 @@ static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
}
static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *incoming_buffer, grpc_closure *cb) {
+ grpc_slice_buffer *incoming_buffer, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
GPR_ASSERT(tcp->read_cb == NULL);
tcp->read_cb = cb;
tcp->incoming_buffer = incoming_buffer;
- gpr_slice_buffer_reset_and_unref(incoming_buffer);
- gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
+ grpc_slice_buffer_reset_and_unref(incoming_buffer);
+ grpc_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
TCP_REF(tcp, "read");
if (tcp->finished_edge) {
tcp->finished_edge = false;
@@ -347,11 +332,11 @@ static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
iov_size != MAX_WRITE_IOVEC;
iov_size++) {
iov[iov_size].iov_base =
- GPR_SLICE_START_PTR(
+ GRPC_SLICE_START_PTR(
tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
tcp->outgoing_byte_idx;
iov[iov_size].iov_len =
- GPR_SLICE_LENGTH(
+ GRPC_SLICE_LENGTH(
tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
tcp->outgoing_byte_idx;
sending_length += iov[iov_size].iov_len;
@@ -392,7 +377,7 @@ static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
size_t slice_length;
tcp->outgoing_slice_idx--;
- slice_length = GPR_SLICE_LENGTH(
+ slice_length = GRPC_SLICE_LENGTH(
tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
if (slice_length > trailing) {
tcp->outgoing_byte_idx = slice_length - trailing;
@@ -442,7 +427,7 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
}
static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *buf, grpc_closure *cb) {
+ grpc_slice_buffer *buf, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_error *error = GRPC_ERROR_NONE;
@@ -451,7 +436,7 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
for (i = 0; i < buf->count; i++) {
char *data =
- gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ grpc_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
gpr_free(data);
}
@@ -508,6 +493,11 @@ static char *tcp_get_peer(grpc_endpoint *ep) {
return gpr_strdup(tcp->peer_string);
}
+static int tcp_get_fd(grpc_endpoint *ep) {
+ grpc_tcp *tcp = (grpc_tcp *)ep;
+ return tcp->fd;
+}
+
static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return grpc_fd_get_workqueue(tcp->em_fd);
@@ -515,7 +505,7 @@ static grpc_workqueue *tcp_get_workqueue(grpc_endpoint *ep) {
static grpc_resource_user *tcp_get_resource_user(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- return &tcp->resource_user;
+ return tcp->resource_user;
}
static const grpc_endpoint_vtable vtable = {tcp_read,
@@ -526,7 +516,8 @@ static const grpc_endpoint_vtable vtable = {tcp_read,
tcp_shutdown,
tcp_destroy,
tcp_get_resource_user,
- tcp_get_peer};
+ tcp_get_peer,
+ tcp_get_fd};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
grpc_resource_quota *resource_quota,
@@ -543,20 +534,18 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
tcp->slice_size = slice_size;
tcp->iov_size = 1;
tcp->finished_edge = true;
- /* paired with unref in grpc_tcp_destroy, and with the shutdown for our
- * resource_user */
- gpr_ref_init(&tcp->refcount, 2);
+ /* paired with unref in grpc_tcp_destroy */
+ gpr_ref_init(&tcp->refcount, 1);
gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
tcp->em_fd = em_fd;
tcp->read_closure.cb = tcp_handle_read;
tcp->read_closure.cb_arg = tcp;
tcp->write_closure.cb = tcp_handle_write;
tcp->write_closure.cb_arg = tcp;
- gpr_slice_buffer_init(&tcp->last_read_buffer);
- grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
- grpc_resource_user_slice_allocator_init(&tcp->slice_allocator,
- &tcp->resource_user,
- tcp_read_allocation_done, tcp);
+ grpc_slice_buffer_init(&tcp->last_read_buffer);
+ tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
+ grpc_resource_user_slice_allocator_init(
+ &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
/* Tell network status tracker about new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
@@ -576,8 +565,7 @@ void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
GPR_ASSERT(ep->vtable == &vtable);
tcp->release_fd = fd;
tcp->release_fd_cb = done;
- tcp_maybe_shutdown_resource_user(exec_ctx, tcp);
- gpr_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+ grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
TCP_UNREF(exec_ctx, tcp, "destroy");
}
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index b6fc1e4ca2..7e2fb0f1f9 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -657,41 +657,46 @@ done:
}
}
+/* Return listener at port_index or NULL. Should only be called with s->mu
+ locked. */
+static grpc_tcp_listener *get_port_index(grpc_tcp_server *s,
+ unsigned port_index) {
+ unsigned num_ports = 0;
+ grpc_tcp_listener *sp;
+ for (sp = s->head; sp; sp = sp->next) {
+ if (!sp->is_sibling) {
+ if (++num_ports > port_index) {
+ return sp;
+ }
+ }
+ }
+ return NULL;
+}
+
unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server *s,
unsigned port_index) {
unsigned num_fds = 0;
- grpc_tcp_listener *sp;
gpr_mu_lock(&s->mu);
- for (sp = s->head; sp && port_index != 0; sp = sp->next) {
- if (!sp->is_sibling) {
- --port_index;
- }
+ grpc_tcp_listener *sp = get_port_index(s, port_index);
+ for (; sp; sp = sp->sibling) {
+ ++num_fds;
}
- for (; sp; sp = sp->sibling, ++num_fds)
- ;
gpr_mu_unlock(&s->mu);
return num_fds;
}
int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
unsigned fd_index) {
- grpc_tcp_listener *sp;
- int fd;
gpr_mu_lock(&s->mu);
- for (sp = s->head; sp && port_index != 0; sp = sp->next) {
- if (!sp->is_sibling) {
- --port_index;
+ grpc_tcp_listener *sp = get_port_index(s, port_index);
+ for (; sp; sp = sp->sibling, --fd_index) {
+ if (fd_index == 0) {
+ gpr_mu_unlock(&s->mu);
+ return sp->fd;
}
}
- for (; sp && fd_index != 0; sp = sp->sibling, --fd_index)
- ;
- if (sp) {
- fd = sp->fd;
- } else {
- fd = -1;
- }
gpr_mu_unlock(&s->mu);
- return fd;
+ return -1;
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index ae54c70d2d..b8a391c059 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -73,6 +73,7 @@ struct grpc_tcp_listener {
/* The cached AcceptEx for that port. */
LPFN_ACCEPTEX AcceptEx;
int shutting_down;
+ int outstanding_calls;
/* closure for socket notification of accept being ready */
grpc_closure on_accept;
/* linked list */
@@ -140,10 +141,9 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
return GRPC_ERROR_NONE;
}
-static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
- if (s->shutdown_complete != NULL) {
- grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
- }
+static void destroy_server(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
+ grpc_tcp_server *s = arg;
/* Now that the accepts have been aborted, we can destroy the sockets.
The IOCP won't get notified on these, so we can flag them as already
@@ -159,6 +159,16 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
gpr_free(s);
}
+static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
+ grpc_tcp_server *s) {
+ if (s->shutdown_complete != NULL) {
+ grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
+ }
+
+ grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(destroy_server, s),
+ GRPC_ERROR_NONE, NULL);
+}
+
grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
gpr_ref_non_zero(&s->refs);
return s;
@@ -180,17 +190,14 @@ static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
/* First, shutdown all fd's. This will queue abortion calls for all
of the pending accepts due to the normal operation mechanism. */
if (s->active_ports == 0) {
- immediately_done = 1;
- }
- for (sp = s->head; sp; sp = sp->next) {
- sp->shutting_down = 1;
- grpc_winsocket_shutdown(sp->socket);
+ finish_shutdown_locked(exec_ctx, s);
+ } else {
+ for (sp = s->head; sp; sp = sp->next) {
+ sp->shutting_down = 1;
+ grpc_winsocket_shutdown(sp->socket);
+ }
}
gpr_mu_unlock(&s->mu);
-
- if (immediately_done) {
- finish_shutdown(exec_ctx, s);
- }
}
void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
@@ -251,31 +258,30 @@ failure:
return error;
}
-static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
- grpc_tcp_listener *sp) {
+static void decrement_active_ports_and_notify_locked(grpc_exec_ctx *exec_ctx,
+ grpc_tcp_listener *sp) {
int notify = 0;
sp->shutting_down = 0;
- gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
if (0 == --sp->server->active_ports) {
- notify = 1;
- }
- gpr_mu_unlock(&sp->server->mu);
- if (notify) {
- finish_shutdown(exec_ctx, sp->server);
+ finish_shutdown_locked(exec_ctx, sp->server);
}
}
/* In order to do an async accept, we need to create a socket first which
will be the one assigned to the new incoming connection. */
-static grpc_error *start_accept(grpc_exec_ctx *exec_ctx,
- grpc_tcp_listener *port) {
+static grpc_error *start_accept_locked(grpc_exec_ctx *exec_ctx,
+ grpc_tcp_listener *port) {
SOCKET sock = INVALID_SOCKET;
BOOL success;
DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
DWORD bytes_received = 0;
grpc_error *error = GRPC_ERROR_NONE;
+ if (port->shutting_down) {
+ return GRPC_ERROR_NONE;
+ }
+
sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) {
@@ -305,20 +311,11 @@ static grpc_error *start_accept(grpc_exec_ctx *exec_ctx,
immediately process an accept that happened in the meantime. */
port->new_socket = sock;
grpc_socket_notify_on_read(exec_ctx, port->socket, &port->on_accept);
+ port->outstanding_calls++;
return error;
failure:
GPR_ASSERT(error != GRPC_ERROR_NONE);
- if (port->shutting_down) {
- /* We are abandoning the listener port, take that into account to prevent
- occasional hangs on shutdown. The hang happens when sp->shutting_down
- change is not seen by on_accept and we proceed to trying new accept,
- but we fail there because the listening port has been closed in the
- meantime. */
- decrement_active_ports_and_notify(exec_ctx, port);
- GRPC_ERROR_UNREF(error);
- return GRPC_ERROR_NONE;
- }
if (sock != INVALID_SOCKET) closesocket(sock);
return error;
}
@@ -338,6 +335,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
BOOL wsa_success;
int err;
+ gpr_mu_lock(&sp->server->mu);
+
peer_name.len = sizeof(struct sockaddr_storage);
/* The general mechanism for shutting down is to queue abortion calls. While
@@ -347,6 +346,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
const char *msg = grpc_error_string(error);
gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
grpc_error_free_string(msg);
+ gpr_mu_unlock(&sp->server->mu);
return;
}
@@ -356,17 +356,12 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
&transfered_bytes, FALSE, &flags);
if (!wsa_success) {
- if (sp->shutting_down) {
- /* During the shutdown case, we ARE expecting an error. So that's well,
- and we can wake up the shutdown thread. */
- decrement_active_ports_and_notify(exec_ctx, sp);
- return;
- } else {
+ if (!sp->shutting_down) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
gpr_free(utf8_message);
- closesocket(sock);
}
+ closesocket(sock);
} else {
if (!sp->shutting_down) {
peer_name_string = NULL;
@@ -408,7 +403,12 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
the former socked we created has now either been destroy or assigned
to the new connection. We need to create a new one for the next
connection. */
- GPR_ASSERT(GRPC_LOG_IF_ERROR("start_accept", start_accept(exec_ctx, sp)));
+ GPR_ASSERT(
+ GRPC_LOG_IF_ERROR("start_accept", start_accept_locked(exec_ctx, sp)));
+ if (0 == --sp->outstanding_calls) {
+ decrement_active_ports_and_notify_locked(exec_ctx, sp);
+ }
+ gpr_mu_unlock(&sp->server->mu);
}
static grpc_error *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
@@ -456,6 +456,7 @@ static grpc_error *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
sp->server = s;
sp->socket = grpc_winsocket_create(sock, "listener");
sp->shutting_down = 0;
+ sp->outstanding_calls = 0;
sp->AcceptEx = AcceptEx;
sp->new_socket = INVALID_SOCKET;
sp->port = port;
@@ -553,7 +554,8 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
s->on_accept_cb = on_accept_cb;
s->on_accept_cb_arg = on_accept_cb_arg;
for (sp = s->head; sp; sp = sp->next) {
- GPR_ASSERT(GRPC_LOG_IF_ERROR("start_accept", start_accept(exec_ctx, sp)));
+ GPR_ASSERT(
+ GRPC_LOG_IF_ERROR("start_accept", start_accept_locked(exec_ctx, sp)));
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c
index 8e74c9e863..6e2ad1dbe9 100644
--- a/src/core/lib/iomgr/tcp_uv.c
+++ b/src/core/lib/iomgr/tcp_uv.c
@@ -38,14 +38,17 @@
#include <limits.h>
#include <string.h>
+#include <grpc/slice_buffer.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/network_status_tracker.h"
+#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/tcp_uv.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
int grpc_tcp_trace = 0;
@@ -62,15 +65,14 @@ typedef struct {
grpc_closure *read_cb;
grpc_closure *write_cb;
- gpr_slice read_slice;
- gpr_slice_buffer *read_slices;
- gpr_slice_buffer *write_slices;
+ grpc_slice read_slice;
+ grpc_slice_buffer *read_slices;
+ grpc_slice_buffer *write_slices;
uv_buf_t *write_buffers;
- grpc_resource_user resource_user;
+ grpc_resource_user *resource_user;
bool shutting_down;
- bool resource_user_shutting_down;
char *peer_string;
grpc_pollset *pollset;
@@ -78,23 +80,23 @@ typedef struct {
static void uv_close_callback(uv_handle_t *handle) { gpr_free(handle); }
-static void tcp_free(grpc_tcp *tcp) {
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_resource_user_destroy(&exec_ctx, &tcp->resource_user);
+static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
+ grpc_resource_user_unref(exec_ctx, tcp->resource_user);
gpr_free(tcp);
- grpc_exec_ctx_finish(&exec_ctx);
}
/*#define GRPC_TCP_REFCOUNT_DEBUG*/
#ifdef GRPC_TCP_REFCOUNT_DEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
-#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
- int line) {
+#define TCP_UNREF(exec_ctx, tcp, reason) \
+ tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) \
+ tcp_ref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
+ const char *reason, const char *file, int line) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
reason, tcp->refcount.count, tcp->refcount.count - 1);
if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
+ tcp_free(exec_ctx, tcp);
}
}
@@ -105,11 +107,11 @@ static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
gpr_ref(&tcp->refcount);
}
#else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_UNREF(exec_ctx, tcp, reason) tcp_unref((exec_ctx), (tcp))
#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp *tcp) {
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
+ tcp_free(exec_ctx, tcp);
}
}
@@ -122,15 +124,15 @@ static void alloc_uv_buf(uv_handle_t *handle, size_t suggested_size,
grpc_tcp *tcp = handle->data;
(void)suggested_size;
tcp->read_slice = grpc_resource_user_slice_malloc(
- &exec_ctx, &tcp->resource_user, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
- buf->base = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
- buf->len = GPR_SLICE_LENGTH(tcp->read_slice);
+ &exec_ctx, tcp->resource_user, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
+ buf->base = (char *)GRPC_SLICE_START_PTR(tcp->read_slice);
+ buf->len = GRPC_SLICE_LENGTH(tcp->read_slice);
grpc_exec_ctx_finish(&exec_ctx);
}
static void read_callback(uv_stream_t *stream, ssize_t nread,
const uv_buf_t *buf) {
- gpr_slice sub;
+ grpc_slice sub;
grpc_error *error;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_tcp *tcp = stream->data;
@@ -139,7 +141,7 @@ static void read_callback(uv_stream_t *stream, ssize_t nread,
// Nothing happened. Wait for the next callback
return;
}
- TCP_UNREF(tcp, "read");
+ TCP_UNREF(&exec_ctx, tcp, "read");
tcp->read_cb = NULL;
// TODO(murgatroid99): figure out what the return value here means
uv_read_stop(stream);
@@ -147,8 +149,8 @@ static void read_callback(uv_stream_t *stream, ssize_t nread,
error = GRPC_ERROR_CREATE("EOF");
} else if (nread > 0) {
// Successful read
- sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, (size_t)nread);
- gpr_slice_buffer_add(tcp->read_slices, sub);
+ sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, (size_t)nread);
+ grpc_slice_buffer_add(tcp->read_slices, sub);
error = GRPC_ERROR_NONE;
if (grpc_tcp_trace) {
size_t i;
@@ -156,8 +158,8 @@ static void read_callback(uv_stream_t *stream, ssize_t nread,
gpr_log(GPR_DEBUG, "read: error=%s", str);
grpc_error_free_string(str);
for (i = 0; i < tcp->read_slices->count; i++) {
- char *dump = gpr_dump_slice(tcp->read_slices->slices[i],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *dump = grpc_dump_slice(tcp->read_slices->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string,
dump);
gpr_free(dump);
@@ -172,14 +174,14 @@ static void read_callback(uv_stream_t *stream, ssize_t nread,
}
static void uv_endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *read_slices, grpc_closure *cb) {
+ grpc_slice_buffer *read_slices, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
int status;
grpc_error *error = GRPC_ERROR_NONE;
GPR_ASSERT(tcp->read_cb == NULL);
tcp->read_cb = cb;
tcp->read_slices = read_slices;
- gpr_slice_buffer_reset_and_unref(read_slices);
+ grpc_slice_buffer_reset_and_unref(read_slices);
TCP_REF(tcp, "read");
// TODO(murgatroid99): figure out what the return value here means
status =
@@ -202,7 +204,7 @@ static void write_callback(uv_write_t *req, int status) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
grpc_closure *cb = tcp->write_cb;
tcp->write_cb = NULL;
- TCP_UNREF(tcp, "write");
+ TCP_UNREF(&exec_ctx, tcp, "write");
if (status == 0) {
error = GRPC_ERROR_NONE;
} else {
@@ -213,28 +215,28 @@ static void write_callback(uv_write_t *req, int status) {
gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp, str);
}
gpr_free(tcp->write_buffers);
- grpc_resource_user_free(&exec_ctx, &tcp->resource_user,
+ grpc_resource_user_free(&exec_ctx, tcp->resource_user,
sizeof(uv_buf_t) * tcp->write_slices->count);
grpc_exec_ctx_sched(&exec_ctx, cb, error, NULL);
grpc_exec_ctx_finish(&exec_ctx);
}
static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *write_slices,
+ grpc_slice_buffer *write_slices,
grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
uv_buf_t *buffers;
unsigned int buffer_count;
unsigned int i;
- gpr_slice *slice;
+ grpc_slice *slice;
uv_write_t *write_req;
if (grpc_tcp_trace) {
size_t j;
for (j = 0; j < write_slices->count; j++) {
- char *data = gpr_dump_slice(write_slices->slices[j],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *data = grpc_dump_slice(write_slices->slices[j],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", tcp, tcp->peer_string, data);
gpr_free(data);
}
@@ -259,12 +261,12 @@ static void uv_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
tcp->write_cb = cb;
buffer_count = (unsigned int)tcp->write_slices->count;
buffers = gpr_malloc(sizeof(uv_buf_t) * buffer_count);
- grpc_resource_user_alloc(exec_ctx, &tcp->resource_user,
+ grpc_resource_user_alloc(exec_ctx, tcp->resource_user,
sizeof(uv_buf_t) * buffer_count, NULL);
for (i = 0; i < buffer_count; i++) {
slice = &tcp->write_slices->slices[i];
- buffers[i].base = (char *)GPR_SLICE_START_PTR(*slice);
- buffers[i].len = GPR_SLICE_LENGTH(*slice);
+ buffers[i].base = (char *)GRPC_SLICE_START_PTR(*slice);
+ buffers[i].len = GRPC_SLICE_LENGTH(*slice);
}
tcp->write_buffers = buffers;
write_req = &tcp->write_req;
@@ -295,22 +297,6 @@ static void uv_add_to_pollset_set(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
static void shutdown_callback(uv_shutdown_t *req, int status) {}
-static void resource_user_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- TCP_UNREF(arg, "resource_user");
-}
-
-static void uv_resource_user_maybe_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_tcp *tcp) {
- if (!tcp->resource_user_shutting_down) {
- tcp->resource_user_shutting_down = true;
- TCP_REF(tcp, "resource_user");
- grpc_resource_user_shutdown(
- exec_ctx, &tcp->resource_user,
- grpc_closure_create(resource_user_shutdown_done, tcp));
- }
-}
-
static void uv_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
if (!tcp->shutting_down) {
@@ -324,8 +310,7 @@ static void uv_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp *tcp = (grpc_tcp *)ep;
uv_close((uv_handle_t *)tcp->handle, uv_close_callback);
- uv_resource_user_maybe_shutdown(exec_ctx, tcp);
- TCP_UNREF(tcp, "destroy");
+ TCP_UNREF(exec_ctx, tcp, "destroy");
}
static char *uv_get_peer(grpc_endpoint *ep) {
@@ -335,15 +320,18 @@ static char *uv_get_peer(grpc_endpoint *ep) {
static grpc_resource_user *uv_get_resource_user(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- return &tcp->resource_user;
+ return tcp->resource_user;
}
static grpc_workqueue *uv_get_workqueue(grpc_endpoint *ep) { return NULL; }
+static int uv_get_fd(grpc_endpoint *ep) { return -1; }
+
static grpc_endpoint_vtable vtable = {
uv_endpoint_read, uv_endpoint_write, uv_get_workqueue,
uv_add_to_pollset, uv_add_to_pollset_set, uv_endpoint_shutdown,
- uv_destroy, uv_get_resource_user, uv_get_peer};
+ uv_destroy, uv_get_resource_user, uv_get_peer,
+ uv_get_fd};
grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle,
grpc_resource_quota *resource_quota,
@@ -364,8 +352,7 @@ grpc_endpoint *grpc_tcp_create(uv_tcp_t *handle,
gpr_ref_init(&tcp->refcount, 1);
tcp->peer_string = gpr_strdup(peer_string);
tcp->shutting_down = false;
- tcp->resource_user_shutting_down = false;
- grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
+ tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
/* Tell network status tracking code about the new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index 46f0491d10..d4613b674e 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -40,10 +40,10 @@
#include "src/core/lib/iomgr/network_status_tracker.h"
#include "src/core/lib/iomgr/sockaddr_windows.h"
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/log_windows.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
@@ -105,50 +105,39 @@ typedef struct grpc_tcp {
grpc_closure *read_cb;
grpc_closure *write_cb;
- gpr_slice read_slice;
- gpr_slice_buffer *write_slices;
- gpr_slice_buffer *read_slices;
+ grpc_slice read_slice;
+ grpc_slice_buffer *write_slices;
+ grpc_slice_buffer *read_slices;
- grpc_resource_user resource_user;
+ grpc_resource_user *resource_user;
/* The IO Completion Port runs from another thread. We need some mechanism
to protect ourselves when requesting a shutdown. */
gpr_mu mu;
int shutting_down;
- gpr_atm resource_user_shutdown_count;
-
char *peer_string;
} grpc_tcp;
-static void win_unref_closure(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- grpc_error *error);
-
-static void win_maybe_shutdown_resource_user(grpc_exec_ctx *exec_ctx,
- grpc_tcp *tcp) {
- if (gpr_atm_full_fetch_add(&tcp->resource_user_shutdown_count, 1) == 0) {
- grpc_resource_user_shutdown(exec_ctx, &tcp->resource_user,
- grpc_closure_create(win_unref_closure, tcp));
- }
-}
-
-static void tcp_free(grpc_tcp *tcp) {
+static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
grpc_winsocket_destroy(tcp->socket);
gpr_mu_destroy(&tcp->mu);
gpr_free(tcp->peer_string);
+ grpc_resource_user_unref(exec_ctx, tcp->resource_user);
gpr_free(tcp);
}
/*#define GRPC_TCP_REFCOUNT_DEBUG*/
#ifdef GRPC_TCP_REFCOUNT_DEBUG
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_UNREF(exec_ctx, tcp, reason) \
+ tcp_unref((exec_ctx), (tcp), (reason), __FILE__, __LINE__)
#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
-static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
- int line) {
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
+ const char *reason, const char *file, int line) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
reason, tcp->refcount.count, tcp->refcount.count - 1);
if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
+ tcp_free(exec_ctx, tcp);
}
}
@@ -159,28 +148,23 @@ static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
gpr_ref(&tcp->refcount);
}
#else
-#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_UNREF(exec_ctx, tcp, reason) tcp_unref((exec_ctx), (tcp))
#define TCP_REF(tcp, reason) tcp_ref((tcp))
-static void tcp_unref(grpc_tcp *tcp) {
+static void tcp_unref(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
if (gpr_unref(&tcp->refcount)) {
- tcp_free(tcp);
+ tcp_free(exec_ctx, tcp);
}
}
static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
#endif
-static void win_unref_closure(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_error *error) {
- TCP_UNREF(arg, "resource_user");
-}
-
/* Asynchronous callback from the IOCP, or the background thread. */
static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
grpc_tcp *tcp = tcpp;
grpc_closure *cb = tcp->read_cb;
grpc_winsocket *socket = tcp->socket;
- gpr_slice sub;
+ grpc_slice sub;
grpc_winsocket_callback_info *info = &socket->read_info;
GRPC_ERROR_REF(error);
@@ -190,25 +174,25 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
char *utf8_message = gpr_format_message(info->wsa_error);
error = GRPC_ERROR_CREATE(utf8_message);
gpr_free(utf8_message);
- gpr_slice_unref(tcp->read_slice);
+ grpc_slice_unref(tcp->read_slice);
} else {
if (info->bytes_transfered != 0 && !tcp->shutting_down) {
- sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
- gpr_slice_buffer_add(tcp->read_slices, sub);
+ sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
+ grpc_slice_buffer_add(tcp->read_slices, sub);
} else {
- gpr_slice_unref(tcp->read_slice);
+ grpc_slice_unref(tcp->read_slice);
error = GRPC_ERROR_CREATE("End of TCP stream");
}
}
}
tcp->read_cb = NULL;
- TCP_UNREF(tcp, "read");
+ TCP_UNREF(exec_ctx, tcp, "read");
grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *read_slices, grpc_closure *cb) {
+ grpc_slice_buffer *read_slices, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->read_info;
@@ -225,13 +209,13 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
tcp->read_cb = cb;
tcp->read_slices = read_slices;
- gpr_slice_buffer_reset_and_unref(read_slices);
+ grpc_slice_buffer_reset_and_unref(read_slices);
- tcp->read_slice = gpr_slice_malloc(8192);
+ tcp->read_slice = grpc_slice_malloc(8192);
- buffer.len = (ULONG)GPR_SLICE_LENGTH(
+ buffer.len = (ULONG)GRPC_SLICE_LENGTH(
tcp->read_slice); // we know slice size fits in 32bit.
- buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
+ buffer.buf = (char *)GRPC_SLICE_START_PTR(tcp->read_slice);
TCP_REF(tcp, "read");
@@ -287,13 +271,13 @@ static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
}
}
- TCP_UNREF(tcp, "write");
+ TCP_UNREF(exec_ctx, tcp, "write");
grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
/* Initiates a write. */
static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
- gpr_slice_buffer *slices, grpc_closure *cb) {
+ grpc_slice_buffer *slices, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *socket = tcp->socket;
grpc_winsocket_callback_info *info = &socket->write_info;
@@ -320,10 +304,10 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
}
for (i = 0; i < tcp->write_slices->count; i++) {
- len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
+ len = GRPC_SLICE_LENGTH(tcp->write_slices->slices[i]);
GPR_ASSERT(len <= ULONG_MAX);
buffers[i].len = (ULONG)len;
- buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
+ buffers[i].buf = (char *)GRPC_SLICE_START_PTR(tcp->write_slices->slices[i]);
}
/* First, let's try a synchronous, non-blocking write. */
@@ -355,7 +339,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
if (status != 0) {
int wsa_error = WSAGetLastError();
if (wsa_error != WSA_IO_PENDING) {
- TCP_UNREF(tcp, "write");
+ TCP_UNREF(exec_ctx, tcp, "write");
grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"),
NULL);
return;
@@ -396,15 +380,14 @@ static void win_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
callback. See the comments in on_read and on_write. */
tcp->shutting_down = 1;
grpc_winsocket_shutdown(tcp->socket);
- win_maybe_shutdown_resource_user(exec_ctx, tcp);
gpr_mu_unlock(&tcp->mu);
+ grpc_resource_user_shutdown(exec_ctx, tcp->resource_user);
}
static void win_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_network_status_unregister_endpoint(ep);
grpc_tcp *tcp = (grpc_tcp *)ep;
- win_maybe_shutdown_resource_user(exec_ctx, tcp);
- TCP_UNREF(tcp, "destroy");
+ TCP_UNREF(exec_ctx, tcp, "destroy");
}
static char *win_get_peer(grpc_endpoint *ep) {
@@ -416,9 +399,11 @@ static grpc_workqueue *win_get_workqueue(grpc_endpoint *ep) { return NULL; }
static grpc_resource_user *win_get_resource_user(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- return &tcp->resource_user;
+ return tcp->resource_user;
}
+static int win_get_fd(grpc_endpoint *ep) { return -1; }
+
static grpc_endpoint_vtable vtable = {win_read,
win_write,
win_get_workqueue,
@@ -427,7 +412,8 @@ static grpc_endpoint_vtable vtable = {win_read,
win_shutdown,
win_destroy,
win_get_resource_user,
- win_get_peer};
+ win_get_peer,
+ win_get_fd};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
grpc_resource_quota *resource_quota,
@@ -437,11 +423,11 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
tcp->base.vtable = &vtable;
tcp->socket = socket;
gpr_mu_init(&tcp->mu);
- gpr_ref_init(&tcp->refcount, 2);
+ gpr_ref_init(&tcp->refcount, 1);
grpc_closure_init(&tcp->on_read, on_read, tcp);
grpc_closure_init(&tcp->on_write, on_write, tcp);
tcp->peer_string = gpr_strdup(peer_string);
- grpc_resource_user_init(&tcp->resource_user, resource_quota, peer_string);
+ tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
/* Tell network status tracking code about the new endpoint */
grpc_network_status_register_endpoint(&tcp->base);
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index fd0c7a0f9d..3c24ea9afa 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -388,7 +388,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
/* Try listening on IPv6 first. */
addr = &wild6;
// TODO(rjshade): Test and propagate the returned grpc_error*:
- grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
+ GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP,
+ &dsmode, &fd));
allocated_port1 = add_socket_to_server(s, fd, addr, read_cb, orphan_cb);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
@@ -402,7 +403,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s,
}
// TODO(rjshade): Test and propagate the returned grpc_error*:
- grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode, &fd);
+ GRPC_ERROR_UNREF(grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP,
+ &dsmode, &fd));
if (fd < 0) {
gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
}
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.c b/src/core/lib/iomgr/wakeup_fd_pipe.c
index 183f0eb930..e186d63683 100644
--- a/src/core/lib/iomgr/wakeup_fd_pipe.c
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.c
@@ -95,6 +95,8 @@ static void pipe_destroy(grpc_wakeup_fd* fd_info) {
static int pipe_check_availability(void) {
grpc_wakeup_fd fd;
+ fd.read_fd = fd.write_fd = -1;
+
if (pipe_init(&fd) == GRPC_ERROR_NONE) {
pipe_destroy(&fd);
return 1;
diff --git a/src/core/lib/json/json.c b/src/core/lib/json/json.c
index 5b583a1f2e..48b13686d7 100644
--- a/src/core/lib/json/json.c
+++ b/src/core/lib/json/json.c
@@ -37,15 +37,15 @@
#include "src/core/lib/json/json.h"
-grpc_json *grpc_json_create(grpc_json_type type) {
- grpc_json *json = gpr_malloc(sizeof(*json));
+grpc_json* grpc_json_create(grpc_json_type type) {
+ grpc_json* json = gpr_malloc(sizeof(*json));
memset(json, 0, sizeof(*json));
json->type = type;
return json;
}
-void grpc_json_destroy(grpc_json *json) {
+void grpc_json_destroy(grpc_json* json) {
while (json->child) {
grpc_json_destroy(json->child);
}
diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h
index 681df4bb77..7111db0b52 100644
--- a/src/core/lib/json/json.h
+++ b/src/core/lib/json/json.h
@@ -42,14 +42,14 @@
* are not owned by it.
*/
typedef struct grpc_json {
- struct grpc_json *next;
- struct grpc_json *prev;
- struct grpc_json *child;
- struct grpc_json *parent;
+ struct grpc_json* next;
+ struct grpc_json* prev;
+ struct grpc_json* child;
+ struct grpc_json* parent;
grpc_json_type type;
- const char *key;
- const char *value;
+ const char* key;
+ const char* value;
} grpc_json;
/* The next two functions are going to parse the input string, and
@@ -65,8 +65,8 @@ typedef struct grpc_json {
*
* Delete the allocated tree afterward using grpc_json_destroy().
*/
-grpc_json *grpc_json_parse_string_with_len(char *input, size_t size);
-grpc_json *grpc_json_parse_string(char *input);
+grpc_json* grpc_json_parse_string_with_len(char* input, size_t size);
+grpc_json* grpc_json_parse_string(char* input);
/* This function will create a new string using gpr_realloc, and will
* deserialize the grpc_json tree into it. It'll be zero-terminated,
@@ -76,13 +76,13 @@ grpc_json *grpc_json_parse_string(char *input);
* If indent is 0, then newlines will be suppressed as well, and the
* output will be condensed at its maximum.
*/
-char *grpc_json_dump_to_string(grpc_json *json, int indent);
+char* grpc_json_dump_to_string(grpc_json* json, int indent);
/* Use these to create or delete a grpc_json object.
* Deletion is recursive. We will not attempt to free any of the strings
* in any of the objects of that tree.
*/
-grpc_json *grpc_json_create(grpc_json_type type);
-void grpc_json_destroy(grpc_json *json);
+grpc_json* grpc_json_create(grpc_json_type type);
+void grpc_json_destroy(grpc_json* json);
#endif /* GRPC_CORE_LIB_JSON_JSON_H */
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index 6fb5b5b15a..85b3bc5350 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -141,8 +141,8 @@ grpc_channel_credentials_duplicate_without_call_credentials(
/* --- grpc_credentials_md. --- */
typedef struct {
- gpr_slice key;
- gpr_slice value;
+ grpc_slice key;
+ grpc_slice value;
} grpc_credentials_md;
typedef struct {
@@ -157,7 +157,7 @@ grpc_credentials_md_store *grpc_credentials_md_store_create(
/* Will ref key and value. */
void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
- gpr_slice key, gpr_slice value);
+ grpc_slice key, grpc_slice value);
void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
const char *key, const char *value);
grpc_credentials_md_store *grpc_credentials_md_store_ref(
diff --git a/src/core/lib/security/credentials/credentials_metadata.c b/src/core/lib/security/credentials/credentials_metadata.c
index 6a352aab3a..e6cb567734 100644
--- a/src/core/lib/security/credentials/credentials_metadata.c
+++ b/src/core/lib/security/credentials/credentials_metadata.c
@@ -59,11 +59,11 @@ grpc_credentials_md_store *grpc_credentials_md_store_create(
}
void grpc_credentials_md_store_add(grpc_credentials_md_store *store,
- gpr_slice key, gpr_slice value) {
+ grpc_slice key, grpc_slice value) {
if (store == NULL) return;
store_ensure_capacity(store);
- store->entries[store->num_entries].key = gpr_slice_ref(key);
- store->entries[store->num_entries].value = gpr_slice_ref(value);
+ store->entries[store->num_entries].key = grpc_slice_ref(key);
+ store->entries[store->num_entries].value = grpc_slice_ref(value);
store->num_entries++;
}
@@ -72,9 +72,9 @@ void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store,
const char *value) {
if (store == NULL) return;
store_ensure_capacity(store);
- store->entries[store->num_entries].key = gpr_slice_from_copied_string(key);
+ store->entries[store->num_entries].key = grpc_slice_from_copied_string(key);
store->entries[store->num_entries].value =
- gpr_slice_from_copied_string(value);
+ grpc_slice_from_copied_string(value);
store->num_entries++;
}
@@ -91,8 +91,8 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) {
if (store->entries != NULL) {
size_t i;
for (i = 0; i < store->num_entries; i++) {
- gpr_slice_unref(store->entries[i].key);
- gpr_slice_unref(store->entries[i].value);
+ grpc_slice_unref(store->entries[i].key);
+ grpc_slice_unref(store->entries[i].value);
}
gpr_free(store->entries);
}
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c
index cb5ba554b0..afe0e3d357 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.c
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c
@@ -45,6 +45,7 @@
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
#include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
@@ -174,7 +175,7 @@ static grpc_error *create_default_creds_from_path(
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_call_credentials *result = NULL;
- gpr_slice creds_data = gpr_empty_slice();
+ grpc_slice creds_data = gpr_empty_slice();
grpc_error *error = GRPC_ERROR_NONE;
if (creds_path == NULL) {
error = GRPC_ERROR_CREATE("creds_path unset");
@@ -185,9 +186,9 @@ static grpc_error *create_default_creds_from_path(
goto end;
}
json = grpc_json_parse_string_with_len(
- (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
+ (char *)GRPC_SLICE_START_PTR(creds_data), GRPC_SLICE_LENGTH(creds_data));
if (json == NULL) {
- char *dump = gpr_dump_slice(creds_data, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *dump = grpc_dump_slice(creds_data, GPR_DUMP_HEX | GPR_DUMP_ASCII);
error = grpc_error_set_str(GRPC_ERROR_CREATE("Failed to parse JSON"),
GRPC_ERROR_STR_RAW_BYTES, dump);
gpr_free(dump);
@@ -224,7 +225,7 @@ static grpc_error *create_default_creds_from_path(
end:
GPR_ASSERT((result == NULL) + (error == GRPC_ERROR_NONE) == 1);
if (creds_path != NULL) gpr_free(creds_path);
- gpr_slice_unref(creds_data);
+ grpc_slice_unref(creds_data);
if (json != NULL) grpc_json_destroy(json);
*creds = result;
return error;
diff --git a/src/core/lib/security/credentials/jwt/json_token.h b/src/core/lib/security/credentials/jwt/json_token.h
index 07fc5bf0e0..c13eb55803 100644
--- a/src/core/lib/security/credentials/jwt/json_token.h
+++ b/src/core/lib/security/credentials/jwt/json_token.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include <openssl/rsa.h>
#include "src/core/lib/json/json.h"
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c
index f87ba0ce8d..3daf0f4ef7 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.c
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c
@@ -144,17 +144,44 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
return &c->base;
}
+static char *redact_private_key(const char *json_key) {
+ char *json_copy = gpr_strdup(json_key);
+ grpc_json *json = grpc_json_parse_string(json_copy);
+ if (!json) {
+ gpr_free(json_copy);
+ return gpr_strdup("<Json failed to parse.>");
+ }
+ const char *redacted = "<redacted>";
+ grpc_json *current = json->child;
+ while (current) {
+ if (current->type == GRPC_JSON_STRING &&
+ strcmp(current->key, "private_key") == 0) {
+ current->value = (char *)redacted;
+ break;
+ }
+ current = current->next;
+ }
+ char *clean_json = grpc_json_dump_to_string(json, 2);
+ gpr_free(json_copy);
+ grpc_json_destroy(json);
+ return clean_json;
+}
+
grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
const char *json_key, gpr_timespec token_lifetime, void *reserved) {
- GRPC_API_TRACE(
- "grpc_service_account_jwt_access_credentials_create("
- "json_key=%s, "
- "token_lifetime="
- "gpr_timespec { tv_sec: %" PRId64
- ", tv_nsec: %d, clock_type: %d }, "
- "reserved=%p)",
- 5, (json_key, token_lifetime.tv_sec, token_lifetime.tv_nsec,
- (int)token_lifetime.clock_type, reserved));
+ if (grpc_api_trace) {
+ char *clean_json = redact_private_key(json_key);
+ gpr_log(GPR_INFO,
+ "grpc_service_account_jwt_access_credentials_create("
+ "json_key=%s, "
+ "token_lifetime="
+ "gpr_timespec { tv_sec: %" PRId64
+ ", tv_nsec: %d, clock_type: %d }, "
+ "reserved=%p)",
+ clean_json, token_lifetime.tv_sec, token_lifetime.tv_nsec,
+ (int)token_lifetime.clock_type, reserved);
+ gpr_free(clean_json);
+ }
GPR_ASSERT(reserved == NULL);
return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
grpc_auth_json_key_create_from_string(json_key), token_lifetime);
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index 43eb642515..42bd89dd0a 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -85,18 +85,18 @@ static const EVP_MD *evp_md_from_alg(const char *alg) {
}
static grpc_json *parse_json_part_from_jwt(const char *str, size_t len,
- gpr_slice *buffer) {
+ grpc_slice *buffer) {
grpc_json *json;
*buffer = grpc_base64_decode_with_len(str, len, 1);
- if (GPR_SLICE_IS_EMPTY(*buffer)) {
+ if (GRPC_SLICE_IS_EMPTY(*buffer)) {
gpr_log(GPR_ERROR, "Invalid base64.");
return NULL;
}
- json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer),
- GPR_SLICE_LENGTH(*buffer));
+ json = grpc_json_parse_string_with_len((char *)GRPC_SLICE_START_PTR(*buffer),
+ GRPC_SLICE_LENGTH(*buffer));
if (json == NULL) {
- gpr_slice_unref(*buffer);
+ grpc_slice_unref(*buffer);
gpr_log(GPR_ERROR, "JSON parsing error.");
}
return json;
@@ -129,16 +129,16 @@ typedef struct {
const char *kid;
const char *typ;
/* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */
- gpr_slice buffer;
+ grpc_slice buffer;
} jose_header;
static void jose_header_destroy(jose_header *h) {
- gpr_slice_unref(h->buffer);
+ grpc_slice_unref(h->buffer);
gpr_free(h);
}
/* Takes ownership of json and buffer. */
-static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) {
+static jose_header *jose_header_from_json(grpc_json *json, grpc_slice buffer) {
grpc_json *cur;
jose_header *h = gpr_malloc(sizeof(jose_header));
memset(h, 0, sizeof(jose_header));
@@ -190,12 +190,12 @@ struct grpc_jwt_claims {
gpr_timespec nbf;
grpc_json *json;
- gpr_slice buffer;
+ grpc_slice buffer;
};
void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) {
grpc_json_destroy(claims->json);
- gpr_slice_unref(claims->buffer);
+ grpc_slice_unref(claims->buffer);
gpr_free(claims);
}
@@ -240,7 +240,7 @@ gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims) {
}
/* Takes ownership of json and buffer even in case of failure. */
-grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer) {
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) {
grpc_json *cur;
grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims));
memset(claims, 0, sizeof(grpc_jwt_claims));
@@ -333,8 +333,8 @@ typedef struct {
jose_header *header;
grpc_jwt_claims *claims;
char *audience;
- gpr_slice signature;
- gpr_slice signed_data;
+ grpc_slice signature;
+ grpc_slice signed_data;
void *user_data;
grpc_jwt_verification_done_cb user_cb;
grpc_http_response responses[HTTP_RESPONSE_COUNT];
@@ -343,7 +343,7 @@ typedef struct {
/* Takes ownership of the header, claims and signature. */
static verifier_cb_ctx *verifier_cb_ctx_create(
grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header,
- grpc_jwt_claims *claims, const char *audience, gpr_slice signature,
+ grpc_jwt_claims *claims, const char *audience, grpc_slice signature,
const char *signed_jwt, size_t signed_jwt_len, void *user_data,
grpc_jwt_verification_done_cb cb) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -355,7 +355,7 @@ static verifier_cb_ctx *verifier_cb_ctx_create(
ctx->audience = gpr_strdup(audience);
ctx->claims = claims;
ctx->signature = signature;
- ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len);
+ ctx->signed_data = grpc_slice_from_copied_buffer(signed_jwt, signed_jwt_len);
ctx->user_data = user_data;
ctx->user_cb = cb;
grpc_exec_ctx_finish(&exec_ctx);
@@ -365,8 +365,8 @@ static verifier_cb_ctx *verifier_cb_ctx_create(
void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) {
if (ctx->audience != NULL) gpr_free(ctx->audience);
if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims);
- gpr_slice_unref(ctx->signature);
- gpr_slice_unref(ctx->signed_data);
+ grpc_slice_unref(ctx->signature);
+ grpc_slice_unref(ctx->signed_data);
jose_header_destroy(ctx->header);
for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) {
grpc_http_response_destroy(&ctx->responses[i]);
@@ -449,17 +449,17 @@ end:
static BIGNUM *bignum_from_base64(const char *b64) {
BIGNUM *result = NULL;
- gpr_slice bin;
+ grpc_slice bin;
if (b64 == NULL) return NULL;
bin = grpc_base64_decode(b64, 1);
- if (GPR_SLICE_IS_EMPTY(bin)) {
+ if (GRPC_SLICE_IS_EMPTY(bin)) {
gpr_log(GPR_ERROR, "Invalid base64 for big num.");
return NULL;
}
- result = BN_bin2bn(GPR_SLICE_START_PTR(bin),
- TSI_SIZE_AS_SIZE(GPR_SLICE_LENGTH(bin)), NULL);
- gpr_slice_unref(bin);
+ result = BN_bin2bn(GRPC_SLICE_START_PTR(bin),
+ TSI_SIZE_AS_SIZE(GRPC_SLICE_LENGTH(bin)), NULL);
+ grpc_slice_unref(bin);
return result;
}
@@ -553,7 +553,7 @@ static EVP_PKEY *find_verification_key(const grpc_json *json,
}
static int verify_jwt_signature(EVP_PKEY *key, const char *alg,
- gpr_slice signature, gpr_slice signed_data) {
+ grpc_slice signature, grpc_slice signed_data) {
EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
const EVP_MD *md = evp_md_from_alg(alg);
int result = 0;
@@ -567,13 +567,13 @@ static int verify_jwt_signature(EVP_PKEY *key, const char *alg,
gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed.");
goto end;
}
- if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data),
- GPR_SLICE_LENGTH(signed_data)) != 1) {
+ if (EVP_DigestVerifyUpdate(md_ctx, GRPC_SLICE_START_PTR(signed_data),
+ GRPC_SLICE_LENGTH(signed_data)) != 1) {
gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed.");
goto end;
}
- if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature),
- GPR_SLICE_LENGTH(signature)) != 1) {
+ if (EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(signature),
+ GRPC_SLICE_LENGTH(signature)) != 1) {
gpr_log(GPR_ERROR, "JWT signature verification failed.");
goto end;
}
@@ -799,9 +799,9 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx,
grpc_json *json;
jose_header *header = NULL;
grpc_jwt_claims *claims = NULL;
- gpr_slice header_buffer;
- gpr_slice claims_buffer;
- gpr_slice signature;
+ grpc_slice header_buffer;
+ grpc_slice claims_buffer;
+ grpc_slice signature;
size_t signed_jwt_len;
const char *cur = jwt;
@@ -824,7 +824,7 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx,
signed_jwt_len = (size_t)(dot - jwt);
cur = dot + 1;
signature = grpc_base64_decode(cur, 1);
- if (GPR_SLICE_IS_EMPTY(signature)) goto error;
+ if (GRPC_SLICE_IS_EMPTY(signature)) goto error;
retrieve_key_and_verify(
exec_ctx,
verifier_cb_ctx_create(verifier, pollset, header, claims, audience,
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h
index b0f6d1c240..f09f9d5d47 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -37,7 +37,7 @@
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/json/json.h"
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include <grpc/support/time.h>
/* --- Constants. --- */
@@ -129,7 +129,7 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx,
/* --- TESTING ONLY exposed functions. --- */
-grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer);
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer);
grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
const char *audience);
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
index d980577c46..b3625b22c0 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
@@ -392,15 +392,32 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token(
return &c->base.base;
}
+static char *create_loggable_refresh_token(grpc_auth_refresh_token *token) {
+ if (strcmp(token->type, GRPC_AUTH_JSON_TYPE_INVALID) == 0) {
+ return gpr_strdup("<Invalid json token>");
+ }
+ char *loggable_token = NULL;
+ gpr_asprintf(&loggable_token,
+ "{\n type: %s\n client_id: %s\n client_secret: "
+ "<redacted>\n refresh_token: <redacted>\n}",
+ token->type, token->client_id);
+ return loggable_token;
+}
+
grpc_call_credentials *grpc_google_refresh_token_credentials_create(
const char *json_refresh_token, void *reserved) {
- GRPC_API_TRACE(
- "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
- "reserved=%p)",
- 2, (json_refresh_token, reserved));
+ grpc_auth_refresh_token token =
+ grpc_auth_refresh_token_create_from_string(json_refresh_token);
+ if (grpc_api_trace) {
+ char *loggable_token = create_loggable_refresh_token(&token);
+ gpr_log(GPR_INFO,
+ "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
+ "reserved=%p)",
+ loggable_token, reserved);
+ gpr_free(loggable_token);
+ }
GPR_ASSERT(reserved == NULL);
- return grpc_refresh_token_credentials_create_from_auth_refresh_token(
- grpc_auth_refresh_token_create_from_string(json_refresh_token));
+ return grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
}
//
@@ -430,9 +447,9 @@ grpc_call_credentials *grpc_access_token_credentials_create(
gpr_malloc(sizeof(grpc_access_token_credentials));
char *token_md_value;
GRPC_API_TRACE(
- "grpc_access_token_credentials_create(access_token=%s, "
+ "grpc_access_token_credentials_create(access_token=<redacted>, "
"reserved=%p)",
- 2, (access_token, reserved));
+ 1, (reserved));
GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(grpc_access_token_credentials));
c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c
index 905de3723e..5d950098a0 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.c
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c
@@ -93,17 +93,19 @@ static void plugin_md_request_metadata_ready(void *request,
} else if (num_md > 0) {
md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
for (i = 0; i < num_md; i++) {
- md_array[i].key = gpr_slice_from_copied_string(md[i].key);
+ md_array[i].key = grpc_slice_from_copied_string(md[i].key);
md_array[i].value =
- gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
+ grpc_slice_from_copied_buffer(md[i].value, md[i].value_length);
}
r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK,
NULL);
for (i = 0; i < num_md; i++) {
- gpr_slice_unref(md_array[i].key);
- gpr_slice_unref(md_array[i].value);
+ grpc_slice_unref(md_array[i].key);
+ grpc_slice_unref(md_array[i].value);
}
gpr_free(md_array);
+ } else if (num_md == 0) {
+ r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL);
}
}
gpr_free(r);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index b366d1410f..053bf5972c 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -92,7 +92,7 @@ static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_status_code status, const char *error_msg) {
call_data *calld = elem->call_data;
gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg);
- gpr_slice error_slice = gpr_slice_from_copied_string(error_msg);
+ grpc_slice error_slice = grpc_slice_from_copied_string(error_msg);
grpc_transport_stream_op_add_close(&calld->op, status, &error_slice);
grpc_call_next_op(exec_ctx, elem, &calld->op);
}
@@ -121,8 +121,8 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
for (i = 0; i < num_md; i++) {
grpc_metadata_batch_add_tail(
mdb, &calld->md_links[i],
- grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key),
- gpr_slice_ref(md_elems[i].value)));
+ grpc_mdelem_from_slices(grpc_slice_ref(md_elems[i].key),
+ grpc_slice_ref(md_elems[i].value)));
}
grpc_call_next_op(exec_ctx, elem, op);
}
@@ -341,14 +341,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter");
}
-const grpc_channel_filter grpc_client_auth_filter = {auth_start_transport_op,
- grpc_channel_next_op,
- sizeof(call_data),
- init_call_elem,
- set_pollset_or_pollset_set,
- destroy_call_elem,
- sizeof(channel_data),
- init_channel_elem,
- destroy_channel_elem,
- grpc_call_next_get_peer,
- "client-auth"};
+const grpc_channel_filter grpc_client_auth_filter = {
+ auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
+ init_call_elem, set_pollset_or_pollset_set, destroy_call_elem,
+ sizeof(channel_data), init_channel_elem, destroy_channel_elem,
+ grpc_call_next_get_peer, grpc_channel_next_get_info, "client-auth"};
diff --git a/src/core/lib/security/transport/handshake.c b/src/core/lib/security/transport/handshake.c
deleted file mode 100644
index fbeec312b6..0000000000
--- a/src/core/lib/security/transport/handshake.c
+++ /dev/null
@@ -1,374 +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/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.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"
-
-#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;
- gpr_slice_buffer left_overs;
- gpr_slice_buffer incoming;
- gpr_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_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);
- gpr_slice_buffer_destroy(&h->left_overs);
- gpr_slice_buffer_destroy(&h->outgoing);
- gpr_slice_buffer_destroy(&h->incoming);
- GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
- GRPC_SECURITY_CONNECTOR_UNREF(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_ERROR, "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(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;
- gpr_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 =
- gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
- gpr_slice_buffer_reset_and_unref(&h->outgoing);
- gpr_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 = GPR_SLICE_LENGTH(h->incoming.slices[i]);
- result = tsi_handshaker_process_bytes_from_peer(
- h->handshaker, GPR_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 < GPR_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) {
- gpr_slice_buffer_add(
- &h->left_overs,
- gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size));
- gpr_slice_unref(
- h->incoming.slices[i]); /* split_tail above increments refcount. */
- }
- gpr_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(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, gpr_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);
- gpr_slice_buffer_init(&h->left_overs);
- gpr_slice_buffer_init(&h->outgoing);
- gpr_slice_buffer_init(&h->incoming);
- if (read_buffer != NULL) {
- gpr_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);
-}
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 3924997d31..1b278410e8 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -31,15 +31,22 @@
*
*/
-#include "src/core/lib/security/transport/secure_endpoint.h"
+/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when
+ using that endpoint. Because of various transitive includes in uv.h,
+ including windows.h on Windows, uv.h must be included before other system
+ headers. Therefore, sockaddr.h must always be included first */
+#include "src/core/lib/iomgr/sockaddr.h"
+
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/sync.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/profiling/timers.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_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/transport_security_interface.h"
@@ -54,15 +61,15 @@ typedef struct {
grpc_closure *read_cb;
grpc_closure *write_cb;
grpc_closure on_read;
- gpr_slice_buffer *read_buffer;
- gpr_slice_buffer source_buffer;
+ grpc_slice_buffer *read_buffer;
+ grpc_slice_buffer source_buffer;
/* saved handshaker leftover data to unprotect. */
- gpr_slice_buffer leftover_bytes;
+ grpc_slice_buffer leftover_bytes;
/* buffers for read and write */
- gpr_slice read_staging_buffer;
+ grpc_slice read_staging_buffer;
- gpr_slice write_staging_buffer;
- gpr_slice_buffer output_buffer;
+ grpc_slice write_staging_buffer;
+ grpc_slice_buffer output_buffer;
gpr_refcount ref;
} secure_endpoint;
@@ -73,11 +80,11 @@ static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) {
secure_endpoint *ep = secure_ep;
grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep);
tsi_frame_protector_destroy(ep->protector);
- gpr_slice_buffer_destroy(&ep->leftover_bytes);
- gpr_slice_unref(ep->read_staging_buffer);
- gpr_slice_unref(ep->write_staging_buffer);
- gpr_slice_buffer_destroy(&ep->output_buffer);
- gpr_slice_buffer_destroy(&ep->source_buffer);
+ grpc_slice_buffer_destroy(&ep->leftover_bytes);
+ grpc_slice_unref(ep->read_staging_buffer);
+ grpc_slice_unref(ep->write_staging_buffer);
+ grpc_slice_buffer_destroy(&ep->output_buffer);
+ grpc_slice_buffer_destroy(&ep->source_buffer);
gpr_mu_destroy(&ep->protector_mu);
gpr_free(ep);
}
@@ -121,10 +128,10 @@ static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur,
uint8_t **end) {
- gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
- ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
- *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
- *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+ grpc_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
+ ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
+ *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
+ *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
}
static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
@@ -132,8 +139,8 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
if (grpc_trace_secure_endpoint) {
size_t i;
for (i = 0; i < ep->read_buffer->count; i++) {
- char *data = gpr_dump_slice(ep->read_buffer->slices[i],
- GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ char *data = grpc_dump_slice(ep->read_buffer->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
gpr_free(data);
}
@@ -149,11 +156,11 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
uint8_t keep_looping = 0;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)user_data;
- uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
- uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+ uint8_t *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer);
+ uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
if (error != GRPC_ERROR_NONE) {
- gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+ grpc_slice_buffer_reset_and_unref(ep->read_buffer);
call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING(
"Secure read failed", &error, 1));
return;
@@ -161,9 +168,9 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
/* TODO(yangg) check error, maybe bail out early */
for (i = 0; i < ep->source_buffer.count; i++) {
- gpr_slice encrypted = ep->source_buffer.slices[i];
- uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted);
- size_t message_size = GPR_SLICE_LENGTH(encrypted);
+ grpc_slice encrypted = ep->source_buffer.slices[i];
+ uint8_t *message_bytes = GRPC_SLICE_START_PTR(encrypted);
+ size_t message_size = GRPC_SLICE_LENGTH(encrypted);
while (message_size > 0 || keep_looping) {
size_t unprotected_buffer_size_written = (size_t)(end - cur);
@@ -198,20 +205,20 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
if (result != TSI_OK) break;
}
- if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
- gpr_slice_buffer_add(
+ if (cur != GRPC_SLICE_START_PTR(ep->read_staging_buffer)) {
+ grpc_slice_buffer_add(
ep->read_buffer,
- gpr_slice_split_head(
+ grpc_slice_split_head(
&ep->read_staging_buffer,
- (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer))));
+ (size_t)(cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer))));
}
/* TODO(yangg) experiment with moving this block after read_cb to see if it
helps latency */
- gpr_slice_buffer_reset_and_unref(&ep->source_buffer);
+ grpc_slice_buffer_reset_and_unref(&ep->source_buffer);
if (result != TSI_OK) {
- gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+ grpc_slice_buffer_reset_and_unref(ep->read_buffer);
call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result(
GRPC_ERROR_CREATE("Unwrap failed"), result));
return;
@@ -221,15 +228,15 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
}
static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
- gpr_slice_buffer *slices, grpc_closure *cb) {
+ grpc_slice_buffer *slices, grpc_closure *cb) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
ep->read_cb = cb;
ep->read_buffer = slices;
- gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+ grpc_slice_buffer_reset_and_unref(ep->read_buffer);
SECURE_ENDPOINT_REF(ep, "read");
if (ep->leftover_bytes.count) {
- gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
+ grpc_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
GPR_ASSERT(ep->leftover_bytes.count == 0);
on_read(exec_ctx, ep, GRPC_ERROR_NONE);
return;
@@ -241,37 +248,37 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur,
uint8_t **end) {
- gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
- ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
- *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
- *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+ grpc_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer);
+ ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
+ *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
+ *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);
}
static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
- gpr_slice_buffer *slices, grpc_closure *cb) {
+ grpc_slice_buffer *slices, grpc_closure *cb) {
GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0);
unsigned i;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)secure_ep;
- uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
- uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
+ uint8_t *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
+ uint8_t *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);
- gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
+ grpc_slice_buffer_reset_and_unref(&ep->output_buffer);
if (grpc_trace_secure_endpoint) {
for (i = 0; i < slices->count; i++) {
char *data =
- gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
gpr_free(data);
}
}
for (i = 0; i < slices->count; i++) {
- gpr_slice plain = slices->slices[i];
- uint8_t *message_bytes = GPR_SLICE_START_PTR(plain);
- size_t message_size = GPR_SLICE_LENGTH(plain);
+ grpc_slice plain = slices->slices[i];
+ uint8_t *message_bytes = GRPC_SLICE_START_PTR(plain);
+ size_t message_size = GRPC_SLICE_LENGTH(plain);
while (message_size > 0) {
size_t protected_buffer_size_to_send = (size_t)(end - cur);
size_t processed_message_size = message_size;
@@ -310,18 +317,18 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
flush_write_staging_buffer(ep, &cur, &end);
}
} while (still_pending_size > 0);
- if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) {
- gpr_slice_buffer_add(
+ if (cur != GRPC_SLICE_START_PTR(ep->write_staging_buffer)) {
+ grpc_slice_buffer_add(
&ep->output_buffer,
- gpr_slice_split_head(
+ grpc_slice_split_head(
&ep->write_staging_buffer,
- (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer))));
+ (size_t)(cur - GRPC_SLICE_START_PTR(ep->write_staging_buffer))));
}
}
if (result != TSI_OK) {
/* TODO(yangg) do different things according to the error type? */
- gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
+ grpc_slice_buffer_reset_and_unref(&ep->output_buffer);
grpc_exec_ctx_sched(
exec_ctx, cb,
grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
@@ -365,6 +372,8 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
return grpc_endpoint_get_peer(ep->wrapped_ep);
}
+static int endpoint_get_fd(grpc_endpoint *secure_ep) { return -1; }
+
static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
return grpc_endpoint_get_workqueue(ep->wrapped_ep);
@@ -384,25 +393,26 @@ static const grpc_endpoint_vtable vtable = {endpoint_read,
endpoint_shutdown,
endpoint_destroy,
endpoint_get_resource_user,
- endpoint_get_peer};
+ endpoint_get_peer,
+ endpoint_get_fd};
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *transport,
- gpr_slice *leftover_slices, size_t leftover_nslices) {
+ grpc_slice *leftover_slices, size_t leftover_nslices) {
size_t i;
secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint));
ep->base.vtable = &vtable;
ep->wrapped_ep = transport;
ep->protector = protector;
- gpr_slice_buffer_init(&ep->leftover_bytes);
+ grpc_slice_buffer_init(&ep->leftover_bytes);
for (i = 0; i < leftover_nslices; i++) {
- gpr_slice_buffer_add(&ep->leftover_bytes,
- gpr_slice_ref(leftover_slices[i]));
+ grpc_slice_buffer_add(&ep->leftover_bytes,
+ grpc_slice_ref(leftover_slices[i]));
}
- ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
- ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
- gpr_slice_buffer_init(&ep->output_buffer);
- gpr_slice_buffer_init(&ep->source_buffer);
+ ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
+ ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
+ grpc_slice_buffer_init(&ep->output_buffer);
+ grpc_slice_buffer_init(&ep->source_buffer);
ep->read_buffer = NULL;
grpc_closure_init(&ep->on_read, on_read, ep);
gpr_mu_init(&ep->protector_mu);
diff --git a/src/core/lib/security/transport/secure_endpoint.h b/src/core/lib/security/transport/secure_endpoint.h
index d00075b769..a61f40a4fa 100644
--- a/src/core/lib/security/transport/secure_endpoint.h
+++ b/src/core/lib/security/transport/secure_endpoint.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "src/core/lib/iomgr/endpoint.h"
struct tsi_frame_protector;
@@ -44,6 +44,6 @@ extern int grpc_trace_secure_endpoint;
/* Takes ownership of protector and to_wrap, and refs leftover_slices. */
grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
- gpr_slice *leftover_slices, size_t leftover_nslices);
+ grpc_slice *leftover_slices, size_t leftover_nslices);
#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H */
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index ebf72a3abb..a2e0c7c7c7 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -36,18 +36,18 @@
#include <stdbool.h>
#include <string.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/alpn/alpn.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
-#include "src/core/lib/security/transport/handshake.h"
#include "src/core/lib/security/transport/secure_endpoint.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/support/env.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/fake_transport_security.h"
@@ -111,58 +111,34 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
return NULL;
}
-void grpc_server_security_connector_shutdown(
- grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
- grpc_security_connector_handshake_list *tmp;
- gpr_mu_lock(&connector->mu);
- while (connector->handshaking_handshakes) {
- tmp = connector->handshaking_handshakes;
- grpc_security_handshake_shutdown(
- exec_ctx, connector->handshaking_handshakes->handshake);
- connector->handshaking_handshakes = tmp->next;
- gpr_free(tmp);
+void grpc_channel_security_connector_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
+ grpc_handshake_manager *handshake_mgr) {
+ if (connector != NULL) {
+ connector->create_handshakers(exec_ctx, connector, handshake_mgr);
}
- gpr_mu_unlock(&connector->mu);
}
-void grpc_channel_security_connector_do_handshake(
- grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
- gpr_timespec deadline, grpc_security_handshake_done_cb cb,
- void *user_data) {
- if (sc == NULL || nonsecure_endpoint == NULL) {
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
- } else {
- sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, read_buffer, deadline,
- cb, user_data);
- }
-}
-
-void grpc_server_security_connector_do_handshake(
- grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
- grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data) {
- if (sc == NULL || nonsecure_endpoint == NULL) {
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
- } else {
- sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, read_buffer,
- deadline, cb, user_data);
+void grpc_server_security_connector_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector,
+ grpc_handshake_manager *handshake_mgr) {
+ if (connector != NULL) {
+ connector->create_handshakers(exec_ctx, connector, handshake_mgr);
}
}
void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
tsi_peer peer,
- grpc_security_peer_check_cb cb,
- void *user_data) {
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
if (sc == NULL) {
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
+ grpc_exec_ctx_sched(
+ exec_ctx, on_peer_checked,
+ GRPC_ERROR_CREATE("cannot check peer -- no security connector"), NULL);
tsi_peer_destruct(&peer);
} else {
- sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data);
+ sc->vtable->check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
}
}
@@ -262,45 +238,41 @@ static void fake_channel_destroy(grpc_security_connector *sc) {
gpr_free(sc);
}
-static void fake_server_destroy(grpc_security_connector *sc) {
- grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
- gpr_mu_destroy(&c->mu);
- gpr_free(sc);
-}
+static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
static void fake_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
- grpc_security_peer_check_cb cb, void *user_data) {
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
const char *prop_name;
- grpc_security_status status = GRPC_SECURITY_OK;
- grpc_auth_context *auth_context = NULL;
+ grpc_error *error = GRPC_ERROR_NONE;
+ *auth_context = NULL;
if (peer.property_count != 1) {
- gpr_log(GPR_ERROR, "Fake peers should only have 1 property.");
- status = GRPC_SECURITY_ERROR;
+ error = GRPC_ERROR_CREATE("Fake peers should only have 1 property.");
goto end;
}
prop_name = peer.properties[0].name;
if (prop_name == NULL ||
strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) {
- gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.",
- prop_name == NULL ? "<EMPTY>" : prop_name);
- status = GRPC_SECURITY_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "Unexpected property in fake peer: %s.",
+ prop_name == NULL ? "<EMPTY>" : prop_name);
+ error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
goto end;
}
if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE,
peer.properties[0].value.length)) {
- gpr_log(GPR_ERROR, "Invalid value for cert type property.");
- status = GRPC_SECURITY_ERROR;
+ error = GRPC_ERROR_CREATE("Invalid value for cert type property.");
goto end;
}
- auth_context = grpc_auth_context_create(NULL);
+ *auth_context = grpc_auth_context_create(NULL);
grpc_auth_context_add_cstring_property(
- auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
+ *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
end:
- cb(exec_ctx, user_data, status, auth_context);
- grpc_auth_context_unref(auth_context);
+ grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
@@ -313,26 +285,20 @@ static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, GRPC_SECURITY_OK);
}
-static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
- grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer,
- gpr_timespec deadline,
- grpc_security_handshake_done_cb cb,
- void *user_data) {
- grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
- true, nonsecure_endpoint, read_buffer, deadline,
- cb, user_data);
+static void fake_channel_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+ grpc_handshake_manager *handshake_mgr) {
+ grpc_security_create_handshakers(
+ exec_ctx, tsi_create_fake_handshaker(true /* is_client */), &sc->base,
+ handshake_mgr);
}
-static void fake_server_do_handshake(
+static void fake_server_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
- grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data) {
- grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
- false, nonsecure_endpoint, read_buffer, deadline,
- cb, user_data);
+ grpc_handshake_manager *handshake_mgr) {
+ grpc_security_create_handshakers(
+ exec_ctx, tsi_create_fake_handshaker(false /* is_client */), &sc->base,
+ handshake_mgr);
}
static grpc_security_connector_vtable fake_channel_vtable = {
@@ -350,7 +316,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
c->base.vtable = &fake_channel_vtable;
c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
c->check_call_host = fake_channel_check_call_host;
- c->do_handshake = fake_channel_do_handshake;
+ c->create_handshakers = fake_channel_create_handshakers;
return c;
}
@@ -362,8 +328,7 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create(
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
- c->do_handshake = fake_server_do_handshake;
- gpr_mu_init(&c->mu);
+ c->create_handshakers = fake_server_create_handshakers;
return c;
}
@@ -396,11 +361,9 @@ static void ssl_channel_destroy(grpc_security_connector *sc) {
static void ssl_server_destroy(grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
-
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
- gpr_mu_destroy(&c->base.mu);
gpr_free(sc);
}
@@ -419,49 +382,33 @@ static grpc_security_status ssl_create_handshaker(
return GRPC_SECURITY_OK;
}
-static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
- grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer,
- gpr_timespec deadline,
- grpc_security_handshake_done_cb cb,
- void *user_data) {
+static void ssl_channel_create_handshakers(
+ grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
+ grpc_handshake_manager *handshake_mgr) {
grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc;
- tsi_handshaker *handshaker;
- grpc_security_status status = ssl_create_handshaker(
- c->handshaker_factory, true,
- c->overridden_target_name != NULL ? c->overridden_target_name
- : c->target_name,
- &handshaker);
- if (status != GRPC_SECURITY_OK) {
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, status, NULL, NULL);
- } else {
- grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
- nonsecure_endpoint, read_buffer, deadline, cb,
- user_data);
- }
-}
-
-static void ssl_server_do_handshake(
+ // Instantiate TSI handshaker.
+ tsi_handshaker *tsi_hs = NULL;
+ ssl_create_handshaker(c->handshaker_factory, true /* is_client */,
+ c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
+ &tsi_hs);
+ // Create handshakers.
+ grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
+}
+
+static void ssl_server_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
- grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data) {
+ grpc_handshake_manager *handshake_mgr) {
grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
- tsi_handshaker *handshaker;
- grpc_security_status status =
- ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
- if (status != GRPC_SECURITY_OK) {
- gpr_free(read_buffer);
- cb(exec_ctx, user_data, status, NULL, NULL);
- } else {
- grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
- nonsecure_endpoint, read_buffer, deadline, cb,
- user_data);
- }
+ // Instantiate TSI handshaker.
+ tsi_handshaker *tsi_hs = NULL;
+ ssl_create_handshaker(c->handshaker_factory, false /* is_client */,
+ NULL /* peer_name */, &tsi_hs);
+ // Create handshakers.
+ grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr);
}
static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
@@ -518,57 +465,53 @@ grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) {
return ctx;
}
-static grpc_security_status ssl_check_peer(grpc_security_connector *sc,
- const char *peer_name,
- const tsi_peer *peer,
- grpc_auth_context **auth_context) {
+static grpc_error *ssl_check_peer(grpc_security_connector *sc,
+ const char *peer_name, const tsi_peer *peer,
+ grpc_auth_context **auth_context) {
/* Check the ALPN. */
const tsi_peer_property *p =
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
if (p == NULL) {
- gpr_log(GPR_ERROR, "Missing selected ALPN property.");
- return GRPC_SECURITY_ERROR;
+ return GRPC_ERROR_CREATE(
+ "Cannot check peer: missing selected ALPN property.");
}
if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) {
- gpr_log(GPR_ERROR, "Invalid ALPN value.");
- return GRPC_SECURITY_ERROR;
+ return GRPC_ERROR_CREATE("Cannot check peer: invalid ALPN value.");
}
/* Check the peer name if specified. */
if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
- gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
- return GRPC_SECURITY_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name);
+ grpc_error *error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return error;
}
*auth_context = tsi_ssl_peer_to_auth_context(peer);
- return GRPC_SECURITY_OK;
+ return GRPC_ERROR_NONE;
}
static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
- grpc_security_peer_check_cb cb,
- void *user_data) {
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_connector *)sc;
- grpc_security_status status;
- grpc_auth_context *auth_context = NULL;
- status = ssl_check_peer(sc, c->overridden_target_name != NULL
- ? c->overridden_target_name
- : c->target_name,
- &peer, &auth_context);
- cb(exec_ctx, user_data, status, auth_context);
- grpc_auth_context_unref(auth_context);
+ grpc_error *error = ssl_check_peer(sc, c->overridden_target_name != NULL
+ ? c->overridden_target_name
+ : c->target_name,
+ &peer, auth_context);
+ grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
tsi_peer_destruct(&peer);
}
static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, tsi_peer peer,
- grpc_security_peer_check_cb cb,
- void *user_data) {
- grpc_auth_context *auth_context = NULL;
- grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context);
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked) {
+ grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context);
tsi_peer_destruct(&peer);
- cb(exec_ctx, user_data, status, auth_context);
- grpc_auth_context_unref(auth_context);
+ grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
}
static void add_shallow_auth_property_to_peer(tsi_peer *peer,
@@ -642,8 +585,8 @@ static grpc_security_connector_vtable ssl_channel_vtable = {
static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer};
-static gpr_slice compute_default_pem_root_certs_once(void) {
- gpr_slice result = gpr_empty_slice();
+static grpc_slice compute_default_pem_root_certs_once(void) {
+ grpc_slice result = gpr_empty_slice();
/* First try to load the roots from the environment. */
char *default_root_certs_path =
@@ -656,17 +599,17 @@ static gpr_slice compute_default_pem_root_certs_once(void) {
/* Try overridden roots if needed. */
grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
- if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
+ if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
char *pem_root_certs = NULL;
ovrd_res = ssl_roots_override_cb(&pem_root_certs);
if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
GPR_ASSERT(pem_root_certs != NULL);
- result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
+ result = grpc_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
}
}
/* Fall back to installed certs if needed. */
- if (GPR_SLICE_IS_EMPTY(result) &&
+ if (GRPC_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(installed_roots_path, 0, &result));
@@ -674,13 +617,13 @@ static gpr_slice compute_default_pem_root_certs_once(void) {
return result;
}
-static gpr_slice default_pem_root_certs;
+static grpc_slice default_pem_root_certs;
static void init_default_pem_root_certs(void) {
default_pem_root_certs = compute_default_pem_root_certs_once();
}
-gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
+grpc_slice grpc_get_default_ssl_roots_for_testing(void) {
return compute_default_pem_root_certs_once();
}
@@ -714,8 +657,8 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
loading all the roots once for the lifetime of the process. */
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, init_default_pem_root_certs);
- *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs);
- return GPR_SLICE_LENGTH(default_pem_root_certs);
+ *pem_root_certs = GRPC_SLICE_START_PTR(default_pem_root_certs);
+ return GRPC_SLICE_LENGTH(default_pem_root_certs);
}
grpc_security_status grpc_ssl_channel_security_connector_create(
@@ -765,7 +708,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host;
- c->base.do_handshake = ssl_channel_do_handshake;
+ c->base.create_handshakers = ssl_channel_create_handshakers;
gpr_split_host_port(target_name, &c->target_name, &port);
gpr_free(port);
if (overridden_target_name != NULL) {
@@ -840,8 +783,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
*sc = NULL;
goto error;
}
- gpr_mu_init(&c->base.mu);
- c->base.do_handshake = ssl_server_do_handshake;
+ c->base.create_handshakers = ssl_server_create_handshakers;
*sc = &c->base;
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index 0b5b44bf1a..696db0e02e 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -35,6 +35,8 @@
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
#include <grpc/grpc_security.h>
+
+#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/tsi/transport_security_interface.h"
@@ -57,21 +59,11 @@ typedef struct grpc_security_connector grpc_security_connector;
#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
-typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx,
- void *user_data,
- grpc_security_status status,
- grpc_auth_context *auth_context);
-
-/* Ownership of the secure_endpoint is transfered. */
-typedef void (*grpc_security_handshake_done_cb)(
- grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status,
- grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context);
-
typedef struct {
void (*destroy)(grpc_security_connector *sc);
void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
- tsi_peer peer, grpc_security_peer_check_cb cb,
- void *user_data);
+ tsi_peer peer, grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked);
} grpc_security_connector_vtable;
typedef struct grpc_security_connector_handshake_list {
@@ -106,12 +98,12 @@ void grpc_security_connector_unref(grpc_security_connector *policy);
#endif
/* Check the peer. Callee takes ownership of the peer object.
- The callback will include the resulting auth_context. */
+ Sets *auth_context and invokes on_peer_checked when done. */
void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
tsi_peer peer,
- grpc_security_peer_check_cb cb,
- void *user_data);
+ grpc_auth_context **auth_context,
+ grpc_closure *on_peer_checked);
/* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
@@ -141,11 +133,9 @@ struct grpc_channel_security_connector {
grpc_channel_security_connector *sc, const char *host,
grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data);
- void (*do_handshake)(grpc_exec_ctx *exec_ctx,
- grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data);
+ void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
+ grpc_channel_security_connector *sc,
+ grpc_handshake_manager *handshake_mgr);
};
/* Checks that the host that will be set for a call is acceptable. */
@@ -154,11 +144,10 @@ void grpc_channel_security_connector_check_call_host(
const char *host, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data);
-/* Handshake. */
-void grpc_channel_security_connector_do_handshake(
+/* Registers handshakers with \a handshake_mgr. */
+void grpc_channel_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
- grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
- gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
+ grpc_handshake_manager *handshake_mgr);
/* --- server_security_connector object. ---
@@ -169,25 +158,14 @@ typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector {
grpc_security_connector base;
- gpr_mu mu;
- grpc_security_connector_handshake_list *handshaking_handshakes;
- const grpc_channel_args *channel_args;
- void (*do_handshake)(grpc_exec_ctx *exec_ctx,
- grpc_server_security_connector *sc,
- grpc_tcp_server_acceptor *acceptor,
- grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data);
+ void (*create_handshakers)(grpc_exec_ctx *exec_ctx,
+ grpc_server_security_connector *sc,
+ grpc_handshake_manager *handshake_mgr);
};
-void grpc_server_security_connector_do_handshake(
+void grpc_server_security_connector_create_handshakers(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
- grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- gpr_slice_buffer *read_buffer, gpr_timespec deadline,
- grpc_security_handshake_done_cb cb, void *user_data);
-
-void grpc_server_security_connector_shutdown(
- grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
+ grpc_handshake_manager *handshake_mgr);
/* --- Creation security connectors. --- */
@@ -233,7 +211,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
/* Exposed for TESTING ONLY!. */
-gpr_slice grpc_get_default_ssl_roots_for_testing(void);
+grpc_slice grpc_get_default_ssl_roots_for_testing(void);
/* Config for ssl servers. */
typedef struct {
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
new file mode 100644
index 0000000000..fc01bec2f2
--- /dev/null
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -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(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(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(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(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(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(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));
+ }
+}
diff --git a/src/core/lib/security/transport/handshake.h b/src/core/lib/security/transport/security_handshaker.h
index 53092f5421..f71f43a359 100644
--- a/src/core/lib/security/transport/handshake.h
+++ b/src/core/lib/security/transport/security_handshaker.h
@@ -31,20 +31,17 @@
*
*/
-#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H
-#define GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H
+#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
+#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/security/transport/security_connector.h"
-/* Calls the callback upon completion. Takes owership of handshaker and
- * read_buffer. */
-void grpc_do_security_handshake(
- grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
- grpc_security_connector *connector, bool is_client_side,
- grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
- gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
+/// Creates any necessary security handshakers and adds them to
+/// \a handshake_mgr.
+void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx,
+ tsi_handshaker *handshaker,
+ grpc_security_connector *connector,
+ grpc_handshake_manager *handshake_mgr);
-void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
-
-#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H */
+#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index b2c6815af8..eaa1d0720b 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -78,7 +78,7 @@ static grpc_metadata_array metadata_batch_to_md_array(
usr_md = &result.metadata[result.count++];
usr_md->key = grpc_mdstr_as_c_string(key);
usr_md->value = grpc_mdstr_as_c_string(value);
- usr_md->value_length = GPR_SLICE_LENGTH(value->slice);
+ usr_md->value_length = GRPC_SLICE_LENGTH(value->slice);
}
return result;
}
@@ -92,14 +92,14 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
/* Maybe we could do a pointer comparison but we do not have any guarantee
that the metadata processor used the same pointers for consumed_md in the
callback. */
- if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
- GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
+ if (GRPC_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
+ GRPC_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
continue;
}
- if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key,
- GPR_SLICE_LENGTH(md->key->slice)) == 0 &&
- memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value,
- GPR_SLICE_LENGTH(md->value->slice)) == 0) {
+ if (memcmp(GRPC_SLICE_START_PTR(md->key->slice), consumed_md->key,
+ GRPC_SLICE_LENGTH(md->key->slice)) == 0 &&
+ memcmp(GRPC_SLICE_START_PTR(md->value->slice), consumed_md->value,
+ GRPC_SLICE_LENGTH(md->value->slice)) == 0) {
return NULL; /* Delete. */
}
}
@@ -134,14 +134,14 @@ static void on_md_processing_done(
grpc_metadata_array_destroy(&calld->md);
grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
} else {
- gpr_slice message;
+ grpc_slice message;
grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op));
memset(close_op, 0, sizeof(*close_op));
grpc_metadata_array_destroy(&calld->md);
error_details = error_details != NULL
? error_details
: "Authentication metadata processing failed.";
- message = gpr_slice_from_copied_string(error_details);
+ message = grpc_slice_from_copied_string(error_details);
calld->transport_op->send_initial_metadata = NULL;
if (calld->transport_op->send_message != NULL) {
grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
@@ -278,4 +278,5 @@ const grpc_channel_filter grpc_server_auth_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"server-auth"};
diff --git a/src/core/lib/security/util/b64.c b/src/core/lib/security/util/b64.c
index 9da42e4e73..4892e8e621 100644
--- a/src/core/lib/security/util/b64.c
+++ b/src/core/lib/security/util/b64.c
@@ -120,7 +120,7 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe,
return result;
}
-gpr_slice grpc_base64_decode(const char *b64, int url_safe) {
+grpc_slice grpc_base64_decode(const char *b64, int url_safe) {
return grpc_base64_decode_with_len(b64, strlen(b64), url_safe);
}
@@ -182,10 +182,10 @@ static int decode_group(const unsigned char *codes, size_t num_codes,
return 1;
}
-gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
- int url_safe) {
- gpr_slice result = gpr_slice_malloc(b64_len);
- unsigned char *current = GPR_SLICE_START_PTR(result);
+grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
+ int url_safe) {
+ grpc_slice result = grpc_slice_malloc(b64_len);
+ unsigned char *current = GRPC_SLICE_START_PTR(result);
size_t result_size = 0;
unsigned char codes[4];
size_t num_codes = 0;
@@ -224,10 +224,10 @@ gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
!decode_group(codes, num_codes, current, &result_size)) {
goto fail;
}
- GPR_SLICE_SET_LENGTH(result, result_size);
+ GRPC_SLICE_SET_LENGTH(result, result_size);
return result;
fail:
- gpr_slice_unref(result);
+ grpc_slice_unref(result);
return gpr_empty_slice();
}
diff --git a/src/core/lib/security/util/b64.h b/src/core/lib/security/util/b64.h
index 6908095287..6ea0b5365b 100644
--- a/src/core/lib/security/util/b64.h
+++ b/src/core/lib/security/util/b64.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_LIB_SECURITY_UTIL_B64_H
#define GRPC_CORE_LIB_SECURITY_UTIL_B64_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
/* Encodes data using base64. It is the caller's responsability to free
the returned char * using gpr_free. Returns NULL on NULL input. */
@@ -43,10 +43,10 @@ char *grpc_base64_encode(const void *data, size_t data_size, int url_safe,
/* Decodes data according to the base64 specification. Returns an empty
slice in case of failure. */
-gpr_slice grpc_base64_decode(const char *b64, int url_safe);
+grpc_slice grpc_base64_decode(const char *b64, int url_safe);
/* Same as above except that the length is provided by the caller. */
-gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
- int url_safe);
+grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
+ int url_safe);
#endif /* GRPC_CORE_LIB_SECURITY_UTIL_B64_H */
diff --git a/src/core/lib/support/percent_encoding.c b/src/core/lib/slice/percent_encoding.c
index 3c19f264f9..b9e35f1c71 100644
--- a/src/core/lib/support/percent_encoding.c
+++ b/src/core/lib/slice/percent_encoding.c
@@ -31,15 +31,15 @@
*
*/
-#include "src/core/lib/support/percent_encoding.h"
+#include "src/core/lib/slice/percent_encoding.h"
#include <grpc/support/log.h>
-const uint8_t gpr_url_percent_encoding_unreserved_bytes[256 / 8] = {
+const uint8_t grpc_url_percent_encoding_unreserved_bytes[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0xfe, 0xff, 0xff,
0x87, 0xfe, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const uint8_t gpr_compatible_percent_encoding_unreserved_bytes[256 / 8] = {
+const uint8_t grpc_compatible_percent_encoding_unreserved_bytes[256 / 8] = {
0x00, 0x00, 0x00, 0x00, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -49,14 +49,14 @@ static bool is_unreserved_character(uint8_t c,
return ((unreserved_bytes[c / 8] >> (c % 8)) & 1) != 0;
}
-gpr_slice gpr_percent_encode_slice(gpr_slice slice,
- const uint8_t *unreserved_bytes) {
+grpc_slice grpc_percent_encode_slice(grpc_slice slice,
+ const uint8_t *unreserved_bytes) {
static const uint8_t hex[] = "0123456789ABCDEF";
// first pass: count the number of bytes needed to output this string
size_t output_length = 0;
- const uint8_t *slice_start = GPR_SLICE_START_PTR(slice);
- const uint8_t *slice_end = GPR_SLICE_END_PTR(slice);
+ const uint8_t *slice_start = GRPC_SLICE_START_PTR(slice);
+ const uint8_t *slice_end = GRPC_SLICE_END_PTR(slice);
const uint8_t *p;
bool any_reserved_bytes = false;
for (p = slice_start; p < slice_end; p++) {
@@ -66,11 +66,11 @@ gpr_slice gpr_percent_encode_slice(gpr_slice slice,
}
// no unreserved bytes: return the string unmodified
if (!any_reserved_bytes) {
- return gpr_slice_ref(slice);
+ return grpc_slice_ref(slice);
}
// second pass: actually encode
- gpr_slice out = gpr_slice_malloc(output_length);
- uint8_t *q = GPR_SLICE_START_PTR(out);
+ grpc_slice out = grpc_slice_malloc(output_length);
+ uint8_t *q = GRPC_SLICE_START_PTR(out);
for (p = slice_start; p < slice_end; p++) {
if (is_unreserved_character(*p, unreserved_bytes)) {
*q++ = *p;
@@ -80,7 +80,7 @@ gpr_slice gpr_percent_encode_slice(gpr_slice slice,
*q++ = hex[*p & 15];
}
}
- GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
+ GPR_ASSERT(q == GRPC_SLICE_END_PTR(out));
return out;
}
@@ -97,11 +97,11 @@ static uint8_t dehex(uint8_t c) {
GPR_UNREACHABLE_CODE(return 255);
}
-bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
- const uint8_t *unreserved_bytes,
- gpr_slice *slice_out) {
- const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
- const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
+bool grpc_strict_percent_decode_slice(grpc_slice slice_in,
+ const uint8_t *unreserved_bytes,
+ grpc_slice *slice_out) {
+ const uint8_t *p = GRPC_SLICE_START_PTR(slice_in);
+ const uint8_t *in_end = GRPC_SLICE_END_PTR(slice_in);
size_t out_length = 0;
bool any_percent_encoded_stuff = false;
while (p != in_end) {
@@ -119,12 +119,12 @@ bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
}
}
if (!any_percent_encoded_stuff) {
- *slice_out = gpr_slice_ref(slice_in);
+ *slice_out = grpc_slice_ref(slice_in);
return true;
}
- p = GPR_SLICE_START_PTR(slice_in);
- *slice_out = gpr_slice_malloc(out_length);
- uint8_t *q = GPR_SLICE_START_PTR(*slice_out);
+ p = GRPC_SLICE_START_PTR(slice_in);
+ *slice_out = grpc_slice_malloc(out_length);
+ uint8_t *q = GRPC_SLICE_START_PTR(*slice_out);
while (p != in_end) {
if (*p == '%') {
*q++ = (uint8_t)(dehex(p[1]) << 4) | (dehex(p[2]));
@@ -133,13 +133,13 @@ bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
*q++ = *p++;
}
}
- GPR_ASSERT(q == GPR_SLICE_END_PTR(*slice_out));
+ GPR_ASSERT(q == GRPC_SLICE_END_PTR(*slice_out));
return true;
}
-gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in) {
- const uint8_t *p = GPR_SLICE_START_PTR(slice_in);
- const uint8_t *in_end = GPR_SLICE_END_PTR(slice_in);
+grpc_slice grpc_permissive_percent_decode_slice(grpc_slice slice_in) {
+ const uint8_t *p = GRPC_SLICE_START_PTR(slice_in);
+ const uint8_t *in_end = GRPC_SLICE_END_PTR(slice_in);
size_t out_length = 0;
bool any_percent_encoded_stuff = false;
while (p != in_end) {
@@ -158,11 +158,11 @@ gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in) {
}
}
if (!any_percent_encoded_stuff) {
- return gpr_slice_ref(slice_in);
+ return grpc_slice_ref(slice_in);
}
- p = GPR_SLICE_START_PTR(slice_in);
- gpr_slice out = gpr_slice_malloc(out_length);
- uint8_t *q = GPR_SLICE_START_PTR(out);
+ p = GRPC_SLICE_START_PTR(slice_in);
+ grpc_slice out = grpc_slice_malloc(out_length);
+ uint8_t *q = GRPC_SLICE_START_PTR(out);
while (p != in_end) {
if (*p == '%') {
if (!valid_hex(p + 1, in_end) || !valid_hex(p + 2, in_end)) {
@@ -175,6 +175,6 @@ gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in) {
*q++ = *p++;
}
}
- GPR_ASSERT(q == GPR_SLICE_END_PTR(out));
+ GPR_ASSERT(q == GRPC_SLICE_END_PTR(out));
return out;
}
diff --git a/src/core/lib/support/percent_encoding.h b/src/core/lib/slice/percent_encoding.h
index 000bf14ede..189bdbe312 100644
--- a/src/core/lib/support/percent_encoding.h
+++ b/src/core/lib/slice/percent_encoding.h
@@ -31,8 +31,8 @@
*
*/
-#ifndef GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H
-#define GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H
+#ifndef GRPC_CORE_LIB_SLICE_PERCENT_ENCODING_H
+#define GRPC_CORE_LIB_SLICE_PERCENT_ENCODING_H
/* Percent encoding and decoding of slices.
Transforms arbitrary strings into safe-for-transmission strings by using
@@ -43,36 +43,36 @@
#include <stdbool.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
/* URL percent encoding spec bitfield (usabel as 'unreserved_bytes' in
- gpr_percent_encode_slice, gpr_strict_percent_decode_slice).
+ grpc_percent_encode_slice, grpc_strict_percent_decode_slice).
Flags [A-Za-z0-9-_.~] as unreserved bytes for the percent encoding routines
*/
-extern const uint8_t gpr_url_percent_encoding_unreserved_bytes[256 / 8];
+extern const uint8_t grpc_url_percent_encoding_unreserved_bytes[256 / 8];
/* URL percent encoding spec bitfield (usabel as 'unreserved_bytes' in
- gpr_percent_encode_slice, gpr_strict_percent_decode_slice).
+ grpc_percent_encode_slice, grpc_strict_percent_decode_slice).
Flags ascii7 non-control characters excluding '%' as unreserved bytes for the
percent encoding routines */
-extern const uint8_t gpr_compatible_percent_encoding_unreserved_bytes[256 / 8];
+extern const uint8_t grpc_compatible_percent_encoding_unreserved_bytes[256 / 8];
/* Percent-encode a slice, returning the new slice (this cannot fail):
unreserved_bytes is a bitfield indicating which bytes are considered
unreserved and thus do not need percent encoding */
-gpr_slice gpr_percent_encode_slice(gpr_slice slice,
- const uint8_t *unreserved_bytes);
+grpc_slice grpc_percent_encode_slice(grpc_slice slice,
+ const uint8_t *unreserved_bytes);
/* Percent-decode a slice, strictly.
If the input is legal (contains no unreserved bytes, and legal % encodings),
returns true and sets *slice_out to the decoded slice.
If the input is not legal, returns false and leaves *slice_out untouched.
unreserved_bytes is a bitfield indicating which bytes are considered
unreserved and thus do not need percent encoding */
-bool gpr_strict_percent_decode_slice(gpr_slice slice_in,
- const uint8_t *unreserved_bytes,
- gpr_slice *slice_out);
+bool grpc_strict_percent_decode_slice(grpc_slice slice_in,
+ const uint8_t *unreserved_bytes,
+ grpc_slice *slice_out);
/* Percent-decode a slice, permissively.
If a % triplet can not be decoded, pass it through verbatim.
This cannot fail. */
-gpr_slice gpr_permissive_percent_decode_slice(gpr_slice slice_in);
+grpc_slice grpc_permissive_percent_decode_slice(grpc_slice slice_in);
-#endif /* GRPC_CORE_LIB_SUPPORT_PERCENT_ENCODING_H */
+#endif /* GRPC_CORE_LIB_SLICE_PERCENT_ENCODING_H */
diff --git a/src/core/lib/support/slice.c b/src/core/lib/slice/slice.c
index 8a2c0a9086..52977e6d9a 100644
--- a/src/core/lib/support/slice.c
+++ b/src/core/lib/slice/slice.c
@@ -31,51 +31,51 @@
*
*/
+#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
#include <string.h>
-gpr_slice gpr_empty_slice(void) {
- gpr_slice out;
+grpc_slice gpr_empty_slice(void) {
+ grpc_slice out;
out.refcount = 0;
out.data.inlined.length = 0;
return out;
}
-gpr_slice gpr_slice_ref(gpr_slice slice) {
+grpc_slice grpc_slice_ref(grpc_slice slice) {
if (slice.refcount) {
slice.refcount->ref(slice.refcount);
}
return slice;
}
-void gpr_slice_unref(gpr_slice slice) {
+void grpc_slice_unref(grpc_slice slice) {
if (slice.refcount) {
slice.refcount->unref(slice.refcount);
}
}
-/* gpr_slice_from_static_string support structure - a refcount that does
+/* grpc_slice_from_static_string support structure - a refcount that does
nothing */
static void noop_ref_or_unref(void *unused) {}
-static gpr_slice_refcount noop_refcount = {noop_ref_or_unref,
- noop_ref_or_unref};
+static grpc_slice_refcount noop_refcount = {noop_ref_or_unref,
+ noop_ref_or_unref};
-gpr_slice gpr_slice_from_static_string(const char *s) {
- gpr_slice slice;
+grpc_slice grpc_slice_from_static_string(const char *s) {
+ grpc_slice slice;
slice.refcount = &noop_refcount;
slice.data.refcounted.bytes = (uint8_t *)s;
slice.data.refcounted.length = strlen(s);
return slice;
}
-/* gpr_slice_new support structures - we create a refcount object extended
+/* grpc_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {
- gpr_slice_refcount rc;
+ grpc_slice_refcount rc;
gpr_refcount refs;
void (*user_destroy)(void *);
void *user_data;
@@ -94,10 +94,10 @@ static void new_slice_unref(void *p) {
}
}
-gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
- void (*destroy)(void *),
- void *user_data) {
- gpr_slice slice;
+grpc_slice grpc_slice_new_with_user_data(void *p, size_t len,
+ void (*destroy)(void *),
+ void *user_data) {
+ grpc_slice slice;
new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
gpr_ref_init(&rc->refs, 1);
rc->rc.ref = new_slice_ref;
@@ -111,15 +111,15 @@ gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
return slice;
}
-gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+grpc_slice grpc_slice_new(void *p, size_t len, void (*destroy)(void *)) {
/* Pass "p" to *destroy when the slice is no longer needed. */
- return gpr_slice_new_with_user_data(p, len, destroy, p);
+ return grpc_slice_new_with_user_data(p, len, destroy, p);
}
-/* gpr_slice_new_with_len support structures - we create a refcount object
+/* grpc_slice_new_with_len support structures - we create a refcount object
extended with the user provided data pointer & destroy function */
typedef struct new_with_len_slice_refcount {
- gpr_slice_refcount rc;
+ grpc_slice_refcount rc;
gpr_refcount refs;
void *user_data;
size_t user_length;
@@ -139,9 +139,9 @@ static void new_with_len_unref(void *p) {
}
}
-gpr_slice gpr_slice_new_with_len(void *p, size_t len,
- void (*destroy)(void *, size_t)) {
- gpr_slice slice;
+grpc_slice grpc_slice_new_with_len(void *p, size_t len,
+ void (*destroy)(void *, size_t)) {
+ grpc_slice slice;
new_with_len_slice_refcount *rc =
gpr_malloc(sizeof(new_with_len_slice_refcount));
gpr_ref_init(&rc->refs, 1);
@@ -157,18 +157,18 @@ gpr_slice gpr_slice_new_with_len(void *p, size_t len,
return slice;
}
-gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) {
- gpr_slice slice = gpr_slice_malloc(length);
- memcpy(GPR_SLICE_START_PTR(slice), source, length);
+grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t length) {
+ grpc_slice slice = grpc_slice_malloc(length);
+ memcpy(GRPC_SLICE_START_PTR(slice), source, length);
return slice;
}
-gpr_slice gpr_slice_from_copied_string(const char *source) {
- return gpr_slice_from_copied_buffer(source, strlen(source));
+grpc_slice grpc_slice_from_copied_string(const char *source) {
+ return grpc_slice_from_copied_buffer(source, strlen(source));
}
typedef struct {
- gpr_slice_refcount base;
+ grpc_slice_refcount base;
gpr_refcount refs;
} malloc_refcount;
@@ -184,8 +184,8 @@ static void malloc_unref(void *p) {
}
}
-gpr_slice gpr_slice_malloc(size_t length) {
- gpr_slice slice;
+grpc_slice grpc_slice_malloc(size_t length) {
+ grpc_slice slice;
if (length > sizeof(slice.data.inlined.bytes)) {
/* Memory layout used by the slice created here:
@@ -221,8 +221,8 @@ gpr_slice gpr_slice_malloc(size_t length) {
return slice;
}
-gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) {
- gpr_slice subset;
+grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
+ grpc_slice subset;
GPR_ASSERT(end >= begin);
@@ -246,24 +246,24 @@ gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) {
return subset;
}
-gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) {
- gpr_slice subset;
+grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
+ grpc_slice subset;
if (end - begin <= sizeof(subset.data.inlined.bytes)) {
subset.refcount = NULL;
subset.data.inlined.length = (uint8_t)(end - begin);
- memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin,
+ memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
end - begin);
} else {
- subset = gpr_slice_sub_no_ref(source, begin, end);
+ subset = grpc_slice_sub_no_ref(source, begin, end);
/* Bump the refcount */
subset.refcount->ref(subset.refcount);
}
return subset;
}
-gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) {
- gpr_slice tail;
+grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) {
+ grpc_slice tail;
if (source->refcount == NULL) {
/* inlined data, copy it out */
@@ -297,8 +297,8 @@ gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) {
return tail;
}
-gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
- gpr_slice head;
+grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) {
+ grpc_slice head;
if (source->refcount == NULL) {
GPR_ASSERT(source->data.inlined.length >= split);
@@ -335,16 +335,24 @@ gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) {
return head;
}
-int gpr_slice_cmp(gpr_slice a, gpr_slice b) {
- int d = (int)(GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b));
+int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
+ int d = (int)(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
if (d != 0) return d;
- return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b),
- GPR_SLICE_LENGTH(a));
+ return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
+ GRPC_SLICE_LENGTH(a));
}
-int gpr_slice_str_cmp(gpr_slice a, const char *b) {
+int grpc_slice_str_cmp(grpc_slice a, const char *b) {
size_t b_length = strlen(b);
- int d = (int)(GPR_SLICE_LENGTH(a) - b_length);
+ int d = (int)(GRPC_SLICE_LENGTH(a) - b_length);
if (d != 0) return d;
- return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
+ return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
+}
+
+int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
+ if (a.refcount == NULL || b.refcount == NULL) {
+ return grpc_slice_cmp(a, b) == 0;
+ }
+ return a.data.refcounted.length == b.data.refcounted.length &&
+ a.data.refcounted.bytes == b.data.refcounted.bytes;
}
diff --git a/src/core/lib/support/slice_buffer.c b/src/core/lib/slice/slice_buffer.c
index 66f111d767..990ef128bd 100644
--- a/src/core/lib/support/slice_buffer.c
+++ b/src/core/lib/slice/slice_buffer.c
@@ -31,8 +31,8 @@
*
*/
+#include <grpc/slice_buffer.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice_buffer.h>
#include <string.h>
@@ -43,35 +43,35 @@
/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
#define GROW(x) (3 * (x) / 2)
-static void maybe_embiggen(gpr_slice_buffer *sb) {
+static void maybe_embiggen(grpc_slice_buffer *sb) {
if (sb->count == sb->capacity) {
sb->capacity = GROW(sb->capacity);
GPR_ASSERT(sb->capacity > sb->count);
if (sb->slices == sb->inlined) {
- sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
- memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
+ sb->slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
+ memcpy(sb->slices, sb->inlined, sb->count * sizeof(grpc_slice));
} else {
- sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+ sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(grpc_slice));
}
}
}
-void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
+void grpc_slice_buffer_init(grpc_slice_buffer *sb) {
sb->count = 0;
sb->length = 0;
sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
sb->slices = sb->inlined;
}
-void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
- gpr_slice_buffer_reset_and_unref(sb);
+void grpc_slice_buffer_destroy(grpc_slice_buffer *sb) {
+ grpc_slice_buffer_reset_and_unref(sb);
if (sb->slices != sb->inlined) {
gpr_free(sb->slices);
}
}
-uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) {
- gpr_slice *back;
+uint8_t *grpc_slice_buffer_tiny_add(grpc_slice_buffer *sb, size_t n) {
+ grpc_slice *back;
uint8_t *out;
sb->length += n;
@@ -94,16 +94,16 @@ add_new:
return back->data.inlined.bytes;
}
-size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
+size_t grpc_slice_buffer_add_indexed(grpc_slice_buffer *sb, grpc_slice s) {
size_t out = sb->count;
maybe_embiggen(sb);
sb->slices[out] = s;
- sb->length += GPR_SLICE_LENGTH(s);
+ sb->length += GRPC_SLICE_LENGTH(s);
sb->count = out + 1;
return out;
}
-void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
+void grpc_slice_buffer_add(grpc_slice_buffer *sb, grpc_slice s) {
size_t n = sb->count;
/* if both the last slice in the slice buffer and the slice being added
are inlined (that is, that they carry their data inside the slice data
@@ -111,19 +111,20 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
into the back slice, preventing many small slices being passed into
writes */
if (!s.refcount && n) {
- gpr_slice *back = &sb->slices[n - 1];
- if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
+ grpc_slice *back = &sb->slices[n - 1];
+ if (!back->refcount &&
+ back->data.inlined.length < GRPC_SLICE_INLINED_SIZE) {
if (s.data.inlined.length + back->data.inlined.length <=
- GPR_SLICE_INLINED_SIZE) {
+ GRPC_SLICE_INLINED_SIZE) {
memcpy(back->data.inlined.bytes + back->data.inlined.length,
s.data.inlined.bytes, s.data.inlined.length);
back->data.inlined.length =
(uint8_t)(back->data.inlined.length + s.data.inlined.length);
} else {
- size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
+ size_t cp1 = GRPC_SLICE_INLINED_SIZE - back->data.inlined.length;
memcpy(back->data.inlined.bytes + back->data.inlined.length,
s.data.inlined.bytes, cp1);
- back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
+ back->data.inlined.length = GRPC_SLICE_INLINED_SIZE;
maybe_embiggen(sb);
back = &sb->slices[n];
sb->count = n + 1;
@@ -136,35 +137,35 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
return; /* early out */
}
}
- gpr_slice_buffer_add_indexed(sb, s);
+ grpc_slice_buffer_add_indexed(sb, s);
}
-void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
+void grpc_slice_buffer_addn(grpc_slice_buffer *sb, grpc_slice *s, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
- gpr_slice_buffer_add(sb, s[i]);
+ grpc_slice_buffer_add(sb, s[i]);
}
}
-void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
+void grpc_slice_buffer_pop(grpc_slice_buffer *sb) {
if (sb->count != 0) {
size_t count = --sb->count;
- sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
+ sb->length -= GRPC_SLICE_LENGTH(sb->slices[count]);
}
}
-void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
+void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb) {
size_t i;
for (i = 0; i < sb->count; i++) {
- gpr_slice_unref(sb->slices[i]);
+ grpc_slice_unref(sb->slices[i]);
}
sb->count = 0;
sb->length = 0;
}
-void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
+void grpc_slice_buffer_swap(grpc_slice_buffer *a, grpc_slice_buffer *b) {
GPR_SWAP(size_t, a->count, b->count);
GPR_SWAP(size_t, a->capacity, b->capacity);
GPR_SWAP(size_t, a->length, b->length);
@@ -172,111 +173,112 @@ void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
if (a->slices == a->inlined) {
if (b->slices == b->inlined) {
/* swap contents of inlined buffer */
- gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
- memcpy(temp, a->slices, b->count * sizeof(gpr_slice));
- memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice));
- memcpy(b->slices, temp, b->count * sizeof(gpr_slice));
+ grpc_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
+ memcpy(temp, a->slices, b->count * sizeof(grpc_slice));
+ memcpy(a->slices, b->slices, a->count * sizeof(grpc_slice));
+ memcpy(b->slices, temp, b->count * sizeof(grpc_slice));
} else {
/* a is inlined, b is not - copy a inlined into b, fix pointers */
a->slices = b->slices;
b->slices = b->inlined;
- memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice));
+ memcpy(b->slices, a->inlined, b->count * sizeof(grpc_slice));
}
} else if (b->slices == b->inlined) {
/* b is inlined, a is not - copy b inlined int a, fix pointers */
b->slices = a->slices;
a->slices = a->inlined;
- memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice));
+ memcpy(a->slices, b->inlined, a->count * sizeof(grpc_slice));
} else {
/* no inlining: easy swap */
- GPR_SWAP(gpr_slice *, a->slices, b->slices);
+ GPR_SWAP(grpc_slice *, a->slices, b->slices);
}
}
-void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) {
+void grpc_slice_buffer_move_into(grpc_slice_buffer *src,
+ grpc_slice_buffer *dst) {
/* anything to move? */
if (src->count == 0) {
return;
}
/* anything in dst? */
if (dst->count == 0) {
- gpr_slice_buffer_swap(src, dst);
+ grpc_slice_buffer_swap(src, dst);
return;
}
/* both buffers have data - copy, and reset src */
- gpr_slice_buffer_addn(dst, src->slices, src->count);
+ grpc_slice_buffer_addn(dst, src->slices, src->count);
src->count = 0;
src->length = 0;
}
-void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
- gpr_slice_buffer *dst) {
+void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n,
+ grpc_slice_buffer *dst) {
size_t src_idx;
size_t output_len = dst->length + n;
size_t new_input_len = src->length - n;
GPR_ASSERT(src->length >= n);
if (src->length == n) {
- gpr_slice_buffer_move_into(src, dst);
+ grpc_slice_buffer_move_into(src, dst);
return;
}
src_idx = 0;
while (src_idx < src->capacity) {
- gpr_slice slice = src->slices[src_idx];
- size_t slice_len = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = src->slices[src_idx];
+ size_t slice_len = GRPC_SLICE_LENGTH(slice);
if (n > slice_len) {
- gpr_slice_buffer_add(dst, slice);
+ grpc_slice_buffer_add(dst, slice);
n -= slice_len;
src_idx++;
} else if (n == slice_len) {
- gpr_slice_buffer_add(dst, slice);
+ grpc_slice_buffer_add(dst, slice);
src_idx++;
break;
} else { /* n < slice_len */
- src->slices[src_idx] = gpr_slice_split_tail(&slice, n);
- GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n);
- GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
- gpr_slice_buffer_add(dst, slice);
+ src->slices[src_idx] = grpc_slice_split_tail(&slice, n);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n);
+ GPR_ASSERT(GRPC_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
+ grpc_slice_buffer_add(dst, slice);
break;
}
}
GPR_ASSERT(dst->length == output_len);
memmove(src->slices, src->slices + src_idx,
- sizeof(gpr_slice) * (src->count - src_idx));
+ sizeof(grpc_slice) * (src->count - src_idx));
src->count -= src_idx;
src->length = new_input_len;
GPR_ASSERT(src->count > 0);
}
-void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n,
- gpr_slice_buffer *garbage) {
+void grpc_slice_buffer_trim_end(grpc_slice_buffer *sb, size_t n,
+ grpc_slice_buffer *garbage) {
GPR_ASSERT(n <= sb->length);
sb->length -= n;
for (;;) {
size_t idx = sb->count - 1;
- gpr_slice slice = sb->slices[idx];
- size_t slice_len = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = sb->slices[idx];
+ size_t slice_len = GRPC_SLICE_LENGTH(slice);
if (slice_len > n) {
- sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n);
- gpr_slice_buffer_add_indexed(garbage, slice);
+ sb->slices[idx] = grpc_slice_split_head(&slice, slice_len - n);
+ grpc_slice_buffer_add_indexed(garbage, slice);
return;
} else if (slice_len == n) {
- gpr_slice_buffer_add_indexed(garbage, slice);
+ grpc_slice_buffer_add_indexed(garbage, slice);
sb->count = idx;
return;
} else {
- gpr_slice_buffer_add_indexed(garbage, slice);
+ grpc_slice_buffer_add_indexed(garbage, slice);
n -= slice_len;
sb->count = idx;
}
}
}
-gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) {
- gpr_slice slice;
+grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer *sb) {
+ grpc_slice slice;
GPR_ASSERT(sb->count > 0);
slice = sb->slices[0];
- memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice));
+ memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(grpc_slice));
sb->count--;
- sb->length -= GPR_SLICE_LENGTH(slice);
+ sb->length -= GRPC_SLICE_LENGTH(slice);
return slice;
}
diff --git a/src/core/lib/slice/slice_string_helpers.c b/src/core/lib/slice/slice_string_helpers.c
new file mode 100644
index 0000000000..4731762ece
--- /dev/null
+++ b/src/core/lib/slice/slice_string_helpers.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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/slice/slice_string_helpers.h"
+
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/support/string.h"
+
+char *grpc_dump_slice(grpc_slice s, uint32_t flags) {
+ return gpr_dump((const char *)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
+ flags);
+}
+
+/** Finds the initial (\a begin) and final (\a end) offsets of the next
+ * substring from \a str + \a read_offset until the next \a sep or the end of \a
+ * str.
+ *
+ * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
+static int slice_find_separator_offset(const grpc_slice str, const char *sep,
+ const size_t read_offset, size_t *begin,
+ size_t *end) {
+ size_t i;
+ const uint8_t *str_ptr = GRPC_SLICE_START_PTR(str) + read_offset;
+ const size_t str_len = GRPC_SLICE_LENGTH(str) - read_offset;
+ const size_t sep_len = strlen(sep);
+ if (str_len < sep_len) {
+ return 0;
+ }
+
+ for (i = 0; i <= str_len - sep_len; i++) {
+ if (memcmp(str_ptr + i, sep, sep_len) == 0) {
+ *begin = read_offset;
+ *end = read_offset + i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst) {
+ const size_t sep_len = strlen(sep);
+ size_t begin, end;
+
+ GPR_ASSERT(sep_len > 0);
+
+ if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) {
+ do {
+ grpc_slice_buffer_add_indexed(dst, grpc_slice_sub(str, begin, end));
+ } while (slice_find_separator_offset(str, sep, end + sep_len, &begin,
+ &end) != 0);
+ grpc_slice_buffer_add_indexed(
+ dst, grpc_slice_sub(str, end + sep_len, GRPC_SLICE_LENGTH(str)));
+ } else { /* no sep found, add whole input */
+ grpc_slice_buffer_add_indexed(dst, grpc_slice_ref(str));
+ }
+}
diff --git a/src/core/lib/slice/slice_string_helpers.h b/src/core/lib/slice/slice_string_helpers.h
new file mode 100644
index 0000000000..151c720777
--- /dev/null
+++ b/src/core/lib/slice/slice_string_helpers.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * 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_LIB_SLICE_SLICE_STRING_HELPERS_H
+#define GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H
+
+#include <stddef.h>
+
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
+#include <grpc/support/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Calls gpr_dump on a slice. */
+char *grpc_dump_slice(grpc_slice slice, uint32_t flags);
+
+/** Split \a str by the separator \a sep. Results are stored in \a dst, which
+ * should be a properly initialized instance. */
+void grpc_slice_split(grpc_slice str, const char *sep, grpc_slice_buffer *dst);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H */
diff --git a/src/core/lib/support/backoff.c b/src/core/lib/support/backoff.c
index e89ef47220..0612472712 100644
--- a/src/core/lib/support/backoff.c
+++ b/src/core/lib/support/backoff.c
@@ -35,8 +35,10 @@
#include <grpc/support/useful.h>
-void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
+void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
+ double multiplier, double jitter,
int64_t min_timeout_millis, int64_t max_timeout_millis) {
+ backoff->initial_connect_timeout = initial_connect_timeout;
backoff->multiplier = multiplier;
backoff->jitter = jitter;
backoff->min_timeout_millis = min_timeout_millis;
@@ -45,9 +47,10 @@ void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
}
gpr_timespec gpr_backoff_begin(gpr_backoff *backoff, gpr_timespec now) {
- backoff->current_timeout_millis = backoff->min_timeout_millis;
- return gpr_time_add(
- now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
+ backoff->current_timeout_millis = backoff->initial_connect_timeout;
+ const int64_t first_timeout =
+ GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
+ return gpr_time_add(now, gpr_time_from_millis(first_timeout, GPR_TIMESPAN));
}
/* Generate a random number between 0 and 1. */
@@ -57,20 +60,28 @@ static double generate_uniform_random_number(uint32_t *rng_state) {
}
gpr_timespec gpr_backoff_step(gpr_backoff *backoff, gpr_timespec now) {
- double new_timeout_millis =
+ const double new_timeout_millis =
backoff->multiplier * (double)backoff->current_timeout_millis;
- double jitter_range = backoff->jitter * new_timeout_millis;
- double jitter =
+ backoff->current_timeout_millis =
+ GPR_MIN((int64_t)new_timeout_millis, backoff->max_timeout_millis);
+
+ const double jitter_range_width = backoff->jitter * new_timeout_millis;
+ const double jitter =
(2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
- jitter_range;
+ jitter_range_width;
+
backoff->current_timeout_millis =
- GPR_CLAMP((int64_t)(new_timeout_millis + jitter),
- backoff->min_timeout_millis, backoff->max_timeout_millis);
- return gpr_time_add(
+ (int64_t)((double)(backoff->current_timeout_millis) + jitter);
+
+ const gpr_timespec current_deadline = gpr_time_add(
now, gpr_time_from_millis(backoff->current_timeout_millis, GPR_TIMESPAN));
+
+ const gpr_timespec min_deadline = gpr_time_add(
+ now, gpr_time_from_millis(backoff->min_timeout_millis, GPR_TIMESPAN));
+
+ return gpr_time_max(current_deadline, min_deadline);
}
void gpr_backoff_reset(gpr_backoff *backoff) {
- // forces step() to return a timeout of min_timeout_millis
- backoff->current_timeout_millis = 0;
+ backoff->current_timeout_millis = backoff->initial_connect_timeout;
}
diff --git a/src/core/lib/support/backoff.h b/src/core/lib/support/backoff.h
index 6d40c15546..5e9b740824 100644
--- a/src/core/lib/support/backoff.h
+++ b/src/core/lib/support/backoff.h
@@ -37,7 +37,9 @@
#include <grpc/support/time.h>
typedef struct {
- /// const: multiplier between retry attempts
+ /// const: how long to wait after the first failure before retrying
+ int64_t initial_connect_timeout;
+ /// const: factor with which to multiply backoff after a failed retry
double multiplier;
/// const: amount to randomize backoffs
double jitter;
@@ -54,7 +56,8 @@ typedef struct {
} gpr_backoff;
/// Initialize backoff machinery - does not need to be destroyed
-void gpr_backoff_init(gpr_backoff *backoff, double multiplier, double jitter,
+void gpr_backoff_init(gpr_backoff *backoff, int64_t initial_connect_timeout,
+ double multiplier, double jitter,
int64_t min_timeout_millis, int64_t max_timeout_millis);
/// Begin retry loop: returns a timespec for the NEXT retry
diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h
index ec3959bc6e..6ada5d9390 100644
--- a/src/core/lib/support/env.h
+++ b/src/core/lib/support/env.h
@@ -36,8 +36,6 @@
#include <stdio.h>
-#include <grpc/support/slice.h>
-
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index d17fb9da4b..f10a30f0fd 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -34,7 +34,9 @@
#include "src/core/lib/support/string.h"
#include <ctype.h>
+#include <limits.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <grpc/support/alloc.h>
@@ -120,11 +122,6 @@ char *gpr_dump(const char *buf, size_t len, uint32_t flags) {
return out.data;
}
-char *gpr_dump_slice(gpr_slice s, uint32_t flags) {
- return gpr_dump((const char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s),
- flags);
-}
-
int gpr_parse_bytes_to_uint32(const char *buf, size_t len, uint32_t *result) {
uint32_t out = 0;
uint32_t new;
@@ -194,6 +191,13 @@ int int64_ttoa(int64_t value, char *string) {
return i;
}
+int gpr_parse_nonnegative_int(const char *value) {
+ char *end;
+ long result = strtol(value, &end, 0);
+ if (*end != '\0' || result < 0 || result > INT_MAX) return -1;
+ return (int)result;
+}
+
char *gpr_leftpad(const char *str, char flag, size_t length) {
const size_t str_length = strlen(str);
const size_t out_length = str_length > length ? str_length : length;
@@ -239,50 +243,6 @@ char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
return out;
}
-/** Finds the initial (\a begin) and final (\a end) offsets of the next
- * substring from \a str + \a read_offset until the next \a sep or the end of \a
- * str.
- *
- * Returns 1 and updates \a begin and \a end. Returns 0 otherwise. */
-static int slice_find_separator_offset(const gpr_slice str, const char *sep,
- const size_t read_offset, size_t *begin,
- size_t *end) {
- size_t i;
- const uint8_t *str_ptr = GPR_SLICE_START_PTR(str) + read_offset;
- const size_t str_len = GPR_SLICE_LENGTH(str) - read_offset;
- const size_t sep_len = strlen(sep);
- if (str_len < sep_len) {
- return 0;
- }
-
- for (i = 0; i <= str_len - sep_len; i++) {
- if (memcmp(str_ptr + i, sep, sep_len) == 0) {
- *begin = read_offset;
- *end = read_offset + i;
- return 1;
- }
- }
- return 0;
-}
-
-void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst) {
- const size_t sep_len = strlen(sep);
- size_t begin, end;
-
- GPR_ASSERT(sep_len > 0);
-
- if (slice_find_separator_offset(str, sep, 0, &begin, &end) != 0) {
- do {
- gpr_slice_buffer_add_indexed(dst, gpr_slice_sub(str, begin, end));
- } while (slice_find_separator_offset(str, sep, end + sep_len, &begin,
- &end) != 0);
- gpr_slice_buffer_add_indexed(
- dst, gpr_slice_sub(str, end + sep_len, GPR_SLICE_LENGTH(str)));
- } else { /* no sep found, add whole input */
- gpr_slice_buffer_add_indexed(dst, gpr_slice_ref(str));
- }
-}
-
void gpr_strvec_init(gpr_strvec *sv) { memset(sv, 0, sizeof(*sv)); }
void gpr_strvec_destroy(gpr_strvec *sv) {
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index 9a94e9471c..e933e2eb46 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -36,9 +36,9 @@
#include <stddef.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#ifdef __cplusplus
extern "C" {
@@ -54,9 +54,6 @@ extern "C" {
Result should be freed with gpr_free() */
char *gpr_dump(const char *buf, size_t len, uint32_t flags);
-/* Calls gpr_dump on a slice. */
-char *gpr_dump_slice(gpr_slice slice, uint32_t flags);
-
/* Parses an array of bytes into an integer (base 10). Returns 1 on success,
0 on failure. */
int gpr_parse_bytes_to_uint32(const char *data, size_t length,
@@ -80,6 +77,9 @@ NOTE: This function ensures sufficient bit width even on Win x64,
where long is 32bit is size.*/
int int64_ttoa(int64_t value, char *output);
+// Parses a non-negative number from a value string. Returns -1 on error.
+int gpr_parse_nonnegative_int(const char *value);
+
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
@@ -98,10 +98,6 @@ char *gpr_strjoin(const char **strs, size_t nstrs, size_t *total_length);
char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
size_t *total_length);
-/** Split \a str by the separator \a sep. Results are stored in \a dst, which
- * should be a properly initialized instance. */
-void gpr_slice_split(gpr_slice str, const char *sep, gpr_slice_buffer *dst);
-
/* A vector of strings... for building up a final string one piece at a time */
typedef struct {
char **strs;
diff --git a/src/core/lib/support/subprocess_posix.c b/src/core/lib/support/subprocess_posix.c
index 4f4de9298e..4247a1c12b 100644
--- a/src/core/lib/support/subprocess_posix.c
+++ b/src/core/lib/support/subprocess_posix.c
@@ -40,6 +40,7 @@
#include <assert.h>
#include <errno.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -52,7 +53,7 @@
struct gpr_subprocess {
int pid;
- int joined;
+ bool joined;
};
const char *gpr_subprocess_binary_extension() { return ""; }
@@ -97,9 +98,11 @@ retry:
if (errno == EINTR) {
goto retry;
}
- gpr_log(GPR_ERROR, "waitpid failed: %s", strerror(errno));
+ gpr_log(GPR_ERROR, "waitpid failed for pid %d: %s", p->pid,
+ strerror(errno));
return -1;
}
+ p->joined = true;
return status;
}
diff --git a/src/core/lib/support/tmpfile.h b/src/core/lib/support/tmpfile.h
index 059142ab0f..8952e5ec3d 100644
--- a/src/core/lib/support/tmpfile.h
+++ b/src/core/lib/support/tmpfile.h
@@ -36,7 +36,7 @@
#include <stdio.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#ifdef __cplusplus
extern "C" {
diff --git a/src/core/lib/surface/byte_buffer.c b/src/core/lib/surface/byte_buffer.c
index 054a6e6c58..d646591a65 100644
--- a/src/core/lib/surface/byte_buffer.c
+++ b/src/core/lib/surface/byte_buffer.c
@@ -35,22 +35,23 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
+grpc_byte_buffer *grpc_raw_byte_buffer_create(grpc_slice *slices,
size_t nslices) {
return grpc_raw_compressed_byte_buffer_create(slices, nslices,
GRPC_COMPRESS_NONE);
}
grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
- gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression) {
+ grpc_slice *slices, size_t nslices,
+ grpc_compression_algorithm compression) {
size_t i;
grpc_byte_buffer *bb = gpr_malloc(sizeof(grpc_byte_buffer));
bb->type = GRPC_BB_RAW;
bb->data.raw.compression = compression;
- gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
+ grpc_slice_buffer_init(&bb->data.raw.slice_buffer);
for (i = 0; i < nslices; i++) {
- gpr_slice_ref(slices[i]);
- gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]);
+ grpc_slice_ref(slices[i]);
+ grpc_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]);
}
return bb;
}
@@ -58,13 +59,13 @@ grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
grpc_byte_buffer_reader *reader) {
grpc_byte_buffer *bb = gpr_malloc(sizeof(grpc_byte_buffer));
- gpr_slice slice;
+ grpc_slice slice;
bb->type = GRPC_BB_RAW;
bb->data.raw.compression = GRPC_COMPRESS_NONE;
- gpr_slice_buffer_init(&bb->data.raw.slice_buffer);
+ grpc_slice_buffer_init(&bb->data.raw.slice_buffer);
while (grpc_byte_buffer_reader_next(reader, &slice)) {
- gpr_slice_buffer_add(&bb->data.raw.slice_buffer, slice);
+ grpc_slice_buffer_add(&bb->data.raw.slice_buffer, slice);
}
return bb;
}
@@ -83,7 +84,7 @@ void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
if (!bb) return;
switch (bb->type) {
case GRPC_BB_RAW:
- gpr_slice_buffer_destroy(&bb->data.raw.slice_buffer);
+ grpc_slice_buffer_destroy(&bb->data.raw.slice_buffer);
break;
}
gpr_free(bb);
diff --git a/src/core/lib/surface/byte_buffer_reader.c b/src/core/lib/surface/byte_buffer_reader.c
index 310bacb2c9..0089959fbb 100644
--- a/src/core/lib/surface/byte_buffer_reader.c
+++ b/src/core/lib/surface/byte_buffer_reader.c
@@ -37,9 +37,9 @@
#include <grpc/byte_buffer.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice_buffer.h>
#include "src/core/lib/compression/message_compress.h"
@@ -56,11 +56,11 @@ static int is_compressed(grpc_byte_buffer *buffer) {
int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer) {
- gpr_slice_buffer decompressed_slices_buffer;
+ grpc_slice_buffer decompressed_slices_buffer;
reader->buffer_in = buffer;
switch (reader->buffer_in->type) {
case GRPC_BB_RAW:
- gpr_slice_buffer_init(&decompressed_slices_buffer);
+ grpc_slice_buffer_init(&decompressed_slices_buffer);
if (is_compressed(reader->buffer_in)) {
if (grpc_msg_decompress(reader->buffer_in->data.raw.compression,
&reader->buffer_in->data.raw.slice_buffer,
@@ -76,7 +76,7 @@ int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices,
decompressed_slices_buffer.count);
}
- gpr_slice_buffer_destroy(&decompressed_slices_buffer);
+ grpc_slice_buffer_destroy(&decompressed_slices_buffer);
} else { /* not compressed, use the input buffer as output */
reader->buffer_out = reader->buffer_in;
}
@@ -98,13 +98,13 @@ void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
}
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
- gpr_slice *slice) {
+ grpc_slice *slice) {
switch (reader->buffer_in->type) {
case GRPC_BB_RAW: {
- gpr_slice_buffer *slice_buffer;
+ grpc_slice_buffer *slice_buffer;
slice_buffer = &reader->buffer_out->data.raw.slice_buffer;
if (reader->current.index < slice_buffer->count) {
- *slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
+ *slice = grpc_slice_ref(slice_buffer->slices[reader->current.index]);
reader->current.index += 1;
return 1;
}
@@ -114,18 +114,18 @@ int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
return 0;
}
-gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
- gpr_slice in_slice;
+grpc_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader) {
+ grpc_slice in_slice;
size_t bytes_read = 0;
const size_t input_size = grpc_byte_buffer_length(reader->buffer_out);
- gpr_slice out_slice = gpr_slice_malloc(input_size);
- uint8_t *const outbuf = GPR_SLICE_START_PTR(out_slice); /* just an alias */
+ grpc_slice out_slice = grpc_slice_malloc(input_size);
+ uint8_t *const outbuf = GRPC_SLICE_START_PTR(out_slice); /* just an alias */
while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) {
- const size_t slice_length = GPR_SLICE_LENGTH(in_slice);
- memcpy(&(outbuf[bytes_read]), GPR_SLICE_START_PTR(in_slice), slice_length);
+ const size_t slice_length = GRPC_SLICE_LENGTH(in_slice);
+ memcpy(&(outbuf[bytes_read]), GRPC_SLICE_START_PTR(in_slice), slice_length);
bytes_read += slice_length;
- gpr_slice_unref(in_slice);
+ grpc_slice_unref(in_slice);
GPR_ASSERT(bytes_read <= input_size);
}
return out_slice;
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 6c25952c0a..1e0f3eeca5 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -39,9 +39,9 @@
#include <grpc/compression.h>
#include <grpc/grpc.h>
+#include <grpc/slice.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
@@ -49,6 +49,7 @@
#include "src/core/lib/compression/algorithm_metadata.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
@@ -122,6 +123,7 @@ struct grpc_call {
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
+ gpr_timespec start_time;
/* TODO(ctiller): share with cq if possible? */
gpr_mu mu;
@@ -184,7 +186,7 @@ struct grpc_call {
grpc_slice_buffer_stream sending_stream;
grpc_byte_stream *receiving_stream;
grpc_byte_buffer **receiving_buffer;
- gpr_slice receiving_slice;
+ grpc_slice receiving_slice;
grpc_closure receiving_slice_ready;
grpc_closure receiving_stream_ready;
grpc_closure receiving_initial_metadata_ready;
@@ -239,6 +241,7 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args,
call->channel = args->channel;
call->cq = args->cq;
call->parent = args->parent_call;
+ call->start_time = gpr_now(GPR_CLOCK_MONOTONIC);
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
call->is_client = args->server_transport_data == NULL;
@@ -311,10 +314,10 @@ grpc_error *grpc_call_create(const grpc_call_create_args *args,
GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
/* initial refcount dropped by grpc_call_destroy */
- grpc_error *error =
- grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
- call->context, args->server_transport_data, path,
- send_deadline, CALL_STACK_FROM_CALL(call));
+ grpc_error *error = grpc_call_stack_init(
+ &exec_ctx, channel_stack, 1, destroy_call, call, call->context,
+ args->server_transport_data, path, call->start_time, send_deadline,
+ CALL_STACK_FROM_CALL(call));
if (error != GRPC_ERROR_NONE) {
grpc_status_code status;
const char *error_str;
@@ -427,6 +430,8 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
get_final_status(call, set_status_value_directly,
&c->final_info.final_status);
+ c->final_info.stats.latency =
+ gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
@@ -493,8 +498,8 @@ static void destroy_encodings_accepted_by_peer(void *p) { return; }
static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
size_t i;
grpc_compression_algorithm algorithm;
- gpr_slice_buffer accept_encoding_parts;
- gpr_slice accept_encoding_slice;
+ grpc_slice_buffer accept_encoding_parts;
+ grpc_slice accept_encoding_slice;
void *accepted_user_data;
accepted_user_data =
@@ -506,23 +511,23 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
}
accept_encoding_slice = mdel->value->slice;
- gpr_slice_buffer_init(&accept_encoding_parts);
- gpr_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
+ grpc_slice_buffer_init(&accept_encoding_parts);
+ grpc_slice_split(accept_encoding_slice, ",", &accept_encoding_parts);
/* No need to zero call->encodings_accepted_by_peer: grpc_call_create already
* zeroes the whole grpc_call */
/* Always support no compression */
GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
for (i = 0; i < accept_encoding_parts.count; i++) {
- const gpr_slice *accept_encoding_entry_slice =
+ const grpc_slice *accept_encoding_entry_slice =
&accept_encoding_parts.slices[i];
if (grpc_compression_algorithm_parse(
- (const char *)GPR_SLICE_START_PTR(*accept_encoding_entry_slice),
- GPR_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
+ (const char *)GRPC_SLICE_START_PTR(*accept_encoding_entry_slice),
+ GRPC_SLICE_LENGTH(*accept_encoding_entry_slice), &algorithm)) {
GPR_BITSET(&call->encodings_accepted_by_peer, algorithm);
} else {
char *accept_encoding_entry_str =
- gpr_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
+ grpc_dump_slice(*accept_encoding_entry_slice, GPR_DUMP_ASCII);
gpr_log(GPR_ERROR,
"Invalid entry in accept encoding metadata: '%s'. Ignoring.",
accept_encoding_entry_str);
@@ -530,7 +535,7 @@ static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
}
}
- gpr_slice_buffer_destroy(&accept_encoding_parts);
+ grpc_slice_buffer_destroy(&accept_encoding_parts);
grpc_mdelem_set_user_data(
mdel, destroy_encodings_accepted_by_peer,
@@ -551,14 +556,14 @@ static void get_final_details(grpc_call *call, char **out_details,
for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
if (call->status[i].is_set) {
if (call->status[i].details) {
- gpr_slice details = call->status[i].details->slice;
- size_t len = GPR_SLICE_LENGTH(details);
+ grpc_slice details = call->status[i].details->slice;
+ size_t len = GRPC_SLICE_LENGTH(details);
if (len + 1 > *out_details_capacity) {
*out_details_capacity =
GPR_MAX(len + 1, *out_details_capacity * 3 / 2);
*out_details = gpr_realloc(*out_details, *out_details_capacity);
}
- memcpy(*out_details, GPR_SLICE_START_PTR(details), len);
+ memcpy(*out_details, GRPC_SLICE_START_PTR(details), len);
(*out_details)[len] = 0;
} else {
goto no_details;
@@ -632,9 +637,6 @@ static int prepare_application_metadata(grpc_call *call, int count,
if (call->send_extra_metadata_count == 0) {
prepend_extra_metadata = 0;
} else {
- for (i = 0; i < call->send_extra_metadata_count; i++) {
- GRPC_MDELEM_REF(call->send_extra_metadata[i].md);
- }
for (i = 1; i < call->send_extra_metadata_count; i++) {
call->send_extra_metadata[i].prev = &call->send_extra_metadata[i - 1];
}
@@ -680,6 +682,7 @@ static int prepare_application_metadata(grpc_call *call, int count,
&call->send_extra_metadata[call->send_extra_metadata_count - 1];
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
+ call->send_extra_metadata_count = 0;
break;
case 3: {
/* prepend AND md */
@@ -695,6 +698,7 @@ static int prepare_application_metadata(grpc_call *call, int count,
batch->list.tail = linked_from_md(last_md);
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
+ call->send_extra_metadata_count = 0;
break;
}
default:
@@ -900,7 +904,7 @@ static uint32_t decode_status(grpc_mdelem *md) {
status = ((uint32_t)(intptr_t)user_data) - STATUS_OFFSET;
} else {
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
- GPR_SLICE_LENGTH(md->value->slice),
+ GRPC_SLICE_LENGTH(md->value->slice),
&status)) {
status = GRPC_STATUS_UNKNOWN; /* could not parse status code */
}
@@ -953,7 +957,7 @@ static grpc_mdelem *publish_app_metadata(grpc_call *call, grpc_mdelem *elem,
mdusr = &dest->metadata[dest->count++];
mdusr->key = grpc_mdstr_as_c_string(elem->key);
mdusr->value = grpc_mdstr_as_c_string(elem->value);
- mdusr->value_length = GPR_SLICE_LENGTH(elem->value->slice);
+ mdusr->value_length = GRPC_SLICE_LENGTH(elem->value->slice);
GPR_TIMER_END("publish_app_metadata", 0);
return elem;
}
@@ -1085,8 +1089,8 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
if (grpc_byte_stream_next(exec_ctx, call->receiving_stream,
&call->receiving_slice, remaining,
&call->receiving_slice_ready)) {
- gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
- call->receiving_slice);
+ grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+ call->receiving_slice);
} else {
return;
}
@@ -1099,8 +1103,8 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_call *call = bctl->call;
if (error == GRPC_ERROR_NONE) {
- gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
- call->receiving_slice);
+ grpc_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+ call->receiving_slice);
continue_receiving_slices(exec_ctx, bctl);
} else {
if (grpc_trace_operation_failures) {
@@ -1461,6 +1465,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
grpc_slice_buffer_stream_init(
&call->sending_stream,
&op->data.send_message->data.raw.slice_buffer, op->flags);
+ /* If the outgoing buffer is already compressed, mark it as so in the
+ flags. These will be picked up by the compression filter and further
+ (wasteful) attempts at compression skipped. */
+ if (op->data.send_message->data.raw.compression > GRPC_COMPRESS_NONE) {
+ call->sending_stream.base.flags |= GRPC_WRITE_INTERNAL_COMPRESS;
+ }
stream_op->send_message = &call->sending_stream.base;
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 92d783b78d..1389df6886 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -175,6 +175,15 @@ char *grpc_channel_get_target(grpc_channel *channel) {
return gpr_strdup(channel->target);
}
+void grpc_channel_get_info(grpc_channel *channel,
+ const grpc_channel_info *channel_info) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_channel_element *elem =
+ grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+ elem->filter->get_channel_info(&exec_ctx, elem, channel_info);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
static grpc_call *grpc_channel_create_call_internal(
grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index d32c884e8e..d0df8e7e17 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -88,6 +88,10 @@ static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
return NULL;
}
+static void lame_get_channel_info(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {}
+
static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_transport_op *op) {
@@ -140,6 +144,7 @@ const grpc_channel_filter grpc_lame_filter = {
init_channel_elem,
destroy_channel_elem,
lame_get_peer,
+ lame_get_channel_info,
"lame-client",
};
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 3a90308058..fe73aa375c 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -195,6 +195,7 @@ struct grpc_server {
grpc_completion_queue **cqs;
grpc_pollset **pollsets;
size_t cq_count;
+ size_t pollset_count;
bool started;
/* The two following mutexes control access to server-state
@@ -264,13 +265,13 @@ static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) {
struct shutdown_cleanup_args {
grpc_closure closure;
- gpr_slice slice;
+ grpc_slice slice;
};
static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) {
struct shutdown_cleanup_args *a = arg;
- gpr_slice_unref(a->slice);
+ grpc_slice_unref(a->slice);
gpr_free(a);
}
@@ -283,7 +284,7 @@ static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
op->send_goaway = send_goaway;
op->set_accept_stream = true;
- sc->slice = gpr_slice_from_copied_string("Server shutdown");
+ sc->slice = grpc_slice_from_copied_string("Server shutdown");
op->goaway_message = &sc->slice;
op->goaway_status = GRPC_STATUS_OK;
op->disconnect_with_error = send_disconnect;
@@ -459,8 +460,8 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
}
static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
- gpr_slice slice = value->slice;
- size_t len = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = value->slice;
+ size_t len = GRPC_SLICE_LENGTH(slice);
if (len + 1 > *capacity) {
*capacity = GPR_MAX(len + 1, *capacity * 2);
@@ -965,6 +966,7 @@ const grpc_channel_filter grpc_server_top_filter = {
init_channel_elem,
destroy_channel_elem,
grpc_call_next_get_peer,
+ grpc_channel_next_get_info,
"server",
};
@@ -1084,7 +1086,7 @@ void grpc_server_start(grpc_server *server) {
GRPC_API_TRACE("grpc_server_start(server=%p)", 1, (server));
server->started = true;
- size_t pollset_count = 0;
+ server->pollset_count = 0;
server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
server->request_freelist_per_cq =
gpr_malloc(sizeof(*server->request_freelist_per_cq) * server->cq_count);
@@ -1092,7 +1094,8 @@ void grpc_server_start(grpc_server *server) {
gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
for (i = 0; i < server->cq_count; i++) {
if (!grpc_cq_is_non_listening_server_cq(server->cqs[i])) {
- server->pollsets[pollset_count++] = grpc_cq_pollset(server->cqs[i]);
+ server->pollsets[server->pollset_count++] =
+ grpc_cq_pollset(server->cqs[i]);
}
server->request_freelist_per_cq[i] =
gpr_stack_lockfree_create((size_t)server->max_requested_calls_per_cq);
@@ -1111,7 +1114,8 @@ void grpc_server_start(grpc_server *server) {
}
for (l = server->listeners; l; l = l->next) {
- l->start(&exec_ctx, server, l->arg, server->pollsets, pollset_count);
+ l->start(&exec_ctx, server, l->arg, server->pollsets,
+ server->pollset_count);
}
grpc_exec_ctx_finish(&exec_ctx);
@@ -1119,7 +1123,7 @@ void grpc_server_start(grpc_server *server) {
void grpc_server_get_pollsets(grpc_server *server, grpc_pollset ***pollsets,
size_t *pollset_count) {
- *pollset_count = server->cq_count;
+ *pollset_count = server->pollset_count;
*pollsets = server->pollsets;
}
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 41242684da..0db8b41aa9 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,6 +36,6 @@
#include <grpc/grpc.h>
-const char *grpc_version_string(void) { return "1.1.0-dev"; }
+const char *grpc_version_string(void) { return "2.0.0-dev"; }
const char *grpc_g_stands_for(void) { return "good"; }
diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c
index 2f6c75cb6a..2f1d7b7c60 100644
--- a/src/core/lib/transport/byte_stream.c
+++ b/src/core/lib/transport/byte_stream.c
@@ -38,7 +38,7 @@
#include <grpc/support/log.h>
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
- grpc_byte_stream *byte_stream, gpr_slice *slice,
+ grpc_byte_stream *byte_stream, grpc_slice *slice,
size_t max_size_hint, grpc_closure *on_complete) {
return byte_stream->next(exec_ctx, byte_stream, slice, max_size_hint,
on_complete);
@@ -53,11 +53,11 @@ void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
static int slice_buffer_stream_next(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream,
- gpr_slice *slice, size_t max_size_hint,
+ grpc_slice *slice, size_t max_size_hint,
grpc_closure *on_complete) {
grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
- *slice = gpr_slice_ref(stream->backing_buffer->slices[stream->cursor]);
+ *slice = grpc_slice_ref(stream->backing_buffer->slices[stream->cursor]);
stream->cursor++;
return 1;
}
@@ -66,7 +66,7 @@ static void slice_buffer_stream_destroy(grpc_exec_ctx *exec_ctx,
grpc_byte_stream *byte_stream) {}
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
- gpr_slice_buffer *slice_buffer,
+ grpc_slice_buffer *slice_buffer,
uint32_t flags) {
GPR_ASSERT(slice_buffer->length <= UINT32_MAX);
stream->base.length = (uint32_t)slice_buffer->length;
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index e64dce6283..1fdd5b4d77 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
#define GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H
-#include <grpc/support/slice_buffer.h>
+#include <grpc/slice_buffer.h>
#include "src/core/lib/iomgr/exec_ctx.h"
/** Internal bit flag for grpc_begin_message's \a flags signaling the use of
@@ -50,7 +50,7 @@ struct grpc_byte_stream {
uint32_t length;
uint32_t flags;
int (*next)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream,
- gpr_slice *slice, size_t max_size_hint,
+ grpc_slice *slice, size_t max_size_hint,
grpc_closure *on_complete);
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_byte_stream *byte_stream);
};
@@ -65,7 +65,7 @@ struct grpc_byte_stream {
* once a slice is returned into *slice, it is owned by the caller.
*/
int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
- grpc_byte_stream *byte_stream, gpr_slice *slice,
+ grpc_byte_stream *byte_stream, grpc_slice *slice,
size_t max_size_hint, grpc_closure *on_complete);
void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
@@ -74,12 +74,12 @@ void grpc_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
/* grpc_byte_stream that wraps a slice buffer */
typedef struct grpc_slice_buffer_stream {
grpc_byte_stream base;
- gpr_slice_buffer *backing_buffer;
+ grpc_slice_buffer *backing_buffer;
size_t cursor;
} grpc_slice_buffer_stream;
void grpc_slice_buffer_stream_init(grpc_slice_buffer_stream *stream,
- gpr_slice_buffer *slice_buffer,
+ grpc_slice_buffer *slice_buffer,
uint32_t flags);
#endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
index fdb5307814..4f49d7cf7d 100644
--- a/src/core/lib/transport/connectivity_state.c
+++ b/src/core/lib/transport/connectivity_state.c
@@ -43,6 +43,8 @@ int grpc_connectivity_state_trace = 0;
const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
switch (state) {
+ case GRPC_CHANNEL_INIT:
+ return "INIT";
case GRPC_CHANNEL_IDLE:
return "IDLE";
case GRPC_CHANNEL_CONNECTING:
@@ -98,7 +100,12 @@ grpc_connectivity_state grpc_connectivity_state_check(
return tracker->current_state;
}
-int grpc_connectivity_state_notify_on_state_change(
+bool grpc_connectivity_state_has_watchers(
+ grpc_connectivity_state_tracker *connectivity_state) {
+ return connectivity_state->watchers != NULL;
+}
+
+bool grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify) {
if (grpc_connectivity_state_trace) {
@@ -117,7 +124,7 @@ int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
tracker->watchers = w->next;
gpr_free(w);
- return 0;
+ return false;
}
while (w != NULL) {
grpc_connectivity_state_watcher *rm_candidate = w->next;
@@ -125,11 +132,11 @@ int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
w->next = w->next->next;
gpr_free(rm_candidate);
- return 0;
+ return false;
}
w = w->next;
}
- return 0;
+ return false;
} else {
if (tracker->current_state != *current) {
*current = tracker->current_state;
@@ -159,6 +166,7 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_error_free_string(error_string);
}
switch (state) {
+ case GRPC_CHANNEL_INIT:
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
case GRPC_CHANNEL_READY:
diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h
index 7a2fa52c10..769c675b79 100644
--- a/src/core/lib/transport/connectivity_state.h
+++ b/src/core/lib/transport/connectivity_state.h
@@ -75,13 +75,16 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_error *associated_error,
const char *reason);
+bool grpc_connectivity_state_has_watchers(
+ grpc_connectivity_state_tracker *tracker);
+
grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker, grpc_error **current_error);
/** Return 1 if the channel should start connecting, 0 otherwise.
If current==NULL cancel notify if it is already queued (success==0 in that
case) */
-int grpc_connectivity_state_notify_on_state_change(
+bool grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify);
diff --git a/src/core/lib/transport/mdstr_hash_table.c b/src/core/lib/transport/mdstr_hash_table.c
index 8e914c420b..3d01e56df7 100644
--- a/src/core/lib/transport/mdstr_hash_table.c
+++ b/src/core/lib/transport/mdstr_hash_table.c
@@ -41,7 +41,6 @@
struct grpc_mdstr_hash_table {
gpr_refcount refs;
- size_t num_entries;
size_t size;
grpc_mdstr_hash_table_entry* entries;
};
@@ -77,7 +76,6 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table));
memset(table, 0, sizeof(*table));
gpr_ref_init(&table->refs, 1);
- table->num_entries = num_entries;
// Quadratic probing gets best performance when the table is no more
// than half full.
table->size = num_entries * 2;
@@ -96,7 +94,7 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) {
return table;
}
-int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
+void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
if (table != NULL && gpr_unref(&table->refs)) {
for (size_t i = 0; i < table->size; ++i) {
grpc_mdstr_hash_table_entry* entry = &table->entries[i];
@@ -107,13 +105,7 @@ int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
}
gpr_free(table->entries);
gpr_free(table);
- return 1;
}
- return 0;
-}
-
-size_t grpc_mdstr_hash_table_num_entries(const grpc_mdstr_hash_table* table) {
- return table->num_entries;
}
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
@@ -123,35 +115,3 @@ void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
if (idx == table->size) return NULL; // Not found.
return table->entries[idx].value;
}
-
-int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
- const grpc_mdstr_hash_table* table2) {
- // Compare by num_entries.
- if (table1->num_entries < table2->num_entries) return -1;
- if (table1->num_entries > table2->num_entries) return 1;
- for (size_t i = 0; i < table1->num_entries; ++i) {
- grpc_mdstr_hash_table_entry* e1 = &table1->entries[i];
- grpc_mdstr_hash_table_entry* e2 = &table2->entries[i];
- // Compare keys by hash value.
- if (e1->key->hash < e2->key->hash) return -1;
- if (e1->key->hash > e2->key->hash) return 1;
- // Compare by vtable (pointer equality).
- if (e1->vtable < e2->vtable) return -1;
- if (e1->vtable > e2->vtable) return 1;
- // Compare values via vtable.
- const int value_result = e1->vtable->compare_value(e1->value, e2->value);
- if (value_result != 0) return value_result;
- }
- return 0;
-}
-
-void grpc_mdstr_hash_table_iterate(
- const grpc_mdstr_hash_table* table,
- void (*func)(const grpc_mdstr_hash_table_entry* entry, void* user_data),
- void* user_data) {
- for (size_t i = 0; i < table->size; ++i) {
- if (table->entries[i].key != NULL) {
- func(&table->entries[i], user_data);
- }
- }
-}
diff --git a/src/core/lib/transport/mdstr_hash_table.h b/src/core/lib/transport/mdstr_hash_table.h
index bceb4df93d..8982ec3a8d 100644
--- a/src/core/lib/transport/mdstr_hash_table.h
+++ b/src/core/lib/transport/mdstr_hash_table.h
@@ -51,7 +51,6 @@ typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table;
typedef struct grpc_mdstr_hash_table_vtable {
void (*destroy_value)(void* value);
void* (*copy_value)(void* value);
- int (*compare_value)(void* value1, void* value2);
} grpc_mdstr_hash_table_vtable;
typedef struct grpc_mdstr_hash_table_entry {
@@ -67,26 +66,11 @@ grpc_mdstr_hash_table* grpc_mdstr_hash_table_create(
size_t num_entries, grpc_mdstr_hash_table_entry* entries);
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table);
-/** Returns 1 when \a table is destroyed. */
-int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
-
-/** Returns the number of entries in \a table. */
-size_t grpc_mdstr_hash_table_num_entries(const grpc_mdstr_hash_table* table);
+void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
/** Returns the value from \a table associated with \a key.
Returns NULL if \a key is not found. */
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table,
const grpc_mdstr* key);
-/** Compares two hash tables.
- The sort order is stable but undefined. */
-int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1,
- const grpc_mdstr_hash_table* table2);
-
-/** Iterates over the entries in \a table, calling \a func for each entry. */
-void grpc_mdstr_hash_table_iterate(
- const grpc_mdstr_hash_table* table,
- void (*func)(const grpc_mdstr_hash_table_entry* entry, void* user_data),
- void* user_data);
-
#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 4b40c275ad..fac19b91d9 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -51,7 +51,7 @@
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
-gpr_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(gpr_slice input);
+grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input);
/* There are two kinds of mdelem and mdstr instances.
* Static instances are declared in static_metadata.{h,c} and
@@ -85,16 +85,16 @@ typedef void (*destroy_user_data_func)(void *user_data);
/* Shadow structure for grpc_mdstr for non-static values */
typedef struct internal_string {
/* must be byte compatible with grpc_mdstr */
- gpr_slice slice;
+ grpc_slice slice;
uint32_t hash;
/* private only data */
gpr_atm refcnt;
uint8_t has_base64_and_huffman_encoded;
- gpr_slice_refcount refcount;
+ grpc_slice_refcount refcount;
- gpr_slice base64_and_huffman;
+ grpc_slice base64_and_huffman;
gpr_atm size_in_decoder_table;
@@ -174,7 +174,7 @@ void grpc_mdctx_global_init(void) {
grpc_mdstr *elem = &grpc_static_mdstr_table[i];
const char *str = grpc_static_metadata_strings[i];
uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
- *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
+ *(grpc_slice *)&elem->slice = grpc_slice_from_static_string(str);
*(uint32_t *)&elem->hash = hash;
for (j = 0;; j++) {
size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
@@ -321,7 +321,7 @@ static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
internal_string *cur;
GPR_TIMER_BEGIN("internal_destroy_string", 0);
if (is->has_base64_and_huffman_encoded) {
- gpr_slice_unref(is->base64_and_huffman);
+ grpc_slice_unref(is->base64_and_huffman);
}
for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
shard->capacity)],
@@ -350,10 +350,10 @@ grpc_mdstr *grpc_mdstr_from_string(const char *str) {
return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
}
-grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
- grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
- GPR_SLICE_LENGTH(slice));
- gpr_slice_unref(slice);
+grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice) {
+ grpc_mdstr *result = grpc_mdstr_from_buffer(GRPC_SLICE_START_PTR(slice),
+ GRPC_SLICE_LENGTH(slice));
+ grpc_slice_unref(slice);
return result;
}
@@ -373,9 +373,9 @@ grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
ss = g_static_strtab[idx];
if (ss == NULL) break;
- if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
+ if (ss->hash == hash && GRPC_SLICE_LENGTH(ss->slice) == length &&
(length == 0 ||
- 0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length))) {
+ 0 == memcmp(buf, GRPC_SLICE_START_PTR(ss->slice), length))) {
GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
return ss;
}
@@ -386,8 +386,8 @@ grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
/* search for an existing string */
idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
for (s = shard->strs[idx]; s; s = s->bucket_next) {
- if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
- 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
+ if (s->hash == hash && GRPC_SLICE_LENGTH(s->slice) == length &&
+ 0 == memcmp(buf, GRPC_SLICE_START_PTR(s->slice), length)) {
if (gpr_atm_full_fetch_add(&s->refcnt, 1) == 0) {
/* If we get here, we've added a ref to something that was about to
* die - drop it immediately.
@@ -404,7 +404,7 @@ grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
}
/* not found: create a new string */
- if (length + 1 < GPR_SLICE_INLINED_SIZE) {
+ if (length + 1 < GRPC_SLICE_INLINED_SIZE) {
/* string data goes directly into the slice */
s = gpr_malloc(sizeof(internal_string));
gpr_atm_rel_store(&s->refcnt, 1);
@@ -589,7 +589,7 @@ grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
grpc_mdstr_from_string(value));
}
-grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
+grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value) {
return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
grpc_mdstr_from_slice(value));
}
@@ -607,12 +607,12 @@ static size_t get_base64_encoded_size(size_t raw_length) {
}
size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
- size_t overhead_and_key = 32 + GPR_SLICE_LENGTH(elem->key->slice);
- size_t value_len = GPR_SLICE_LENGTH(elem->value->slice);
+ size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(elem->key->slice);
+ size_t value_len = GRPC_SLICE_LENGTH(elem->value->slice);
if (is_mdstr_static(elem->value)) {
if (grpc_is_binary_header(
- (const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice))) {
+ (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
+ GRPC_SLICE_LENGTH(elem->key->slice))) {
return overhead_and_key + get_base64_encoded_size(value_len);
} else {
return overhead_and_key + value_len;
@@ -622,8 +622,8 @@ size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
gpr_atm current_size = gpr_atm_acq_load(&is->size_in_decoder_table);
if (current_size == SIZE_IN_DECODER_TABLE_NOT_SET) {
if (grpc_is_binary_header(
- (const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice))) {
+ (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
+ GRPC_SLICE_LENGTH(elem->key->slice))) {
current_size = (gpr_atm)get_base64_encoded_size(value_len);
} else {
current_size = (gpr_atm)value_len;
@@ -679,7 +679,7 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
}
const char *grpc_mdstr_as_c_string(const grpc_mdstr *s) {
- return (const char *)GPR_SLICE_START_PTR(s->slice);
+ return (const char *)GRPC_SLICE_START_PTR(s->slice);
}
size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); }
@@ -687,6 +687,11 @@ size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); }
grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
if (is_mdstr_static(gs)) return gs;
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR REF:%p:%zu->%zu: '%s'",
+ (void *)s, gpr_atm_no_barrier_load(&s->refcnt),
+ gpr_atm_no_barrier_load(&s->refcnt) + 1, grpc_mdstr_as_c_string(gs));
+#endif
GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) > 0);
return gs;
}
@@ -694,6 +699,11 @@ grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
if (is_mdstr_static(gs)) return;
+#ifdef GRPC_METADATA_REFCOUNT_DEBUG
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%zu->%zu: '%s'",
+ (void *)s, gpr_atm_no_barrier_load(&s->refcnt),
+ gpr_atm_no_barrier_load(&s->refcnt) - 1, grpc_mdstr_as_c_string(gs));
+#endif
if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
strtab_shard *shard =
&g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
@@ -718,8 +728,8 @@ void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
return result;
}
-void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
- void *user_data) {
+void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+ void *user_data) {
internal_metadata *im = (internal_metadata *)md;
GPR_ASSERT(!is_mdelem_static(md));
GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
@@ -730,16 +740,17 @@ void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
if (destroy_func != NULL) {
destroy_func(user_data);
}
- return;
+ return (void *)gpr_atm_no_barrier_load(&im->user_data);
}
gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
gpr_mu_unlock(&im->mu_user_data);
+ return user_data;
}
-gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
+grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
internal_string *s = (internal_string *)gs;
- gpr_slice slice;
+ grpc_slice slice;
strtab_shard *shard =
&g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
gpr_mu_lock(&shard->mu);
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 71eff0acf2..a4955a1ea7 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -34,7 +34,7 @@
#ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_H
#define GRPC_CORE_LIB_TRANSPORT_METADATA_H
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include <grpc/support/useful.h>
#ifdef __cplusplus
@@ -77,7 +77,7 @@ typedef struct grpc_mdelem grpc_mdelem;
/* if changing this, make identical changes in internal_string in metadata.c */
struct grpc_mdstr {
- const gpr_slice slice;
+ const grpc_slice slice;
const uint32_t hash;
/* there is a private part to this in metadata.c */
};
@@ -96,12 +96,12 @@ void grpc_test_only_set_metadata_hash_seed(uint32_t seed);
clients may have handy */
grpc_mdstr *grpc_mdstr_from_string(const char *str);
/* Unrefs the slice. */
-grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice);
+grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice);
grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length);
/* Returns a borrowed slice from the mdstr with its contents base64 encoded
and huffman compressed */
-gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
+grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *str);
/* Constructors for grpc_mdelem instances; take a variety of data types that
clients may have handy */
@@ -109,7 +109,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
grpc_mdstr *value);
grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
/* Unrefs the slices. */
-grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value);
+grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value);
grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
const uint8_t *value,
size_t value_length);
@@ -120,8 +120,8 @@ size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem);
is used as a type tag and is checked during user_data fetch. */
void *grpc_mdelem_get_user_data(grpc_mdelem *md,
void (*if_destroy_func)(void *));
-void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
- void *user_data);
+void *grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
+ void *user_data);
/* Reference counting */
//#define GRPC_METADATA_REFCOUNT_DEBUG
@@ -149,7 +149,7 @@ void grpc_mdelem_unref(grpc_mdelem *md);
Does not promise that the returned string has no embedded nulls however. */
const char *grpc_mdstr_as_c_string(const grpc_mdstr *s);
-#define GRPC_MDSTR_LENGTH(s) (GPR_SLICE_LENGTH(s->slice))
+#define GRPC_MDSTR_LENGTH(s) (GRPC_SLICE_LENGTH(s->slice))
/* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */
#define GRPC_MDELEM_LENGTH(e) \
@@ -165,8 +165,8 @@ void grpc_mdctx_global_init(void);
void grpc_mdctx_global_shutdown(void);
/* Implementation provided by chttp2_transport */
-extern gpr_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(
- gpr_slice input);
+extern grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(
+ grpc_slice input);
#ifdef __cplusplus
}
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 0424b4db98..7a9ccb4bc8 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -37,8 +37,8 @@
#include <stdbool.h>
#include <grpc/grpc.h>
+#include <grpc/slice.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
#include <grpc/support/time.h>
#include "src/core/lib/transport/metadata.h"
diff --git a/src/core/lib/transport/method_config.c b/src/core/lib/transport/method_config.c
deleted file mode 100644
index 57d97700bf..0000000000
--- a/src/core/lib/transport/method_config.c
+++ /dev/null
@@ -1,340 +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/transport/method_config.h"
-
-#include <string.h>
-
-#include <grpc/impl/codegen/grpc_types.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/string_util.h>
-#include <grpc/support/time.h>
-
-#include "src/core/lib/transport/mdstr_hash_table.h"
-#include "src/core/lib/transport/metadata.h"
-
-//
-// grpc_method_config
-//
-
-// bool vtable
-
-static void* bool_copy(void* valuep) {
- bool value = *(bool*)valuep;
- bool* new_value = gpr_malloc(sizeof(bool));
- *new_value = value;
- return new_value;
-}
-
-static int bool_cmp(void* v1, void* v2) {
- bool b1 = *(bool*)v1;
- bool b2 = *(bool*)v2;
- if (!b1 && b2) return -1;
- if (b1 && !b2) return 1;
- return 0;
-}
-
-static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy,
- bool_cmp};
-
-// timespec vtable
-
-static void* timespec_copy(void* valuep) {
- gpr_timespec value = *(gpr_timespec*)valuep;
- gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
- *new_value = value;
- return new_value;
-}
-
-static int timespec_cmp(void* v1, void* v2) {
- return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
-}
-
-static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy,
- timespec_cmp};
-
-// int32 vtable
-
-static void* int32_copy(void* valuep) {
- int32_t value = *(int32_t*)valuep;
- int32_t* new_value = gpr_malloc(sizeof(int32_t));
- *new_value = value;
- return new_value;
-}
-
-static int int32_cmp(void* v1, void* v2) {
- int32_t i1 = *(int32_t*)v1;
- int32_t i2 = *(int32_t*)v2;
- if (i1 < i2) return -1;
- if (i1 > i2) return 1;
- return 0;
-}
-
-static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy,
- int32_cmp};
-
-// Hash table keys.
-#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
-#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
-#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
- "grpc.max_request_message_bytes" // int32
-#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
- "grpc.max_response_message_bytes" // int32
-
-struct grpc_method_config {
- grpc_mdstr_hash_table* table;
- grpc_mdstr* wait_for_ready_key;
- grpc_mdstr* timeout_key;
- grpc_mdstr* max_request_message_bytes_key;
- grpc_mdstr* max_response_message_bytes_key;
-};
-
-grpc_method_config* grpc_method_config_create(
- bool* wait_for_ready, gpr_timespec* timeout,
- int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
- grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
- memset(method_config, 0, sizeof(grpc_method_config));
- method_config->wait_for_ready_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
- method_config->timeout_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
- method_config->max_request_message_bytes_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
- method_config->max_response_message_bytes_key =
- grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
- grpc_mdstr_hash_table_entry entries[4];
- size_t num_entries = 0;
- if (wait_for_ready != NULL) {
- entries[num_entries].key = method_config->wait_for_ready_key;
- entries[num_entries].value = wait_for_ready;
- entries[num_entries].vtable = &bool_vtable;
- ++num_entries;
- }
- if (timeout != NULL) {
- entries[num_entries].key = method_config->timeout_key;
- entries[num_entries].value = timeout;
- entries[num_entries].vtable = &timespec_vtable;
- ++num_entries;
- }
- if (max_request_message_bytes != NULL) {
- entries[num_entries].key = method_config->max_request_message_bytes_key;
- entries[num_entries].value = max_request_message_bytes;
- entries[num_entries].vtable = &int32_vtable;
- ++num_entries;
- }
- if (max_response_message_bytes != NULL) {
- entries[num_entries].key = method_config->max_response_message_bytes_key;
- entries[num_entries].value = max_response_message_bytes;
- entries[num_entries].vtable = &int32_vtable;
- ++num_entries;
- }
- method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
- return method_config;
-}
-
-grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
- grpc_mdstr_hash_table_ref(method_config->table);
- return method_config;
-}
-
-void grpc_method_config_unref(grpc_method_config* method_config) {
- if (grpc_mdstr_hash_table_unref(method_config->table)) {
- GRPC_MDSTR_UNREF(method_config->wait_for_ready_key);
- GRPC_MDSTR_UNREF(method_config->timeout_key);
- GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key);
- GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key);
- gpr_free(method_config);
- }
-}
-
-int grpc_method_config_cmp(const grpc_method_config* method_config1,
- const grpc_method_config* method_config2) {
- return grpc_mdstr_hash_table_cmp(method_config1->table,
- method_config2->table);
-}
-
-const bool* grpc_method_config_get_wait_for_ready(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(method_config->table,
- method_config->wait_for_ready_key);
-}
-
-const gpr_timespec* grpc_method_config_get_timeout(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(method_config->table,
- method_config->timeout_key);
-}
-
-const int32_t* grpc_method_config_get_max_request_message_bytes(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(
- method_config->table, method_config->max_request_message_bytes_key);
-}
-
-const int32_t* grpc_method_config_get_max_response_message_bytes(
- const grpc_method_config* method_config) {
- return grpc_mdstr_hash_table_get(
- method_config->table, method_config->max_response_message_bytes_key);
-}
-
-//
-// grpc_method_config_table
-//
-
-static void method_config_unref(void* valuep) {
- grpc_method_config_unref(valuep);
-}
-
-static void* method_config_ref(void* valuep) {
- return grpc_method_config_ref(valuep);
-}
-
-static int method_config_cmp(void* valuep1, void* valuep2) {
- return grpc_method_config_cmp(valuep1, valuep2);
-}
-
-static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
- method_config_unref, method_config_ref, method_config_cmp};
-
-grpc_method_config_table* grpc_method_config_table_create(
- size_t num_entries, grpc_method_config_table_entry* entries) {
- grpc_mdstr_hash_table_entry* hash_table_entries =
- gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
- for (size_t i = 0; i < num_entries; ++i) {
- hash_table_entries[i].key = entries[i].method_name;
- hash_table_entries[i].value = entries[i].method_config;
- hash_table_entries[i].vtable = &method_config_table_vtable;
- }
- grpc_method_config_table* method_config_table =
- grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
- gpr_free(hash_table_entries);
- return method_config_table;
-}
-
-grpc_method_config_table* grpc_method_config_table_ref(
- grpc_method_config_table* table) {
- return grpc_mdstr_hash_table_ref(table);
-}
-
-void grpc_method_config_table_unref(grpc_method_config_table* table) {
- grpc_mdstr_hash_table_unref(table);
-}
-
-int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
- const grpc_method_config_table* table2) {
- return grpc_mdstr_hash_table_cmp(table1, table2);
-}
-
-void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path) {
- void* value = grpc_mdstr_hash_table_get(table, path);
- // If we didn't find a match for the path, try looking for a wildcard
- // entry (i.e., change "/service/method" to "/service/*").
- if (value == NULL) {
- const char* path_str = grpc_mdstr_as_c_string(path);
- const char* sep = strrchr(path_str, '/') + 1;
- const size_t len = (size_t)(sep - path_str);
- char* buf = gpr_malloc(len + 2); // '*' and NUL
- memcpy(buf, path_str, len);
- buf[len] = '*';
- buf[len + 1] = '\0';
- grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
- gpr_free(buf);
- value = grpc_mdstr_hash_table_get(table, wildcard_path);
- GRPC_MDSTR_UNREF(wildcard_path);
- }
- return value;
-}
-
-static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
-
-static void destroy_arg(void* p) { grpc_method_config_table_unref(p); }
-
-static int cmp_arg(void* p1, void* p2) {
- return grpc_method_config_table_cmp(p1, p2);
-}
-
-static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
-
-grpc_arg grpc_method_config_table_create_channel_arg(
- grpc_method_config_table* table) {
- grpc_arg arg;
- arg.type = GRPC_ARG_POINTER;
- arg.key = GRPC_ARG_SERVICE_CONFIG;
- arg.value.pointer.p = table;
- arg.value.pointer.vtable = &arg_vtable;
- return arg;
-}
-
-// State used by convert_entry() below.
-typedef struct conversion_state {
- void* (*convert_value)(const grpc_method_config* method_config);
- const grpc_mdstr_hash_table_vtable* vtable;
- size_t num_entries;
- grpc_mdstr_hash_table_entry* entries;
-} conversion_state;
-
-// A function to be passed to grpc_mdstr_hash_table_iterate() to create
-// a copy of the entries.
-static void convert_entry(const grpc_mdstr_hash_table_entry* entry,
- void* user_data) {
- conversion_state* state = user_data;
- state->entries[state->num_entries].key = GRPC_MDSTR_REF(entry->key);
- state->entries[state->num_entries].value = state->convert_value(entry->value);
- state->entries[state->num_entries].vtable = state->vtable;
- ++state->num_entries;
-}
-
-grpc_mdstr_hash_table* grpc_method_config_table_convert(
- const grpc_method_config_table* table,
- void* (*convert_value)(const grpc_method_config* method_config),
- const grpc_mdstr_hash_table_vtable* vtable) {
- // Create an array of the entries in the table with converted values.
- conversion_state state;
- state.convert_value = convert_value;
- state.vtable = vtable;
- state.num_entries = 0;
- state.entries = gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) *
- grpc_mdstr_hash_table_num_entries(table));
- grpc_mdstr_hash_table_iterate(table, convert_entry, &state);
- // Create a new table based on the array we just constructed.
- grpc_mdstr_hash_table* new_table =
- grpc_mdstr_hash_table_create(state.num_entries, state.entries);
- // Clean up the array.
- for (size_t i = 0; i < state.num_entries; ++i) {
- GRPC_MDSTR_UNREF(state.entries[i].key);
- vtable->destroy_value(state.entries[i].value);
- }
- gpr_free(state.entries);
- // Return the new table.
- return new_table;
-}
diff --git a/src/core/lib/transport/method_config.h b/src/core/lib/transport/method_config.h
deleted file mode 100644
index 58fedd9436..0000000000
--- a/src/core/lib/transport/method_config.h
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-// Copyright 2016, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-
-#ifndef GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
-#define GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
-
-#include <stdbool.h>
-
-#include <grpc/impl/codegen/gpr_types.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-#include "src/core/lib/transport/mdstr_hash_table.h"
-#include "src/core/lib/transport/metadata.h"
-
-/// Per-method configuration.
-typedef struct grpc_method_config grpc_method_config;
-
-/// Creates a grpc_method_config with the specified parameters.
-/// Any parameter may be NULL to indicate that the value is unset.
-///
-/// \a wait_for_ready indicates whether the client should wait until the
-/// request deadline for the channel to become ready, even if there is a
-/// temporary failure before the deadline while attempting to connect.
-///
-/// \a timeout indicates the timeout for calls.
-///
-/// \a max_request_message_bytes and \a max_response_message_bytes
-/// indicate the maximum sizes of the request (checked when sending) and
-/// response (checked when receiving) messages.
-grpc_method_config* grpc_method_config_create(
- bool* wait_for_ready, gpr_timespec* timeout,
- int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
-
-grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
-void grpc_method_config_unref(grpc_method_config* method_config);
-
-/// Compares two grpc_method_configs.
-/// The sort order is stable but undefined.
-int grpc_method_config_cmp(const grpc_method_config* method_config1,
- const grpc_method_config* method_config2);
-
-/// These methods return NULL if the requested field is unset.
-/// The caller does NOT take ownership of the result.
-const bool* grpc_method_config_get_wait_for_ready(
- const grpc_method_config* method_config);
-const gpr_timespec* grpc_method_config_get_timeout(
- const grpc_method_config* method_config);
-const int32_t* grpc_method_config_get_max_request_message_bytes(
- const grpc_method_config* method_config);
-const int32_t* grpc_method_config_get_max_response_message_bytes(
- const grpc_method_config* method_config);
-
-/// A table of method configs.
-typedef grpc_mdstr_hash_table grpc_method_config_table;
-
-typedef struct grpc_method_config_table_entry {
- /// The name is of one of the following forms:
- /// service/method -- specifies exact service and method name
- /// service/* -- matches all methods for the specified service
- grpc_mdstr* method_name;
- grpc_method_config* method_config;
-} grpc_method_config_table_entry;
-
-/// Takes new references to all keys and values in \a entries.
-grpc_method_config_table* grpc_method_config_table_create(
- size_t num_entries, grpc_method_config_table_entry* entries);
-
-grpc_method_config_table* grpc_method_config_table_ref(
- grpc_method_config_table* table);
-void grpc_method_config_table_unref(grpc_method_config_table* table);
-
-/// Compares two grpc_method_config_tables.
-/// The sort order is stable but undefined.
-int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
- const grpc_method_config_table* table2);
-
-/// Gets the method config for the specified \a path, which should be of
-/// the form "/service/method".
-/// Returns NULL if the method has no config.
-/// Caller does NOT own a reference to the result.
-///
-/// Note: This returns a void* instead of a grpc_method_config* so that
-/// it can also be used for tables constructed via
-/// grpc_method_config_table_convert().
-void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
- const grpc_mdstr* path);
-
-/// Returns a channel arg containing \a table.
-grpc_arg grpc_method_config_table_create_channel_arg(
- grpc_method_config_table* table);
-
-/// Generates a new table from \a table whose values are converted to a
-/// new form via the \a convert_value function. The new table will use
-/// \a vtable for its values.
-///
-/// This is generally used to convert the table's value type from
-/// grpc_method_config to a simple struct containing only the parameters
-/// relevant to a particular filter, thus avoiding the need for a hash
-/// table lookup on the fast path. In that scenario, \a convert_value
-/// will return a new instance of the struct containing the values from
-/// the grpc_method_config, and \a vtable provides the methods for
-/// operating on the struct type.
-grpc_mdstr_hash_table* grpc_method_config_table_convert(
- const grpc_method_config_table* table,
- void* (*convert_value)(const grpc_method_config* method_config),
- const grpc_mdstr_hash_table_vtable* vtable);
-
-#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */
diff --git a/src/core/lib/transport/pid_controller.c b/src/core/lib/transport/pid_controller.c
new file mode 100644
index 0000000000..3cef225d4b
--- /dev/null
+++ b/src/core/lib/transport/pid_controller.c
@@ -0,0 +1,57 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/transport/pid_controller.h"
+
+void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
+ double gain_p, double gain_i, double gain_d) {
+ pid_controller->gain_p = gain_p;
+ pid_controller->gain_i = gain_i;
+ pid_controller->gain_d = gain_d;
+ grpc_pid_controller_reset(pid_controller);
+}
+
+void grpc_pid_controller_reset(grpc_pid_controller *pid_controller) {
+ pid_controller->last_error = 0.0;
+ pid_controller->error_integral = 0.0;
+}
+
+double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
+ double error, double dt) {
+ pid_controller->error_integral += error * dt;
+ double diff_error = (error - pid_controller->last_error) / dt;
+ pid_controller->last_error = error;
+ return dt * (pid_controller->gain_p * error +
+ pid_controller->gain_i * pid_controller->error_integral +
+ pid_controller->gain_d * diff_error);
+}
diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h
new file mode 100644
index 0000000000..059b5b0834
--- /dev/null
+++ b/src/core/lib/transport/pid_controller.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
+#define GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H
+
+/* \file Simple PID controller.
+ Implements a proportional-integral-derivative controller.
+ Used when we want to iteratively control a variable to converge some other
+ observed value to a 'set-point'.
+ Gains can be set to adjust sensitivity to current error (p), the integral
+ of error (i), and the derivative of error (d). */
+
+typedef struct {
+ double gain_p;
+ double gain_i;
+ double gain_d;
+ double last_error;
+ double error_integral;
+} grpc_pid_controller;
+
+/** Initialize the controller */
+void grpc_pid_controller_init(grpc_pid_controller *pid_controller,
+ double gain_p, double gain_i, double gain_d);
+
+/** Reset the controller: useful when things have changed significantly */
+void grpc_pid_controller_reset(grpc_pid_controller *pid_controller);
+
+/** Update the controller: given a current error estimate, and the time since
+ the last update, returns a delta to the control value */
+double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
+ double error, double dt);
+
+#endif
diff --git a/src/core/lib/transport/service_config.c b/src/core/lib/transport/service_config.c
new file mode 100644
index 0000000000..2e2b59e3f7
--- /dev/null
+++ b/src/core/lib/transport/service_config.c
@@ -0,0 +1,249 @@
+//
+// 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/transport/service_config.h"
+
+#include <string.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/mdstr_hash_table.h"
+
+// The main purpose of the code here is to parse the service config in
+// JSON form, which will look like this:
+//
+// {
+// "loadBalancingPolicy": "string", // optional
+// "methodConfig": [ // array of one or more method_config objects
+// {
+// "name": [ // array of one or more name objects
+// {
+// "service": "string", // required
+// "method": "string", // optional
+// }
+// ],
+// // remaining fields are optional.
+// // see https://developers.google.com/protocol-buffers/docs/proto3#json
+// // for format details.
+// "waitForReady": bool,
+// "timeout": "duration_string",
+// "maxRequestMessageBytes": "int64_string",
+// "maxResponseMessageBytes": "int64_string",
+// }
+// ]
+// }
+
+struct grpc_service_config {
+ char* json_string; // Underlying storage for json_tree.
+ grpc_json* json_tree;
+};
+
+grpc_service_config* grpc_service_config_create(const char* json_string) {
+ grpc_service_config* service_config = gpr_malloc(sizeof(*service_config));
+ service_config->json_string = gpr_strdup(json_string);
+ service_config->json_tree =
+ grpc_json_parse_string(service_config->json_string);
+ if (service_config->json_tree == NULL) {
+ gpr_log(GPR_INFO, "failed to parse JSON for service config");
+ gpr_free(service_config->json_string);
+ gpr_free(service_config);
+ return NULL;
+ }
+ return service_config;
+}
+
+void grpc_service_config_destroy(grpc_service_config* service_config) {
+ grpc_json_destroy(service_config->json_tree);
+ gpr_free(service_config->json_string);
+ gpr_free(service_config);
+}
+
+const char* grpc_service_config_get_lb_policy_name(
+ const grpc_service_config* service_config) {
+ const grpc_json* json = service_config->json_tree;
+ if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
+ const char* lb_policy_name = NULL;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) return NULL;
+ if (strcmp(field->key, "loadBalancingPolicy") == 0) {
+ if (lb_policy_name != NULL) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_STRING) return NULL;
+ lb_policy_name = field->value;
+ }
+ }
+ return lb_policy_name;
+}
+
+// Returns the number of names specified in the method config \a json.
+static size_t count_names_in_method_config_json(grpc_json* json) {
+ size_t num_names = 0;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key != NULL && strcmp(field->key, "name") == 0) ++num_names;
+ }
+ return num_names;
+}
+
+// Returns a path string for the JSON name object specified by \a json.
+// Returns NULL on error. Caller takes ownership of result.
+static char* parse_json_method_name(grpc_json* json) {
+ if (json->type != GRPC_JSON_OBJECT) return NULL;
+ const char* service_name = NULL;
+ const char* method_name = NULL;
+ for (grpc_json* child = json->child; child != NULL; child = child->next) {
+ if (child->key == NULL) return NULL;
+ if (child->type != GRPC_JSON_STRING) return NULL;
+ if (strcmp(child->key, "service") == 0) {
+ if (service_name != NULL) return NULL; // Duplicate.
+ if (child->value == NULL) return NULL;
+ service_name = child->value;
+ } else if (strcmp(child->key, "method") == 0) {
+ if (method_name != NULL) return NULL; // Duplicate.
+ if (child->value == NULL) return NULL;
+ method_name = child->value;
+ }
+ }
+ if (service_name == NULL) return NULL; // Required field.
+ char* path;
+ gpr_asprintf(&path, "/%s/%s", service_name,
+ method_name == NULL ? "*" : method_name);
+ return path;
+}
+
+// Parses the method config from \a json. Adds an entry to \a entries for
+// each name found, incrementing \a idx for each entry added.
+// Returns false on error.
+static bool parse_json_method_config(
+ grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_mdstr_hash_table_vtable* vtable,
+ grpc_mdstr_hash_table_entry* entries, size_t* idx) {
+ // Construct value.
+ void* method_config = create_value(json);
+ if (method_config == NULL) return false;
+ // Construct list of paths.
+ bool success = false;
+ gpr_strvec paths;
+ gpr_strvec_init(&paths);
+ for (grpc_json* child = json->child; child != NULL; child = child->next) {
+ if (child->key == NULL) continue;
+ if (strcmp(child->key, "name") == 0) {
+ if (child->type != GRPC_JSON_ARRAY) goto done;
+ for (grpc_json* name = child->child; name != NULL; name = name->next) {
+ char* path = parse_json_method_name(name);
+ gpr_strvec_add(&paths, path);
+ }
+ }
+ }
+ if (paths.count == 0) goto done; // No names specified.
+ // Add entry for each path.
+ for (size_t i = 0; i < paths.count; ++i) {
+ entries[*idx].key = grpc_mdstr_from_string(paths.strs[i]);
+ entries[*idx].value = vtable->copy_value(method_config);
+ entries[*idx].vtable = vtable;
+ ++*idx;
+ }
+ success = true;
+done:
+ vtable->destroy_value(method_config);
+ gpr_strvec_destroy(&paths);
+ return success;
+}
+
+grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
+ const grpc_service_config* service_config,
+ void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_mdstr_hash_table_vtable* vtable) {
+ const grpc_json* json = service_config->json_tree;
+ // Traverse parsed JSON tree.
+ if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
+ size_t num_entries = 0;
+ grpc_mdstr_hash_table_entry* entries = NULL;
+ for (grpc_json* field = json->child; field != NULL; field = field->next) {
+ if (field->key == NULL) return NULL;
+ if (strcmp(field->key, "methodConfig") == 0) {
+ if (entries != NULL) return NULL; // Duplicate.
+ if (field->type != GRPC_JSON_ARRAY) return NULL;
+ // Find number of entries.
+ for (grpc_json* method = field->child; method != NULL;
+ method = method->next) {
+ num_entries += count_names_in_method_config_json(method);
+ }
+ // Populate method config table entries.
+ entries = gpr_malloc(num_entries * sizeof(grpc_mdstr_hash_table_entry));
+ size_t idx = 0;
+ for (grpc_json* method = field->child; method != NULL;
+ method = method->next) {
+ if (!parse_json_method_config(method, create_value, vtable, entries,
+ &idx)) {
+ return NULL;
+ }
+ }
+ GPR_ASSERT(idx == num_entries);
+ }
+ }
+ // Instantiate method config table.
+ grpc_mdstr_hash_table* method_config_table = NULL;
+ if (entries != NULL) {
+ method_config_table = grpc_mdstr_hash_table_create(num_entries, entries);
+ // Clean up.
+ for (size_t i = 0; i < num_entries; ++i) {
+ GRPC_MDSTR_UNREF(entries[i].key);
+ vtable->destroy_value(entries[i].value);
+ }
+ gpr_free(entries);
+ }
+ return method_config_table;
+}
+
+void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
+ const grpc_mdstr* path) {
+ void* value = grpc_mdstr_hash_table_get(table, path);
+ // If we didn't find a match for the path, try looking for a wildcard
+ // entry (i.e., change "/service/method" to "/service/*").
+ if (value == NULL) {
+ const char* path_str = grpc_mdstr_as_c_string(path);
+ const char* sep = strrchr(path_str, '/') + 1;
+ const size_t len = (size_t)(sep - path_str);
+ char* buf = gpr_malloc(len + 2); // '*' and NUL
+ memcpy(buf, path_str, len);
+ buf[len] = '*';
+ buf[len + 1] = '\0';
+ grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
+ gpr_free(buf);
+ value = grpc_mdstr_hash_table_get(table, wildcard_path);
+ GRPC_MDSTR_UNREF(wildcard_path);
+ }
+ return value;
+}
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
new file mode 100644
index 0000000000..2ffe475193
--- /dev/null
+++ b/src/core/lib/transport/service_config.h
@@ -0,0 +1,70 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
+#define GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/json/json.h"
+#include "src/core/lib/transport/mdstr_hash_table.h"
+
+typedef struct grpc_service_config grpc_service_config;
+
+grpc_service_config* grpc_service_config_create(const char* json_string);
+void grpc_service_config_destroy(grpc_service_config* service_config);
+
+/// Gets the LB policy name from \a service_config.
+/// Returns NULL if no LB policy name was specified.
+/// Caller does NOT take ownership.
+const char* grpc_service_config_get_lb_policy_name(
+ const grpc_service_config* service_config);
+
+/// Creates a method config table based on the data in \a json.
+/// The table's keys are request paths. The table's value type is
+/// returned by \a create_value(), based on data parsed from the JSON tree.
+/// \a vtable provides methods used to manage the values.
+/// Returns NULL on error.
+grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
+ const grpc_service_config* service_config,
+ void* (*create_value)(const grpc_json* method_config_json),
+ const grpc_mdstr_hash_table_vtable* vtable);
+
+/// A helper function for looking up values in the table returned by
+/// \a grpc_service_config_create_method_config_table().
+/// Gets the method config for the specified \a path, which should be of
+/// the form "/service/method".
+/// Returns NULL if the method has no config.
+/// Caller does NOT own a reference to the result.
+void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
+ const grpc_mdstr* path);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 75aec7a5b4..b448126da8 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -40,6 +40,7 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport_impl.h"
@@ -159,6 +160,11 @@ char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
return transport->vtable->get_peer(exec_ctx, transport);
}
+grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx,
+ grpc_transport *transport) {
+ return transport->vtable->get_endpoint(exec_ctx, transport);
+}
+
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
grpc_transport_stream_op *op,
grpc_error *error) {
@@ -207,21 +213,21 @@ void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
void grpc_transport_stream_op_add_cancellation_with_message(
grpc_transport_stream_op *op, grpc_status_code status,
- gpr_slice *optional_message) {
+ grpc_slice *optional_message) {
GPR_ASSERT(status != GRPC_STATUS_OK);
if (op->cancel_error != GRPC_ERROR_NONE) {
if (optional_message) {
- gpr_slice_unref(*optional_message);
+ grpc_slice_unref(*optional_message);
}
return;
}
grpc_error *error;
if (optional_message != NULL) {
- char *msg = gpr_dump_slice(*optional_message, GPR_DUMP_ASCII);
+ char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII);
error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_STR_GRPC_MESSAGE, msg);
gpr_free(msg);
- gpr_slice_unref(*optional_message);
+ grpc_slice_unref(*optional_message);
} else {
error = GRPC_ERROR_CREATE("Call cancelled");
}
@@ -231,22 +237,22 @@ void grpc_transport_stream_op_add_cancellation_with_message(
void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
grpc_status_code status,
- gpr_slice *optional_message) {
+ grpc_slice *optional_message) {
GPR_ASSERT(status != GRPC_STATUS_OK);
if (op->cancel_error != GRPC_ERROR_NONE ||
op->close_error != GRPC_ERROR_NONE) {
if (optional_message) {
- gpr_slice_unref(*optional_message);
+ grpc_slice_unref(*optional_message);
}
return;
}
grpc_error *error;
if (optional_message != NULL) {
- char *msg = gpr_dump_slice(*optional_message, GPR_DUMP_ASCII);
+ char *msg = grpc_dump_slice(*optional_message, GPR_DUMP_ASCII);
error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
GRPC_ERROR_STR_GRPC_MESSAGE, msg);
gpr_free(msg);
- gpr_slice_unref(*optional_message);
+ grpc_slice_unref(*optional_message);
} else {
error = GRPC_ERROR_CREATE("Call force closed");
}
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 50253ebad1..96c26749c8 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -37,6 +37,7 @@
#include <stddef.h>
#include "src/core/lib/channel/context.h"
+#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
@@ -181,7 +182,7 @@ typedef struct grpc_transport_op {
bool send_goaway;
/** what should the goaway contain? */
grpc_status_code goaway_status;
- gpr_slice *goaway_message;
+ grpc_slice *goaway_message;
/** set the callback for accepting new streams;
this is a permanent callback, unlike the other one-shot closures.
If true, the callback is set to set_accept_stream_fn, with its
@@ -249,11 +250,11 @@ void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
void grpc_transport_stream_op_add_cancellation_with_message(
grpc_transport_stream_op *op, grpc_status_code status,
- gpr_slice *optional_message);
+ grpc_slice *optional_message);
void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
grpc_status_code status,
- gpr_slice *optional_message);
+ grpc_slice *optional_message);
char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
char *grpc_transport_op_string(grpc_transport_op *op);
@@ -283,7 +284,7 @@ void grpc_transport_ping(grpc_transport *transport, grpc_closure *cb);
/* Advise peer of pending connection termination. */
void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
- gpr_slice debug_data);
+ grpc_slice debug_data);
/* Close a transport. Aborts all open streams. */
void grpc_transport_close(grpc_transport *transport);
@@ -295,6 +296,10 @@ void grpc_transport_destroy(grpc_exec_ctx *exec_ctx, grpc_transport *transport);
char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
grpc_transport *transport);
+/* Get the endpoint used by \a transport */
+grpc_endpoint *grpc_transport_get_endpoint(grpc_exec_ctx *exec_ctx,
+ grpc_transport *transport);
+
/* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to
\a on_consumed and then delete the returned transport op */
grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed);
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index fc7140671b..8553148c35 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -74,6 +74,9 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_get_peer */
char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
+
+ /* implementation of grpc_transport_get_endpoint */
+ grpc_endpoint *(*get_endpoint)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
} grpc_transport_vtable;
/* an instance of a grpc transport */
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 533ec52077..58d6ad508e 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -40,6 +40,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
+#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/connectivity_state.h"
@@ -48,12 +49,12 @@
static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
gpr_strvec_add(b, gpr_strdup("key="));
- gpr_strvec_add(b,
- gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ gpr_strvec_add(
+ b, grpc_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
gpr_strvec_add(b, gpr_strdup(" value="));
gpr_strvec_add(
- b, gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
+ b, grpc_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII));
}
static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
@@ -175,8 +176,8 @@ char *grpc_transport_op_string(grpc_transport_op *op) {
first = false;
char *msg = op->goaway_message == NULL
? "null"
- : gpr_dump_slice(*op->goaway_message,
- GPR_DUMP_ASCII | GPR_DUMP_HEX);
+ : grpc_dump_slice(*op->goaway_message,
+ GPR_DUMP_ASCII | GPR_DUMP_HEX);
gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg);
if (op->goaway_message != NULL) gpr_free(msg);
gpr_strvec_add(&b, tmp);
diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc
index 847c8c7dc0..357d8317ad 100644
--- a/src/cpp/client/channel_cc.cc
+++ b/src/cpp/client/channel_cc.cc
@@ -47,8 +47,9 @@
#include <grpc++/support/status.h>
#include <grpc++/support/time.h>
#include <grpc/grpc.h>
+#include <grpc/slice.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
#include "src/core/lib/profiling/timers.h"
namespace grpc {
@@ -61,6 +62,35 @@ Channel::Channel(const grpc::string& host, grpc_channel* channel)
Channel::~Channel() { grpc_channel_destroy(c_channel_); }
+namespace {
+
+grpc::string GetChannelInfoField(grpc_channel* channel,
+ grpc_channel_info* channel_info,
+ char*** channel_info_field) {
+ char* value = NULL;
+ memset(channel_info, 0, sizeof(*channel_info));
+ *channel_info_field = &value;
+ grpc_channel_get_info(channel, channel_info);
+ if (value == NULL) return "";
+ grpc::string result = value;
+ gpr_free(value);
+ return result;
+}
+
+} // namespace
+
+grpc::string Channel::GetLoadBalancingPolicyName() const {
+ grpc_channel_info channel_info;
+ return GetChannelInfoField(c_channel_, &channel_info,
+ &channel_info.lb_policy_name);
+}
+
+grpc::string Channel::GetServiceConfigJSON() const {
+ grpc_channel_info channel_info;
+ return GetChannelInfoField(c_channel_, &channel_info,
+ &channel_info.service_config_json);
+}
+
Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) {
const bool kRegistered = method.channel_tag() && context->authority().empty();
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index c6cad8eeae..0301b5b8ec 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -34,18 +34,17 @@
#include <sstream>
+#include <grpc++/grpc++.h>
#include <grpc++/resource_quota.h>
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_args.h"
-
+#include "src/core/lib/iomgr/socket_mutator.h"
namespace grpc {
ChannelArguments::ChannelArguments() {
- std::ostringstream user_agent_prefix;
- user_agent_prefix << "grpc-c++/" << grpc_version_string();
// This will be ignored if used on the server side.
- SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix.str());
+ SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + Version());
}
ChannelArguments::ChannelArguments(const ChannelArguments& other)
@@ -89,6 +88,24 @@ void ChannelArguments::SetCompressionAlgorithm(
SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, algorithm);
}
+void ChannelArguments::SetSocketMutator(grpc_socket_mutator* mutator) {
+ if (!mutator) {
+ return;
+ }
+ grpc_arg mutator_arg = grpc_socket_mutator_to_arg(mutator);
+ bool replaced = false;
+ for (auto it = args_.begin(); it != args_.end(); ++it) {
+ if (it->type == mutator_arg.type &&
+ grpc::string(it->key) == grpc::string(mutator_arg.key)) {
+ it->value.pointer.vtable->destroy(it->value.pointer.p);
+ it->value.pointer = mutator_arg.value.pointer;
+ }
+ }
+ if (!replaced) {
+ args_.push_back(mutator_arg);
+ }
+}
+
// Note: a second call to this will add in front the result of the first call.
// An example is calling this on a copy of ChannelArguments which already has a
// prefix. The user can build up a prefix string by calling this multiple times,
@@ -126,6 +143,11 @@ void ChannelArguments::SetLoadBalancingPolicyName(
SetString(GRPC_ARG_LB_POLICY_NAME, lb_policy_name);
}
+void ChannelArguments::SetServiceConfigJSON(
+ const grpc::string& service_config_json) {
+ SetString(GRPC_ARG_SERVICE_CONFIG, service_config_json);
+}
+
void ChannelArguments::SetInt(const grpc::string& key, int value) {
grpc_arg arg;
arg.type = GRPC_ARG_INTEGER;
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
index 25cd49cb7c..ad2c0f2295 100644
--- a/src/cpp/common/channel_filter.cc
+++ b/src/cpp/common/channel_filter.cc
@@ -57,6 +57,11 @@ void ChannelData::StartTransportOp(grpc_exec_ctx *exec_ctx,
grpc_channel_next_op(exec_ctx, elem, op->op());
}
+void ChannelData::GetInfo(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {
+ grpc_channel_next_get_info(exec_ctx, elem, channel_info);
+}
+
// CallData
void CallData::StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index fc0deff3b3..e420efc71c 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -224,9 +224,13 @@ class ChannelData {
const char *peer() const { return peer_; }
// TODO(roth): Find a way to avoid passing elem into these methods.
+
virtual void StartTransportOp(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem, TransportOp *op);
+ virtual void GetInfo(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ const grpc_channel_info *channel_info);
+
protected:
/// Takes ownership of \a peer.
ChannelData(const grpc_channel_args &args, const char *peer) : peer_(peer) {}
@@ -296,6 +300,13 @@ class ChannelFilter final {
channel_data->StartTransportOp(exec_ctx, elem, &op_wrapper);
}
+ static void GetChannelInfo(grpc_exec_ctx *exec_ctx,
+ grpc_channel_element *elem,
+ const grpc_channel_info *channel_info) {
+ ChannelDataType *channel_data = (ChannelDataType *)elem->channel_data;
+ channel_data->GetInfo(exec_ctx, elem, channel_info);
+ }
+
static const size_t call_data_size = sizeof(CallDataType);
static grpc_error *InitCallElement(grpc_exec_ctx *exec_ctx,
@@ -376,7 +387,8 @@ void RegisterChannelFilter(
FilterType::call_data_size, FilterType::InitCallElement,
FilterType::SetPollsetOrPollsetSet, FilterType::DestroyCallElement,
FilterType::channel_data_size, FilterType::InitChannelElement,
- FilterType::DestroyChannelElement, FilterType::GetPeer, name}};
+ FilterType::DestroyChannelElement, FilterType::GetPeer,
+ FilterType::GetChannelInfo, name}};
internal::channel_filters->push_back(filter_record);
}
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index ce02202976..a07ad54376 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -39,11 +39,11 @@
#include <grpc/byte_buffer.h>
#include <grpc/byte_buffer_reader.h>
#include <grpc/grpc.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/sync.h>
#include "src/core/lib/profiling/timers.h"
@@ -102,31 +102,34 @@ void CoreCodegen::grpc_byte_buffer_reader_destroy(
}
int CoreCodegen::grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
- gpr_slice* slice) {
+ grpc_slice* slice) {
return ::grpc_byte_buffer_reader_next(reader, slice);
}
-grpc_byte_buffer* CoreCodegen::grpc_raw_byte_buffer_create(gpr_slice* slice,
+grpc_byte_buffer* CoreCodegen::grpc_raw_byte_buffer_create(grpc_slice* slice,
size_t nslices) {
return ::grpc_raw_byte_buffer_create(slice, nslices);
}
-gpr_slice CoreCodegen::gpr_slice_malloc(size_t length) {
- return ::gpr_slice_malloc(length);
+grpc_slice CoreCodegen::grpc_slice_malloc(size_t length) {
+ return ::grpc_slice_malloc(length);
}
-void CoreCodegen::gpr_slice_unref(gpr_slice slice) { ::gpr_slice_unref(slice); }
+void CoreCodegen::grpc_slice_unref(grpc_slice slice) {
+ ::grpc_slice_unref(slice);
+}
-gpr_slice CoreCodegen::gpr_slice_split_tail(gpr_slice* s, size_t split) {
- return ::gpr_slice_split_tail(s, split);
+grpc_slice CoreCodegen::grpc_slice_split_tail(grpc_slice* s, size_t split) {
+ return ::grpc_slice_split_tail(s, split);
}
-void CoreCodegen::gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) {
- ::gpr_slice_buffer_add(sb, slice);
+void CoreCodegen::grpc_slice_buffer_add(grpc_slice_buffer* sb,
+ grpc_slice slice) {
+ ::grpc_slice_buffer_add(sb, slice);
}
-void CoreCodegen::gpr_slice_buffer_pop(gpr_slice_buffer* sb) {
- ::gpr_slice_buffer_pop(sb);
+void CoreCodegen::grpc_slice_buffer_pop(grpc_slice_buffer* sb) {
+ ::grpc_slice_buffer_pop(sb);
}
void CoreCodegen::grpc_metadata_array_init(grpc_metadata_array* array) {
diff --git a/src/core/lib/iomgr/ev_poll_and_epoll_posix.h b/src/cpp/common/version_cc.cc
index 06d6dbf29d..7be338417f 100644
--- a/src/core/lib/iomgr/ev_poll_and_epoll_posix.h
+++ b/src/cpp/common/version_cc.cc
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,11 @@
*
*/
-#ifndef GRPC_CORE_LIB_IOMGR_EV_POLL_AND_EPOLL_POSIX_H
-#define GRPC_CORE_LIB_IOMGR_EV_POLL_AND_EPOLL_POSIX_H
+/* This file is autogenerated from:
+ templates/src/core/surface/version.c.template */
-#include "src/core/lib/iomgr/ev_posix.h"
+#include <grpc++/grpc++.h>
-const grpc_event_engine_vtable *grpc_init_poll_and_epoll_posix(void);
-
-#endif /* GRPC_CORE_LIB_IOMGR_EV_POLL_AND_EPOLL_POSIX_H */
+namespace grpc {
+grpc::string Version() { return "1.1.0-dev"; }
+}
diff --git a/src/cpp/util/byte_buffer_cc.cc b/src/cpp/util/byte_buffer_cc.cc
index 91ed66b766..cbe0aad26c 100644
--- a/src/cpp/util/byte_buffer_cc.cc
+++ b/src/cpp/util/byte_buffer_cc.cc
@@ -38,18 +38,18 @@ namespace grpc {
ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) {
// The following assertions check that the representation of a grpc::Slice is
- // identical to that of a gpr_slice: it has a gpr_slice field, and nothing
+ // identical to that of a grpc_slice: it has a grpc_slice field, and nothing
// else.
- static_assert(std::is_same<decltype(slices[0].slice_), gpr_slice>::value,
- "Slice must have same representation as gpr_slice");
- static_assert(sizeof(Slice) == sizeof(gpr_slice),
- "Slice must have same representation as gpr_slice");
+ static_assert(std::is_same<decltype(slices[0].slice_), grpc_slice>::value,
+ "Slice must have same representation as grpc_slice");
+ static_assert(sizeof(Slice) == sizeof(grpc_slice),
+ "Slice must have same representation as grpc_slice");
// The const_cast is legal if grpc_raw_byte_buffer_create() does no more
// than its advertised side effect of increasing the reference count of the
// slices it processes, and such an increase does not affect the semantics
// seen by the caller of this constructor.
buffer_ = grpc_raw_byte_buffer_create(
- reinterpret_cast<gpr_slice*>(const_cast<Slice*>(slices)), nslices);
+ reinterpret_cast<grpc_slice*>(const_cast<Slice*>(slices)), nslices);
}
ByteBuffer::~ByteBuffer() {
@@ -75,7 +75,7 @@ Status ByteBuffer::Dump(std::vector<Slice>* slices) const {
return Status(StatusCode::INTERNAL,
"Couldn't initialize byte buffer reader");
}
- gpr_slice s;
+ grpc_slice s;
while (grpc_byte_buffer_reader_next(&reader, &s)) {
slices->push_back(Slice(s, Slice::STEAL_REF));
}
diff --git a/src/cpp/util/slice_cc.cc b/src/cpp/util/slice_cc.cc
index 7e88423b6c..c05f1cf124 100644
--- a/src/cpp/util/slice_cc.cc
+++ b/src/cpp/util/slice_cc.cc
@@ -37,12 +37,12 @@ namespace grpc {
Slice::Slice() : slice_(gpr_empty_slice()) {}
-Slice::~Slice() { gpr_slice_unref(slice_); }
+Slice::~Slice() { grpc_slice_unref(slice_); }
-Slice::Slice(gpr_slice slice, AddRef) : slice_(gpr_slice_ref(slice)) {}
+Slice::Slice(grpc_slice slice, AddRef) : slice_(grpc_slice_ref(slice)) {}
-Slice::Slice(gpr_slice slice, StealRef) : slice_(slice) {}
+Slice::Slice(grpc_slice slice, StealRef) : slice_(slice) {}
-Slice::Slice(const Slice& other) : slice_(gpr_slice_ref(other.slice_)) {}
+Slice::Slice(const Slice& other) : slice_(grpc_slice_ref(other.slice_)) {}
} // namespace grpc
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index a44aaf1fdd..99e8c1a3da 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -87,7 +87,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
- <None Include="Grpc.Auth.nuspec" />
<None Include="Grpc.Auth.project.json" />
<None Include="packages.config" />
</ItemGroup>
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
deleted file mode 100644
index a1f5668e2e..0000000000
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ /dev/null
@@ -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>
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
index 595e29f50a..4052ec8398 100644
--- a/src/csharp/Grpc.Auth/project.json
+++ b/src/csharp/Grpc.Auth/project.json
@@ -15,7 +15,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
index 99a2d47e6e..3c3b9f7745 100644
--- a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
@@ -67,6 +67,9 @@ namespace Grpc.Core.Tests
var credentials = new FakeCallCredentials();
Assert.AreSame(credentials, options.WithCredentials(credentials).Credentials);
+ var flags = CallFlags.WaitForReady | CallFlags.CacheableRequest;
+ Assert.AreEqual(flags, options.WithFlags(flags).Flags);
+
// Check that the original instance is unchanged.
Assert.IsNull(options.Headers);
Assert.IsNull(options.Deadline);
@@ -74,6 +77,7 @@ namespace Grpc.Core.Tests
Assert.IsNull(options.WriteOptions);
Assert.IsNull(options.PropagationToken);
Assert.IsNull(options.Credentials);
+ Assert.AreEqual(default(CallFlags), options.Flags);
}
[Test]
@@ -94,5 +98,16 @@ namespace Grpc.Core.Tests
Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken);
Assert.Throws(typeof(ArgumentException), () => new CallOptions(cancellationToken: token, propagationToken: propagationToken2).Normalize());
}
+
+ [Test]
+ public void WaitForReady()
+ {
+ var callOptions = new CallOptions();
+ Assert.IsFalse(callOptions.IsWaitForReady);
+
+ Assert.AreEqual(CallFlags.WaitForReady, callOptions.WithWaitForReady().Flags);
+ Assert.IsTrue(callOptions.WithWaitForReady().IsWaitForReady);
+ Assert.IsFalse(callOptions.WithWaitForReady(true).WithWaitForReady(false).IsWaitForReady);
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index d99bf8e4e1..19a68ab9ea 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -39,15 +39,15 @@
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
- <Reference Include="System.Interactive.Async">
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="nunitlite">
<HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
index 909112a47c..fe067fe8b0 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
@@ -115,27 +115,27 @@ namespace Grpc.Core.Internal.Tests
return "PEER";
}
- public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
}
- public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
throw new NotImplementedException();
}
- public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
+ public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
UnaryResponseClientHandler = callback;
}
- public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
}
- public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
+ public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
ReceivedStatusOnClientHandler = callback;
}
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index f1eb13dffc..1c28277df5 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -115,7 +115,8 @@ namespace Grpc.Core.Tests
var otherAssemblies = new[] {
"Grpc.Examples.Tests",
"Grpc.HealthCheck.Tests",
- "Grpc.IntegrationTesting"
+ "Grpc.IntegrationTesting",
+ "Grpc.Reflection.Tests",
};
foreach (var assemblyName in otherAssemblies)
{
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
index 456ffcd8d0..4750735fad 100644
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ b/src/csharp/Grpc.Core.Tests/packages.config
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NUnit" version="3.2.0" targetFramework="net45" />
- <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
<package id="NUnit.ConsoleRunner" version="3.2.0" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
<package id="OpenCover" version="4.6.519" />
<package id="ReportGenerator" version="2.4.4.0" />
-</packages>
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
index faf28dcee8..509084a71a 100644
--- a/src/csharp/Grpc.Core.Tests/project.json
+++ b/src/csharp/Grpc.Core.Tests/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -26,7 +25,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index 35548cfc96..ce43dae171 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -50,6 +50,7 @@ namespace Grpc.Core
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
CallCredentials credentials;
+ CallFlags flags;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@@ -69,6 +70,7 @@ namespace Grpc.Core
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
this.credentials = credentials;
+ this.flags = default(CallFlags);
}
/// <summary>
@@ -126,6 +128,24 @@ namespace Grpc.Core
}
/// <summary>
+ /// If <c>true</c> and and channel is in <c>ChannelState.TransientFailure</c>, the call will attempt waiting for the channel to recover
+ /// instead of failing immediately (which is the default "FailFast" semantics).
+ /// Note: experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public bool IsWaitForReady
+ {
+ get { return (this.flags & CallFlags.WaitForReady) == CallFlags.WaitForReady; }
+ }
+
+ /// <summary>
+ /// Flags to use for this call.
+ /// </summary>
+ internal CallFlags Flags
+ {
+ get { return this.flags; }
+ }
+
+ /// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
@@ -198,6 +218,32 @@ namespace Grpc.Core
}
/// <summary>
+ /// Returns new instance of <see cref="CallOptions"/> with "WaitForReady" semantics enabled/disabled.
+ /// <see cref="IsWaitForReady"/>.
+ /// Note: experimental API that can change or be removed without any prior notice.
+ /// </summary>
+ public CallOptions WithWaitForReady(bool waitForReady = true)
+ {
+ if (waitForReady)
+ {
+ return WithFlags(this.flags | CallFlags.WaitForReady);
+ }
+ return WithFlags(this.flags & ~CallFlags.WaitForReady);
+ }
+
+ /// <summary>
+ /// Returns new instance of <see cref="CallOptions"/> with
+ /// <c>Flags</c> set to the value provided. Values of all other fields are preserved.
+ /// </summary>
+ /// <param name="flags">The call flags.</param>
+ internal CallOptions WithFlags(CallFlags flags)
+ {
+ var newOptions = this;
+ newOptions.flags = flags;
+ return newOptions;
+ }
+
+ /// <summary>
/// Returns a new instance of <see cref="CallOptions"/> with
/// all previously unset values set to their defaults and deadline and cancellation
/// token propagated when appropriate.
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index d315e6d667..5bfb978ca6 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -40,7 +40,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Interactive.Async">
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -140,9 +140,9 @@
<Compile Include="Logging\LogLevelFilterLogger.cs" />
<Compile Include="Internal\RequestCallContextSafeHandle.cs" />
<Compile Include="Utils\TaskUtils.cs" />
+ <Compile Include="Internal\CallFlags.cs" />
</ItemGroup>
<ItemGroup>
- <None Include="Grpc.Core.nuspec" />
<None Include="Grpc.Core.project.json" />
<None Include="packages.config" />
</ItemGroup>
@@ -154,4 +154,4 @@
<Link>roots.pem</Link>
</EmbeddedResource>
</ItemGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
deleted file mode 100644
index a8459c4d9c..0000000000
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ /dev/null
@@ -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.0.0" />
- </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>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 5e61e9ec12..1f738a3b6f 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -106,7 +106,7 @@ namespace Grpc.Core.Internal
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
using (var ctx = BatchContextSafeHandle.Create())
{
- call.StartUnary(ctx, payload, metadataArray, GetWriteFlagsForCall());
+ call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
var ev = cq.Pluck(ctx.Handle);
@@ -150,7 +150,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
- call.StartUnary(HandleUnaryResponse, payload, metadataArray, GetWriteFlagsForCall());
+ call.StartUnary(HandleUnaryResponse, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
}
@@ -174,7 +174,7 @@ namespace Grpc.Core.Internal
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
- call.StartClientStreaming(HandleUnaryResponse, metadataArray);
+ call.StartClientStreaming(HandleUnaryResponse, metadataArray, details.Options.Flags);
}
return unaryResponseTcs.Task;
@@ -200,7 +200,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
- call.StartServerStreaming(HandleFinished, payload, metadataArray, GetWriteFlagsForCall());
+ call.StartServerStreaming(HandleFinished, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
}
@@ -222,7 +222,7 @@ namespace Grpc.Core.Internal
streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
{
- call.StartDuplexStreaming(HandleFinished, metadataArray);
+ call.StartDuplexStreaming(HandleFinished, metadataArray, details.Options.Flags);
}
call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
}
@@ -388,35 +388,29 @@ namespace Grpc.Core.Internal
private void Initialize(CompletionQueueSafeHandle cq)
{
- using (Profilers.ForCurrentThread().NewScope("AsyncCall.Initialize"))
- {
- var call = CreateNativeCall(cq);
+ var call = CreateNativeCall(cq);
- details.Channel.AddCallReference(this);
- InitializeInternal(call);
- RegisterCancellationCallback();
- }
+ details.Channel.AddCallReference(this);
+ InitializeInternal(call);
+ RegisterCancellationCallback();
}
private INativeCall CreateNativeCall(CompletionQueueSafeHandle cq)
{
- using (Profilers.ForCurrentThread().NewScope("AsyncCall.CreateNativeCall"))
- {
- if (injectedNativeCall != null)
- {
- return injectedNativeCall; // allows injecting a mock INativeCall in tests.
- }
+ if (injectedNativeCall != null)
+ {
+ return injectedNativeCall; // allows injecting a mock INativeCall in tests.
+ }
- var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
+ var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
- var credentials = details.Options.Credentials;
- using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
- {
- var result = details.Channel.Handle.CreateCall(
- parentCall, ContextPropagationToken.DefaultMask, cq,
- details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
- return result;
- }
+ var credentials = details.Options.Credentials;
+ using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
+ {
+ var result = details.Channel.Handle.CreateCall(
+ parentCall, ContextPropagationToken.DefaultMask, cq,
+ details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
+ return result;
}
}
@@ -456,47 +450,44 @@ namespace Grpc.Core.Internal
// NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT,
// success will be always set to true.
- using (Profilers.ForCurrentThread().NewScope("AsyncCall.HandleUnaryResponse"))
+ TaskCompletionSource<object> delayedStreamingWriteTcs = null;
+ TResponse msg = default(TResponse);
+ var deserializeException = TryDeserialize(receivedMessage, out msg);
+
+ lock (myLock)
{
- TaskCompletionSource<object> delayedStreamingWriteTcs = null;
- TResponse msg = default(TResponse);
- var deserializeException = TryDeserialize(receivedMessage, out msg);
+ finished = true;
- lock (myLock)
+ if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK)
{
- finished = true;
-
- if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK)
- {
- receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers);
- }
- finishedStatus = receivedStatus;
-
- if (isStreamingWriteCompletionDelayed)
- {
- delayedStreamingWriteTcs = streamingWriteTcs;
- streamingWriteTcs = null;
- }
-
- ReleaseResourcesIfPossible();
+ receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers);
}
+ finishedStatus = receivedStatus;
- responseHeadersTcs.SetResult(responseHeaders);
-
- if (delayedStreamingWriteTcs != null)
+ if (isStreamingWriteCompletionDelayed)
{
- delayedStreamingWriteTcs.SetException(GetRpcExceptionClientOnly());
+ delayedStreamingWriteTcs = streamingWriteTcs;
+ streamingWriteTcs = null;
}
- var status = receivedStatus.Status;
- if (status.StatusCode != StatusCode.OK)
- {
- unaryResponseTcs.SetException(new RpcException(status));
- return;
- }
+ ReleaseResourcesIfPossible();
+ }
+
+ responseHeadersTcs.SetResult(responseHeaders);
- unaryResponseTcs.SetResult(msg);
+ if (delayedStreamingWriteTcs != null)
+ {
+ delayedStreamingWriteTcs.SetException(GetRpcExceptionClientOnly());
+ }
+
+ var status = receivedStatus.Status;
+ if (status.StatusCode != StatusCode.OK)
+ {
+ unaryResponseTcs.SetException(new RpcException(status));
+ return;
}
+
+ unaryResponseTcs.SetResult(msg);
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 9f9d260e7e..8668903f6e 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -181,19 +181,16 @@ namespace Grpc.Core.Internal
/// </summary>
protected bool ReleaseResourcesIfPossible()
{
- using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.ReleaseResourcesIfPossible"))
+ if (!disposed && call != null)
{
- if (!disposed && call != null)
+ bool noMoreSendCompletions = streamingWriteTcs == null && (halfcloseRequested || cancelRequested || finished);
+ if (noMoreSendCompletions && readingDone && finished)
{
- bool noMoreSendCompletions = streamingWriteTcs == null && (halfcloseRequested || cancelRequested || finished);
- if (noMoreSendCompletions && readingDone && finished)
- {
- ReleaseResources();
- return true;
- }
+ ReleaseResources();
+ return true;
}
- return false;
}
+ return false;
}
protected abstract bool IsClient
@@ -229,28 +226,20 @@ namespace Grpc.Core.Internal
protected byte[] UnsafeSerialize(TWrite msg)
{
- using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.UnsafeSerialize"))
- {
- return serializer(msg);
- }
+ return serializer(msg);
}
protected Exception TryDeserialize(byte[] payload, out TRead msg)
{
- using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.TryDeserialize"))
+ try
{
- try
- {
-
- msg = deserializer(payload);
- return null;
-
- }
- catch (Exception e)
- {
- msg = default(TRead);
- return e;
- }
+ msg = deserializer(payload);
+ return null;
+ }
+ catch (Exception e)
+ {
+ msg = default(TRead);
+ return e;
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CallFlags.cs b/src/csharp/Grpc.Core/Internal/CallFlags.cs
new file mode 100644
index 0000000000..454fa9b1f4
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/CallFlags.cs
@@ -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
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 82361f5797..6bfcc7fa74 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -63,53 +63,50 @@ namespace Grpc.Core.Internal
Native.grpcsharp_call_set_credentials(this, credentials).CheckOk();
}
- public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
- Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags)
+ Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
.CheckOk();
}
}
- public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
- using (Profilers.ForCurrentThread().NewScope("CallSafeHandle.StartUnary"))
- {
- Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags)
- .CheckOk();
- }
+ Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
+ .CheckOk();
}
- public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray)
+ public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
- Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
+ Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}
- public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
+ public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
- Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray, writeFlags).CheckOk();
+ Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags).CheckOk();
}
}
- public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray)
+ public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
{
using (completionQueue.NewScope())
{
var ctx = BatchContextSafeHandle.Create();
completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
- Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
+ Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, callFlags).CheckOk();
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 62864dff0c..0fb6360a23 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -65,16 +65,13 @@ namespace Grpc.Core.Internal
public CallSafeHandle CreateCall(CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CallCredentialsSafeHandle credentials)
{
- using (Profilers.ForCurrentThread().NewScope("ChannelSafeHandle.CreateCall"))
+ var result = Native.grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline);
+ if (credentials != null)
{
- var result = Native.grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline);
- if (credentials != null)
- {
- result.SetCredentials(credentials);
- }
- result.Initialize(cq);
- return result;
+ result.SetCredentials(credentials);
}
+ result.Initialize(cq);
+ return result;
}
public ChannelState CheckConnectivityState(bool tryToConnect)
diff --git a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
index 46f5624223..6c9a31921e 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionQueueSafeHandle.cs
@@ -70,10 +70,7 @@ namespace Grpc.Core.Internal
public CompletionQueueEvent Pluck(IntPtr tag)
{
- using (Profilers.ForCurrentThread().NewScope("CompletionQueueSafeHandle.Pluck"))
- {
- return Native.grpcsharp_completion_queue_pluck(this, tag);
- }
+ return Native.grpcsharp_completion_queue_pluck(this, tag);
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index a446c1f99f..25a6589f11 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -37,6 +37,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Logging;
+using Grpc.Core.Profiling;
using Grpc.Core.Utils;
namespace Grpc.Core.Internal
@@ -54,6 +55,8 @@ namespace Grpc.Core.Internal
readonly int poolSize;
readonly int completionQueueCount;
+ readonly List<BasicProfiler> threadProfilers = new List<BasicProfiler>(); // profilers assigned to threadpool threads
+
bool stopRequested;
IReadOnlyCollection<CompletionQueueSafeHandle> completionQueues;
@@ -82,7 +85,8 @@ namespace Grpc.Core.Internal
for (int i = 0; i < poolSize; i++)
{
- threads.Add(CreateAndStartThread(i));
+ var optionalProfiler = i < threadProfilers.Count ? threadProfilers[i] : null;
+ threads.Add(CreateAndStartThread(i, optionalProfiler));
}
}
}
@@ -111,6 +115,11 @@ namespace Grpc.Core.Internal
{
cq.Dispose();
}
+
+ for (int i = 0; i < threadProfilers.Count; i++)
+ {
+ threadProfilers[i].Dump(string.Format("grpc_trace_thread_{0}.txt", i));
+ }
});
}
@@ -137,12 +146,12 @@ namespace Grpc.Core.Internal
}
}
- private Thread CreateAndStartThread(int threadIndex)
+ private Thread CreateAndStartThread(int threadIndex, IProfiler optionalProfiler)
{
var cqIndex = threadIndex % completionQueues.Count;
var cq = completionQueues.ElementAt(cqIndex);
- var thread = new Thread(new ThreadStart(() => RunHandlerLoop(cq)));
+ var thread = new Thread(new ThreadStart(() => RunHandlerLoop(cq, optionalProfiler)));
thread.IsBackground = true;
thread.Name = string.Format("grpc {0} (cq {1})", threadIndex, cqIndex);
thread.Start();
@@ -153,8 +162,13 @@ namespace Grpc.Core.Internal
/// <summary>
/// Body of the polling thread.
/// </summary>
- private void RunHandlerLoop(CompletionQueueSafeHandle cq)
+ private void RunHandlerLoop(CompletionQueueSafeHandle cq, IProfiler optionalProfiler)
{
+ if (optionalProfiler != null)
+ {
+ Profilers.SetForCurrentThread(optionalProfiler);
+ }
+
CompletionQueueEvent ev;
do
{
diff --git a/src/csharp/Grpc.Core/Internal/INativeCall.cs b/src/csharp/Grpc.Core/Internal/INativeCall.cs
index cd3719cb50..94fbb08feb 100644
--- a/src/csharp/Grpc.Core/Internal/INativeCall.cs
+++ b/src/csharp/Grpc.Core/Internal/INativeCall.cs
@@ -31,6 +31,7 @@
#endregion
using System;
+using Grpc.Core;
namespace Grpc.Core.Internal
{
@@ -54,19 +55,19 @@ namespace Grpc.Core.Internal
{
void Cancel();
- void CancelWithStatus(Grpc.Core.Status status);
+ void CancelWithStatus(Status status);
string GetPeer();
- void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
+ void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
- void StartUnary(BatchContextSafeHandle ctx, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
+ void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
- void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray);
+ void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
- void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, Grpc.Core.WriteFlags writeFlags);
+ void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
- void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray);
+ void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
void StartReceiveMessage(ReceivedMessageHandler callback);
@@ -74,11 +75,11 @@ namespace Grpc.Core.Internal
void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray);
- void StartSendMessage(SendCompletionHandler callback, byte[] payload, Grpc.Core.WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+ void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
void StartSendCloseFromClient(SendCompletionHandler callback);
- void StartSendStatusFromServer(SendCompletionHandler callback, Grpc.Core.Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, Grpc.Core.WriteFlags writeFlags);
+ void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
void StartServerSide(ReceivedCloseOnServerHandler callback);
}
diff --git a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
index dc9f62fdab..05dda5b148 100644
--- a/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/MetadataArraySafeHandle.cs
@@ -48,22 +48,19 @@ namespace Grpc.Core.Internal
public static MetadataArraySafeHandle Create(Metadata metadata)
{
- using (Profilers.ForCurrentThread().NewScope("MetadataArraySafeHandle.Create"))
+ if (metadata.Count == 0)
{
- if (metadata.Count == 0)
- {
- return new MetadataArraySafeHandle();
- }
+ return new MetadataArraySafeHandle();
+ }
- // TODO(jtattermusch): we might wanna check that the metadata is readonly
- var metadataArray = Native.grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count));
- for (int i = 0; i < metadata.Count; i++)
- {
- var valueBytes = metadata[i].GetSerializedValueUnsafe();
- Native.grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length));
- }
- return metadataArray;
+ // TODO(jtattermusch): we might wanna check that the metadata is readonly
+ var metadataArray = Native.grpcsharp_metadata_array_create(new UIntPtr((ulong)metadata.Count));
+ for (int i = 0; i < metadata.Count; i++)
+ {
+ var valueBytes = metadata[i].GetSerializedValueUnsafe();
+ Native.grpcsharp_metadata_array_add(metadataArray, metadata[i].Key, valueBytes, new UIntPtr((ulong)valueBytes.Length));
}
+ return metadataArray;
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 40ba7e30cb..ce38e37093 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -325,14 +325,14 @@ namespace Grpc.Core.Internal
public delegate CallError grpcsharp_call_cancel_delegate(CallSafeHandle call);
public delegate CallError grpcsharp_call_cancel_with_status_delegate(CallSafeHandle call, StatusCode status, string description);
public delegate CallError grpcsharp_call_start_unary_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_client_streaming_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
+ BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_server_streaming_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen,
- MetadataArraySafeHandle metadataArray, WriteFlags writeFlags);
+ BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags,
+ MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_start_duplex_streaming_delegate(CallSafeHandle call,
- BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
+ BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray, CallFlags metadataFlags);
public delegate CallError grpcsharp_call_send_message_delegate(CallSafeHandle call,
BatchContextSafeHandle ctx, byte[] sendBuffer, UIntPtr sendBufferLen, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
public delegate CallError grpcsharp_call_send_close_from_client_delegate(CallSafeHandle call,
diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs
index aa0d96c0e0..6afabff6a7 100644
--- a/src/csharp/Grpc.Core/Profiling/Profilers.cs
+++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs
@@ -80,7 +80,7 @@ namespace Grpc.Core.Profiling
ProfilerEntry[] entries;
int count;
- public BasicProfiler() : this(1024*1024)
+ public BasicProfiler() : this(20*1024*1024)
{
}
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
index 6514774021..53cfad52f0 100644
--- a/src/csharp/Grpc.Core/packages.config
+++ b/src/csharp/Grpc.Core/packages.config
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
index aa1e4cc7fb..4405ecc5a2 100644
--- a/src/csharp/Grpc.Core/project.json
+++ b/src/csharp/Grpc.Core/project.json
@@ -27,11 +27,10 @@
"embed": [ "../../../etc/roots.pem" ],
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true
},
"dependencies": {
- "System.Interactive.Async": "3.0.0"
+ "System.Interactive.Async": "3.1.1"
},
"frameworks": {
"net45": { },
diff --git a/src/csharp/Grpc.Dotnet.sln b/src/csharp/Grpc.Dotnet.sln
index 98b3cd54ab..824c6822f7 100644
--- a/src/csharp/Grpc.Dotnet.sln
+++ b/src/csharp/Grpc.Dotnet.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core", "Grpc.Core\Grpc.Core.xproj", "{DC9908B6-F291-4FC8-A46D-2EA2551790EC}"
EndProject
@@ -31,6 +31,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Ser
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.xproj", "{0EBC910B-8867-4D3E-8686-91F34183D839}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Reflection", "Grpc.Reflection\Grpc.Reflection.xproj", "{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.xproj", "{FE90181D-A4B3-4A5C-8490-F07561E18E3B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -93,6 +97,14 @@ Global
{0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/csharp/Grpc.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
index 628f532966..9a8880b5d4 100644
--- a/src/csharp/Grpc.Examples.MathClient/project.json
+++ b/src/csharp/Grpc.Examples.MathClient/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -26,7 +25,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
index 628f532966..9a8880b5d4 100644
--- a/src/csharp/Grpc.Examples.MathServer/project.json
+++ b/src/csharp/Grpc.Examples.MathServer/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -26,7 +25,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index a114d96127..16d7a44f92 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -39,15 +39,15 @@
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
- <Reference Include="System.Interactive.Async">
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="nunitlite">
<HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
</Reference>
<Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
index f14517d2e2..0fed4dbd41 100644
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ b/src/csharp/Grpc.Examples.Tests/packages.config
@@ -3,5 +3,5 @@
<package id="Google.Protobuf" version="3.0.0" targetFramework="net45" />
<package id="NUnit" version="3.2.0" targetFramework="net45" />
<package id="NUnitLite" version="3.2.0" targetFramework="net45" />
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.Tests/project.json b/src/csharp/Grpc.Examples.Tests/project.json
index 0109617e6b..3e130beeac 100644
--- a/src/csharp/Grpc.Examples.Tests/project.json
+++ b/src/csharp/Grpc.Examples.Tests/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -26,7 +25,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index dcbef5fc0b..c1ea2e2833 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -42,13 +42,12 @@
</Reference>
<Reference Include="System" />
<Reference Include="System.Data.Linq" />
- <Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.Examples/Math.cs b/src/csharp/Grpc.Examples/Math.cs
index fae4fd3c26..e5b76f8305 100644
--- a/src/csharp/Grpc.Examples/Math.cs
+++ b/src/csharp/Grpc.Examples/Math.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: math.proto
+// source: math/math.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -9,11 +9,11 @@ using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Math {
- /// <summary>Holder for reflection information generated from math.proto</summary>
+ /// <summary>Holder for reflection information generated from math/math.proto</summary>
public static partial class MathReflection {
#region Descriptor
- /// <summary>File descriptor for math.proto</summary>
+ /// <summary>File descriptor for math/math.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
@@ -22,15 +22,15 @@ namespace Math {
static MathReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB",
- "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB",
- "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB",
- "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50",
- "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu",
- "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E",
- "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51",
- "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAFiBnByb3Rv",
- "Mw=="));
+ "Cg9tYXRoL21hdGgucHJvdG8SBG1hdGgiLAoHRGl2QXJncxIQCghkaXZpZGVu",
+ "ZBgBIAEoAxIPCgdkaXZpc29yGAIgASgDIi8KCERpdlJlcGx5EhAKCHF1b3Rp",
+ "ZW50GAEgASgDEhEKCXJlbWFpbmRlchgCIAEoAyIYCgdGaWJBcmdzEg0KBWxp",
+ "bWl0GAEgASgDIhIKA051bRILCgNudW0YASABKAMiGQoIRmliUmVwbHkSDQoF",
+ "Y291bnQYASABKAMypAEKBE1hdGgSJgoDRGl2Eg0ubWF0aC5EaXZBcmdzGg4u",
+ "bWF0aC5EaXZSZXBseSIAEi4KB0Rpdk1hbnkSDS5tYXRoLkRpdkFyZ3MaDi5t",
+ "YXRoLkRpdlJlcGx5IgAoATABEiMKA0ZpYhINLm1hdGguRmliQXJncxoJLm1h",
+ "dGguTnVtIgAwARIfCgNTdW0SCS5tYXRoLk51bRoJLm1hdGguTnVtIgAoAWIG",
+ "cHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index d6ba61e7dc..8b431c7218 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: math.proto
+// source: math/math.proto
// Original file comments:
// Copyright 2015, Google Inc.
// All rights reserved.
@@ -38,7 +38,7 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Math {
- public static class Math
+ public static partial class Math
{
static readonly string __ServiceName = "math.Math";
@@ -82,7 +82,7 @@ namespace Math {
}
/// <summary>Base class for server-side implementations of Math</summary>
- public abstract class MathBase
+ public abstract partial class MathBase
{
/// <summary>
/// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
@@ -126,7 +126,7 @@ namespace Math {
}
/// <summary>Client for Math</summary>
- public class MathClient : ClientBase<MathClient>
+ public partial class MathClient : ClientBase<MathClient>
{
/// <summary>Creates a new client for Math</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
diff --git a/src/csharp/Grpc.Examples/packages.config b/src/csharp/Grpc.Examples/packages.config
index d17347f08f..c7db26bd64 100644
--- a/src/csharp/Grpc.Examples/packages.config
+++ b/src/csharp/Grpc.Examples/packages.config
@@ -2,5 +2,5 @@
<packages>
<package id="Google.Protobuf" version="3.0.0" targetFramework="net45" />
<package id="NUnit" version="3.2.0" targetFramework="net45" />
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/project.json b/src/csharp/Grpc.HealthCheck.Tests/project.json
index 66dcd79a39..addc782afe 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/project.json
+++ b/src/csharp/Grpc.HealthCheck.Tests/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -26,7 +25,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 54a2984964..7418768316 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -40,10 +40,6 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
- <Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -52,6 +48,9 @@
<Reference Include="Google.Protobuf">
<HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
</Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -63,13 +62,12 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
- <None Include="Grpc.HealthCheck.nuspec" />
<None Include="Grpc.HealthCheck.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
- <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
</ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
deleted file mode 100644
index 4ffd18ccb2..0000000000
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
+++ /dev/null
@@ -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.0.0" />
- </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>
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
index b8e2e2274c..b9880d9636 100644
--- a/src/csharp/Grpc.HealthCheck/Health.cs
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: health.proto
+// source: grpc/health/v1/health.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -9,11 +9,11 @@ using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Grpc.Health.V1 {
- /// <summary>Holder for reflection information generated from health.proto</summary>
+ /// <summary>Holder for reflection information generated from grpc/health/v1/health.proto</summary>
public static partial class HealthReflection {
#region Descriptor
- /// <summary>File descriptor for health.proto</summary>
+ /// <summary>File descriptor for grpc/health/v1/health.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
@@ -22,14 +22,14 @@ namespace Grpc.Health.V1 {
static HealthReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgxoZWFsdGgucHJvdG8SDmdycGMuaGVhbHRoLnYxIiUKEkhlYWx0aENoZWNr",
- "UmVxdWVzdBIPCgdzZXJ2aWNlGAEgASgJIpQBChNIZWFsdGhDaGVja1Jlc3Bv",
- "bnNlEkEKBnN0YXR1cxgBIAEoDjIxLmdycGMuaGVhbHRoLnYxLkhlYWx0aENo",
- "ZWNrUmVzcG9uc2UuU2VydmluZ1N0YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsK",
- "B1VOS05PV04QABILCgdTRVJWSU5HEAESDwoLTk9UX1NFUlZJTkcQAjJaCgZI",
- "ZWFsdGgSUAoFQ2hlY2sSIi5ncnBjLmhlYWx0aC52MS5IZWFsdGhDaGVja1Jl",
- "cXVlc3QaIy5ncnBjLmhlYWx0aC52MS5IZWFsdGhDaGVja1Jlc3BvbnNlQhGq",
- "Ag5HcnBjLkhlYWx0aC5WMWIGcHJvdG8z"));
+ "ChtncnBjL2hlYWx0aC92MS9oZWFsdGgucHJvdG8SDmdycGMuaGVhbHRoLnYx",
+ "IiUKEkhlYWx0aENoZWNrUmVxdWVzdBIPCgdzZXJ2aWNlGAEgASgJIpQBChNI",
+ "ZWFsdGhDaGVja1Jlc3BvbnNlEkEKBnN0YXR1cxgBIAEoDjIxLmdycGMuaGVh",
+ "bHRoLnYxLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0YXR1cyI6Cg1T",
+ "ZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5HEAESDwoLTk9U",
+ "X1NFUlZJTkcQAjJaCgZIZWFsdGgSUAoFQ2hlY2sSIi5ncnBjLmhlYWx0aC52",
+ "MS5IZWFsdGhDaGVja1JlcXVlc3QaIy5ncnBjLmhlYWx0aC52MS5IZWFsdGhD",
+ "aGVja1Jlc3BvbnNlQhGqAg5HcnBjLkhlYWx0aC5WMWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index b2a35a79be..ad5cf11b75 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: health.proto
+// source: grpc/health/v1/health.proto
// Original file comments:
// Copyright 2015, Google Inc.
// All rights reserved.
@@ -38,7 +38,7 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Health.V1 {
- public static class Health
+ public static partial class Health
{
static readonly string __ServiceName = "grpc.health.v1.Health";
@@ -59,7 +59,7 @@ namespace Grpc.Health.V1 {
}
/// <summary>Base class for server-side implementations of Health</summary>
- public abstract class HealthBase
+ public abstract partial class HealthBase
{
public virtual global::System.Threading.Tasks.Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context)
{
@@ -69,7 +69,7 @@ namespace Grpc.Health.V1 {
}
/// <summary>Client for Health</summary>
- public class HealthClient : ClientBase<HealthClient>
+ public partial class HealthClient : ClientBase<HealthClient>
{
/// <summary>Creates a new client for Health</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
index f8e353bf26..5ab40b7a8c 100644
--- a/src/csharp/Grpc.HealthCheck/packages.config
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Google.Protobuf" version="3.0.0" targetFramework="net45" />
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
index 9d631229d8..8f1237d003 100644
--- a/src/csharp/Grpc.HealthCheck/project.json
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -15,7 +15,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/project.json b/src/csharp/Grpc.IntegrationTesting.Client/project.json
index 1b900c8af3..ad81cbc48b 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.Client/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -29,7 +28,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
index fe200f8d44..2c7643b74f 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -29,7 +28,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/project.json b/src/csharp/Grpc.IntegrationTesting.Server/project.json
index 1b900c8af3..ad81cbc48b 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.Server/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -29,7 +28,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
index 1b900c8af3..ad81cbc48b 100644
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -29,7 +28,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.IntegrationTesting/Control.cs b/src/csharp/Grpc.IntegrationTesting/Control.cs
index 7928b51ba5..3f4862d567 100644
--- a/src/csharp/Grpc.IntegrationTesting/Control.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Control.cs
@@ -45,44 +45,48 @@ namespace Grpc.Testing {
"dGF0cxgBIAEoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cyIVCgRNYXJr",
"Eg0KBXJlc2V0GAEgASgIImgKCkNsaWVudEFyZ3MSKwoFc2V0dXAYASABKAsy",
"Gi5ncnBjLnRlc3RpbmcuQ2xpZW50Q29uZmlnSAASIgoEbWFyaxgCIAEoCzIS",
- "LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSKWAgoMU2VydmVyQ29u",
+ "LmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSK0AgoMU2VydmVyQ29u",
"ZmlnEi0KC3NlcnZlcl90eXBlGAEgASgOMhguZ3JwYy50ZXN0aW5nLlNlcnZl",
"clR5cGUSNQoPc2VjdXJpdHlfcGFyYW1zGAIgASgLMhwuZ3JwYy50ZXN0aW5n",
"LlNlY3VyaXR5UGFyYW1zEgwKBHBvcnQYBCABKAUSHAoUYXN5bmNfc2VydmVy",
"X3RocmVhZHMYByABKAUSEgoKY29yZV9saW1pdBgIIAEoBRIzCg5wYXlsb2Fk",
"X2NvbmZpZxgJIAEoCzIbLmdycGMudGVzdGluZy5QYXlsb2FkQ29uZmlnEhEK",
- "CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJImgK",
- "ClNlcnZlckFyZ3MSKwoFc2V0dXAYASABKAsyGi5ncnBjLnRlc3RpbmcuU2Vy",
- "dmVyQ29uZmlnSAASIgoEbWFyaxgCIAEoCzISLmdycGMudGVzdGluZy5NYXJr",
- "SABCCQoHYXJndHlwZSJVCgxTZXJ2ZXJTdGF0dXMSKAoFc3RhdHMYASABKAsy",
- "GS5ncnBjLnRlc3RpbmcuU2VydmVyU3RhdHMSDAoEcG9ydBgCIAEoBRINCgVj",
- "b3JlcxgDIAEoBSINCgtDb3JlUmVxdWVzdCIdCgxDb3JlUmVzcG9uc2USDQoF",
- "Y29yZXMYASABKAUiBgoEVm9pZCL9AQoIU2NlbmFyaW8SDAoEbmFtZRgBIAEo",
- "CRIxCg1jbGllbnRfY29uZmlnGAIgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVu",
- "dENvbmZpZxITCgtudW1fY2xpZW50cxgDIAEoBRIxCg1zZXJ2ZXJfY29uZmln",
- "GAQgASgLMhouZ3JwYy50ZXN0aW5nLlNlcnZlckNvbmZpZxITCgtudW1fc2Vy",
- "dmVycxgFIAEoBRIWCg53YXJtdXBfc2Vjb25kcxgGIAEoBRIZChFiZW5jaG1h",
- "cmtfc2Vjb25kcxgHIAEoBRIgChhzcGF3bl9sb2NhbF93b3JrZXJfY291bnQY",
- "CCABKAUiNgoJU2NlbmFyaW9zEikKCXNjZW5hcmlvcxgBIAMoCzIWLmdycGMu",
- "dGVzdGluZy5TY2VuYXJpbyKSAgoVU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EgsK",
- "A3FwcxgBIAEoARIbChNxcHNfcGVyX3NlcnZlcl9jb3JlGAIgASgBEhoKEnNl",
- "cnZlcl9zeXN0ZW1fdGltZRgDIAEoARIYChBzZXJ2ZXJfdXNlcl90aW1lGAQg",
- "ASgBEhoKEmNsaWVudF9zeXN0ZW1fdGltZRgFIAEoARIYChBjbGllbnRfdXNl",
- "cl90aW1lGAYgASgBEhIKCmxhdGVuY3lfNTAYByABKAESEgoKbGF0ZW5jeV85",
- "MBgIIAEoARISCgpsYXRlbmN5Xzk1GAkgASgBEhIKCmxhdGVuY3lfOTkYCiAB",
- "KAESEwoLbGF0ZW5jeV85OTkYCyABKAEiyAIKDlNjZW5hcmlvUmVzdWx0EigK",
- "CHNjZW5hcmlvGAEgASgLMhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxh",
- "dGVuY2llcxgCIAEoCzIbLmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8K",
- "DGNsaWVudF9zdGF0cxgDIAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0",
- "cxIvCgxzZXJ2ZXJfc3RhdHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVy",
- "U3RhdHMSFAoMc2VydmVyX2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsy",
- "Iy5ncnBjLnRlc3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVu",
- "dF9zdWNjZXNzGAcgAygIEhYKDnNlcnZlcl9zdWNjZXNzGAggAygIKkEKCkNs",
- "aWVudFR5cGUSDwoLU1lOQ19DTElFTlQQABIQCgxBU1lOQ19DTElFTlQQARIQ",
- "CgxPVEhFUl9DTElFTlQQAipbCgpTZXJ2ZXJUeXBlEg8KC1NZTkNfU0VSVkVS",
- "EAASEAoMQVNZTkNfU0VSVkVSEAESGAoUQVNZTkNfR0VORVJJQ19TRVJWRVIQ",
- "AhIQCgxPVEhFUl9TRVJWRVIQAyojCgdScGNUeXBlEgkKBVVOQVJZEAASDQoJ",
- "U1RSRUFNSU5HEAFiBnByb3RvMw=="));
+ "CWNvcmVfbGlzdBgKIAMoBRIYChBvdGhlcl9zZXJ2ZXJfYXBpGAsgASgJEhwK",
+ "E3Jlc291cmNlX3F1b3RhX3NpemUY6QcgASgFImgKClNlcnZlckFyZ3MSKwoF",
+ "c2V0dXAYASABKAsyGi5ncnBjLnRlc3RpbmcuU2VydmVyQ29uZmlnSAASIgoE",
+ "bWFyaxgCIAEoCzISLmdycGMudGVzdGluZy5NYXJrSABCCQoHYXJndHlwZSJV",
+ "CgxTZXJ2ZXJTdGF0dXMSKAoFc3RhdHMYASABKAsyGS5ncnBjLnRlc3Rpbmcu",
+ "U2VydmVyU3RhdHMSDAoEcG9ydBgCIAEoBRINCgVjb3JlcxgDIAEoBSINCgtD",
+ "b3JlUmVxdWVzdCIdCgxDb3JlUmVzcG9uc2USDQoFY29yZXMYASABKAUiBgoE",
+ "Vm9pZCL9AQoIU2NlbmFyaW8SDAoEbmFtZRgBIAEoCRIxCg1jbGllbnRfY29u",
+ "ZmlnGAIgASgLMhouZ3JwYy50ZXN0aW5nLkNsaWVudENvbmZpZxITCgtudW1f",
+ "Y2xpZW50cxgDIAEoBRIxCg1zZXJ2ZXJfY29uZmlnGAQgASgLMhouZ3JwYy50",
+ "ZXN0aW5nLlNlcnZlckNvbmZpZxITCgtudW1fc2VydmVycxgFIAEoBRIWCg53",
+ "YXJtdXBfc2Vjb25kcxgGIAEoBRIZChFiZW5jaG1hcmtfc2Vjb25kcxgHIAEo",
+ "BRIgChhzcGF3bl9sb2NhbF93b3JrZXJfY291bnQYCCABKAUiNgoJU2NlbmFy",
+ "aW9zEikKCXNjZW5hcmlvcxgBIAMoCzIWLmdycGMudGVzdGluZy5TY2VuYXJp",
+ "byL4AgoVU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EgsKA3FwcxgBIAEoARIbChNx",
+ "cHNfcGVyX3NlcnZlcl9jb3JlGAIgASgBEhoKEnNlcnZlcl9zeXN0ZW1fdGlt",
+ "ZRgDIAEoARIYChBzZXJ2ZXJfdXNlcl90aW1lGAQgASgBEhoKEmNsaWVudF9z",
+ "eXN0ZW1fdGltZRgFIAEoARIYChBjbGllbnRfdXNlcl90aW1lGAYgASgBEhIK",
+ "CmxhdGVuY3lfNTAYByABKAESEgoKbGF0ZW5jeV85MBgIIAEoARISCgpsYXRl",
+ "bmN5Xzk1GAkgASgBEhIKCmxhdGVuY3lfOTkYCiABKAESEwoLbGF0ZW5jeV85",
+ "OTkYCyABKAESGAoQc2VydmVyX2NwdV91c2FnZRgMIAEoARImCh5zdWNjZXNz",
+ "ZnVsX3JlcXVlc3RzX3Blcl9zZWNvbmQYDSABKAESIgoaZmFpbGVkX3JlcXVl",
+ "c3RzX3Blcl9zZWNvbmQYDiABKAEigwMKDlNjZW5hcmlvUmVzdWx0EigKCHNj",
+ "ZW5hcmlvGAEgASgLMhYuZ3JwYy50ZXN0aW5nLlNjZW5hcmlvEi4KCWxhdGVu",
+ "Y2llcxgCIAEoCzIbLmdycGMudGVzdGluZy5IaXN0b2dyYW1EYXRhEi8KDGNs",
+ "aWVudF9zdGF0cxgDIAMoCzIZLmdycGMudGVzdGluZy5DbGllbnRTdGF0cxIv",
+ "CgxzZXJ2ZXJfc3RhdHMYBCADKAsyGS5ncnBjLnRlc3RpbmcuU2VydmVyU3Rh",
+ "dHMSFAoMc2VydmVyX2NvcmVzGAUgAygFEjQKB3N1bW1hcnkYBiABKAsyIy5n",
+ "cnBjLnRlc3RpbmcuU2NlbmFyaW9SZXN1bHRTdW1tYXJ5EhYKDmNsaWVudF9z",
+ "dWNjZXNzGAcgAygIEhYKDnNlcnZlcl9zdWNjZXNzGAggAygIEjkKD3JlcXVl",
+ "c3RfcmVzdWx0cxgJIAMoCzIgLmdycGMudGVzdGluZy5SZXF1ZXN0UmVzdWx0",
+ "Q291bnQqQQoKQ2xpZW50VHlwZRIPCgtTWU5DX0NMSUVOVBAAEhAKDEFTWU5D",
+ "X0NMSUVOVBABEhAKDE9USEVSX0NMSUVOVBACKlsKClNlcnZlclR5cGUSDwoL",
+ "U1lOQ19TRVJWRVIQABIQCgxBU1lOQ19TRVJWRVIQARIYChRBU1lOQ19HRU5F",
+ "UklDX1NFUlZFUhACEhAKDE9USEVSX1NFUlZFUhADKiMKB1JwY1R5cGUSCQoF",
+ "VU5BUlkQABINCglTVFJFQU1JTkcQAWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.PayloadsReflection.Descriptor, global::Grpc.Testing.StatsReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.ClientType), typeof(global::Grpc.Testing.ServerType), typeof(global::Grpc.Testing.RpcType), }, new pbr::GeneratedClrTypeInfo[] {
@@ -94,7 +98,7 @@ namespace Grpc.Testing {
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStatus), global::Grpc.Testing.ClientStatus.Parser, new[]{ "Stats" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Mark), global::Grpc.Testing.Mark.Parser, new[]{ "Reset" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientArgs), global::Grpc.Testing.ClientArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerConfig), global::Grpc.Testing.ServerConfig.Parser, new[]{ "ServerType", "SecurityParams", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig", "CoreList", "OtherServerApi" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerConfig), global::Grpc.Testing.ServerConfig.Parser, new[]{ "ServerType", "SecurityParams", "Port", "AsyncServerThreads", "CoreLimit", "PayloadConfig", "CoreList", "OtherServerApi", "ResourceQuotaSize" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerArgs), global::Grpc.Testing.ServerArgs.Parser, new[]{ "Setup", "Mark" }, new[]{ "Argtype" }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerStatus), global::Grpc.Testing.ServerStatus.Parser, new[]{ "Stats", "Port", "Cores" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.CoreRequest), global::Grpc.Testing.CoreRequest.Parser, null, null, null, null),
@@ -102,8 +106,8 @@ namespace Grpc.Testing {
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Void), global::Grpc.Testing.Void.Parser, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenario), global::Grpc.Testing.Scenario.Parser, new[]{ "Name", "ClientConfig", "NumClients", "ServerConfig", "NumServers", "WarmupSeconds", "BenchmarkSeconds", "SpawnLocalWorkerCount" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Scenarios), global::Grpc.Testing.Scenarios.Parser, new[]{ "Scenarios_" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResultSummary), global::Grpc.Testing.ScenarioResultSummary.Parser, new[]{ "Qps", "QpsPerServerCore", "ServerSystemTime", "ServerUserTime", "ClientSystemTime", "ClientUserTime", "Latency50", "Latency90", "Latency95", "Latency99", "Latency999" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResult), global::Grpc.Testing.ScenarioResult.Parser, new[]{ "Scenario", "Latencies", "ClientStats", "ServerStats", "ServerCores", "Summary", "ClientSuccess", "ServerSuccess" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResultSummary), global::Grpc.Testing.ScenarioResultSummary.Parser, new[]{ "Qps", "QpsPerServerCore", "ServerSystemTime", "ServerUserTime", "ClientSystemTime", "ClientUserTime", "Latency50", "Latency90", "Latency95", "Latency99", "Latency999", "ServerCpuUsage", "SuccessfulRequestsPerSecond", "FailedRequestsPerSecond" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ScenarioResult), global::Grpc.Testing.ScenarioResult.Parser, new[]{ "Scenario", "Latencies", "ClientStats", "ServerStats", "ServerCores", "Summary", "ClientSuccess", "ServerSuccess", "RequestResults" }, null, null, null)
}));
}
#endregion
@@ -1641,6 +1645,7 @@ namespace Grpc.Testing {
PayloadConfig = other.payloadConfig_ != null ? other.PayloadConfig.Clone() : null;
coreList_ = other.coreList_.Clone();
otherServerApi_ = other.otherServerApi_;
+ resourceQuotaSize_ = other.resourceQuotaSize_;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1753,6 +1758,20 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "resource_quota_size" field.</summary>
+ public const int ResourceQuotaSizeFieldNumber = 1001;
+ private int resourceQuotaSize_;
+ /// <summary>
+ /// Buffer pool size (no buffer pool specified if unset)
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int ResourceQuotaSize {
+ get { return resourceQuotaSize_; }
+ set {
+ resourceQuotaSize_ = value;
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ServerConfig);
@@ -1774,6 +1793,7 @@ namespace Grpc.Testing {
if (!object.Equals(PayloadConfig, other.PayloadConfig)) return false;
if(!coreList_.Equals(other.coreList_)) return false;
if (OtherServerApi != other.OtherServerApi) return false;
+ if (ResourceQuotaSize != other.ResourceQuotaSize) return false;
return true;
}
@@ -1788,6 +1808,7 @@ namespace Grpc.Testing {
if (payloadConfig_ != null) hash ^= PayloadConfig.GetHashCode();
hash ^= coreList_.GetHashCode();
if (OtherServerApi.Length != 0) hash ^= OtherServerApi.GetHashCode();
+ if (ResourceQuotaSize != 0) hash ^= ResourceQuotaSize.GetHashCode();
return hash;
}
@@ -1827,6 +1848,10 @@ namespace Grpc.Testing {
output.WriteRawTag(90);
output.WriteString(OtherServerApi);
}
+ if (ResourceQuotaSize != 0) {
+ output.WriteRawTag(200, 62);
+ output.WriteInt32(ResourceQuotaSize);
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1854,6 +1879,9 @@ namespace Grpc.Testing {
if (OtherServerApi.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(OtherServerApi);
}
+ if (ResourceQuotaSize != 0) {
+ size += 2 + pb::CodedOutputStream.ComputeInt32Size(ResourceQuotaSize);
+ }
return size;
}
@@ -1890,6 +1918,9 @@ namespace Grpc.Testing {
if (other.OtherServerApi.Length != 0) {
OtherServerApi = other.OtherServerApi;
}
+ if (other.ResourceQuotaSize != 0) {
+ ResourceQuotaSize = other.ResourceQuotaSize;
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1939,6 +1970,10 @@ namespace Grpc.Testing {
OtherServerApi = input.ReadString();
break;
}
+ case 8008: {
+ ResourceQuotaSize = input.ReadInt32();
+ break;
+ }
}
}
}
@@ -3117,6 +3152,9 @@ namespace Grpc.Testing {
latency95_ = other.latency95_;
latency99_ = other.latency99_;
latency999_ = other.latency999_;
+ serverCpuUsage_ = other.serverCpuUsage_;
+ successfulRequestsPerSecond_ = other.successfulRequestsPerSecond_;
+ failedRequestsPerSecond_ = other.failedRequestsPerSecond_;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3266,6 +3304,45 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "server_cpu_usage" field.</summary>
+ public const int ServerCpuUsageFieldNumber = 12;
+ private double serverCpuUsage_;
+ /// <summary>
+ /// server cpu usage percentage
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public double ServerCpuUsage {
+ get { return serverCpuUsage_; }
+ set {
+ serverCpuUsage_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "successful_requests_per_second" field.</summary>
+ public const int SuccessfulRequestsPerSecondFieldNumber = 13;
+ private double successfulRequestsPerSecond_;
+ /// <summary>
+ /// Number of requests that succeeded/failed
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public double SuccessfulRequestsPerSecond {
+ get { return successfulRequestsPerSecond_; }
+ set {
+ successfulRequestsPerSecond_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "failed_requests_per_second" field.</summary>
+ public const int FailedRequestsPerSecondFieldNumber = 14;
+ private double failedRequestsPerSecond_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public double FailedRequestsPerSecond {
+ get { return failedRequestsPerSecond_; }
+ set {
+ failedRequestsPerSecond_ = value;
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ScenarioResultSummary);
@@ -3290,6 +3367,9 @@ namespace Grpc.Testing {
if (Latency95 != other.Latency95) return false;
if (Latency99 != other.Latency99) return false;
if (Latency999 != other.Latency999) return false;
+ if (ServerCpuUsage != other.ServerCpuUsage) return false;
+ if (SuccessfulRequestsPerSecond != other.SuccessfulRequestsPerSecond) return false;
+ if (FailedRequestsPerSecond != other.FailedRequestsPerSecond) return false;
return true;
}
@@ -3307,6 +3387,9 @@ namespace Grpc.Testing {
if (Latency95 != 0D) hash ^= Latency95.GetHashCode();
if (Latency99 != 0D) hash ^= Latency99.GetHashCode();
if (Latency999 != 0D) hash ^= Latency999.GetHashCode();
+ if (ServerCpuUsage != 0D) hash ^= ServerCpuUsage.GetHashCode();
+ if (SuccessfulRequestsPerSecond != 0D) hash ^= SuccessfulRequestsPerSecond.GetHashCode();
+ if (FailedRequestsPerSecond != 0D) hash ^= FailedRequestsPerSecond.GetHashCode();
return hash;
}
@@ -3361,6 +3444,18 @@ namespace Grpc.Testing {
output.WriteRawTag(89);
output.WriteDouble(Latency999);
}
+ if (ServerCpuUsage != 0D) {
+ output.WriteRawTag(97);
+ output.WriteDouble(ServerCpuUsage);
+ }
+ if (SuccessfulRequestsPerSecond != 0D) {
+ output.WriteRawTag(105);
+ output.WriteDouble(SuccessfulRequestsPerSecond);
+ }
+ if (FailedRequestsPerSecond != 0D) {
+ output.WriteRawTag(113);
+ output.WriteDouble(FailedRequestsPerSecond);
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3399,6 +3494,15 @@ namespace Grpc.Testing {
if (Latency999 != 0D) {
size += 1 + 8;
}
+ if (ServerCpuUsage != 0D) {
+ size += 1 + 8;
+ }
+ if (SuccessfulRequestsPerSecond != 0D) {
+ size += 1 + 8;
+ }
+ if (FailedRequestsPerSecond != 0D) {
+ size += 1 + 8;
+ }
return size;
}
@@ -3440,6 +3544,15 @@ namespace Grpc.Testing {
if (other.Latency999 != 0D) {
Latency999 = other.Latency999;
}
+ if (other.ServerCpuUsage != 0D) {
+ ServerCpuUsage = other.ServerCpuUsage;
+ }
+ if (other.SuccessfulRequestsPerSecond != 0D) {
+ SuccessfulRequestsPerSecond = other.SuccessfulRequestsPerSecond;
+ }
+ if (other.FailedRequestsPerSecond != 0D) {
+ FailedRequestsPerSecond = other.FailedRequestsPerSecond;
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3494,6 +3607,18 @@ namespace Grpc.Testing {
Latency999 = input.ReadDouble();
break;
}
+ case 97: {
+ ServerCpuUsage = input.ReadDouble();
+ break;
+ }
+ case 105: {
+ SuccessfulRequestsPerSecond = input.ReadDouble();
+ break;
+ }
+ case 113: {
+ FailedRequestsPerSecond = input.ReadDouble();
+ break;
+ }
}
}
}
@@ -3535,6 +3660,7 @@ namespace Grpc.Testing {
Summary = other.summary_ != null ? other.Summary.Clone() : null;
clientSuccess_ = other.clientSuccess_.Clone();
serverSuccess_ = other.serverSuccess_.Clone();
+ requestResults_ = other.requestResults_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3646,6 +3772,19 @@ namespace Grpc.Testing {
get { return serverSuccess_; }
}
+ /// <summary>Field number for the "request_results" field.</summary>
+ public const int RequestResultsFieldNumber = 9;
+ private static readonly pb::FieldCodec<global::Grpc.Testing.RequestResultCount> _repeated_requestResults_codec
+ = pb::FieldCodec.ForMessage(74, global::Grpc.Testing.RequestResultCount.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.RequestResultCount> requestResults_ = new pbc::RepeatedField<global::Grpc.Testing.RequestResultCount>();
+ /// <summary>
+ /// Number of failed requests (one row per status code seen)
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField<global::Grpc.Testing.RequestResultCount> RequestResults {
+ get { return requestResults_; }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ScenarioResult);
@@ -3667,6 +3806,7 @@ namespace Grpc.Testing {
if (!object.Equals(Summary, other.Summary)) return false;
if(!clientSuccess_.Equals(other.clientSuccess_)) return false;
if(!serverSuccess_.Equals(other.serverSuccess_)) return false;
+ if(!requestResults_.Equals(other.requestResults_)) return false;
return true;
}
@@ -3681,6 +3821,7 @@ namespace Grpc.Testing {
if (summary_ != null) hash ^= Summary.GetHashCode();
hash ^= clientSuccess_.GetHashCode();
hash ^= serverSuccess_.GetHashCode();
+ hash ^= requestResults_.GetHashCode();
return hash;
}
@@ -3708,6 +3849,7 @@ namespace Grpc.Testing {
}
clientSuccess_.WriteTo(output, _repeated_clientSuccess_codec);
serverSuccess_.WriteTo(output, _repeated_serverSuccess_codec);
+ requestResults_.WriteTo(output, _repeated_requestResults_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3727,6 +3869,7 @@ namespace Grpc.Testing {
}
size += clientSuccess_.CalculateSize(_repeated_clientSuccess_codec);
size += serverSuccess_.CalculateSize(_repeated_serverSuccess_codec);
+ size += requestResults_.CalculateSize(_repeated_requestResults_codec);
return size;
}
@@ -3758,6 +3901,7 @@ namespace Grpc.Testing {
}
clientSuccess_.Add(other.clientSuccess_);
serverSuccess_.Add(other.serverSuccess_);
+ requestResults_.Add(other.requestResults_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -3812,6 +3956,10 @@ namespace Grpc.Testing {
serverSuccess_.AddEntriesFrom(input, _repeated_serverSuccess_codec);
break;
}
+ case 74: {
+ requestResults_.AddEntriesFrom(input, _repeated_requestResults_codec);
+ break;
+ }
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index afd85fb484..161b015300 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -51,9 +51,6 @@
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
</Reference>
- <Reference Include="System.Interactive.Async">
- <HintPath>..\packages\System.Interactive.Async.3.0.0\lib\net45\System.Interactive.Async.dll</HintPath>
- </Reference>
<Reference Include="nunitlite">
<HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
</Reference>
@@ -90,6 +87,9 @@
<Reference Include="Moq">
<HintPath>..\packages\Moq.4.6.38-alpha\lib\net45\Moq.dll</HintPath>
</Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index eb3bb8a28b..d55e658d94 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -103,6 +103,34 @@ namespace Grpc.IntegrationTesting
client.UnaryCall(new SimpleRequest { }, new CallOptions(credentials: callCredentials));
}
+ [Test]
+ public void MetadataCredentials_InterceptorLeavesMetadataEmpty()
+ {
+ var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(),
+ CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) => TaskUtils.CompletedTask)));
+ channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
+ client = new TestService.TestServiceClient(channel);
+
+ var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { }));
+ // StatusCode.Unknown as the server-side handler throws an exception after not receiving the authorization header.
+ Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public void MetadataCredentials_InterceptorThrows()
+ {
+ var callCredentials = CallCredentials.FromInterceptor(new AsyncAuthInterceptor((context, metadata) =>
+ {
+ throw new Exception("Auth interceptor throws");
+ }));
+ var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(), callCredentials);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
+ client = new TestService.TestServiceClient(channel);
+
+ var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { }));
+ Assert.AreEqual(StatusCode.Unauthenticated, ex.Status.StatusCode);
+ }
+
private class FakeTestService : TestService.TestServiceBase
{
public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index bcd7e3c040..d0bf0afc1d 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -44,7 +44,7 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Testing {
- public static class MetricsService
+ public static partial class MetricsService
{
static readonly string __ServiceName = "grpc.testing.MetricsService";
@@ -73,7 +73,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of MetricsService</summary>
- public abstract class MetricsServiceBase
+ public abstract partial class MetricsServiceBase
{
/// <summary>
/// Returns the values of all the gauges that are currently being maintained by
@@ -95,7 +95,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for MetricsService</summary>
- public class MetricsServiceClient : ClientBase<MetricsServiceClient>
+ public partial class MetricsServiceClient : ClientBase<MetricsServiceClient>
{
/// <summary>Creates a new client for MetricsService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 848dd04fa7..3cc4ed9f3c 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -40,7 +40,7 @@ using System.Threading.Tasks;
using Grpc.Core;
namespace Grpc.Testing {
- public static class BenchmarkService
+ public static partial class BenchmarkService
{
static readonly string __ServiceName = "grpc.testing.BenchmarkService";
@@ -68,7 +68,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of BenchmarkService</summary>
- public abstract class BenchmarkServiceBase
+ public abstract partial class BenchmarkServiceBase
{
/// <summary>
/// One request followed by one response.
@@ -91,7 +91,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for BenchmarkService</summary>
- public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>
+ public partial class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>
{
/// <summary>Creates a new client for BenchmarkService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
@@ -177,7 +177,7 @@ namespace Grpc.Testing {
}
}
- public static class WorkerService
+ public static partial class WorkerService
{
static readonly string __ServiceName = "grpc.testing.WorkerService";
@@ -224,7 +224,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of WorkerService</summary>
- public abstract class WorkerServiceBase
+ public abstract partial class WorkerServiceBase
{
/// <summary>
/// Start server with specified workload.
@@ -271,7 +271,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for WorkerService</summary>
- public class WorkerServiceClient : ClientBase<WorkerServiceClient>
+ public partial class WorkerServiceClient : ClientBase<WorkerServiceClient>
{
/// <summary>Creates a new client for WorkerService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
diff --git a/src/csharp/Grpc.IntegrationTesting/Stats.cs b/src/csharp/Grpc.IntegrationTesting/Stats.cs
index 0ae77cfb92..504aa11d8a 100644
--- a/src/csharp/Grpc.IntegrationTesting/Stats.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Stats.cs
@@ -23,22 +23,27 @@ namespace Grpc.Testing {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CiJzcmMvcHJvdG8vZ3JwYy90ZXN0aW5nL3N0YXRzLnByb3RvEgxncnBjLnRl",
- "c3RpbmciSwoLU2VydmVyU3RhdHMSFAoMdGltZV9lbGFwc2VkGAEgASgBEhEK",
- "CXRpbWVfdXNlchgCIAEoARITCgt0aW1lX3N5c3RlbRgDIAEoASI7Cg9IaXN0",
- "b2dyYW1QYXJhbXMSEgoKcmVzb2x1dGlvbhgBIAEoARIUCgxtYXhfcG9zc2li",
- "bGUYAiABKAEidwoNSGlzdG9ncmFtRGF0YRIOCgZidWNrZXQYASADKA0SEAoI",
- "bWluX3NlZW4YAiABKAESEAoIbWF4X3NlZW4YAyABKAESCwoDc3VtGAQgASgB",
- "EhYKDnN1bV9vZl9zcXVhcmVzGAUgASgBEg0KBWNvdW50GAYgASgBInsKC0Ns",
- "aWVudFN0YXRzEi4KCWxhdGVuY2llcxgBIAEoCzIbLmdycGMudGVzdGluZy5I",
- "aXN0b2dyYW1EYXRhEhQKDHRpbWVfZWxhcHNlZBgCIAEoARIRCgl0aW1lX3Vz",
- "ZXIYAyABKAESEwoLdGltZV9zeXN0ZW0YBCABKAFiBnByb3RvMw=="));
+ "c3RpbmciegoLU2VydmVyU3RhdHMSFAoMdGltZV9lbGFwc2VkGAEgASgBEhEK",
+ "CXRpbWVfdXNlchgCIAEoARITCgt0aW1lX3N5c3RlbRgDIAEoARIWCg50b3Rh",
+ "bF9jcHVfdGltZRgEIAEoBBIVCg1pZGxlX2NwdV90aW1lGAUgASgEIjsKD0hp",
+ "c3RvZ3JhbVBhcmFtcxISCgpyZXNvbHV0aW9uGAEgASgBEhQKDG1heF9wb3Nz",
+ "aWJsZRgCIAEoASJ3Cg1IaXN0b2dyYW1EYXRhEg4KBmJ1Y2tldBgBIAMoDRIQ",
+ "CghtaW5fc2VlbhgCIAEoARIQCghtYXhfc2VlbhgDIAEoARILCgNzdW0YBCAB",
+ "KAESFgoOc3VtX29mX3NxdWFyZXMYBSABKAESDQoFY291bnQYBiABKAEiOAoS",
+ "UmVxdWVzdFJlc3VsdENvdW50EhMKC3N0YXR1c19jb2RlGAEgASgFEg0KBWNv",
+ "dW50GAIgASgDIrYBCgtDbGllbnRTdGF0cxIuCglsYXRlbmNpZXMYASABKAsy",
+ "Gy5ncnBjLnRlc3RpbmcuSGlzdG9ncmFtRGF0YRIUCgx0aW1lX2VsYXBzZWQY",
+ "AiABKAESEQoJdGltZV91c2VyGAMgASgBEhMKC3RpbWVfc3lzdGVtGAQgASgB",
+ "EjkKD3JlcXVlc3RfcmVzdWx0cxgFIAMoCzIgLmdycGMudGVzdGluZy5SZXF1",
+ "ZXN0UmVzdWx0Q291bnRiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerStats), global::Grpc.Testing.ServerStats.Parser, new[]{ "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ServerStats), global::Grpc.Testing.ServerStats.Parser, new[]{ "TimeElapsed", "TimeUser", "TimeSystem", "TotalCpuTime", "IdleCpuTime" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.HistogramParams), global::Grpc.Testing.HistogramParams.Parser, new[]{ "Resolution", "MaxPossible" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.HistogramData), global::Grpc.Testing.HistogramData.Parser, new[]{ "Bucket", "MinSeen", "MaxSeen", "Sum", "SumOfSquares", "Count" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStats), global::Grpc.Testing.ClientStats.Parser, new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem" }, null, null, null)
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.RequestResultCount), global::Grpc.Testing.RequestResultCount.Parser, new[]{ "StatusCode", "Count" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ClientStats), global::Grpc.Testing.ClientStats.Parser, new[]{ "Latencies", "TimeElapsed", "TimeUser", "TimeSystem", "RequestResults" }, null, null, null)
}));
}
#endregion
@@ -72,6 +77,8 @@ namespace Grpc.Testing {
timeElapsed_ = other.timeElapsed_;
timeUser_ = other.timeUser_;
timeSystem_ = other.timeSystem_;
+ totalCpuTime_ = other.totalCpuTime_;
+ idleCpuTime_ = other.idleCpuTime_;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -122,6 +129,34 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "total_cpu_time" field.</summary>
+ public const int TotalCpuTimeFieldNumber = 4;
+ private ulong totalCpuTime_;
+ /// <summary>
+ /// change in total cpu time of the server (data from proc/stat)
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ulong TotalCpuTime {
+ get { return totalCpuTime_; }
+ set {
+ totalCpuTime_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "idle_cpu_time" field.</summary>
+ public const int IdleCpuTimeFieldNumber = 5;
+ private ulong idleCpuTime_;
+ /// <summary>
+ /// change in idle time of the server (data from proc/stat)
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ulong IdleCpuTime {
+ get { return idleCpuTime_; }
+ set {
+ idleCpuTime_ = value;
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ServerStats);
@@ -138,6 +173,8 @@ namespace Grpc.Testing {
if (TimeElapsed != other.TimeElapsed) return false;
if (TimeUser != other.TimeUser) return false;
if (TimeSystem != other.TimeSystem) return false;
+ if (TotalCpuTime != other.TotalCpuTime) return false;
+ if (IdleCpuTime != other.IdleCpuTime) return false;
return true;
}
@@ -147,6 +184,8 @@ namespace Grpc.Testing {
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
+ if (TotalCpuTime != 0UL) hash ^= TotalCpuTime.GetHashCode();
+ if (IdleCpuTime != 0UL) hash ^= IdleCpuTime.GetHashCode();
return hash;
}
@@ -169,6 +208,14 @@ namespace Grpc.Testing {
output.WriteRawTag(25);
output.WriteDouble(TimeSystem);
}
+ if (TotalCpuTime != 0UL) {
+ output.WriteRawTag(32);
+ output.WriteUInt64(TotalCpuTime);
+ }
+ if (IdleCpuTime != 0UL) {
+ output.WriteRawTag(40);
+ output.WriteUInt64(IdleCpuTime);
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -183,6 +230,12 @@ namespace Grpc.Testing {
if (TimeSystem != 0D) {
size += 1 + 8;
}
+ if (TotalCpuTime != 0UL) {
+ size += 1 + pb::CodedOutputStream.ComputeUInt64Size(TotalCpuTime);
+ }
+ if (IdleCpuTime != 0UL) {
+ size += 1 + pb::CodedOutputStream.ComputeUInt64Size(IdleCpuTime);
+ }
return size;
}
@@ -200,6 +253,12 @@ namespace Grpc.Testing {
if (other.TimeSystem != 0D) {
TimeSystem = other.TimeSystem;
}
+ if (other.TotalCpuTime != 0UL) {
+ TotalCpuTime = other.TotalCpuTime;
+ }
+ if (other.IdleCpuTime != 0UL) {
+ IdleCpuTime = other.IdleCpuTime;
+ }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -222,6 +281,14 @@ namespace Grpc.Testing {
TimeSystem = input.ReadDouble();
break;
}
+ case 32: {
+ TotalCpuTime = input.ReadUInt64();
+ break;
+ }
+ case 40: {
+ IdleCpuTime = input.ReadUInt64();
+ break;
+ }
}
}
}
@@ -635,6 +702,151 @@ namespace Grpc.Testing {
}
+ public sealed partial class RequestResultCount : pb::IMessage<RequestResultCount> {
+ private static readonly pb::MessageParser<RequestResultCount> _parser = new pb::MessageParser<RequestResultCount>(() => new RequestResultCount());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<RequestResultCount> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[3]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public RequestResultCount() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public RequestResultCount(RequestResultCount other) : this() {
+ statusCode_ = other.statusCode_;
+ count_ = other.count_;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public RequestResultCount Clone() {
+ return new RequestResultCount(this);
+ }
+
+ /// <summary>Field number for the "status_code" field.</summary>
+ public const int StatusCodeFieldNumber = 1;
+ private int statusCode_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int StatusCode {
+ get { return statusCode_; }
+ set {
+ statusCode_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "count" field.</summary>
+ public const int CountFieldNumber = 2;
+ private long count_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public long Count {
+ get { return count_; }
+ set {
+ count_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as RequestResultCount);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(RequestResultCount other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (StatusCode != other.StatusCode) return false;
+ if (Count != other.Count) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (StatusCode != 0) hash ^= StatusCode.GetHashCode();
+ if (Count != 0L) hash ^= Count.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (StatusCode != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(StatusCode);
+ }
+ if (Count != 0L) {
+ output.WriteRawTag(16);
+ output.WriteInt64(Count);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (StatusCode != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(StatusCode);
+ }
+ if (Count != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(RequestResultCount other) {
+ if (other == null) {
+ return;
+ }
+ if (other.StatusCode != 0) {
+ StatusCode = other.StatusCode;
+ }
+ if (other.Count != 0L) {
+ Count = other.Count;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ StatusCode = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ Count = input.ReadInt64();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
public sealed partial class ClientStats : pb::IMessage<ClientStats> {
private static readonly pb::MessageParser<ClientStats> _parser = new pb::MessageParser<ClientStats>(() => new ClientStats());
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -642,7 +854,7 @@ namespace Grpc.Testing {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[3]; }
+ get { return global::Grpc.Testing.StatsReflection.Descriptor.MessageTypes[4]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -663,6 +875,7 @@ namespace Grpc.Testing {
timeElapsed_ = other.timeElapsed_;
timeUser_ = other.timeUser_;
timeSystem_ = other.timeSystem_;
+ requestResults_ = other.requestResults_.Clone();
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -720,6 +933,19 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "request_results" field.</summary>
+ public const int RequestResultsFieldNumber = 5;
+ private static readonly pb::FieldCodec<global::Grpc.Testing.RequestResultCount> _repeated_requestResults_codec
+ = pb::FieldCodec.ForMessage(42, global::Grpc.Testing.RequestResultCount.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.RequestResultCount> requestResults_ = new pbc::RepeatedField<global::Grpc.Testing.RequestResultCount>();
+ /// <summary>
+ /// Number of failed requests (one row per status code seen)
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField<global::Grpc.Testing.RequestResultCount> RequestResults {
+ get { return requestResults_; }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as ClientStats);
@@ -737,6 +963,7 @@ namespace Grpc.Testing {
if (TimeElapsed != other.TimeElapsed) return false;
if (TimeUser != other.TimeUser) return false;
if (TimeSystem != other.TimeSystem) return false;
+ if(!requestResults_.Equals(other.requestResults_)) return false;
return true;
}
@@ -747,6 +974,7 @@ namespace Grpc.Testing {
if (TimeElapsed != 0D) hash ^= TimeElapsed.GetHashCode();
if (TimeUser != 0D) hash ^= TimeUser.GetHashCode();
if (TimeSystem != 0D) hash ^= TimeSystem.GetHashCode();
+ hash ^= requestResults_.GetHashCode();
return hash;
}
@@ -773,6 +1001,7 @@ namespace Grpc.Testing {
output.WriteRawTag(33);
output.WriteDouble(TimeSystem);
}
+ requestResults_.WriteTo(output, _repeated_requestResults_codec);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -790,6 +1019,7 @@ namespace Grpc.Testing {
if (TimeSystem != 0D) {
size += 1 + 8;
}
+ size += requestResults_.CalculateSize(_repeated_requestResults_codec);
return size;
}
@@ -813,6 +1043,7 @@ namespace Grpc.Testing {
if (other.TimeSystem != 0D) {
TimeSystem = other.TimeSystem;
}
+ requestResults_.Add(other.requestResults_);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -842,6 +1073,10 @@ namespace Grpc.Testing {
TimeSystem = input.ReadDouble();
break;
}
+ case 42: {
+ requestResults_.AddEntriesFrom(input, _repeated_requestResults_codec);
+ break;
+ }
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 8d649bf5c5..43dbc2865f 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -45,7 +45,7 @@ namespace Grpc.Testing {
/// A simple service to test the various types of RPCs and experiment with
/// performance with various types of payload.
/// </summary>
- public static class TestService
+ public static partial class TestService
{
static readonly string __ServiceName = "grpc.testing.TestService";
@@ -120,7 +120,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of TestService</summary>
- public abstract class TestServiceBase
+ public abstract partial class TestServiceBase
{
/// <summary>
/// One empty request followed by one empty response.
@@ -199,7 +199,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for TestService</summary>
- public class TestServiceClient : ClientBase<TestServiceClient>
+ public partial class TestServiceClient : ClientBase<TestServiceClient>
{
/// <summary>Creates a new client for TestService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
@@ -441,7 +441,7 @@ namespace Grpc.Testing {
/// A simple service NOT implemented at servers so clients can test for
/// that case.
/// </summary>
- public static class UnimplementedService
+ public static partial class UnimplementedService
{
static readonly string __ServiceName = "grpc.testing.UnimplementedService";
@@ -461,7 +461,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of UnimplementedService</summary>
- public abstract class UnimplementedServiceBase
+ public abstract partial class UnimplementedServiceBase
{
/// <summary>
/// A call that no server should implement
@@ -474,7 +474,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for UnimplementedService</summary>
- public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>
+ public partial class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>
{
/// <summary>Creates a new client for UnimplementedService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
@@ -542,7 +542,7 @@ namespace Grpc.Testing {
/// <summary>
/// A service used to control reconnect server.
/// </summary>
- public static class ReconnectService
+ public static partial class ReconnectService
{
static readonly string __ServiceName = "grpc.testing.ReconnectService";
@@ -571,7 +571,7 @@ namespace Grpc.Testing {
}
/// <summary>Base class for server-side implementations of ReconnectService</summary>
- public abstract class ReconnectServiceBase
+ public abstract partial class ReconnectServiceBase
{
public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context)
{
@@ -586,7 +586,7 @@ namespace Grpc.Testing {
}
/// <summary>Client for ReconnectService</summary>
- public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>
+ public partial class ReconnectServiceClient : ClientBase<ReconnectServiceClient>
{
/// <summary>Creates a new client for ReconnectService</summary>
/// <param name="channel">The channel to use to make remote calls.</param>
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index a39fb3a23e..a03ee926f4 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -12,6 +12,6 @@
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NUnit" version="3.2.0" targetFramework="net45" />
<package id="NUnitLite" version="3.2.0" targetFramework="net45" />
- <package id="System.Interactive.Async" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
<package id="Zlib.Portable.Signed" version="1.11.0" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
index 0225abb414..e47b5953da 100644
--- a/src/csharp/Grpc.IntegrationTesting/project.json
+++ b/src/csharp/Grpc.IntegrationTesting/project.json
@@ -7,7 +7,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
@@ -29,7 +28,6 @@
"buildOptions": {
"define": [ "SIGNED" ],
"keyFile": "../keys/Grpc.snk",
- "publicSign": true,
"xmlDoc": true,
"compile": {
"includeFiles": [ "../Grpc.Core/Version.cs" ]
diff --git a/src/csharp/Grpc.Reflection.Tests/.gitignore b/src/csharp/Grpc.Reflection.Tests/.gitignore
new file mode 100644
index 0000000000..1746e3269e
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
new file mode 100644
index 0000000000..cebcf59ce8
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{B88F91D6-436D-4C78-8B99-47800FA8DE03}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Grpc.Reflection.Tests</RootNamespace>
+ <AssemblyName>Grpc.Reflection.Tests</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="nunit.framework">
+ <HintPath>..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="nunitlite">
+ <HintPath>..\packages\NUnitLite.3.2.0\lib\net45\nunitlite.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Protobuf">
+ <HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Grpc.Core\Version.cs">
+ <Link>Version.cs</Link>
+ </Compile>
+ <Compile Include="SymbolRegistryTest.cs" />
+ <Compile Include="ReflectionClientServerTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="NUnitMain.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Grpc.Reflection\Grpc.Reflection.csproj">
+ <Project>{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}</Project>
+ <Name>Grpc.Reflection</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Grpc.Reflection.Tests.project.json" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj
new file mode 100644
index 0000000000..4a3100853d
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>fe90181d-a4b3-4a5c-8490-f07561e18e3b</ProjectGuid>
+ <RootNamespace>Grpc.Reflection.Tests</RootNamespace>
+ <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+ <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs b/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs
new file mode 100644
index 0000000000..a60d7b03eb
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/NUnitMain.cs
@@ -0,0 +1,59 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Logging;
+using NUnit.Common;
+using NUnitLite;
+
+namespace Grpc.Reflection.Tests
+{
+ /// <summary>
+ /// Provides entry point for NUnitLite
+ /// </summary>
+ public class NUnitMain
+ {
+ public static int Main(string[] args)
+ {
+ // Make logger immune to NUnit capturing stdout and stderr to workaround https://github.com/nunit/nunit/issues/1406.
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+#if NETCOREAPP1_0
+ return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
+#else
+ return new AutoRun().Execute(args);
+#endif
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Reflection.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..d29054a4d1
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,44 @@
+#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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.Reflection.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs b/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs
new file mode 100644
index 0000000000..1d0845e276
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/ReflectionClientServerTest.cs
@@ -0,0 +1,154 @@
+#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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Reflection;
+using Grpc.Reflection.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.Reflection.Tests
+{
+ /// <summary>
+ /// Reflection client talks to reflection server.
+ /// </summary>
+ public class ReflectionClientServerTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ ServerReflection.ServerReflectionClient client;
+ ReflectionServiceImpl serviceImpl;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ serviceImpl = new ReflectionServiceImpl(ServerReflection.Descriptor);
+
+ server = new Server
+ {
+ Services = { ServerReflection.BindService(serviceImpl) },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
+ server.Start();
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
+
+ client = new ServerReflection.ServerReflectionClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public async Task FileByFilename_NotFound()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ FileByFilename = "somepackage/nonexistent.proto"
+ });
+ Assert.AreEqual((int)StatusCode.NotFound, response.ErrorResponse.ErrorCode);
+ }
+
+ [Test]
+ public async Task FileByFilename()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ FileByFilename = "grpc/reflection/v1alpha/reflection.proto"
+ });
+ Assert.AreEqual(1, response.FileDescriptorResponse.FileDescriptorProto.Count);
+ Assert.AreEqual(ReflectionReflection.Descriptor.SerializedData, response.FileDescriptorResponse.FileDescriptorProto[0]);
+ }
+
+ [Test]
+ public async Task FileContainingSymbol()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ FileContainingSymbol = "grpc.reflection.v1alpha.ServerReflection"
+ });
+ Assert.AreEqual(1, response.FileDescriptorResponse.FileDescriptorProto.Count);
+ Assert.AreEqual(ReflectionReflection.Descriptor.SerializedData, response.FileDescriptorResponse.FileDescriptorProto[0]);
+ }
+
+ [Test]
+ public async Task FileContainingSymbol_NotFound()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ FileContainingSymbol = "somepackage.Nonexistent"
+ });
+ Assert.AreEqual((int)StatusCode.NotFound, response.ErrorResponse.ErrorCode);
+ }
+
+ [Test]
+ public async Task ListServices()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ ListServices = ""
+ });
+ Assert.AreEqual(1, response.ListServicesResponse.Service.Count);
+ Assert.AreEqual(ServerReflection.Descriptor.FullName, response.ListServicesResponse.Service[0].Name);
+ }
+
+ [Test]
+ public async Task FileContainingExtension()
+ {
+ var response = await SingleRequestAsync(new ServerReflectionRequest
+ {
+ FileContainingExtension = new ExtensionRequest()
+ });
+ Assert.AreEqual((int)StatusCode.Unimplemented, response.ErrorResponse.ErrorCode);
+ }
+
+ private async Task<ServerReflectionResponse> SingleRequestAsync(ServerReflectionRequest request)
+ {
+ var call = client.ServerReflectionInfo();
+ await call.RequestStream.WriteAsync(request);
+ Assert.IsTrue(await call.ResponseStream.MoveNext());
+
+ var response = call.ResponseStream.Current;
+ await call.RequestStream.CompleteAsync();
+ Assert.IsFalse(await call.ResponseStream.MoveNext());
+ return response;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection.Tests/SymbolRegistryTest.cs b/src/csharp/Grpc.Reflection.Tests/SymbolRegistryTest.cs
new file mode 100644
index 0000000000..68ee6dc10d
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/SymbolRegistryTest.cs
@@ -0,0 +1,63 @@
+#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 Grpc.Reflection;
+using Grpc.Reflection.V1Alpha;
+using NUnit.Framework;
+
+
+namespace Grpc.Reflection.Tests
+{
+ /// <summary>
+ /// Tests for ReflectionServiceImpl
+ /// </summary>
+ public class SymbolRegistryTest
+ {
+ SymbolRegistry registry = SymbolRegistry.FromFiles(new[] { ReflectionReflection.Descriptor, Google.Protobuf.WellKnownTypes.Duration.Descriptor.File });
+
+ [Test]
+ public void FileByName()
+ {
+ Assert.AreSame(Google.Protobuf.WellKnownTypes.Duration.Descriptor.File, registry.FileByName("google/protobuf/duration.proto"));
+ Assert.IsNull(registry.FileByName("somepackage/nonexistent.proto"));
+ }
+
+ [Test]
+ public void FileContainingSymbol()
+ {
+ Assert.AreSame(Google.Protobuf.WellKnownTypes.Duration.Descriptor.File, registry.FileContainingSymbol("google.protobuf.Duration"));
+ Assert.AreSame(ReflectionReflection.Descriptor, registry.FileContainingSymbol("grpc.reflection.v1alpha.ServerReflection.ServerReflectionInfo")); // method
+ Assert.AreSame(ReflectionReflection.Descriptor, registry.FileContainingSymbol("grpc.reflection.v1alpha.ServerReflection")); // service
+ Assert.AreSame(ReflectionReflection.Descriptor, registry.FileContainingSymbol("grpc.reflection.v1alpha.ServerReflectionRequest")); // message
+ Assert.IsNull(registry.FileContainingSymbol("somepackage.Nonexistent"));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection.Tests/packages.config b/src/csharp/Grpc.Reflection.Tests/packages.config
new file mode 100644
index 0000000000..0fed4dbd41
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/packages.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Google.Protobuf" version="3.0.0" targetFramework="net45" />
+ <package id="NUnit" version="3.2.0" targetFramework="net45" />
+ <package id="NUnitLite" version="3.2.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection.Tests/project.json b/src/csharp/Grpc.Reflection.Tests/project.json
new file mode 100644
index 0000000000..61d3b7e47b
--- /dev/null
+++ b/src/csharp/Grpc.Reflection.Tests/project.json
@@ -0,0 +1,65 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "define": [ "SIGNED" ],
+ "keyFile": "../keys/Grpc.snk",
+ "xmlDoc": true,
+ "compile": {
+ "includeFiles": [ "../Grpc.Core/Version.cs" ]
+ },
+ "copyToOutput": {
+ "mappings": {
+ "grpc_csharp_ext.x64.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "grpc_csharp_ext.x86.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "define": [ "SIGNED" ],
+ "keyFile": "../keys/Grpc.snk",
+ "xmlDoc": true,
+ "compile": {
+ "includeFiles": [ "../Grpc.Core/Version.cs" ]
+ },
+ "copyToOutput": {
+ "mappings": {
+ "grpc_csharp_ext.x64.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "grpc_csharp_ext.x86.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+
+ "dependencies": {
+ "Grpc.Reflection": {
+ "target": "project"
+ },
+ "NUnit": "3.2.0",
+ "NUnitLite": "3.2.0-*"
+ },
+ "frameworks": {
+ "net45": { },
+ "netcoreapp1.0": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "Microsoft.NETCore.App": {
+ "type": "platform",
+ "version": "1.0.0"
+ }
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection/.gitignore b/src/csharp/Grpc.Reflection/.gitignore
new file mode 100644
index 0000000000..1746e3269e
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
new file mode 100644
index 0000000000..ea65998ce3
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Grpc.Reflection</RootNamespace>
+ <AssemblyName>Grpc.Reflection</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <DocumentationFile>bin\$(Configuration)\Grpc.Reflection.Xml</DocumentationFile>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseSigned|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\ReleaseSigned</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <SignAssembly>True</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\keys\Grpc.snk</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="Google.Protobuf">
+ <HintPath>..\packages\Google.Protobuf.3.0.0\lib\net45\Google.Protobuf.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Interactive.Async">
+ <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Grpc.Core\Version.cs">
+ <Link>Version.cs</Link>
+ </Compile>
+ <Compile Include="SymbolRegistry.cs" />
+ <Compile Include="ReflectionServiceImpl.cs" />
+ <Compile Include="Reflection.cs" />
+ <Compile Include="ReflectionGrpc.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Grpc.Reflection.project.json" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json b/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj
new file mode 100644
index 0000000000..833d98b121
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>2b372155-80ba-4cf9-82d6-4b938e8ec3a0</ProjectGuid>
+ <RootNamespace>Grpc.Reflection</RootNamespace>
+ <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
+ <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+ </PropertyGroup>
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Reflection/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..3104ecdd54
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Properties/AssemblyInfo.cs
@@ -0,0 +1,44 @@
+#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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.Reflection")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.Reflection/Reflection.cs b/src/csharp/Grpc.Reflection/Reflection.cs
new file mode 100644
index 0000000000..06c5d08030
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Reflection.cs
@@ -0,0 +1,1556 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: grpc/reflection/v1alpha/reflection.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Reflection.V1Alpha {
+
+ /// <summary>Holder for reflection information generated from grpc/reflection/v1alpha/reflection.proto</summary>
+ public static partial class ReflectionReflection {
+
+ #region Descriptor
+ /// <summary>File descriptor for grpc/reflection/v1alpha/reflection.proto</summary>
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static ReflectionReflection() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CihncnBjL3JlZmxlY3Rpb24vdjFhbHBoYS9yZWZsZWN0aW9uLnByb3RvEhdn",
+ "cnBjLnJlZmxlY3Rpb24udjFhbHBoYSKKAgoXU2VydmVyUmVmbGVjdGlvblJl",
+ "cXVlc3QSDAoEaG9zdBgBIAEoCRIaChBmaWxlX2J5X2ZpbGVuYW1lGAMgASgJ",
+ "SAASIAoWZmlsZV9jb250YWluaW5nX3N5bWJvbBgEIAEoCUgAEk4KGWZpbGVf",
+ "Y29udGFpbmluZ19leHRlbnNpb24YBSABKAsyKS5ncnBjLnJlZmxlY3Rpb24u",
+ "djFhbHBoYS5FeHRlbnNpb25SZXF1ZXN0SAASJwodYWxsX2V4dGVuc2lvbl9u",
+ "dW1iZXJzX29mX3R5cGUYBiABKAlIABIXCg1saXN0X3NlcnZpY2VzGAcgASgJ",
+ "SABCEQoPbWVzc2FnZV9yZXF1ZXN0IkUKEEV4dGVuc2lvblJlcXVlc3QSFwoP",
+ "Y29udGFpbmluZ190eXBlGAEgASgJEhgKEGV4dGVuc2lvbl9udW1iZXIYAiAB",
+ "KAUi0QMKGFNlcnZlclJlZmxlY3Rpb25SZXNwb25zZRISCgp2YWxpZF9ob3N0",
+ "GAEgASgJEkoKEG9yaWdpbmFsX3JlcXVlc3QYAiABKAsyMC5ncnBjLnJlZmxl",
+ "Y3Rpb24udjFhbHBoYS5TZXJ2ZXJSZWZsZWN0aW9uUmVxdWVzdBJTChhmaWxl",
+ "X2Rlc2NyaXB0b3JfcmVzcG9uc2UYBCABKAsyLy5ncnBjLnJlZmxlY3Rpb24u",
+ "djFhbHBoYS5GaWxlRGVzY3JpcHRvclJlc3BvbnNlSAASWgoeYWxsX2V4dGVu",
+ "c2lvbl9udW1iZXJzX3Jlc3BvbnNlGAUgASgLMjAuZ3JwYy5yZWZsZWN0aW9u",
+ "LnYxYWxwaGEuRXh0ZW5zaW9uTnVtYmVyUmVzcG9uc2VIABJOChZsaXN0X3Nl",
+ "cnZpY2VzX3Jlc3BvbnNlGAYgASgLMiwuZ3JwYy5yZWZsZWN0aW9uLnYxYWxw",
+ "aGEuTGlzdFNlcnZpY2VSZXNwb25zZUgAEkAKDmVycm9yX3Jlc3BvbnNlGAcg",
+ "ASgLMiYuZ3JwYy5yZWZsZWN0aW9uLnYxYWxwaGEuRXJyb3JSZXNwb25zZUgA",
+ "QhIKEG1lc3NhZ2VfcmVzcG9uc2UiNwoWRmlsZURlc2NyaXB0b3JSZXNwb25z",
+ "ZRIdChVmaWxlX2Rlc2NyaXB0b3JfcHJvdG8YASADKAwiSwoXRXh0ZW5zaW9u",
+ "TnVtYmVyUmVzcG9uc2USFgoOYmFzZV90eXBlX25hbWUYASABKAkSGAoQZXh0",
+ "ZW5zaW9uX251bWJlchgCIAMoBSJQChNMaXN0U2VydmljZVJlc3BvbnNlEjkK",
+ "B3NlcnZpY2UYASADKAsyKC5ncnBjLnJlZmxlY3Rpb24udjFhbHBoYS5TZXJ2",
+ "aWNlUmVzcG9uc2UiHwoPU2VydmljZVJlc3BvbnNlEgwKBG5hbWUYASABKAki",
+ "OgoNRXJyb3JSZXNwb25zZRISCgplcnJvcl9jb2RlGAEgASgFEhUKDWVycm9y",
+ "X21lc3NhZ2UYAiABKAkykwEKEFNlcnZlclJlZmxlY3Rpb24SfwoUU2VydmVy",
+ "UmVmbGVjdGlvbkluZm8SMC5ncnBjLnJlZmxlY3Rpb24udjFhbHBoYS5TZXJ2",
+ "ZXJSZWZsZWN0aW9uUmVxdWVzdBoxLmdycGMucmVmbGVjdGlvbi52MWFscGhh",
+ "LlNlcnZlclJlZmxlY3Rpb25SZXNwb25zZSgBMAFiBnByb3RvMw=="));
+ descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ServerReflectionRequest), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser, new[]{ "Host", "FileByFilename", "FileContainingSymbol", "FileContainingExtension", "AllExtensionNumbersOfType", "ListServices" }, new[]{ "MessageRequest" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ExtensionRequest), global::Grpc.Reflection.V1Alpha.ExtensionRequest.Parser, new[]{ "ContainingType", "ExtensionNumber" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ServerReflectionResponse), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser, new[]{ "ValidHost", "OriginalRequest", "FileDescriptorResponse", "AllExtensionNumbersResponse", "ListServicesResponse", "ErrorResponse" }, new[]{ "MessageResponse" }, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.FileDescriptorResponse), global::Grpc.Reflection.V1Alpha.FileDescriptorResponse.Parser, new[]{ "FileDescriptorProto" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse), global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse.Parser, new[]{ "BaseTypeName", "ExtensionNumber" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ListServiceResponse), global::Grpc.Reflection.V1Alpha.ListServiceResponse.Parser, new[]{ "Service" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ServiceResponse), global::Grpc.Reflection.V1Alpha.ServiceResponse.Parser, new[]{ "Name" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Reflection.V1Alpha.ErrorResponse), global::Grpc.Reflection.V1Alpha.ErrorResponse.Parser, new[]{ "ErrorCode", "ErrorMessage" }, null, null, null)
+ }));
+ }
+ #endregion
+
+ }
+ #region Messages
+ /// <summary>
+ /// The message sent by the client when calling ServerReflectionInfo method.
+ /// </summary>
+ public sealed partial class ServerReflectionRequest : pb::IMessage<ServerReflectionRequest> {
+ private static readonly pb::MessageParser<ServerReflectionRequest> _parser = new pb::MessageParser<ServerReflectionRequest>(() => new ServerReflectionRequest());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ServerReflectionRequest> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[0]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionRequest(ServerReflectionRequest other) : this() {
+ host_ = other.host_;
+ switch (other.MessageRequestCase) {
+ case MessageRequestOneofCase.FileByFilename:
+ FileByFilename = other.FileByFilename;
+ break;
+ case MessageRequestOneofCase.FileContainingSymbol:
+ FileContainingSymbol = other.FileContainingSymbol;
+ break;
+ case MessageRequestOneofCase.FileContainingExtension:
+ FileContainingExtension = other.FileContainingExtension.Clone();
+ break;
+ case MessageRequestOneofCase.AllExtensionNumbersOfType:
+ AllExtensionNumbersOfType = other.AllExtensionNumbersOfType;
+ break;
+ case MessageRequestOneofCase.ListServices:
+ ListServices = other.ListServices;
+ break;
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionRequest Clone() {
+ return new ServerReflectionRequest(this);
+ }
+
+ /// <summary>Field number for the "host" field.</summary>
+ public const int HostFieldNumber = 1;
+ private string host_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Host {
+ get { return host_; }
+ set {
+ host_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "file_by_filename" field.</summary>
+ public const int FileByFilenameFieldNumber = 3;
+ /// <summary>
+ /// Find a proto file by the file name.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string FileByFilename {
+ get { return messageRequestCase_ == MessageRequestOneofCase.FileByFilename ? (string) messageRequest_ : ""; }
+ set {
+ messageRequest_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ messageRequestCase_ = MessageRequestOneofCase.FileByFilename;
+ }
+ }
+
+ /// <summary>Field number for the "file_containing_symbol" field.</summary>
+ public const int FileContainingSymbolFieldNumber = 4;
+ /// <summary>
+ /// Find the proto file that declares the given fully-qualified symbol name.
+ /// This field should be a fully-qualified symbol name
+ /// (e.g. &lt;package>.&lt;service>[.&lt;method>] or &lt;package>.&lt;type>).
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string FileContainingSymbol {
+ get { return messageRequestCase_ == MessageRequestOneofCase.FileContainingSymbol ? (string) messageRequest_ : ""; }
+ set {
+ messageRequest_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ messageRequestCase_ = MessageRequestOneofCase.FileContainingSymbol;
+ }
+ }
+
+ /// <summary>Field number for the "file_containing_extension" field.</summary>
+ public const int FileContainingExtensionFieldNumber = 5;
+ /// <summary>
+ /// Find the proto file which defines an extension extending the given
+ /// message type with the given field number.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.ExtensionRequest FileContainingExtension {
+ get { return messageRequestCase_ == MessageRequestOneofCase.FileContainingExtension ? (global::Grpc.Reflection.V1Alpha.ExtensionRequest) messageRequest_ : null; }
+ set {
+ messageRequest_ = value;
+ messageRequestCase_ = value == null ? MessageRequestOneofCase.None : MessageRequestOneofCase.FileContainingExtension;
+ }
+ }
+
+ /// <summary>Field number for the "all_extension_numbers_of_type" field.</summary>
+ public const int AllExtensionNumbersOfTypeFieldNumber = 6;
+ /// <summary>
+ /// Finds the tag numbers used by all known extensions of the given message
+ /// type, and appends them to ExtensionNumberResponse in an undefined order.
+ /// Its corresponding method is best-effort: it's not guaranteed that the
+ /// reflection service will implement this method, and it's not guaranteed
+ /// that this method will provide all extensions. Returns
+ /// StatusCode::UNIMPLEMENTED if it's not implemented.
+ /// This field should be a fully-qualified type name. The format is
+ /// &lt;package>.&lt;type>
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string AllExtensionNumbersOfType {
+ get { return messageRequestCase_ == MessageRequestOneofCase.AllExtensionNumbersOfType ? (string) messageRequest_ : ""; }
+ set {
+ messageRequest_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ messageRequestCase_ = MessageRequestOneofCase.AllExtensionNumbersOfType;
+ }
+ }
+
+ /// <summary>Field number for the "list_services" field.</summary>
+ public const int ListServicesFieldNumber = 7;
+ /// <summary>
+ /// List the full names of registered services. The content will not be
+ /// checked.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ListServices {
+ get { return messageRequestCase_ == MessageRequestOneofCase.ListServices ? (string) messageRequest_ : ""; }
+ set {
+ messageRequest_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ messageRequestCase_ = MessageRequestOneofCase.ListServices;
+ }
+ }
+
+ private object messageRequest_;
+ /// <summary>Enum of possible cases for the "message_request" oneof.</summary>
+ public enum MessageRequestOneofCase {
+ None = 0,
+ FileByFilename = 3,
+ FileContainingSymbol = 4,
+ FileContainingExtension = 5,
+ AllExtensionNumbersOfType = 6,
+ ListServices = 7,
+ }
+ private MessageRequestOneofCase messageRequestCase_ = MessageRequestOneofCase.None;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public MessageRequestOneofCase MessageRequestCase {
+ get { return messageRequestCase_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void ClearMessageRequest() {
+ messageRequestCase_ = MessageRequestOneofCase.None;
+ messageRequest_ = null;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ServerReflectionRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ServerReflectionRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Host != other.Host) return false;
+ if (FileByFilename != other.FileByFilename) return false;
+ if (FileContainingSymbol != other.FileContainingSymbol) return false;
+ if (!object.Equals(FileContainingExtension, other.FileContainingExtension)) return false;
+ if (AllExtensionNumbersOfType != other.AllExtensionNumbersOfType) return false;
+ if (ListServices != other.ListServices) return false;
+ if (MessageRequestCase != other.MessageRequestCase) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Host.Length != 0) hash ^= Host.GetHashCode();
+ if (messageRequestCase_ == MessageRequestOneofCase.FileByFilename) hash ^= FileByFilename.GetHashCode();
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingSymbol) hash ^= FileContainingSymbol.GetHashCode();
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingExtension) hash ^= FileContainingExtension.GetHashCode();
+ if (messageRequestCase_ == MessageRequestOneofCase.AllExtensionNumbersOfType) hash ^= AllExtensionNumbersOfType.GetHashCode();
+ if (messageRequestCase_ == MessageRequestOneofCase.ListServices) hash ^= ListServices.GetHashCode();
+ hash ^= (int) messageRequestCase_;
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Host.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Host);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileByFilename) {
+ output.WriteRawTag(26);
+ output.WriteString(FileByFilename);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingSymbol) {
+ output.WriteRawTag(34);
+ output.WriteString(FileContainingSymbol);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingExtension) {
+ output.WriteRawTag(42);
+ output.WriteMessage(FileContainingExtension);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.AllExtensionNumbersOfType) {
+ output.WriteRawTag(50);
+ output.WriteString(AllExtensionNumbersOfType);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.ListServices) {
+ output.WriteRawTag(58);
+ output.WriteString(ListServices);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Host.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Host);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileByFilename) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(FileByFilename);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingSymbol) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(FileContainingSymbol);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingExtension) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(FileContainingExtension);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.AllExtensionNumbersOfType) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(AllExtensionNumbersOfType);
+ }
+ if (messageRequestCase_ == MessageRequestOneofCase.ListServices) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ListServices);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ServerReflectionRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Host.Length != 0) {
+ Host = other.Host;
+ }
+ switch (other.MessageRequestCase) {
+ case MessageRequestOneofCase.FileByFilename:
+ FileByFilename = other.FileByFilename;
+ break;
+ case MessageRequestOneofCase.FileContainingSymbol:
+ FileContainingSymbol = other.FileContainingSymbol;
+ break;
+ case MessageRequestOneofCase.FileContainingExtension:
+ FileContainingExtension = other.FileContainingExtension;
+ break;
+ case MessageRequestOneofCase.AllExtensionNumbersOfType:
+ AllExtensionNumbersOfType = other.AllExtensionNumbersOfType;
+ break;
+ case MessageRequestOneofCase.ListServices:
+ ListServices = other.ListServices;
+ break;
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Host = input.ReadString();
+ break;
+ }
+ case 26: {
+ FileByFilename = input.ReadString();
+ break;
+ }
+ case 34: {
+ FileContainingSymbol = input.ReadString();
+ break;
+ }
+ case 42: {
+ global::Grpc.Reflection.V1Alpha.ExtensionRequest subBuilder = new global::Grpc.Reflection.V1Alpha.ExtensionRequest();
+ if (messageRequestCase_ == MessageRequestOneofCase.FileContainingExtension) {
+ subBuilder.MergeFrom(FileContainingExtension);
+ }
+ input.ReadMessage(subBuilder);
+ FileContainingExtension = subBuilder;
+ break;
+ }
+ case 50: {
+ AllExtensionNumbersOfType = input.ReadString();
+ break;
+ }
+ case 58: {
+ ListServices = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// The type name and extension number sent by the client when requesting
+ /// file_containing_extension.
+ /// </summary>
+ public sealed partial class ExtensionRequest : pb::IMessage<ExtensionRequest> {
+ private static readonly pb::MessageParser<ExtensionRequest> _parser = new pb::MessageParser<ExtensionRequest>(() => new ExtensionRequest());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ExtensionRequest> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[1]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionRequest() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionRequest(ExtensionRequest other) : this() {
+ containingType_ = other.containingType_;
+ extensionNumber_ = other.extensionNumber_;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionRequest Clone() {
+ return new ExtensionRequest(this);
+ }
+
+ /// <summary>Field number for the "containing_type" field.</summary>
+ public const int ContainingTypeFieldNumber = 1;
+ private string containingType_ = "";
+ /// <summary>
+ /// Fully-qualified type name. The format should be &lt;package>.&lt;type>
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ContainingType {
+ get { return containingType_; }
+ set {
+ containingType_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "extension_number" field.</summary>
+ public const int ExtensionNumberFieldNumber = 2;
+ private int extensionNumber_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int ExtensionNumber {
+ get { return extensionNumber_; }
+ set {
+ extensionNumber_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ExtensionRequest);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ExtensionRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ContainingType != other.ContainingType) return false;
+ if (ExtensionNumber != other.ExtensionNumber) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ContainingType.Length != 0) hash ^= ContainingType.GetHashCode();
+ if (ExtensionNumber != 0) hash ^= ExtensionNumber.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ContainingType.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(ContainingType);
+ }
+ if (ExtensionNumber != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(ExtensionNumber);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (ContainingType.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ContainingType);
+ }
+ if (ExtensionNumber != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ExtensionNumber);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ExtensionRequest other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ContainingType.Length != 0) {
+ ContainingType = other.ContainingType;
+ }
+ if (other.ExtensionNumber != 0) {
+ ExtensionNumber = other.ExtensionNumber;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ ContainingType = input.ReadString();
+ break;
+ }
+ case 16: {
+ ExtensionNumber = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// The message sent by the server to answer ServerReflectionInfo method.
+ /// </summary>
+ public sealed partial class ServerReflectionResponse : pb::IMessage<ServerReflectionResponse> {
+ private static readonly pb::MessageParser<ServerReflectionResponse> _parser = new pb::MessageParser<ServerReflectionResponse>(() => new ServerReflectionResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ServerReflectionResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[2]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionResponse(ServerReflectionResponse other) : this() {
+ validHost_ = other.validHost_;
+ OriginalRequest = other.originalRequest_ != null ? other.OriginalRequest.Clone() : null;
+ switch (other.MessageResponseCase) {
+ case MessageResponseOneofCase.FileDescriptorResponse:
+ FileDescriptorResponse = other.FileDescriptorResponse.Clone();
+ break;
+ case MessageResponseOneofCase.AllExtensionNumbersResponse:
+ AllExtensionNumbersResponse = other.AllExtensionNumbersResponse.Clone();
+ break;
+ case MessageResponseOneofCase.ListServicesResponse:
+ ListServicesResponse = other.ListServicesResponse.Clone();
+ break;
+ case MessageResponseOneofCase.ErrorResponse:
+ ErrorResponse = other.ErrorResponse.Clone();
+ break;
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServerReflectionResponse Clone() {
+ return new ServerReflectionResponse(this);
+ }
+
+ /// <summary>Field number for the "valid_host" field.</summary>
+ public const int ValidHostFieldNumber = 1;
+ private string validHost_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ValidHost {
+ get { return validHost_; }
+ set {
+ validHost_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "original_request" field.</summary>
+ public const int OriginalRequestFieldNumber = 2;
+ private global::Grpc.Reflection.V1Alpha.ServerReflectionRequest originalRequest_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.ServerReflectionRequest OriginalRequest {
+ get { return originalRequest_; }
+ set {
+ originalRequest_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "file_descriptor_response" field.</summary>
+ public const int FileDescriptorResponseFieldNumber = 4;
+ /// <summary>
+ /// This message is used to answer file_by_filename, file_containing_symbol,
+ /// file_containing_extension requests with transitive dependencies. As
+ /// the repeated label is not allowed in oneof fields, we use a
+ /// FileDescriptorResponse message to encapsulate the repeated fields.
+ /// The reflection service is allowed to avoid sending FileDescriptorProtos
+ /// that were previously sent in response to earlier requests in the stream.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.FileDescriptorResponse FileDescriptorResponse {
+ get { return messageResponseCase_ == MessageResponseOneofCase.FileDescriptorResponse ? (global::Grpc.Reflection.V1Alpha.FileDescriptorResponse) messageResponse_ : null; }
+ set {
+ messageResponse_ = value;
+ messageResponseCase_ = value == null ? MessageResponseOneofCase.None : MessageResponseOneofCase.FileDescriptorResponse;
+ }
+ }
+
+ /// <summary>Field number for the "all_extension_numbers_response" field.</summary>
+ public const int AllExtensionNumbersResponseFieldNumber = 5;
+ /// <summary>
+ /// This message is used to answer all_extension_numbers_of_type requst.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse AllExtensionNumbersResponse {
+ get { return messageResponseCase_ == MessageResponseOneofCase.AllExtensionNumbersResponse ? (global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse) messageResponse_ : null; }
+ set {
+ messageResponse_ = value;
+ messageResponseCase_ = value == null ? MessageResponseOneofCase.None : MessageResponseOneofCase.AllExtensionNumbersResponse;
+ }
+ }
+
+ /// <summary>Field number for the "list_services_response" field.</summary>
+ public const int ListServicesResponseFieldNumber = 6;
+ /// <summary>
+ /// This message is used to answer list_services request.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.ListServiceResponse ListServicesResponse {
+ get { return messageResponseCase_ == MessageResponseOneofCase.ListServicesResponse ? (global::Grpc.Reflection.V1Alpha.ListServiceResponse) messageResponse_ : null; }
+ set {
+ messageResponse_ = value;
+ messageResponseCase_ = value == null ? MessageResponseOneofCase.None : MessageResponseOneofCase.ListServicesResponse;
+ }
+ }
+
+ /// <summary>Field number for the "error_response" field.</summary>
+ public const int ErrorResponseFieldNumber = 7;
+ /// <summary>
+ /// This message is used when an error occurs.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public global::Grpc.Reflection.V1Alpha.ErrorResponse ErrorResponse {
+ get { return messageResponseCase_ == MessageResponseOneofCase.ErrorResponse ? (global::Grpc.Reflection.V1Alpha.ErrorResponse) messageResponse_ : null; }
+ set {
+ messageResponse_ = value;
+ messageResponseCase_ = value == null ? MessageResponseOneofCase.None : MessageResponseOneofCase.ErrorResponse;
+ }
+ }
+
+ private object messageResponse_;
+ /// <summary>Enum of possible cases for the "message_response" oneof.</summary>
+ public enum MessageResponseOneofCase {
+ None = 0,
+ FileDescriptorResponse = 4,
+ AllExtensionNumbersResponse = 5,
+ ListServicesResponse = 6,
+ ErrorResponse = 7,
+ }
+ private MessageResponseOneofCase messageResponseCase_ = MessageResponseOneofCase.None;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public MessageResponseOneofCase MessageResponseCase {
+ get { return messageResponseCase_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void ClearMessageResponse() {
+ messageResponseCase_ = MessageResponseOneofCase.None;
+ messageResponse_ = null;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ServerReflectionResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ServerReflectionResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ValidHost != other.ValidHost) return false;
+ if (!object.Equals(OriginalRequest, other.OriginalRequest)) return false;
+ if (!object.Equals(FileDescriptorResponse, other.FileDescriptorResponse)) return false;
+ if (!object.Equals(AllExtensionNumbersResponse, other.AllExtensionNumbersResponse)) return false;
+ if (!object.Equals(ListServicesResponse, other.ListServicesResponse)) return false;
+ if (!object.Equals(ErrorResponse, other.ErrorResponse)) return false;
+ if (MessageResponseCase != other.MessageResponseCase) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ValidHost.Length != 0) hash ^= ValidHost.GetHashCode();
+ if (originalRequest_ != null) hash ^= OriginalRequest.GetHashCode();
+ if (messageResponseCase_ == MessageResponseOneofCase.FileDescriptorResponse) hash ^= FileDescriptorResponse.GetHashCode();
+ if (messageResponseCase_ == MessageResponseOneofCase.AllExtensionNumbersResponse) hash ^= AllExtensionNumbersResponse.GetHashCode();
+ if (messageResponseCase_ == MessageResponseOneofCase.ListServicesResponse) hash ^= ListServicesResponse.GetHashCode();
+ if (messageResponseCase_ == MessageResponseOneofCase.ErrorResponse) hash ^= ErrorResponse.GetHashCode();
+ hash ^= (int) messageResponseCase_;
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ValidHost.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(ValidHost);
+ }
+ if (originalRequest_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(OriginalRequest);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.FileDescriptorResponse) {
+ output.WriteRawTag(34);
+ output.WriteMessage(FileDescriptorResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.AllExtensionNumbersResponse) {
+ output.WriteRawTag(42);
+ output.WriteMessage(AllExtensionNumbersResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.ListServicesResponse) {
+ output.WriteRawTag(50);
+ output.WriteMessage(ListServicesResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.ErrorResponse) {
+ output.WriteRawTag(58);
+ output.WriteMessage(ErrorResponse);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (ValidHost.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ValidHost);
+ }
+ if (originalRequest_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(OriginalRequest);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.FileDescriptorResponse) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(FileDescriptorResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.AllExtensionNumbersResponse) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(AllExtensionNumbersResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.ListServicesResponse) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ListServicesResponse);
+ }
+ if (messageResponseCase_ == MessageResponseOneofCase.ErrorResponse) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ErrorResponse);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ServerReflectionResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ValidHost.Length != 0) {
+ ValidHost = other.ValidHost;
+ }
+ if (other.originalRequest_ != null) {
+ if (originalRequest_ == null) {
+ originalRequest_ = new global::Grpc.Reflection.V1Alpha.ServerReflectionRequest();
+ }
+ OriginalRequest.MergeFrom(other.OriginalRequest);
+ }
+ switch (other.MessageResponseCase) {
+ case MessageResponseOneofCase.FileDescriptorResponse:
+ FileDescriptorResponse = other.FileDescriptorResponse;
+ break;
+ case MessageResponseOneofCase.AllExtensionNumbersResponse:
+ AllExtensionNumbersResponse = other.AllExtensionNumbersResponse;
+ break;
+ case MessageResponseOneofCase.ListServicesResponse:
+ ListServicesResponse = other.ListServicesResponse;
+ break;
+ case MessageResponseOneofCase.ErrorResponse:
+ ErrorResponse = other.ErrorResponse;
+ break;
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ ValidHost = input.ReadString();
+ break;
+ }
+ case 18: {
+ if (originalRequest_ == null) {
+ originalRequest_ = new global::Grpc.Reflection.V1Alpha.ServerReflectionRequest();
+ }
+ input.ReadMessage(originalRequest_);
+ break;
+ }
+ case 34: {
+ global::Grpc.Reflection.V1Alpha.FileDescriptorResponse subBuilder = new global::Grpc.Reflection.V1Alpha.FileDescriptorResponse();
+ if (messageResponseCase_ == MessageResponseOneofCase.FileDescriptorResponse) {
+ subBuilder.MergeFrom(FileDescriptorResponse);
+ }
+ input.ReadMessage(subBuilder);
+ FileDescriptorResponse = subBuilder;
+ break;
+ }
+ case 42: {
+ global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse subBuilder = new global::Grpc.Reflection.V1Alpha.ExtensionNumberResponse();
+ if (messageResponseCase_ == MessageResponseOneofCase.AllExtensionNumbersResponse) {
+ subBuilder.MergeFrom(AllExtensionNumbersResponse);
+ }
+ input.ReadMessage(subBuilder);
+ AllExtensionNumbersResponse = subBuilder;
+ break;
+ }
+ case 50: {
+ global::Grpc.Reflection.V1Alpha.ListServiceResponse subBuilder = new global::Grpc.Reflection.V1Alpha.ListServiceResponse();
+ if (messageResponseCase_ == MessageResponseOneofCase.ListServicesResponse) {
+ subBuilder.MergeFrom(ListServicesResponse);
+ }
+ input.ReadMessage(subBuilder);
+ ListServicesResponse = subBuilder;
+ break;
+ }
+ case 58: {
+ global::Grpc.Reflection.V1Alpha.ErrorResponse subBuilder = new global::Grpc.Reflection.V1Alpha.ErrorResponse();
+ if (messageResponseCase_ == MessageResponseOneofCase.ErrorResponse) {
+ subBuilder.MergeFrom(ErrorResponse);
+ }
+ input.ReadMessage(subBuilder);
+ ErrorResponse = subBuilder;
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// Serialized FileDescriptorProto messages sent by the server answering
+ /// a file_by_filename, file_containing_symbol, or file_containing_extension
+ /// request.
+ /// </summary>
+ public sealed partial class FileDescriptorResponse : pb::IMessage<FileDescriptorResponse> {
+ private static readonly pb::MessageParser<FileDescriptorResponse> _parser = new pb::MessageParser<FileDescriptorResponse>(() => new FileDescriptorResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<FileDescriptorResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[3]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public FileDescriptorResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public FileDescriptorResponse(FileDescriptorResponse other) : this() {
+ fileDescriptorProto_ = other.fileDescriptorProto_.Clone();
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public FileDescriptorResponse Clone() {
+ return new FileDescriptorResponse(this);
+ }
+
+ /// <summary>Field number for the "file_descriptor_proto" field.</summary>
+ public const int FileDescriptorProtoFieldNumber = 1;
+ private static readonly pb::FieldCodec<pb::ByteString> _repeated_fileDescriptorProto_codec
+ = pb::FieldCodec.ForBytes(10);
+ private readonly pbc::RepeatedField<pb::ByteString> fileDescriptorProto_ = new pbc::RepeatedField<pb::ByteString>();
+ /// <summary>
+ /// Serialized FileDescriptorProto messages. We avoid taking a dependency on
+ /// descriptor.proto, which uses proto2 only features, by making them opaque
+ /// bytes instead.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField<pb::ByteString> FileDescriptorProto {
+ get { return fileDescriptorProto_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as FileDescriptorResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(FileDescriptorResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!fileDescriptorProto_.Equals(other.fileDescriptorProto_)) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= fileDescriptorProto_.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ fileDescriptorProto_.WriteTo(output, _repeated_fileDescriptorProto_codec);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += fileDescriptorProto_.CalculateSize(_repeated_fileDescriptorProto_codec);
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(FileDescriptorResponse other) {
+ if (other == null) {
+ return;
+ }
+ fileDescriptorProto_.Add(other.fileDescriptorProto_);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ fileDescriptorProto_.AddEntriesFrom(input, _repeated_fileDescriptorProto_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// A list of extension numbers sent by the server answering
+ /// all_extension_numbers_of_type request.
+ /// </summary>
+ public sealed partial class ExtensionNumberResponse : pb::IMessage<ExtensionNumberResponse> {
+ private static readonly pb::MessageParser<ExtensionNumberResponse> _parser = new pb::MessageParser<ExtensionNumberResponse>(() => new ExtensionNumberResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ExtensionNumberResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[4]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionNumberResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionNumberResponse(ExtensionNumberResponse other) : this() {
+ baseTypeName_ = other.baseTypeName_;
+ extensionNumber_ = other.extensionNumber_.Clone();
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ExtensionNumberResponse Clone() {
+ return new ExtensionNumberResponse(this);
+ }
+
+ /// <summary>Field number for the "base_type_name" field.</summary>
+ public const int BaseTypeNameFieldNumber = 1;
+ private string baseTypeName_ = "";
+ /// <summary>
+ /// Full name of the base type, including the package name. The format
+ /// is &lt;package>.&lt;type>
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string BaseTypeName {
+ get { return baseTypeName_; }
+ set {
+ baseTypeName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ /// <summary>Field number for the "extension_number" field.</summary>
+ public const int ExtensionNumberFieldNumber = 2;
+ private static readonly pb::FieldCodec<int> _repeated_extensionNumber_codec
+ = pb::FieldCodec.ForInt32(18);
+ private readonly pbc::RepeatedField<int> extensionNumber_ = new pbc::RepeatedField<int>();
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField<int> ExtensionNumber {
+ get { return extensionNumber_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ExtensionNumberResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ExtensionNumberResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (BaseTypeName != other.BaseTypeName) return false;
+ if(!extensionNumber_.Equals(other.extensionNumber_)) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (BaseTypeName.Length != 0) hash ^= BaseTypeName.GetHashCode();
+ hash ^= extensionNumber_.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (BaseTypeName.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(BaseTypeName);
+ }
+ extensionNumber_.WriteTo(output, _repeated_extensionNumber_codec);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (BaseTypeName.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(BaseTypeName);
+ }
+ size += extensionNumber_.CalculateSize(_repeated_extensionNumber_codec);
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ExtensionNumberResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.BaseTypeName.Length != 0) {
+ BaseTypeName = other.BaseTypeName;
+ }
+ extensionNumber_.Add(other.extensionNumber_);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ BaseTypeName = input.ReadString();
+ break;
+ }
+ case 18:
+ case 16: {
+ extensionNumber_.AddEntriesFrom(input, _repeated_extensionNumber_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// A list of ServiceResponse sent by the server answering list_services request.
+ /// </summary>
+ public sealed partial class ListServiceResponse : pb::IMessage<ListServiceResponse> {
+ private static readonly pb::MessageParser<ListServiceResponse> _parser = new pb::MessageParser<ListServiceResponse>(() => new ListServiceResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ListServiceResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[5]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListServiceResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListServiceResponse(ListServiceResponse other) : this() {
+ service_ = other.service_.Clone();
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ListServiceResponse Clone() {
+ return new ListServiceResponse(this);
+ }
+
+ /// <summary>Field number for the "service" field.</summary>
+ public const int ServiceFieldNumber = 1;
+ private static readonly pb::FieldCodec<global::Grpc.Reflection.V1Alpha.ServiceResponse> _repeated_service_codec
+ = pb::FieldCodec.ForMessage(10, global::Grpc.Reflection.V1Alpha.ServiceResponse.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Reflection.V1Alpha.ServiceResponse> service_ = new pbc::RepeatedField<global::Grpc.Reflection.V1Alpha.ServiceResponse>();
+ /// <summary>
+ /// The information of each service may be expanded in the future, so we use
+ /// ServiceResponse message to encapsulate it.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public pbc::RepeatedField<global::Grpc.Reflection.V1Alpha.ServiceResponse> Service {
+ get { return service_; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ListServiceResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ListServiceResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if(!service_.Equals(other.service_)) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ hash ^= service_.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ service_.WriteTo(output, _repeated_service_codec);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ size += service_.CalculateSize(_repeated_service_codec);
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ListServiceResponse other) {
+ if (other == null) {
+ return;
+ }
+ service_.Add(other.service_);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ service_.AddEntriesFrom(input, _repeated_service_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// The information of a single service used by ListServiceResponse to answer
+ /// list_services request.
+ /// </summary>
+ public sealed partial class ServiceResponse : pb::IMessage<ServiceResponse> {
+ private static readonly pb::MessageParser<ServiceResponse> _parser = new pb::MessageParser<ServiceResponse>(() => new ServiceResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ServiceResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[6]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServiceResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServiceResponse(ServiceResponse other) : this() {
+ name_ = other.name_;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ServiceResponse Clone() {
+ return new ServiceResponse(this);
+ }
+
+ /// <summary>Field number for the "name" field.</summary>
+ public const int NameFieldNumber = 1;
+ private string name_ = "";
+ /// <summary>
+ /// Full name of a registered service, including its package name. The format
+ /// is &lt;package>.&lt;service>
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string Name {
+ get { return name_; }
+ set {
+ name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ServiceResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ServiceResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Name != other.Name) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Name.Length != 0) hash ^= Name.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Name.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Name);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (Name.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ServiceResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Name.Length != 0) {
+ Name = other.Name;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Name = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ /// <summary>
+ /// The error code and error message sent by the server when an error occurs.
+ /// </summary>
+ public sealed partial class ErrorResponse : pb::IMessage<ErrorResponse> {
+ private static readonly pb::MessageParser<ErrorResponse> _parser = new pb::MessageParser<ErrorResponse>(() => new ErrorResponse());
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pb::MessageParser<ErrorResponse> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.MessageTypes[7]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ErrorResponse() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ErrorResponse(ErrorResponse other) : this() {
+ errorCode_ = other.errorCode_;
+ errorMessage_ = other.errorMessage_;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public ErrorResponse Clone() {
+ return new ErrorResponse(this);
+ }
+
+ /// <summary>Field number for the "error_code" field.</summary>
+ public const int ErrorCodeFieldNumber = 1;
+ private int errorCode_;
+ /// <summary>
+ /// This field uses the error codes defined in grpc::StatusCode.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int ErrorCode {
+ get { return errorCode_; }
+ set {
+ errorCode_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "error_message" field.</summary>
+ public const int ErrorMessageFieldNumber = 2;
+ private string errorMessage_ = "";
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public string ErrorMessage {
+ get { return errorMessage_; }
+ set {
+ errorMessage_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override bool Equals(object other) {
+ return Equals(other as ErrorResponse);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public bool Equals(ErrorResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (ErrorCode != other.ErrorCode) return false;
+ if (ErrorMessage != other.ErrorMessage) return false;
+ return true;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ErrorCode != 0) hash ^= ErrorCode.GetHashCode();
+ if (ErrorMessage.Length != 0) hash ^= ErrorMessage.GetHashCode();
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ErrorCode != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(ErrorCode);
+ }
+ if (ErrorMessage.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(ErrorMessage);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public int CalculateSize() {
+ int size = 0;
+ if (ErrorCode != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ErrorCode);
+ }
+ if (ErrorMessage.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(ErrorMessage);
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(ErrorResponse other) {
+ if (other == null) {
+ return;
+ }
+ if (other.ErrorCode != 0) {
+ ErrorCode = other.ErrorCode;
+ }
+ if (other.ErrorMessage.Length != 0) {
+ ErrorMessage = other.ErrorMessage;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ ErrorCode = input.ReadInt32();
+ break;
+ }
+ case 18: {
+ ErrorMessage = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
new file mode 100644
index 0000000000..1b6f96ce7c
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
@@ -0,0 +1,132 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: grpc/reflection/v1alpha/reflection.proto
+// Original file comments:
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Service exported by server reflection
+//
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Reflection.V1Alpha {
+ public static partial class ServerReflection
+ {
+ static readonly string __ServiceName = "grpc.reflection.v1alpha.ServerReflection";
+
+ static readonly Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> __Marshaller_ServerReflectionRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Marshaller_ServerReflectionResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Reflection.V1Alpha.ServerReflectionResponse.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> __Method_ServerReflectionInfo = new Method<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse>(
+ MethodType.DuplexStreaming,
+ __ServiceName,
+ "ServerReflectionInfo",
+ __Marshaller_ServerReflectionRequest,
+ __Marshaller_ServerReflectionResponse);
+
+ /// <summary>Service descriptor</summary>
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Reflection.V1Alpha.ReflectionReflection.Descriptor.Services[0]; }
+ }
+
+ /// <summary>Base class for server-side implementations of ServerReflection</summary>
+ public abstract partial class ServerReflectionBase
+ {
+ /// <summary>
+ /// The reflection service is structured as a bidirectional stream, ensuring
+ /// all related requests go to a single server.
+ /// </summary>
+ public virtual global::System.Threading.Tasks.Task ServerReflectionInfo(IAsyncStreamReader<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> requestStream, IServerStreamWriter<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> responseStream, ServerCallContext context)
+ {
+ throw new RpcException(new Status(StatusCode.Unimplemented, ""));
+ }
+
+ }
+
+ /// <summary>Client for ServerReflection</summary>
+ public partial class ServerReflectionClient : ClientBase<ServerReflectionClient>
+ {
+ /// <summary>Creates a new client for ServerReflection</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
+ public ServerReflectionClient(Channel channel) : base(channel)
+ {
+ }
+ /// <summary>Creates a new client for ServerReflection that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
+ public ServerReflectionClient(CallInvoker callInvoker) : base(callInvoker)
+ {
+ }
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ protected ServerReflectionClient() : base()
+ {
+ }
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
+ protected ServerReflectionClient(ClientBaseConfiguration configuration) : base(configuration)
+ {
+ }
+
+ /// <summary>
+ /// The reflection service is structured as a bidirectional stream, ensuring
+ /// all related requests go to a single server.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ return ServerReflectionInfo(new CallOptions(headers, deadline, cancellationToken));
+ }
+ /// <summary>
+ /// The reflection service is structured as a bidirectional stream, ensuring
+ /// all related requests go to a single server.
+ /// </summary>
+ public virtual AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(CallOptions options)
+ {
+ return CallInvoker.AsyncDuplexStreamingCall(__Method_ServerReflectionInfo, null, options);
+ }
+ /// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary>
+ protected override ServerReflectionClient NewInstance(ClientBaseConfiguration configuration)
+ {
+ return new ServerReflectionClient(configuration);
+ }
+ }
+
+ /// <summary>Creates service definition that can be registered with a server</summary>
+ public static ServerServiceDefinition BindService(ServerReflectionBase serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder()
+ .AddMethod(__Method_ServerReflectionInfo, serviceImpl.ServerReflectionInfo).Build();
+ }
+
+ }
+}
+#endregion
diff --git a/src/csharp/Grpc.Reflection/ReflectionServiceImpl.cs b/src/csharp/Grpc.Reflection/ReflectionServiceImpl.cs
new file mode 100644
index 0000000000..105c4c963b
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/ReflectionServiceImpl.cs
@@ -0,0 +1,173 @@
+#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;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Reflection.V1Alpha;
+using Google.Protobuf.Reflection;
+
+namespace Grpc.Reflection
+{
+ /// <summary>
+ /// Implementation of server reflection service.
+ /// </summary>
+ public class ReflectionServiceImpl : Grpc.Reflection.V1Alpha.ServerReflection.ServerReflectionBase
+ {
+ readonly List<string> services;
+ readonly SymbolRegistry symbolRegistry;
+
+ /// <summary>
+ /// Creates a new instance of <c>ReflectionServiceIml</c>.
+ /// </summary>
+ public ReflectionServiceImpl(IEnumerable<string> services, SymbolRegistry symbolRegistry)
+ {
+ this.services = new List<string>(services);
+ this.symbolRegistry = symbolRegistry;
+ }
+
+ /// <summary>
+ /// Creates a new instance of <c>ReflectionServiceIml</c>.
+ /// </summary>
+ public ReflectionServiceImpl(IEnumerable<ServiceDescriptor> serviceDescriptors)
+ {
+ this.services = new List<string>(serviceDescriptors.Select((serviceDescriptor) => serviceDescriptor.FullName));
+ this.symbolRegistry = SymbolRegistry.FromFiles(serviceDescriptors.Select((serviceDescriptor) => serviceDescriptor.File));
+ }
+
+ /// <summary>
+ /// Creates a new instance of <c>ReflectionServiceIml</c>.
+ /// </summary>
+ public ReflectionServiceImpl(params ServiceDescriptor[] serviceDescriptors) : this((IEnumerable<ServiceDescriptor>) serviceDescriptors)
+ {
+ }
+
+ public override async Task ServerReflectionInfo(IAsyncStreamReader<ServerReflectionRequest> requestStream, IServerStreamWriter<ServerReflectionResponse> responseStream, ServerCallContext context)
+ {
+ while (await requestStream.MoveNext())
+ {
+ var response = ProcessRequest(requestStream.Current);
+ await responseStream.WriteAsync(response);
+ }
+ }
+
+ ServerReflectionResponse ProcessRequest(ServerReflectionRequest request)
+ {
+ switch (request.MessageRequestCase)
+ {
+ case ServerReflectionRequest.MessageRequestOneofCase.FileByFilename:
+ return FileByFilename(request.FileByFilename);
+ case ServerReflectionRequest.MessageRequestOneofCase.FileContainingSymbol:
+ return FileContainingSymbol(request.FileContainingSymbol);
+ case ServerReflectionRequest.MessageRequestOneofCase.ListServices:
+ return ListServices();
+ case ServerReflectionRequest.MessageRequestOneofCase.AllExtensionNumbersOfType:
+ case ServerReflectionRequest.MessageRequestOneofCase.FileContainingExtension:
+ default:
+ return CreateErrorResponse(StatusCode.Unimplemented, "Request type not supported by C# reflection service.");
+ }
+ }
+
+ ServerReflectionResponse FileByFilename(string filename)
+ {
+ FileDescriptor file = symbolRegistry.FileByName(filename);
+ if (file == null)
+ {
+ return CreateErrorResponse(StatusCode.NotFound, "File not found.");
+ }
+
+ var transitiveDependencies = new HashSet<FileDescriptor>();
+ CollectTransitiveDependencies(file, transitiveDependencies);
+
+ return new ServerReflectionResponse
+ {
+ FileDescriptorResponse = new FileDescriptorResponse { FileDescriptorProto = { transitiveDependencies.Select((d) => d.SerializedData) } }
+ };
+ }
+
+ ServerReflectionResponse FileContainingSymbol(string symbol)
+ {
+ FileDescriptor file = symbolRegistry.FileContainingSymbol(symbol);
+ if (file == null)
+ {
+ return CreateErrorResponse(StatusCode.NotFound, "Symbol not found.");
+ }
+
+ var transitiveDependencies = new HashSet<FileDescriptor>();
+ CollectTransitiveDependencies(file, transitiveDependencies);
+
+ return new ServerReflectionResponse
+ {
+ FileDescriptorResponse = new FileDescriptorResponse { FileDescriptorProto = { transitiveDependencies.Select((d) => d.SerializedData) } }
+ };
+ }
+
+ ServerReflectionResponse ListServices()
+ {
+ var serviceResponses = new ListServiceResponse();
+ foreach (string serviceName in services)
+ {
+ serviceResponses.Service.Add(new ServiceResponse { Name = serviceName });
+ }
+
+ return new ServerReflectionResponse
+ {
+ ListServicesResponse = serviceResponses
+ };
+ }
+
+ ServerReflectionResponse CreateErrorResponse(StatusCode status, string message)
+ {
+ return new ServerReflectionResponse
+ {
+ ErrorResponse = new ErrorResponse { ErrorCode = (int) status, ErrorMessage = message }
+ };
+ }
+
+ void CollectTransitiveDependencies(FileDescriptor descriptor, HashSet<FileDescriptor> pool)
+ {
+ pool.Add(descriptor);
+ foreach (var dependency in descriptor.Dependencies)
+ {
+ if (pool.Add(dependency))
+ {
+ // descriptors cannot have circular dependencies
+ CollectTransitiveDependencies(dependency, pool);
+ }
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection/Settings.StyleCop b/src/csharp/Grpc.Reflection/Settings.StyleCop
new file mode 100644
index 0000000000..2942add962
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/Settings.StyleCop
@@ -0,0 +1,10 @@
+<StyleCopSettings Version="105">
+ <SourceFileList>
+ <SourceFile>Health.cs</SourceFile>
+ <Settings>
+ <GlobalSettings>
+ <BooleanProperty Name="RulesEnabledByDefault">False</BooleanProperty>
+ </GlobalSettings>
+ </Settings>
+ </SourceFileList>
+</StyleCopSettings>
diff --git a/src/csharp/Grpc.Reflection/SymbolRegistry.cs b/src/csharp/Grpc.Reflection/SymbolRegistry.cs
new file mode 100644
index 0000000000..b7104ab2f9
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/SymbolRegistry.cs
@@ -0,0 +1,160 @@
+#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.Collections.Generic;
+using Grpc.Core.Utils;
+using Google.Protobuf.Reflection;
+
+namespace Grpc.Reflection
+{
+ /// <summary>Registry of protobuf symbols</summary>
+ public class SymbolRegistry
+ {
+ private readonly Dictionary<string, FileDescriptor> filesByName;
+ private readonly Dictionary<string, FileDescriptor> filesBySymbol;
+
+ private SymbolRegistry(Dictionary<string, FileDescriptor> filesByName, Dictionary<string, FileDescriptor> filesBySymbol)
+ {
+ this.filesByName = new Dictionary<string, FileDescriptor>(filesByName);
+ this.filesBySymbol = new Dictionary<string, FileDescriptor>(filesBySymbol);
+ }
+
+ /// <summary>
+ /// Creates a symbol registry from the specified set of file descriptors.
+ /// </summary>
+ /// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
+ /// <returns>A symbol registry for the given files.</returns>
+ public static SymbolRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors)
+ {
+ GrpcPreconditions.CheckNotNull(fileDescriptors);
+ var builder = new Builder();
+ foreach (var file in fileDescriptors)
+ {
+ builder.AddFile(file);
+ }
+ return builder.Build();
+ }
+
+ /// <summary>
+ /// Gets file descriptor for given file name (including package path). Returns <c>null</c> if not found.
+ /// </summary>
+ public FileDescriptor FileByName(string filename)
+ {
+ FileDescriptor file;
+ filesByName.TryGetValue(filename, out file);
+ return file;
+ }
+
+ /// <summary>
+ /// Gets file descriptor that contains definition of given symbol full name (including package path). Returns <c>null</c> if not found.
+ /// </summary>
+ public FileDescriptor FileContainingSymbol(string symbol)
+ {
+ FileDescriptor file;
+ filesBySymbol.TryGetValue(symbol, out file);
+ return file;
+ }
+
+ /// <summary>
+ /// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
+ /// </summary>
+ private class Builder
+ {
+ private readonly Dictionary<string, FileDescriptor> filesByName;
+ private readonly Dictionary<string, FileDescriptor> filesBySymbol;
+
+
+ internal Builder()
+ {
+ filesByName = new Dictionary<string, FileDescriptor>();
+ filesBySymbol = new Dictionary<string, FileDescriptor>();
+ }
+
+ internal void AddFile(FileDescriptor fileDescriptor)
+ {
+ if (filesByName.ContainsKey(fileDescriptor.Name))
+ {
+ return;
+ }
+ filesByName.Add(fileDescriptor.Name, fileDescriptor);
+
+ foreach (var dependency in fileDescriptor.Dependencies)
+ {
+ AddFile(dependency);
+ }
+ foreach (var enumeration in fileDescriptor.EnumTypes)
+ {
+ AddEnum(enumeration);
+ }
+ foreach (var message in fileDescriptor.MessageTypes)
+ {
+ AddMessage(message);
+ }
+ foreach (var service in fileDescriptor.Services)
+ {
+ AddService(service);
+ }
+ }
+
+ private void AddEnum(EnumDescriptor enumDescriptor)
+ {
+ filesBySymbol[enumDescriptor.FullName] = enumDescriptor.File;
+ }
+
+ private void AddMessage(MessageDescriptor messageDescriptor)
+ {
+ foreach (var nestedEnum in messageDescriptor.EnumTypes)
+ {
+ AddEnum(nestedEnum);
+ }
+ foreach (var nestedType in messageDescriptor.NestedTypes)
+ {
+ AddMessage(nestedType);
+ }
+ filesBySymbol[messageDescriptor.FullName] = messageDescriptor.File;
+ }
+
+ private void AddService(ServiceDescriptor serviceDescriptor)
+ {
+ foreach (var method in serviceDescriptor.Methods)
+ {
+ filesBySymbol[method.FullName] = method.File;
+ }
+ filesBySymbol[serviceDescriptor.FullName] = serviceDescriptor.File;
+ }
+
+ internal SymbolRegistry Build()
+ {
+ return new SymbolRegistry(filesByName, filesBySymbol);
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Reflection/packages.config b/src/csharp/Grpc.Reflection/packages.config
new file mode 100644
index 0000000000..5ab40b7a8c
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Google.Protobuf" version="3.0.0" targetFramework="net45" />
+ <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection/project.json b/src/csharp/Grpc.Reflection/project.json
new file mode 100644
index 0000000000..2fe617cc7a
--- /dev/null
+++ b/src/csharp/Grpc.Reflection/project.json
@@ -0,0 +1,40 @@
+{
+ "version": "1.1.0-dev",
+ "title": "gRPC C# Reflection",
+ "authors": [ "Google Inc." ],
+ "copyright": "Copyright 2016, Google Inc.",
+ "packOptions": {
+ "summary": "Implementation of gRPC reflection service",
+ "description": "Provides information about services running on a gRPC C# server.",
+ "owners": [ "grpc-packages" ],
+ "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+ "projectUrl": "https://github.com/grpc/grpc",
+ "requireLicenseAcceptance": false,
+ "tags": [ "gRPC reflection" ]
+ },
+ "buildOptions": {
+ "define": [ "SIGNED" ],
+ "keyFile": "../keys/Grpc.snk",
+ "xmlDoc": true,
+ "compile": {
+ "includeFiles": [ "../Grpc.Core/Version.cs" ]
+ }
+ },
+ "dependencies": {
+ "Grpc.Core": "1.1.0-dev",
+ "Google.Protobuf": "3.0.0"
+ },
+ "frameworks": {
+ "net45": {
+ "frameworkAssemblies": {
+ "System.Runtime": "",
+ "System.IO": ""
+ }
+ },
+ "netstandard1.5": {
+ "dependencies": {
+ "NETStandard.Library": "1.6.0"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 9be36c0caa..2e6a8fd435 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -36,6 +36,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Qps
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.csproj", "{ADEBA147-80AE-4710-82E9-5B7F93690266}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Reflection", "Grpc.Reflection\Grpc.Reflection.csproj", "{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{B88F91D6-436D-4C78-8B99-47800FA8DE03}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -55,6 +59,12 @@ Global
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -103,6 +113,12 @@ Global
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.Build.0 = Release|Any CPU
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.ActiveCfg = Release|Any CPU
{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.ReleaseSigned|Any CPU.Build.0 = Release|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.ReleaseSigned|Any CPU.ActiveCfg = ReleaseSigned|Any CPU
+ {B88F91D6-436D-4C78-8B99-47800FA8DE03}.ReleaseSigned|Any CPU.Build.0 = ReleaseSigned|Any CPU
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages_dotnetcli.bat
index c0036df13f..9e8c045a1f 100644..100755
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -27,18 +27,17 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-@rem Builds gRPC NuGet packages
-
-@rem This way of building nuget packages is now obsolete. C# nuget packages
-@rem with CoreCLR support are now being built using the dotnet cli
-@rem in build_packages_dotnetcli.sh
-
@rem Current package versions
set VERSION=1.1.0-dev
set PROTOBUF_VERSION=3.0.0
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
+set DOTNET=C:\dotnet\dotnet.exe
+
+set -ex
+
+mkdir -p ..\..\artifacts\
@rem Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this?
@@ -57,32 +56,22 @@ xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* pr
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64\
-@rem Fetch all dependencies
-%NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
-
-setlocal
-
-@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
-
-@rem We won't use the native libraries from this step, but without this Grpc.sln will fail.
-msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error
-
-msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
+%DOTNET% restore . || goto :error
-endlocal
+%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
-%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
-%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
-%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
-%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
+%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
+%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
@rem copy resulting nuget packages to artifacts directory
-xcopy /Y /I *.nupkg ..\..\artifacts\
+xcopy /Y /I *.nupkg ..\..\artifacts\ || goto :error
@rem create a zipfile with the artifacts as well
-powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_obsolete.zip');"
-xcopy /Y /I csharp_nugets_obsolete.zip ..\..\artifacts\
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets_windows_dotnetcli.zip');"
+xcopy /Y /I csharp_nugets_windows_dotnetcli.zip ..\..\artifacts\ || goto :error
goto :EOF
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 3c127f320b..52cf2f9ddc 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -63,6 +63,7 @@ dotnet restore .
dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
+dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
nuget pack Grpc.nuspec -Version "1.1.0-dev" -OutputDirectory ../../artifacts
nuget pack Grpc.Tools.nuspec -Version "1.1.0-dev" -OutputDirectory ../../artifacts
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 9a5d7869d3..946f5872c0 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -37,7 +37,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include <grpc/support/string_util.h>
#include <grpc/support/thd.h>
#include <grpc/grpc.h>
@@ -59,9 +59,9 @@
#endif
grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
- gpr_slice slice = gpr_slice_from_copied_buffer(buffer, len);
+ grpc_slice slice = grpc_slice_from_copied_buffer(buffer, len);
grpc_byte_buffer *bb = grpc_raw_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
return bb;
}
@@ -282,18 +282,18 @@ GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer(
const grpcsharp_batch_context *ctx, char *buffer, size_t buffer_len) {
grpc_byte_buffer_reader reader;
- gpr_slice slice;
+ grpc_slice slice;
size_t offset = 0;
GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message));
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
- size_t len = GPR_SLICE_LENGTH(slice);
+ size_t len = GRPC_SLICE_LENGTH(slice);
GPR_ASSERT(offset + len <= buffer_len);
- memcpy(buffer + offset, GPR_SLICE_START_PTR(slice),
- GPR_SLICE_LENGTH(slice));
+ memcpy(buffer + offset, GRPC_SLICE_START_PTR(slice),
+ GRPC_SLICE_LENGTH(slice));
offset += len;
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
}
grpc_byte_buffer_reader_destroy(&reader);
@@ -521,8 +521,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
- const char *send_buffer, size_t send_buffer_len,
- grpc_metadata_array *initial_metadata, uint32_t write_flags) {
+ const char *send_buffer, size_t send_buffer_len, uint32_t write_flags,
+ grpc_metadata_array *initial_metadata, uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[6];
memset(ops, 0, sizeof(ops));
@@ -532,7 +532,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
- ops[0].flags = 0;
+ ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
@@ -575,7 +575,8 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_client_streaming(grpc_call *call,
grpcsharp_batch_context *ctx,
- grpc_metadata_array *initial_metadata) {
+ grpc_metadata_array *initial_metadata,
+ uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[4];
memset(ops, 0, sizeof(ops));
@@ -585,7 +586,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
- ops[0].flags = 0;
+ ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
@@ -617,7 +618,8 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer,
- size_t send_buffer_len, grpc_metadata_array *initial_metadata, uint32_t write_flags) {
+ size_t send_buffer_len, uint32_t write_flags,
+ grpc_metadata_array *initial_metadata, uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[4];
memset(ops, 0, sizeof(ops));
@@ -627,7 +629,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
- ops[0].flags = 0;
+ ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_MESSAGE;
@@ -660,7 +662,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
GPR_EXPORT grpc_call_error GPR_CALLTYPE
grpcsharp_call_start_duplex_streaming(grpc_call *call,
grpcsharp_batch_context *ctx,
- grpc_metadata_array *initial_metadata) {
+ grpc_metadata_array *initial_metadata,
+ uint32_t initial_metadata_flags) {
/* TODO: don't use magic number */
grpc_op ops[2];
memset(ops, 0, sizeof(ops));
@@ -670,7 +673,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
ops[0].data.send_initial_metadata.count = ctx->send_initial_metadata.count;
ops[0].data.send_initial_metadata.metadata =
ctx->send_initial_metadata.metadata;
- ops[0].flags = 0;
+ ops[0].flags = initial_metadata_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_RECV_STATUS_ON_CLIENT;
@@ -991,7 +994,11 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
grpc_credentials_plugin_metadata_cb cb,
void *user_data, grpc_metadata_array *metadata,
grpc_status_code status, const char *error_details) {
- cb(user_data, metadata->metadata, metadata->count, status, error_details);
+ if (metadata) {
+ cb(user_data, metadata->metadata, metadata->count, status, error_details);
+ } else {
+ cb(user_data, NULL, 0, status, error_details);
+ }
}
typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 79488e02a5..ea5d678cba 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -36,13 +36,20 @@ PROTOC=bins/opt/protobuf/protoc
PLUGIN=protoc-gen-grpc=bins/opt/grpc_csharp_plugin
EXAMPLES_DIR=src/csharp/Grpc.Examples
HEALTHCHECK_DIR=src/csharp/Grpc.HealthCheck
+REFLECTION_DIR=src/csharp/Grpc.Reflection
TESTING_DIR=src/csharp/Grpc.IntegrationTesting
$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
- -I src/proto/math src/proto/math/math.proto
+ -I src/proto src/proto/math/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
- -I src/proto/grpc/health/v1 src/proto/grpc/health/v1/health.proto
+ -I src/proto src/proto/grpc/health/v1/health.proto
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$REFLECTION_DIR --grpc_out=$REFLECTION_DIR \
+ -I src/proto src/proto/grpc/reflection/v1alpha/reflection.proto
+# TODO(jtattermusch): following .proto files are a bit broken and import paths
+# don't match the package names. Setting -I to the correct value src/proto
+# breaks the code generation.
$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
-I . src/proto/grpc/testing/{control,empty,messages,metrics,payloads,services,stats,test}.proto
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index 7e7aee1093..4ce6769eee 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -48,5 +48,9 @@
"Grpc.IntegrationTesting.MetadataCredentialsTest",
"Grpc.IntegrationTesting.RunnerClientServerTest",
"Grpc.IntegrationTesting.SslCredentialsTest"
+ ],
+ "Grpc.Reflection.Tests": [
+ "Grpc.Reflection.Tests.ReflectionClientServerTest",
+ "Grpc.Reflection.Tests.SymbolRegistryTest"
]
} \ No newline at end of file
diff --git a/src/google_benchmark/gen_build_yaml.py b/src/google_benchmark/gen_build_yaml.py
new file mode 100755
index 0000000000..302e08737a
--- /dev/null
+++ b/src/google_benchmark/gen_build_yaml.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import os
+import sys
+import glob
+import yaml
+
+os.chdir(os.path.dirname(sys.argv[0])+'/../..')
+
+out = {}
+
+out['libs'] = [{
+ 'name': 'google_benchmark',
+ 'build': 'private',
+ 'language': 'c++',
+ 'secure': 'no',
+ 'defaults': 'google_benchmark',
+ 'src': sorted(glob.glob('third_party/google_benchmark/src/*.cc')),
+ 'headers': sorted(
+ glob.glob('third_party/google_benchmark/src/*.h') +
+ glob.glob('third_party/google_benchmark/include/benchmark/*.h')),
+}]
+
+print yaml.dump(out)
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index ad7d0ec8c8..fc339fc462 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -37,7 +37,7 @@
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
-#include "grpc/support/slice.h"
+#include "grpc/slice.h"
#include "byte_buffer.h"
@@ -56,10 +56,10 @@ grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
Nan::HandleScope scope;
int length = ::node::Buffer::Length(buffer);
char *data = ::node::Buffer::Data(buffer);
- gpr_slice slice = gpr_slice_malloc(length);
- memcpy(GPR_SLICE_START_PTR(slice), data, length);
+ grpc_slice slice = grpc_slice_malloc(length);
+ memcpy(GRPC_SLICE_START_PTR(slice), data, length);
grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
return byte_buffer;
}
@@ -77,11 +77,11 @@ Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
Nan::ThrowError("Error initializing byte buffer reader.");
return scope.Escape(Nan::Undefined());
}
- gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
- size_t length = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
+ size_t length = GRPC_SLICE_LENGTH(slice);
char *result = new char[length];
- memcpy(result, GPR_SLICE_START_PTR(slice), length);
- gpr_slice_unref(slice);
+ memcpy(result, GRPC_SLICE_START_PTR(slice), length);
+ grpc_slice_unref(slice);
return scope.Escape(MakeFastBuffer(
Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
}
diff --git a/src/node/src/common.js b/src/node/src/common.js
index c6c6d597a8..98eabf5c0b 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -141,8 +141,14 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
binaryAsBase64 = options.binaryAsBase64;
longsAsStrings = options.longsAsStrings;
}
- return _.fromPairs(_.map(service.children, function(method) {
- return [_.camelCase(method.name), {
+ /* This slightly awkward construction is used to make sure we only use
+ lodash@3.10.1-compatible functions. A previous version used
+ _.fromPairs, which would be cleaner, but was introduced in lodash
+ version 4 */
+ return _.zipObject(_.map(service.children, function(method) {
+ return _.camelCase(method.name);
+ }), _.map(service.children, function(method) {
+ return {
path: prefix + method.name,
requestStream: method.requestStream,
responseStream: method.responseStream,
@@ -150,11 +156,11 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
responseType: method.resolvedResponseType,
requestSerialize: serializeCls(method.resolvedRequestType.build()),
requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
- binaryAsBase64, longsAsStrings),
+ binaryAsBase64, longsAsStrings),
responseSerialize: serializeCls(method.resolvedResponseType.build()),
responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
- binaryAsBase64, longsAsStrings)
- }];
+ binaryAsBase64, longsAsStrings)
+ };
}));
};
diff --git a/src/objective-c/GRPCClient/private/NSData+GRPC.m b/src/objective-c/GRPCClient/private/NSData+GRPC.m
index 98337799e9..6d2ad0a3bd 100644
--- a/src/objective-c/GRPCClient/private/NSData+GRPC.m
+++ b/src/objective-c/GRPCClient/private/NSData+GRPC.m
@@ -53,22 +53,22 @@ static void MallocAndCopyByteBufferToCharArray(grpc_byte_buffer *buffer,
}
// The slice contains uncompressed data even if compressed data was received
// because the reader takes care of automatically decompressing it
- gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
- size_t uncompressed_length = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
+ size_t uncompressed_length = GRPC_SLICE_LENGTH(slice);
char *result = malloc(uncompressed_length);
if (result) {
- memcpy(result, GPR_SLICE_START_PTR(slice), uncompressed_length);
+ memcpy(result, GRPC_SLICE_START_PTR(slice), uncompressed_length);
}
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
*array = result;
*length = uncompressed_length;
}
static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array,
size_t length) {
- gpr_slice slice = gpr_slice_from_copied_buffer(array, length);
+ grpc_slice slice = grpc_slice_from_copied_buffer(array, length);
grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
return buffer;
}
@@ -97,9 +97,9 @@ static grpc_byte_buffer *CopyCharArrayToNewByteBuffer(const char *array,
// appending of byte arrays by not using internally a single contiguous memory
// block for representation.
// The following implementation is thus not optimal, sometimes requiring two
- // copies (one by self.bytes and another by gpr_slice_from_copied_buffer).
+ // copies (one by self.bytes and another by grpc_slice_from_copied_buffer).
// If it turns out to be an issue, we can use enumerateByteRangesUsingblock:
- // to create an array of gpr_slice objects to pass to
+ // to create an array of grpc_slice objects to pass to
// grpc_raw_byte_buffer_create.
// That would make it do exactly one copy, always.
return CopyCharArrayToNewByteBuffer((const char *)self.bytes,
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
new file mode 100644
index 0000000000..4a92cc8e0d
--- /dev/null
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
@@ -0,0 +1,405 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/*
+ * This test file is derived from fixture h2_ssl.c in core end2end test
+ * (test/core/end2end/fixture/h2_ssl.c). The structure of the fixture is
+ * preserved as much as possible
+ *
+ * This fixture creates a server full stack using chttp2 and a client
+ * full stack using Cronet. End-to-end tests are run against this
+ * configuration
+ *
+ */
+
+#import <XCTest/XCTest.h>
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/security/credentials/credentials.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
+#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+#import <Cronet/Cronet.h>
+#include <grpc/grpc_cronet.h>
+
+typedef struct fullstack_secure_fixture_data {
+ char *localaddr;
+} fullstack_secure_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
+ grpc_channel_args *client_args, grpc_channel_args *server_args) {
+ grpc_end2end_test_fixture f;
+ int port = grpc_pick_unused_port_or_die();
+ fullstack_secure_fixture_data *ffd =
+ gpr_malloc(sizeof(fullstack_secure_fixture_data));
+ memset(&f, 0, sizeof(f));
+
+ gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
+
+ f.fixture_data = ffd;
+ f.cq = grpc_completion_queue_create(NULL);
+
+ return f;
+}
+
+static void process_auth_failure(void *state, grpc_auth_context *ctx,
+ const grpc_metadata *md, size_t md_count,
+ grpc_process_auth_metadata_done_cb cb,
+ void *user_data) {
+ GPR_ASSERT(state == NULL);
+ cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
+}
+
+static void cronet_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
+ grpc_channel_args *client_args,
+ cronet_engine *cronetEngine) {
+ fullstack_secure_fixture_data *ffd = f->fixture_data;
+ f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr,
+ client_args, NULL);
+ GPR_ASSERT(f->client != NULL);
+}
+
+static void chttp2_init_server_secure_fullstack(
+ grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
+ grpc_server_credentials *server_creds) {
+ fullstack_secure_fixture_data *ffd = f->fixture_data;
+ if (f->server) {
+ grpc_server_destroy(f->server);
+ }
+ f->server = grpc_server_create(server_args, NULL);
+ grpc_server_register_completion_queue(f->server, f->cq, NULL);
+ GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr,
+ server_creds));
+ grpc_server_credentials_release(server_creds);
+ grpc_server_start(f->server);
+}
+
+static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
+ fullstack_secure_fixture_data *ffd = f->fixture_data;
+ gpr_free(ffd->localaddr);
+ gpr_free(ffd);
+}
+
+static void cronet_init_client_simple_ssl_secure_fullstack(
+ grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
+ cronet_engine *cronetEngine = [Cronet getGlobalEngine];
+
+ grpc_channel_args *new_client_args = grpc_channel_args_copy(client_args);
+ cronet_init_client_secure_fullstack(f, new_client_args, cronetEngine);
+ grpc_channel_args_destroy(new_client_args);
+}
+
+static int fail_server_auth_check(grpc_channel_args *server_args) {
+ size_t i;
+ if (server_args == NULL) return 0;
+ for (i = 0; i < server_args->num_args; i++) {
+ if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) ==
+ 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void chttp2_init_server_simple_ssl_secure_fullstack(
+ grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
+ grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
+ test_server1_cert};
+ grpc_server_credentials *ssl_creds =
+ grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL);
+ if (fail_server_auth_check(server_args)) {
+ grpc_auth_metadata_processor processor = {process_auth_failure, NULL, NULL};
+ grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor);
+ }
+ chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
+}
+
+/* All test configurations */
+
+static grpc_end2end_test_config configs[] = {
+ {"chttp2/simple_ssl_fullstack",
+ FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
+ FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS,
+ chttp2_create_fixture_secure_fullstack,
+ cronet_init_client_simple_ssl_secure_fullstack,
+ chttp2_init_server_simple_ssl_secure_fullstack,
+ chttp2_tear_down_secure_fullstack},
+};
+
+static char *roots_filename;
+
+@interface CoreCronetEnd2EndTests : XCTestCase
+
+@end
+
+@implementation CoreCronetEnd2EndTests
+
+// The setUp() function is run before the test cases run and only run once
++ (void)setUp {
+ [super setUp];
+
+ FILE *roots_file;
+ size_t roots_size = strlen(test_root_cert);
+
+ char *argv[] = {"CoreCronetEnd2EndTests"};
+ grpc_test_init(1, argv);
+ grpc_end2end_tests_pre_init();
+
+ /* Set the SSL roots env var. */
+ roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
+ GPR_ASSERT(roots_filename != NULL);
+ GPR_ASSERT(roots_file != NULL);
+ GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
+ fclose(roots_file);
+ gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
+
+ grpc_init();
+
+ [Cronet setHttp2Enabled:YES];
+ [Cronet enableTestCertVerifierForTesting];
+ NSURL *url = [[[NSFileManager defaultManager]
+ URLsForDirectory:NSDocumentDirectory
+ inDomains:NSUserDomainMask] lastObject];
+ NSLog(@"Documents directory: %@", url);
+ [Cronet start];
+ [Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES];
+}
+
+// The tearDown() function is run after all test cases finish running
++ (void)tearDown {
+ grpc_shutdown();
+
+ /* Cleanup. */
+ remove(roots_filename);
+ gpr_free(roots_filename);
+
+ [super tearDown];
+}
+
+- (void)testIndividualCase:(char *)test_case {
+ char *argv[] = {"h2_ssl", test_case};
+
+ for (int i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+ grpc_end2end_tests(sizeof(argv) / sizeof(argv[0]), argv, configs[i]);
+ }
+}
+
+// TODO(mxyan): Use NSStringFromSelector(_cmd) to acquire test name from the
+// test case method name, so that bodies of test cases can stay identical
+- (void)testAuthorityNotSupported {
+ [self testIndividualCase:"authority_not_supported"];
+}
+
+- (void)testBadHostname {
+ [self testIndividualCase:"bad_hostname"];
+}
+
+- (void)testBinaryMetadata {
+ // NOT SUPPORTED
+ //[self testIndividualCase:"binary_metadata"];
+}
+
+- (void)testCallCreds {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"call_creds"];
+}
+
+- (void)testCancelAfterAccept {
+ [self testIndividualCase:"cancel_after_accept"];
+}
+
+- (void)testCancelAfterClientDone {
+ [self testIndividualCase:"cancel_after_client_done"];
+}
+
+- (void)testCancelAfterInvoke {
+ [self testIndividualCase:"cancel_after_invoke"];
+}
+
+- (void)testCancelBeforeInvoke {
+ [self testIndividualCase:"cancel_before_invoke"];
+}
+
+- (void)testCancelInAVacuum {
+ [self testIndividualCase:"cancel_in_a_vacuum"];
+}
+
+- (void)testCancelWithStatus {
+ [self testIndividualCase:"cancel_with_status"];
+}
+
+- (void)testCompressedPayload {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"compressed_payload"];
+}
+
+- (void)testConnectivity {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"connectivity"];
+}
+
+- (void)testDefaultHost {
+ [self testIndividualCase:"default_host"];
+}
+
+- (void)testDisappearingServer {
+ [self testIndividualCase:"disappearing_server"];
+}
+
+- (void)testEmptyBatch {
+ [self testIndividualCase:"empty_batch"];
+}
+
+- (void)testFilterCausesClose {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"filter_causes_close"];
+}
+
+- (void)testGracefulServerShutdown {
+ [self testIndividualCase:"graceful_server_shutdown"];
+}
+
+- (void)testHighInitialSeqno {
+ [self testIndividualCase:"high_initial_seqno"];
+}
+
+- (void)testHpackSize {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"hpack_size"];
+}
+
+- (void)testIdempotentRequest {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"idempotent_request"];
+}
+
+- (void)testInvokeLargeRequest {
+ [self testIndividualCase:"invoke_large_request"];
+}
+
+- (void)testLargeMetadata {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"large_metadata"];
+}
+
+- (void)testMaxConcurrentStreams {
+ [self testIndividualCase:"max_concurrent_streams"];
+}
+
+- (void)testMaxMessageLength {
+ [self testIndividualCase:"max_message_length"];
+}
+
+- (void)testNegativeDeadline {
+ [self testIndividualCase:"negative_deadline"];
+}
+
+- (void)testNetworkStatusChange {
+ [self testIndividualCase:"network_status_change"];
+}
+
+- (void)testNoOp {
+ [self testIndividualCase:"no_op"];
+}
+
+- (void)testPayload {
+ [self testIndividualCase:"payload"];
+}
+
+- (void)testPing {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"ping"];
+}
+
+- (void)testPingPongStreaming {
+ [self testIndividualCase:"ping_pong_streaming"];
+}
+
+- (void)testRegisteredCall {
+ [self testIndividualCase:"registered_call"];
+}
+
+- (void)testRequestWithFlags {
+ // NOT SUPPORTED
+ // [self testIndividualCase:"request_with_flags"];
+}
+
+- (void)testRequestWithPayload {
+ [self testIndividualCase:"request_with_payload"];
+}
+
+- (void)testServerFinishesRequest {
+ [self testIndividualCase:"server_finishes_request"];
+}
+
+- (void)testShutdownFinishesCalls {
+ [self testIndividualCase:"shutdown_finishes_calls"];
+}
+
+- (void)testShutdownFinishesTags {
+ [self testIndividualCase:"shutdown_finishes_tags"];
+}
+
+- (void)testSimpleDelayedRequest {
+ [self testIndividualCase:"simple_delayed_request"];
+}
+
+- (void)testSimpleMetadata {
+ [self testIndividualCase:"simple_metadata"];
+}
+
+- (void)testSimpleRequest {
+ [self testIndividualCase:"simple_request"];
+}
+
+- (void)testStreamingErrorResponse {
+ [self testIndividualCase:"streaming_error_response"];
+}
+
+- (void)testTrailingMetadata {
+ [self testIndividualCase:"trailing_metadata"];
+}
+
+@end
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 17478fab12..5785b976f2 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -84,9 +84,9 @@ post_install do |installer|
end
# CocoaPods creates duplicated library targets of gRPC-Core when the test targets include
- # non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core.'
+ # non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core'
# and require the same error suppresion.
- if target.name == 'gRPC-Core' or target.name.start_with?('gRPC-Core.')
+ if target.name.start_with?('gRPC-Core')
target.build_configurations.each do |config|
# TODO(zyc): Remove this setting after the issue is resolved
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void
diff --git a/src/php/ext/grpc/byte_buffer.c b/src/php/ext/grpc/byte_buffer.c
index 3be1429f13..b0269854e8 100644
--- a/src/php/ext/grpc/byte_buffer.c
+++ b/src/php/ext/grpc/byte_buffer.c
@@ -47,12 +47,12 @@
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
- gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
+ grpc_slice slice = grpc_slice_from_copied_buffer(string, length);
grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
return buffer;
}
@@ -66,11 +66,11 @@ void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
return;
}
- gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
- size_t length = GPR_SLICE_LENGTH(slice);
+ grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
+ size_t length = GRPC_SLICE_LENGTH(slice);
char *string = ecalloc(length + 1, sizeof(char));
- memcpy(string, GPR_SLICE_START_PTR(slice), length);
- gpr_slice_unref(slice);
+ memcpy(string, GRPC_SLICE_START_PTR(slice), length);
+ grpc_slice_unref(slice);
*out_string = string;
*out_length = length;
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index e24be3fc76..c4d56790f7 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -35,7 +35,7 @@
namespace Grpc;
/**
- * Class AbstractCall
+ * Class AbstractCall.
* @package Grpc
*/
abstract class AbstractCall
@@ -121,13 +121,14 @@ abstract class AbstractCall
}
/**
- * Serialize a message to the protobuf binary format
+ * Serialize a message to the protobuf binary format.
*
* @param mixed $data The Protobuf message
*
* @return string The protobuf binary format
*/
- protected function serializeMessage($data) {
+ protected function serializeMessage($data)
+ {
// Proto3 implementation
if (method_exists($data, 'encode')) {
return $data->encode();
@@ -155,6 +156,7 @@ abstract class AbstractCall
list($className, $deserializeFunc) = $this->deserialize;
$obj = new $className();
$obj->$deserializeFunc($value);
+
return $obj;
}
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 36d94cae2c..d0baeae955 100644
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -252,7 +252,7 @@ class BaseStub
*
* @param string $method The name of the method to call
* @param array $arguments An array or Traversable of arguments to stream to the
- * server
+ * server
* @param callable $deserialize A function that deserializes the response
* @param array $metadata A metadata map to send to the server
*
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 3d62e86ab0..d201915d66 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -477,10 +477,10 @@ function statusCodeAndMessage($stub)
list($result, $status) = $call->wait();
hardAssert($status->code === 2,
- 'Received unexpected UnaryCall status code: ' .
+ 'Received unexpected UnaryCall status code: '.
$status->code);
hardAssert($status->details === 'test status message',
- 'Received unexpected UnaryCall status details: ' .
+ 'Received unexpected UnaryCall status details: '.
$status->details);
$streaming_call = $stub->FullDuplexCall();
@@ -493,10 +493,10 @@ function statusCodeAndMessage($stub)
$status = $streaming_call->getStatus();
hardAssert($status->code === 2,
- 'Received unexpected FullDuplexCall status code: ' .
+ 'Received unexpected FullDuplexCall status code: '.
$status->code);
hardAssert($status->details === 'test status message',
- 'Received unexpected FullDuplexCall status details: ' .
+ 'Received unexpected FullDuplexCall status details: '.
$status->details);
}
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index 1205f0cd8e..f60eb96730 100644
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -94,7 +94,7 @@ class CallTest extends PHPUnit_Framework_TestCase
$batch = [
Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
'key2' => ['value2',
- 'value3'], ],
+ 'value3', ], ],
];
$result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
diff --git a/src/php/tests/unit_tests/ChannelTest.php b/src/php/tests/unit_tests/ChannelTest.php
index 4b35b1a28c..fa33d38911 100644
--- a/src/php/tests/unit_tests/ChannelTest.php
+++ b/src/php/tests/unit_tests/ChannelTest.php
@@ -99,7 +99,7 @@ class ChannelTest extends PHPUnit_Framework_TestCase
$this->channel = new Grpc\Channel('localhost:0',
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$time = new Grpc\Timeval(1000);
- $state = $this->channel->watchConnectivityState(123, $time);
+ $state = $this->channel->watchConnectivityState(1, $time);
$this->assertTrue($state);
unset($time);
}
diff --git a/src/php/tests/unit_tests/ServerTest.php b/src/php/tests/unit_tests/ServerTest.php
index f2346ab113..5f40202f18 100644
--- a/src/php/tests/unit_tests/ServerTest.php
+++ b/src/php/tests/unit_tests/ServerTest.php
@@ -67,9 +67,9 @@ class ServerTest extends PHPUnit_Framework_TestCase
public function testRequestCall()
{
$this->server = new Grpc\Server();
- $port = $this->server->addHttp2Port('0.0.0.0:8888');
+ $port = $this->server->addHttp2Port('0.0.0.0:0');
$this->server->start();
- $channel = new Grpc\Channel('localhost:8888',
+ $channel = new Grpc\Channel('localhost:' . $port,
['credentials' => Grpc\ChannelCredentials::createInsecure()]);
$deadline = Grpc\Timeval::infFuture();
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 918f5fa3e3..be387cf786 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -219,9 +219,12 @@ message ScenarioResultSummary
double latency_99 = 10;
double latency_999 = 11;
+ // server cpu usage percentage
+ double server_cpu_usage = 12;
+
// Number of requests that succeeded/failed
- double successful_requests_per_second = 12;
- double failed_requests_per_second = 13;
+ double successful_requests_per_second = 13;
+ double failed_requests_per_second = 14;
}
// Results of a single benchmark scenario.
diff --git a/src/proto/grpc/testing/stats.proto b/src/proto/grpc/testing/stats.proto
index d40d714801..80014161a1 100644
--- a/src/proto/grpc/testing/stats.proto
+++ b/src/proto/grpc/testing/stats.proto
@@ -41,6 +41,12 @@ message ServerStats {
// change in server time (in seconds) used by the server process and all
// threads since last reset
double time_system = 3;
+
+ // change in total cpu time of the server (data from proc/stat)
+ uint64 total_cpu_time = 4;
+
+ // change in idle time of the server (data from proc/stat)
+ uint64 idle_cpu_time = 5;
}
// Histogram params based on grpc/support/histogram.c
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index 526bd9e14f..6087276d51 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -905,6 +905,21 @@ class Server(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
+ def add_shutdown_handler(self, shutdown_handler):
+ """Adds a handler to be called on server shutdown.
+
+ Shutdown handlers are run on server stop() or in the event that a running
+ server is destroyed unexpectedly. The handlers are run in series before
+ the stop grace period.
+
+ Args:
+ shutdown_handler: A function taking a single arg, a time in seconds
+ within which the handler should complete. None indicates the handler can
+ run for any duration.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
def start(self):
"""Starts this Server's service of RPCs.
@@ -914,7 +929,7 @@ class Server(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
- def stop(self, grace):
+ def stop(self, grace, shutdown_handler_grace=None):
"""Stops this Server's service of RPCs.
All calls to this method immediately stop service of new RPCs. When existing
@@ -927,10 +942,18 @@ class Server(six.with_metaclass(abc.ABCMeta)):
passed in a previous call will not have the effect of stopping the server
later.
+ This method does not block for any significant length of time. If None is
+ passed as the grace value, existing RPCs are immediately aborted and this
+ method blocks until this Server is completely stopped.
+
Args:
- grace: A duration of time in seconds to allow existing RPCs to complete
- before being aborted by this Server's stopping. If None, this method
- will block until the server is completely stopped.
+ grace: A duration of time in seconds or None. If a duration of time in
+ seconds, the time to allow existing RPCs to complete before being
+ aborted by this Server's stopping. If None, all RPCs will be aborted
+ immediately and this method will block until this Server is completely
+ stopped.
+ shutdown_handler_grace: A duration of time in seconds or None. This
+ value is passed to all shutdown handlers.
Returns:
A threading.Event that will be set when this Server has completely
@@ -1225,7 +1248,8 @@ def secure_channel(target, credentials, options=None):
credentials._credentials)
-def server(thread_pool, handlers=None, options=None):
+def server(thread_pool, handlers=None, options=None, exit_grace=None,
+ exit_shutdown_handler_grace=None):
"""Creates a Server with which RPCs can be serviced.
Args:
@@ -1238,13 +1262,19 @@ def server(thread_pool, handlers=None, options=None):
returned Server is started.
options: A sequence of string-value pairs according to which to configure
the created server.
+ exit_grace: The grace period to use when terminating
+ running servers at interpreter exit. None indicates unspecified.
+ exit_shutdown_handler_grace: The shutdown handler grace to use when
+ terminating running servers at interpreter exit. None indicates
+ unspecified.
Returns:
A Server with which RPCs can be serviced.
"""
from grpc import _server
return _server.Server(thread_pool, () if handlers is None else handlers,
- () if options is None else options)
+ () if options is None else options, exit_grace,
+ exit_shutdown_handler_grace)
################################### __all__ #################################
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 9560fad137..ad766186bd 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -53,23 +53,23 @@ cdef extern from "grpc/byte_buffer_reader.h":
cdef extern from "grpc/grpc.h":
- ctypedef struct gpr_slice:
- # don't worry about writing out the members of gpr_slice; we never access
+ ctypedef struct grpc_slice:
+ # don't worry about writing out the members of grpc_slice; we never access
# them directly.
pass
- gpr_slice gpr_slice_ref(gpr_slice s) nogil
- void gpr_slice_unref(gpr_slice s) nogil
- gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) nogil
- gpr_slice gpr_slice_new_with_len(
+ grpc_slice grpc_slice_ref(grpc_slice s) nogil
+ void grpc_slice_unref(grpc_slice s) nogil
+ grpc_slice grpc_slice_new(void *p, size_t len, void (*destroy)(void *)) nogil
+ grpc_slice grpc_slice_new_with_len(
void *p, size_t len, void (*destroy)(void *, size_t)) nogil
- gpr_slice gpr_slice_malloc(size_t length) nogil
- gpr_slice gpr_slice_from_copied_string(const char *source) nogil
- gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len) nogil
+ grpc_slice grpc_slice_malloc(size_t length) nogil
+ grpc_slice grpc_slice_from_copied_string(const char *source) nogil
+ grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t len) nogil
# Declare functions for function-like macros (because Cython)...
- void *gpr_slice_start_ptr "GPR_SLICE_START_PTR" (gpr_slice s) nogil
- size_t gpr_slice_length "GPR_SLICE_LENGTH" (gpr_slice s) nogil
+ void *grpc_slice_start_ptr "GRPC_SLICE_START_PTR" (grpc_slice s) nogil
+ size_t grpc_slice_length "GRPC_SLICE_LENGTH" (grpc_slice s) nogil
ctypedef enum gpr_clock_type:
GPR_CLOCK_MONOTONIC
@@ -101,7 +101,7 @@ cdef extern from "grpc/grpc.h":
# We don't care about the internals.
pass
- grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
+ grpc_byte_buffer *grpc_raw_byte_buffer_create(grpc_slice *slices,
size_t nslices) nogil
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) nogil
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer) nogil
@@ -109,7 +109,7 @@ cdef extern from "grpc/grpc.h":
int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer) nogil
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
- gpr_slice *slice) nogil
+ grpc_slice *slice) nogil
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) nogil
ctypedef enum grpc_status_code:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 8a4eef4d2e..cadfce6ee6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -242,19 +242,19 @@ cdef class ByteBuffer:
return
cdef char *c_data = data
- cdef gpr_slice data_slice
+ cdef grpc_slice data_slice
cdef size_t data_length = len(data)
with nogil:
- data_slice = gpr_slice_from_copied_buffer(c_data, data_length)
+ data_slice = grpc_slice_from_copied_buffer(c_data, data_length)
with nogil:
self.c_byte_buffer = grpc_raw_byte_buffer_create(
&data_slice, 1)
with nogil:
- gpr_slice_unref(data_slice)
+ grpc_slice_unref(data_slice)
def bytes(self):
cdef grpc_byte_buffer_reader reader
- cdef gpr_slice data_slice
+ cdef grpc_slice data_slice
cdef size_t data_slice_length
cdef void *data_slice_pointer
cdef bint reader_status
@@ -267,11 +267,11 @@ cdef class ByteBuffer:
result = bytearray()
with nogil:
while grpc_byte_buffer_reader_next(&reader, &data_slice):
- data_slice_pointer = gpr_slice_start_ptr(data_slice)
- data_slice_length = gpr_slice_length(data_slice)
+ data_slice_pointer = grpc_slice_start_ptr(data_slice)
+ data_slice_length = grpc_slice_length(data_slice)
with gil:
result += (<char *>data_slice_pointer)[:data_slice_length]
- gpr_slice_unref(data_slice)
+ grpc_slice_unref(data_slice)
with nogil:
grpc_byte_buffer_reader_destroy(&reader)
return bytes(result)
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 5223712dfa..d83a2e6ded 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -60,7 +60,8 @@ _CANCELLED = 'cancelled'
_EMPTY_FLAGS = 0
_EMPTY_METADATA = cygrpc.Metadata(())
-_UNEXPECTED_EXIT_SERVER_GRACE = 1.0
+_DEFAULT_EXIT_GRACE = 1.0
+_DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE = 5.0
def _serialized_request(request_event):
@@ -595,14 +596,18 @@ class _ServerStage(enum.Enum):
class _ServerState(object):
- def __init__(self, completion_queue, server, generic_handlers, thread_pool):
+ def __init__(self, completion_queue, server, generic_handlers, thread_pool,
+ exit_grace, exit_shutdown_handler_grace):
self.lock = threading.Lock()
self.completion_queue = completion_queue
self.server = server
self.generic_handlers = list(generic_handlers)
self.thread_pool = thread_pool
+ self.exit_grace = exit_grace
+ self.exit_shutdown_handler_grace = exit_shutdown_handler_grace
self.stage = _ServerStage.STOPPED
self.shutdown_events = None
+ self.shutdown_handlers = []
# TODO(https://github.com/grpc/grpc/issues/6597): eliminate these fields.
self.rpc_states = set()
@@ -672,41 +677,45 @@ def _serve(state):
return
-def _stop(state, grace):
- with state.lock:
- if state.stage is _ServerStage.STOPPED:
- shutdown_event = threading.Event()
- shutdown_event.set()
- return shutdown_event
- else:
- if state.stage is _ServerStage.STARTED:
- state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG)
+def _stop(state, grace, shutdown_handler_grace):
+ shutdown_event = threading.Event()
+
+ def cancel_all_calls_after_grace():
+ with state.lock:
+ if state.stage is _ServerStage.STOPPED:
+ shutdown_event.set()
+ return
+ elif state.stage is _ServerStage.STARTED:
+ do_shutdown = True
state.stage = _ServerStage.GRACE
state.shutdown_events = []
- state.due.add(_SHUTDOWN_TAG)
- shutdown_event = threading.Event()
+ else:
+ do_shutdown = False
state.shutdown_events.append(shutdown_event)
- if grace is None:
+
+ if do_shutdown:
+ # Run Shutdown Handlers without the lock
+ for handler in state.shutdown_handlers:
+ handler(shutdown_handler_grace)
+ with state.lock:
+ state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG)
+ state.stage = _ServerStage.GRACE
+ state.due.add(_SHUTDOWN_TAG)
+
+ if not shutdown_event.wait(timeout=grace):
+ with state.lock:
state.server.cancel_all_calls()
# TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
for rpc_state in state.rpc_states:
with rpc_state.condition:
rpc_state.client = _CANCELLED
rpc_state.condition.notify_all()
- else:
- def cancel_all_calls_after_grace():
- shutdown_event.wait(timeout=grace)
- with state.lock:
- state.server.cancel_all_calls()
- # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
- for rpc_state in state.rpc_states:
- with rpc_state.condition:
- rpc_state.client = _CANCELLED
- rpc_state.condition.notify_all()
- thread = threading.Thread(target=cancel_all_calls_after_grace)
- thread.start()
- return shutdown_event
- shutdown_event.wait()
+
+ if grace is None:
+ cancel_all_calls_after_grace()
+ else:
+ threading.Thread(target=cancel_all_calls_after_grace).start()
+
return shutdown_event
@@ -716,12 +725,12 @@ def _start(state):
raise ValueError('Cannot start already-started server!')
state.server.start()
state.stage = _ServerStage.STARTED
- _request_call(state)
+ _request_call(state)
def cleanup_server(timeout):
if timeout is None:
- _stop(state, _UNEXPECTED_EXIT_SERVER_GRACE).wait()
+ _stop(state, state.exit_grace, state.exit_shutdown_handler_grace).wait()
else:
- _stop(state, timeout).wait()
+ _stop(state, timeout, 0).wait()
thread = _common.CleanupThread(
cleanup_server, target=_serve, args=(state,))
@@ -729,12 +738,16 @@ def _start(state):
class Server(grpc.Server):
- def __init__(self, thread_pool, generic_handlers, options):
+ def __init__(self, thread_pool, generic_handlers, options, exit_grace,
+ exit_shutdown_handler_grace):
completion_queue = cygrpc.CompletionQueue()
server = cygrpc.Server(_common.channel_args(options))
server.register_completion_queue(completion_queue)
self._state = _ServerState(
- completion_queue, server, generic_handlers, thread_pool)
+ completion_queue, server, generic_handlers, thread_pool,
+ _DEFAULT_EXIT_GRACE if exit_grace is None else exit_grace,
+ _DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE if exit_shutdown_handler_grace
+ is None else exit_shutdown_handler_grace)
def add_generic_rpc_handlers(self, generic_rpc_handlers):
_add_generic_handlers(self._state, generic_rpc_handlers)
@@ -745,11 +758,14 @@ class Server(grpc.Server):
def add_secure_port(self, address, server_credentials):
return _add_secure_port(self._state, _common.encode(address), server_credentials)
+ def add_shutdown_handler(self, handler):
+ self._state.shutdown_handlers.append(handler)
+
def start(self):
_start(self._state)
- def stop(self, grace):
- return _stop(self._state, grace)
+ def stop(self, grace, shutdown_handler_grace=None):
+ return _stop(self._state, grace, shutdown_handler_grace)
def __del__(self):
- _stop(self._state, None)
+ _stop(self._state, None, None)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 1ad423909f..d43f93b94f 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -52,9 +52,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/support/log_windows.c',
'src/core/lib/support/mpscq.c',
'src/core/lib/support/murmur_hash.c',
- 'src/core/lib/support/percent_encoding.c',
- 'src/core/lib/support/slice.c',
- 'src/core/lib/support/slice_buffer.c',
'src/core/lib/support/stack_lockfree.c',
'src/core/lib/support/string.c',
'src/core/lib/support/string_posix.c',
@@ -102,7 +99,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/endpoint_pair_windows.c',
'src/core/lib/iomgr/error.c',
'src/core/lib/iomgr/ev_epoll_linux.c',
- 'src/core/lib/iomgr/ev_poll_and_epoll_posix.c',
'src/core/lib/iomgr/ev_poll_posix.c',
'src/core/lib/iomgr/ev_posix.c',
'src/core/lib/iomgr/exec_ctx.c',
@@ -124,6 +120,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/resolve_address_windows.c',
'src/core/lib/iomgr/resource_quota.c',
'src/core/lib/iomgr/sockaddr_utils.c',
+ 'src/core/lib/iomgr/socket_mutator.c',
'src/core/lib/iomgr/socket_utils_common_posix.c',
'src/core/lib/iomgr/socket_utils_linux.c',
'src/core/lib/iomgr/socket_utils_posix.c',
@@ -157,6 +154,10 @@ CORE_SOURCE_FILES = [
'src/core/lib/json/json_reader.c',
'src/core/lib/json/json_string.c',
'src/core/lib/json/json_writer.c',
+ 'src/core/lib/slice/percent_encoding.c',
+ 'src/core/lib/slice/slice.c',
+ 'src/core/lib/slice/slice_buffer.c',
+ 'src/core/lib/slice/slice_string_helpers.c',
'src/core/lib/surface/alarm.c',
'src/core/lib/surface/api_trace.c',
'src/core/lib/surface/byte_buffer.c',
@@ -180,7 +181,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/mdstr_hash_table.c',
'src/core/lib/transport/metadata.c',
'src/core/lib/transport/metadata_batch.c',
- 'src/core/lib/transport/method_config.c',
+ 'src/core/lib/transport/pid_controller.c',
+ 'src/core/lib/transport/service_config.c',
'src/core/lib/transport/static_metadata.c',
'src/core/lib/transport/timeout_encoding.c',
'src/core/lib/transport/transport.c',
@@ -224,9 +226,9 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/plugin/plugin_credentials.c',
'src/core/lib/security/credentials/ssl/ssl_credentials.c',
'src/core/lib/security/transport/client_auth_filter.c',
- 'src/core/lib/security/transport/handshake.c',
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
+ 'src/core/lib/security/transport/security_handshaker.c',
'src/core/lib/security/transport/server_auth_filter.c',
'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c',
@@ -235,6 +237,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/tsi/fake_transport_security.c',
'src/core/lib/tsi/ssl_transport_security.c',
'src/core/lib/tsi/transport_security.c',
+ 'src/core/ext/transport/chttp2/server/chttp2_server.c',
'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
'src/core/ext/client_channel/channel_connectivity.c',
'src/core/ext/client_channel/client_channel.c',
@@ -254,6 +257,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_channel/subchannel.c',
'src/core/ext/client_channel/subchannel_index.c',
'src/core/ext/client_channel/uri_parser.c',
+ 'src/core/ext/transport/chttp2/client/chttp2_connector.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
diff --git a/src/python/grpcio_tests/tests/interop/client.py b/src/python/grpcio_tests/tests/interop/client.py
index 4fbf58f7d9..afaa466254 100644
--- a/src/python/grpcio_tests/tests/interop/client.py
+++ b/src/python/grpcio_tests/tests/interop/client.py
@@ -43,11 +43,13 @@ from tests.interop import resources
def _args():
parser = argparse.ArgumentParser()
parser.add_argument(
- '--server_host', help='the host to which to connect', type=str)
+ '--server_host', help='the host to which to connect', type=str,
+ default="127.0.0.1")
parser.add_argument(
'--server_port', help='the port to which to connect', type=int)
parser.add_argument(
- '--test_case', help='the test case to execute', type=str)
+ '--test_case', help='the test case to execute', type=str,
+ default="large_unary")
parser.add_argument(
'--use_tls', help='require a secure connection', default=False,
type=resources.parse_bool)
@@ -55,7 +57,7 @@ def _args():
'--use_test_ca', help='replace platform root CAs with ca.pem',
default=False, type=resources.parse_bool)
parser.add_argument(
- '--server_host_override',
+ '--server_host_override', default="foo.test.google.fr",
help='the server host to which to claim to connect', type=str)
parser.add_argument('--oauth_scope', help='scope for OAuth tokens', type=str)
parser.add_argument(
diff --git a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
index 089366a8c7..64fd97256e 100644
--- a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
+++ b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
@@ -167,7 +167,7 @@ class SameSeparateTest(unittest.TestCase, SeparateTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
- '--grpc_python_out={}'.format(self.grpc_python_out_directory),
+ '--grpc_python_out=grpc_2_0:{}'.format(self.grpc_python_out_directory),
same_proto_file,
])
if protoc_result != 0:
@@ -241,7 +241,7 @@ class SplitCommonTest(unittest.TestCase, CommonTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
- '--grpc_python_out={}'.format(self.python_out_directory),
+ '--grpc_python_out={}'.format(self.grpc_python_out_directory),
services_proto_file,
messages_proto_file,
])
@@ -285,7 +285,7 @@ class SplitSeparateTest(unittest.TestCase, SeparateTestMixin):
'',
'--proto_path={}'.format(self.proto_directory),
'--python_out={}'.format(self.python_out_directory),
- '--grpc_python_out={}'.format(self.grpc_python_out_directory),
+ '--grpc_python_out=grpc_2_0:{}'.format(self.grpc_python_out_directory),
services_proto_file,
messages_proto_file,
])
diff --git a/src/python/grpcio_tests/tests/stress/client.py b/src/python/grpcio_tests/tests/stress/client.py
index 975f33b4c1..390ea13021 100644
--- a/src/python/grpcio_tests/tests/stress/client.py
+++ b/src/python/grpcio_tests/tests/stress/client.py
@@ -39,6 +39,7 @@ from src.proto.grpc.testing import metrics_pb2
from src.proto.grpc.testing import test_pb2
from tests.interop import methods
+from tests.interop import resources
from tests.qps import histogram
from tests.stress import metrics_server
from tests.stress import test_runner
@@ -71,6 +72,16 @@ def _args():
'--metrics_port',
help='the port to listen for metrics requests on',
default=8081, type=int)
+ parser.add_argument(
+ '--use_test_ca',
+ help='Whether to use our fake CA. Requires --use_tls=true',
+ default=False, type=bool)
+ parser.add_argument(
+ '--use_tls',
+ help='Whether to use TLS', default=False, type=bool)
+ parser.add_argument(
+ '--server_host_override', default="foo.test.google.fr",
+ help='the server host to which to claim to connect', type=str)
return parser.parse_args()
@@ -90,6 +101,19 @@ def _parse_weighted_test_cases(test_case_args):
weighted_test_cases[test_case] = int(weight)
return weighted_test_cases
+def _get_channel(target, args):
+ if args.use_tls:
+ if args.use_test_ca:
+ root_certificates = resources.test_root_certificates()
+ else:
+ root_certificates = None # will load default roots.
+ channel_credentials = grpc.ssl_channel_credentials(
+ root_certificates=root_certificates)
+ options = (('grpc.ssl_target_name_override', args.server_host_override,),)
+ return grpc.secure_channel(
+ target, channel_credentials, options=options)
+ else:
+ return grpc.insecure_channel(target)
def run_test(args):
test_cases = _parse_weighted_test_cases(args.test_cases)
@@ -108,7 +132,7 @@ def run_test(args):
for test_server_target in test_server_targets:
for _ in xrange(args.num_channels_per_server):
- channel = grpc.insecure_channel(test_server_target)
+ channel = _get_channel(test_server_target, args)
for _ in xrange(args.num_stubs_per_channel):
stub = test_pb2.TestServiceStub(channel)
runner = test_runner.TestRunner(stub, test_cases, hist,
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index dd4a0257f5..04a2e44178 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -27,6 +27,7 @@
"unit._cython.cygrpc_test.TypeSmokeTest",
"unit._empty_message_test.EmptyMessageTest",
"unit._exit_test.ExitTest",
+ "unit._exit_test.ShutdownHandlerTest",
"unit._metadata_code_details_test.MetadataCodeDetailsTest",
"unit._metadata_test.MetadataTest",
"unit._rpc_test.RPCTest",
diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py
index 5a4a32887c..342f5fcc10 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_test.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_test.py
@@ -43,6 +43,8 @@ import threading
import time
import unittest
+import grpc
+from grpc.framework.foundation import logging_pool
from tests.unit import _exit_scenarios
SCENARIO_FILE = os.path.abspath(os.path.join(
@@ -52,7 +54,7 @@ BASE_COMMAND = [INTERPRETER, SCENARIO_FILE]
BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt']
INIT_TIME = 1.0
-
+SHUTDOWN_GRACE = 5.0
processes = []
process_lock = threading.Lock()
@@ -182,5 +184,24 @@ class ExitTest(unittest.TestCase):
interrupt_and_wait(process)
+class _ShutDownHandler(object):
+
+ def __init__(self):
+ self.seen_handler_grace = None
+
+ def shutdown_handler(self, handler_grace):
+ self.seen_handler_grace = handler_grace
+
+
+class ShutdownHandlerTest(unittest.TestCase):
+
+ def test_shutdown_handler(self):
+ server = grpc.server(logging_pool.pool(1))
+ handler = _ShutDownHandler()
+ server.add_shutdown_handler(handler.shutdown_handler)
+ server.start()
+ server.stop(0, shutdown_handler_grace=SHUTDOWN_GRACE).wait()
+ self.assertEqual(SHUTDOWN_GRACE, handler.seen_handler_grace)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_rpc_test.py b/src/python/grpcio_tests/tests/unit/_rpc_test.py
index ab6546bf87..eb00156da5 100644
--- a/src/python/grpcio_tests/tests/unit/_rpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_rpc_test.py
@@ -191,6 +191,10 @@ class RPCTest(unittest.TestCase):
self._channel = grpc.insecure_channel('localhost:%d' % port)
+ def tearDown(self):
+ self._server.stop(None)
+ self._server_pool.shutdown(wait=True)
+
def testUnrecognizedMethod(self):
request = b'abc'
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index 61b7c30315..f97890e4a2 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -38,20 +38,20 @@
#include <grpc/grpc.h>
#include <grpc/byte_buffer_reader.h>
-#include <grpc/support/slice.h>
+#include <grpc/slice.h>
#include "rb_grpc.h"
grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) {
- gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
+ grpc_slice slice = grpc_slice_from_copied_buffer(string, length);
grpc_byte_buffer *buffer = grpc_raw_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
+ grpc_slice_unref(slice);
return buffer;
}
VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
VALUE rb_string;
grpc_byte_buffer_reader reader;
- gpr_slice next;
+ grpc_slice next;
if (buffer == NULL) {
return Qnil;
}
@@ -61,9 +61,9 @@ VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
return Qnil;
}
while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
- rb_str_cat(rb_string, (const char *) GPR_SLICE_START_PTR(next),
- GPR_SLICE_LENGTH(next));
- gpr_slice_unref(next);
+ rb_str_cat(rb_string, (const char *) GRPC_SLICE_START_PTR(next),
+ GRPC_SLICE_LENGTH(next));
+ grpc_slice_unref(next);
}
return rb_string;
}
diff --git a/src/ruby/ext/grpc/rb_compression_options.c b/src/ruby/ext/grpc/rb_compression_options.c
index c5668fdab4..6200dbafeb 100644
--- a/src/ruby/ext/grpc/rb_compression_options.c
+++ b/src/ruby/ext/grpc/rb_compression_options.c
@@ -283,6 +283,8 @@ VALUE grpc_rb_compression_options_level_value_to_name_internal(
rb_eArgError,
"Failed to convert compression level value to name for value: %d",
(int)compression_value);
+ /* return something to avoid compiler error about no return */
+ return Qnil;
}
}
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index fd73cc7970..6c36df9113 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -110,6 +110,7 @@ grpc_call_get_peer_type grpc_call_get_peer_import;
grpc_census_call_set_context_type grpc_census_call_set_context_import;
grpc_census_call_get_context_type grpc_census_call_get_context_import;
grpc_channel_get_target_type grpc_channel_get_target_import;
+grpc_channel_get_info_type grpc_channel_get_info_import;
grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
grpc_channel_destroy_type grpc_channel_destroy_import;
@@ -172,6 +173,36 @@ grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex
grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
grpc_call_set_credentials_type grpc_call_set_credentials_import;
grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
+grpc_slice_ref_type grpc_slice_ref_import;
+grpc_slice_unref_type grpc_slice_unref_import;
+grpc_slice_new_type grpc_slice_new_import;
+grpc_slice_new_with_user_data_type grpc_slice_new_with_user_data_import;
+grpc_slice_new_with_len_type grpc_slice_new_with_len_import;
+grpc_slice_malloc_type grpc_slice_malloc_import;
+grpc_slice_from_copied_string_type grpc_slice_from_copied_string_import;
+grpc_slice_from_copied_buffer_type grpc_slice_from_copied_buffer_import;
+grpc_slice_from_static_string_type grpc_slice_from_static_string_import;
+grpc_slice_sub_type grpc_slice_sub_import;
+grpc_slice_sub_no_ref_type grpc_slice_sub_no_ref_import;
+grpc_slice_split_tail_type grpc_slice_split_tail_import;
+grpc_slice_split_head_type grpc_slice_split_head_import;
+gpr_empty_slice_type gpr_empty_slice_import;
+grpc_slice_cmp_type grpc_slice_cmp_import;
+grpc_slice_str_cmp_type grpc_slice_str_cmp_import;
+grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import;
+grpc_slice_buffer_init_type grpc_slice_buffer_init_import;
+grpc_slice_buffer_destroy_type grpc_slice_buffer_destroy_import;
+grpc_slice_buffer_add_type grpc_slice_buffer_add_import;
+grpc_slice_buffer_add_indexed_type grpc_slice_buffer_add_indexed_import;
+grpc_slice_buffer_addn_type grpc_slice_buffer_addn_import;
+grpc_slice_buffer_tiny_add_type grpc_slice_buffer_tiny_add_import;
+grpc_slice_buffer_pop_type grpc_slice_buffer_pop_import;
+grpc_slice_buffer_reset_and_unref_type grpc_slice_buffer_reset_and_unref_import;
+grpc_slice_buffer_swap_type grpc_slice_buffer_swap_import;
+grpc_slice_buffer_move_into_type grpc_slice_buffer_move_into_import;
+grpc_slice_buffer_trim_end_type grpc_slice_buffer_trim_end_import;
+grpc_slice_buffer_move_first_type grpc_slice_buffer_move_first_import;
+grpc_slice_buffer_take_first_type grpc_slice_buffer_take_first_import;
gpr_malloc_type gpr_malloc_import;
gpr_free_type gpr_free_import;
gpr_realloc_type gpr_realloc_import;
@@ -221,35 +252,6 @@ gpr_set_log_verbosity_type gpr_set_log_verbosity_import;
gpr_log_verbosity_init_type gpr_log_verbosity_init_import;
gpr_set_log_function_type gpr_set_log_function_import;
gpr_format_message_type gpr_format_message_import;
-gpr_slice_ref_type gpr_slice_ref_import;
-gpr_slice_unref_type gpr_slice_unref_import;
-gpr_slice_new_type gpr_slice_new_import;
-gpr_slice_new_with_user_data_type gpr_slice_new_with_user_data_import;
-gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
-gpr_slice_malloc_type gpr_slice_malloc_import;
-gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
-gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
-gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
-gpr_slice_sub_type gpr_slice_sub_import;
-gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
-gpr_slice_split_tail_type gpr_slice_split_tail_import;
-gpr_slice_split_head_type gpr_slice_split_head_import;
-gpr_empty_slice_type gpr_empty_slice_import;
-gpr_slice_cmp_type gpr_slice_cmp_import;
-gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
-gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
-gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
-gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
-gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
-gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
-gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
-gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
-gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
-gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
-gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
-gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
-gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
-gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
gpr_strdup_type gpr_strdup_import;
gpr_asprintf_type gpr_asprintf_import;
gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
@@ -384,6 +386,7 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_census_call_set_context_import = (grpc_census_call_set_context_type) GetProcAddress(library, "grpc_census_call_set_context");
grpc_census_call_get_context_import = (grpc_census_call_get_context_type) GetProcAddress(library, "grpc_census_call_get_context");
grpc_channel_get_target_import = (grpc_channel_get_target_type) GetProcAddress(library, "grpc_channel_get_target");
+ grpc_channel_get_info_import = (grpc_channel_get_info_type) GetProcAddress(library, "grpc_channel_get_info");
grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
@@ -446,6 +449,36 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port");
grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials");
grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor");
+ grpc_slice_ref_import = (grpc_slice_ref_type) GetProcAddress(library, "grpc_slice_ref");
+ grpc_slice_unref_import = (grpc_slice_unref_type) GetProcAddress(library, "grpc_slice_unref");
+ grpc_slice_new_import = (grpc_slice_new_type) GetProcAddress(library, "grpc_slice_new");
+ grpc_slice_new_with_user_data_import = (grpc_slice_new_with_user_data_type) GetProcAddress(library, "grpc_slice_new_with_user_data");
+ grpc_slice_new_with_len_import = (grpc_slice_new_with_len_type) GetProcAddress(library, "grpc_slice_new_with_len");
+ grpc_slice_malloc_import = (grpc_slice_malloc_type) GetProcAddress(library, "grpc_slice_malloc");
+ grpc_slice_from_copied_string_import = (grpc_slice_from_copied_string_type) GetProcAddress(library, "grpc_slice_from_copied_string");
+ grpc_slice_from_copied_buffer_import = (grpc_slice_from_copied_buffer_type) GetProcAddress(library, "grpc_slice_from_copied_buffer");
+ grpc_slice_from_static_string_import = (grpc_slice_from_static_string_type) GetProcAddress(library, "grpc_slice_from_static_string");
+ grpc_slice_sub_import = (grpc_slice_sub_type) GetProcAddress(library, "grpc_slice_sub");
+ grpc_slice_sub_no_ref_import = (grpc_slice_sub_no_ref_type) GetProcAddress(library, "grpc_slice_sub_no_ref");
+ grpc_slice_split_tail_import = (grpc_slice_split_tail_type) GetProcAddress(library, "grpc_slice_split_tail");
+ grpc_slice_split_head_import = (grpc_slice_split_head_type) GetProcAddress(library, "grpc_slice_split_head");
+ gpr_empty_slice_import = (gpr_empty_slice_type) GetProcAddress(library, "gpr_empty_slice");
+ grpc_slice_cmp_import = (grpc_slice_cmp_type) GetProcAddress(library, "grpc_slice_cmp");
+ grpc_slice_str_cmp_import = (grpc_slice_str_cmp_type) GetProcAddress(library, "grpc_slice_str_cmp");
+ grpc_slice_is_equivalent_import = (grpc_slice_is_equivalent_type) GetProcAddress(library, "grpc_slice_is_equivalent");
+ grpc_slice_buffer_init_import = (grpc_slice_buffer_init_type) GetProcAddress(library, "grpc_slice_buffer_init");
+ grpc_slice_buffer_destroy_import = (grpc_slice_buffer_destroy_type) GetProcAddress(library, "grpc_slice_buffer_destroy");
+ grpc_slice_buffer_add_import = (grpc_slice_buffer_add_type) GetProcAddress(library, "grpc_slice_buffer_add");
+ grpc_slice_buffer_add_indexed_import = (grpc_slice_buffer_add_indexed_type) GetProcAddress(library, "grpc_slice_buffer_add_indexed");
+ grpc_slice_buffer_addn_import = (grpc_slice_buffer_addn_type) GetProcAddress(library, "grpc_slice_buffer_addn");
+ grpc_slice_buffer_tiny_add_import = (grpc_slice_buffer_tiny_add_type) GetProcAddress(library, "grpc_slice_buffer_tiny_add");
+ grpc_slice_buffer_pop_import = (grpc_slice_buffer_pop_type) GetProcAddress(library, "grpc_slice_buffer_pop");
+ grpc_slice_buffer_reset_and_unref_import = (grpc_slice_buffer_reset_and_unref_type) GetProcAddress(library, "grpc_slice_buffer_reset_and_unref");
+ grpc_slice_buffer_swap_import = (grpc_slice_buffer_swap_type) GetProcAddress(library, "grpc_slice_buffer_swap");
+ grpc_slice_buffer_move_into_import = (grpc_slice_buffer_move_into_type) GetProcAddress(library, "grpc_slice_buffer_move_into");
+ grpc_slice_buffer_trim_end_import = (grpc_slice_buffer_trim_end_type) GetProcAddress(library, "grpc_slice_buffer_trim_end");
+ grpc_slice_buffer_move_first_import = (grpc_slice_buffer_move_first_type) GetProcAddress(library, "grpc_slice_buffer_move_first");
+ grpc_slice_buffer_take_first_import = (grpc_slice_buffer_take_first_type) GetProcAddress(library, "grpc_slice_buffer_take_first");
gpr_malloc_import = (gpr_malloc_type) GetProcAddress(library, "gpr_malloc");
gpr_free_import = (gpr_free_type) GetProcAddress(library, "gpr_free");
gpr_realloc_import = (gpr_realloc_type) GetProcAddress(library, "gpr_realloc");
@@ -495,35 +528,6 @@ void grpc_rb_load_imports(HMODULE library) {
gpr_log_verbosity_init_import = (gpr_log_verbosity_init_type) GetProcAddress(library, "gpr_log_verbosity_init");
gpr_set_log_function_import = (gpr_set_log_function_type) GetProcAddress(library, "gpr_set_log_function");
gpr_format_message_import = (gpr_format_message_type) GetProcAddress(library, "gpr_format_message");
- gpr_slice_ref_import = (gpr_slice_ref_type) GetProcAddress(library, "gpr_slice_ref");
- gpr_slice_unref_import = (gpr_slice_unref_type) GetProcAddress(library, "gpr_slice_unref");
- gpr_slice_new_import = (gpr_slice_new_type) GetProcAddress(library, "gpr_slice_new");
- gpr_slice_new_with_user_data_import = (gpr_slice_new_with_user_data_type) GetProcAddress(library, "gpr_slice_new_with_user_data");
- gpr_slice_new_with_len_import = (gpr_slice_new_with_len_type) GetProcAddress(library, "gpr_slice_new_with_len");
- gpr_slice_malloc_import = (gpr_slice_malloc_type) GetProcAddress(library, "gpr_slice_malloc");
- gpr_slice_from_copied_string_import = (gpr_slice_from_copied_string_type) GetProcAddress(library, "gpr_slice_from_copied_string");
- gpr_slice_from_copied_buffer_import = (gpr_slice_from_copied_buffer_type) GetProcAddress(library, "gpr_slice_from_copied_buffer");
- gpr_slice_from_static_string_import = (gpr_slice_from_static_string_type) GetProcAddress(library, "gpr_slice_from_static_string");
- gpr_slice_sub_import = (gpr_slice_sub_type) GetProcAddress(library, "gpr_slice_sub");
- gpr_slice_sub_no_ref_import = (gpr_slice_sub_no_ref_type) GetProcAddress(library, "gpr_slice_sub_no_ref");
- gpr_slice_split_tail_import = (gpr_slice_split_tail_type) GetProcAddress(library, "gpr_slice_split_tail");
- gpr_slice_split_head_import = (gpr_slice_split_head_type) GetProcAddress(library, "gpr_slice_split_head");
- gpr_empty_slice_import = (gpr_empty_slice_type) GetProcAddress(library, "gpr_empty_slice");
- gpr_slice_cmp_import = (gpr_slice_cmp_type) GetProcAddress(library, "gpr_slice_cmp");
- gpr_slice_str_cmp_import = (gpr_slice_str_cmp_type) GetProcAddress(library, "gpr_slice_str_cmp");
- gpr_slice_buffer_init_import = (gpr_slice_buffer_init_type) GetProcAddress(library, "gpr_slice_buffer_init");
- gpr_slice_buffer_destroy_import = (gpr_slice_buffer_destroy_type) GetProcAddress(library, "gpr_slice_buffer_destroy");
- gpr_slice_buffer_add_import = (gpr_slice_buffer_add_type) GetProcAddress(library, "gpr_slice_buffer_add");
- gpr_slice_buffer_add_indexed_import = (gpr_slice_buffer_add_indexed_type) GetProcAddress(library, "gpr_slice_buffer_add_indexed");
- gpr_slice_buffer_addn_import = (gpr_slice_buffer_addn_type) GetProcAddress(library, "gpr_slice_buffer_addn");
- gpr_slice_buffer_tiny_add_import = (gpr_slice_buffer_tiny_add_type) GetProcAddress(library, "gpr_slice_buffer_tiny_add");
- gpr_slice_buffer_pop_import = (gpr_slice_buffer_pop_type) GetProcAddress(library, "gpr_slice_buffer_pop");
- gpr_slice_buffer_reset_and_unref_import = (gpr_slice_buffer_reset_and_unref_type) GetProcAddress(library, "gpr_slice_buffer_reset_and_unref");
- gpr_slice_buffer_swap_import = (gpr_slice_buffer_swap_type) GetProcAddress(library, "gpr_slice_buffer_swap");
- gpr_slice_buffer_move_into_import = (gpr_slice_buffer_move_into_type) GetProcAddress(library, "gpr_slice_buffer_move_into");
- gpr_slice_buffer_trim_end_import = (gpr_slice_buffer_trim_end_type) GetProcAddress(library, "gpr_slice_buffer_trim_end");
- gpr_slice_buffer_move_first_import = (gpr_slice_buffer_move_first_type) GetProcAddress(library, "gpr_slice_buffer_move_first");
- gpr_slice_buffer_take_first_import = (gpr_slice_buffer_take_first_type) GetProcAddress(library, "gpr_slice_buffer_take_first");
gpr_strdup_import = (gpr_strdup_type) GetProcAddress(library, "gpr_strdup");
gpr_asprintf_import = (gpr_asprintf_type) GetProcAddress(library, "gpr_asprintf");
gpr_subprocess_binary_extension_import = (gpr_subprocess_binary_extension_type) GetProcAddress(library, "gpr_subprocess_binary_extension");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index c2244150f2..5745686adf 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -46,6 +46,8 @@
#include <grpc/grpc.h>
#include <grpc/grpc_posix.h>
#include <grpc/grpc_security.h>
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/avl.h>
#include <grpc/support/cmdline.h>
@@ -54,18 +56,16 @@
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/log_windows.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/slice_buffer.h>
#include <grpc/support/string_util.h>
#include <grpc/support/subprocess.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
-typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_create_type)(gpr_slice *slices, size_t nslices);
+typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_create_type)(grpc_slice *slices, size_t nslices);
extern grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import;
#define grpc_raw_byte_buffer_create grpc_raw_byte_buffer_create_import
-typedef grpc_byte_buffer *(*grpc_raw_compressed_byte_buffer_create_type)(gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression);
+typedef grpc_byte_buffer *(*grpc_raw_compressed_byte_buffer_create_type)(grpc_slice *slices, size_t nslices, grpc_compression_algorithm compression);
extern grpc_raw_compressed_byte_buffer_create_type grpc_raw_compressed_byte_buffer_create_import;
#define grpc_raw_compressed_byte_buffer_create grpc_raw_compressed_byte_buffer_create_import
typedef grpc_byte_buffer *(*grpc_byte_buffer_copy_type)(grpc_byte_buffer *bb);
@@ -83,10 +83,10 @@ extern grpc_byte_buffer_reader_init_type grpc_byte_buffer_reader_init_import;
typedef void(*grpc_byte_buffer_reader_destroy_type)(grpc_byte_buffer_reader *reader);
extern grpc_byte_buffer_reader_destroy_type grpc_byte_buffer_reader_destroy_import;
#define grpc_byte_buffer_reader_destroy grpc_byte_buffer_reader_destroy_import
-typedef int(*grpc_byte_buffer_reader_next_type)(grpc_byte_buffer_reader *reader, gpr_slice *slice);
+typedef int(*grpc_byte_buffer_reader_next_type)(grpc_byte_buffer_reader *reader, grpc_slice *slice);
extern grpc_byte_buffer_reader_next_type grpc_byte_buffer_reader_next_import;
#define grpc_byte_buffer_reader_next grpc_byte_buffer_reader_next_import
-typedef gpr_slice(*grpc_byte_buffer_reader_readall_type)(grpc_byte_buffer_reader *reader);
+typedef grpc_slice(*grpc_byte_buffer_reader_readall_type)(grpc_byte_buffer_reader *reader);
extern grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
#define grpc_byte_buffer_reader_readall grpc_byte_buffer_reader_readall_import
typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_from_reader_type)(grpc_byte_buffer_reader *reader);
@@ -281,6 +281,9 @@ extern grpc_census_call_get_context_type grpc_census_call_get_context_import;
typedef char *(*grpc_channel_get_target_type)(grpc_channel *channel);
extern grpc_channel_get_target_type grpc_channel_get_target_import;
#define grpc_channel_get_target grpc_channel_get_target_import
+typedef void(*grpc_channel_get_info_type)(grpc_channel *channel, const grpc_channel_info *channel_info);
+extern grpc_channel_get_info_type grpc_channel_get_info_import;
+#define grpc_channel_get_info grpc_channel_get_info_import
typedef grpc_channel *(*grpc_insecure_channel_create_type)(const char *target, const grpc_channel_args *args, void *reserved);
extern grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
#define grpc_insecure_channel_create grpc_insecure_channel_create_import
@@ -467,6 +470,96 @@ extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials *creds, grpc_auth_metadata_processor processor);
extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
+typedef grpc_slice(*grpc_slice_ref_type)(grpc_slice s);
+extern grpc_slice_ref_type grpc_slice_ref_import;
+#define grpc_slice_ref grpc_slice_ref_import
+typedef void(*grpc_slice_unref_type)(grpc_slice s);
+extern grpc_slice_unref_type grpc_slice_unref_import;
+#define grpc_slice_unref grpc_slice_unref_import
+typedef grpc_slice(*grpc_slice_new_type)(void *p, size_t len, void (*destroy)(void *));
+extern grpc_slice_new_type grpc_slice_new_import;
+#define grpc_slice_new grpc_slice_new_import
+typedef grpc_slice(*grpc_slice_new_with_user_data_type)(void *p, size_t len, void (*destroy)(void *), void *user_data);
+extern grpc_slice_new_with_user_data_type grpc_slice_new_with_user_data_import;
+#define grpc_slice_new_with_user_data grpc_slice_new_with_user_data_import
+typedef grpc_slice(*grpc_slice_new_with_len_type)(void *p, size_t len, void (*destroy)(void *, size_t));
+extern grpc_slice_new_with_len_type grpc_slice_new_with_len_import;
+#define grpc_slice_new_with_len grpc_slice_new_with_len_import
+typedef grpc_slice(*grpc_slice_malloc_type)(size_t length);
+extern grpc_slice_malloc_type grpc_slice_malloc_import;
+#define grpc_slice_malloc grpc_slice_malloc_import
+typedef grpc_slice(*grpc_slice_from_copied_string_type)(const char *source);
+extern grpc_slice_from_copied_string_type grpc_slice_from_copied_string_import;
+#define grpc_slice_from_copied_string grpc_slice_from_copied_string_import
+typedef grpc_slice(*grpc_slice_from_copied_buffer_type)(const char *source, size_t len);
+extern grpc_slice_from_copied_buffer_type grpc_slice_from_copied_buffer_import;
+#define grpc_slice_from_copied_buffer grpc_slice_from_copied_buffer_import
+typedef grpc_slice(*grpc_slice_from_static_string_type)(const char *source);
+extern grpc_slice_from_static_string_type grpc_slice_from_static_string_import;
+#define grpc_slice_from_static_string grpc_slice_from_static_string_import
+typedef grpc_slice(*grpc_slice_sub_type)(grpc_slice s, size_t begin, size_t end);
+extern grpc_slice_sub_type grpc_slice_sub_import;
+#define grpc_slice_sub grpc_slice_sub_import
+typedef grpc_slice(*grpc_slice_sub_no_ref_type)(grpc_slice s, size_t begin, size_t end);
+extern grpc_slice_sub_no_ref_type grpc_slice_sub_no_ref_import;
+#define grpc_slice_sub_no_ref grpc_slice_sub_no_ref_import
+typedef grpc_slice(*grpc_slice_split_tail_type)(grpc_slice *s, size_t split);
+extern grpc_slice_split_tail_type grpc_slice_split_tail_import;
+#define grpc_slice_split_tail grpc_slice_split_tail_import
+typedef grpc_slice(*grpc_slice_split_head_type)(grpc_slice *s, size_t split);
+extern grpc_slice_split_head_type grpc_slice_split_head_import;
+#define grpc_slice_split_head grpc_slice_split_head_import
+typedef grpc_slice(*gpr_empty_slice_type)(void);
+extern gpr_empty_slice_type gpr_empty_slice_import;
+#define gpr_empty_slice gpr_empty_slice_import
+typedef int(*grpc_slice_cmp_type)(grpc_slice a, grpc_slice b);
+extern grpc_slice_cmp_type grpc_slice_cmp_import;
+#define grpc_slice_cmp grpc_slice_cmp_import
+typedef int(*grpc_slice_str_cmp_type)(grpc_slice a, const char *b);
+extern grpc_slice_str_cmp_type grpc_slice_str_cmp_import;
+#define grpc_slice_str_cmp grpc_slice_str_cmp_import
+typedef int(*grpc_slice_is_equivalent_type)(grpc_slice a, grpc_slice b);
+extern grpc_slice_is_equivalent_type grpc_slice_is_equivalent_import;
+#define grpc_slice_is_equivalent grpc_slice_is_equivalent_import
+typedef void(*grpc_slice_buffer_init_type)(grpc_slice_buffer *sb);
+extern grpc_slice_buffer_init_type grpc_slice_buffer_init_import;
+#define grpc_slice_buffer_init grpc_slice_buffer_init_import
+typedef void(*grpc_slice_buffer_destroy_type)(grpc_slice_buffer *sb);
+extern grpc_slice_buffer_destroy_type grpc_slice_buffer_destroy_import;
+#define grpc_slice_buffer_destroy grpc_slice_buffer_destroy_import
+typedef void(*grpc_slice_buffer_add_type)(grpc_slice_buffer *sb, grpc_slice slice);
+extern grpc_slice_buffer_add_type grpc_slice_buffer_add_import;
+#define grpc_slice_buffer_add grpc_slice_buffer_add_import
+typedef size_t(*grpc_slice_buffer_add_indexed_type)(grpc_slice_buffer *sb, grpc_slice slice);
+extern grpc_slice_buffer_add_indexed_type grpc_slice_buffer_add_indexed_import;
+#define grpc_slice_buffer_add_indexed grpc_slice_buffer_add_indexed_import
+typedef void(*grpc_slice_buffer_addn_type)(grpc_slice_buffer *sb, grpc_slice *slices, size_t n);
+extern grpc_slice_buffer_addn_type grpc_slice_buffer_addn_import;
+#define grpc_slice_buffer_addn grpc_slice_buffer_addn_import
+typedef uint8_t *(*grpc_slice_buffer_tiny_add_type)(grpc_slice_buffer *sb, size_t len);
+extern grpc_slice_buffer_tiny_add_type grpc_slice_buffer_tiny_add_import;
+#define grpc_slice_buffer_tiny_add grpc_slice_buffer_tiny_add_import
+typedef void(*grpc_slice_buffer_pop_type)(grpc_slice_buffer *sb);
+extern grpc_slice_buffer_pop_type grpc_slice_buffer_pop_import;
+#define grpc_slice_buffer_pop grpc_slice_buffer_pop_import
+typedef void(*grpc_slice_buffer_reset_and_unref_type)(grpc_slice_buffer *sb);
+extern grpc_slice_buffer_reset_and_unref_type grpc_slice_buffer_reset_and_unref_import;
+#define grpc_slice_buffer_reset_and_unref grpc_slice_buffer_reset_and_unref_import
+typedef void(*grpc_slice_buffer_swap_type)(grpc_slice_buffer *a, grpc_slice_buffer *b);
+extern grpc_slice_buffer_swap_type grpc_slice_buffer_swap_import;
+#define grpc_slice_buffer_swap grpc_slice_buffer_swap_import
+typedef void(*grpc_slice_buffer_move_into_type)(grpc_slice_buffer *src, grpc_slice_buffer *dst);
+extern grpc_slice_buffer_move_into_type grpc_slice_buffer_move_into_import;
+#define grpc_slice_buffer_move_into grpc_slice_buffer_move_into_import
+typedef void(*grpc_slice_buffer_trim_end_type)(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *garbage);
+extern grpc_slice_buffer_trim_end_type grpc_slice_buffer_trim_end_import;
+#define grpc_slice_buffer_trim_end grpc_slice_buffer_trim_end_import
+typedef void(*grpc_slice_buffer_move_first_type)(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *dst);
+extern grpc_slice_buffer_move_first_type grpc_slice_buffer_move_first_import;
+#define grpc_slice_buffer_move_first grpc_slice_buffer_move_first_import
+typedef grpc_slice(*grpc_slice_buffer_take_first_type)(grpc_slice_buffer *src);
+extern grpc_slice_buffer_take_first_type grpc_slice_buffer_take_first_import;
+#define grpc_slice_buffer_take_first grpc_slice_buffer_take_first_import
typedef void *(*gpr_malloc_type)(size_t size);
extern gpr_malloc_type gpr_malloc_import;
#define gpr_malloc gpr_malloc_import
@@ -596,7 +689,7 @@ extern gpr_join_host_port_type gpr_join_host_port_import;
typedef int(*gpr_split_host_port_type)(const char *name, char **host, char **port);
extern gpr_split_host_port_type gpr_split_host_port_import;
#define gpr_split_host_port gpr_split_host_port_import
-typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...) GPRC_PRINT_FORMAT_CHECK(4, 5);
+typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...) GPR_PRINT_FORMAT_CHECK(4, 5);
extern gpr_log_type gpr_log_import;
#define gpr_log gpr_log_import
typedef void(*gpr_log_message_type)(const char *file, int line, gpr_log_severity severity, const char *message);
@@ -614,97 +707,10 @@ extern gpr_set_log_function_type gpr_set_log_function_import;
typedef char *(*gpr_format_message_type)(int messageid);
extern gpr_format_message_type gpr_format_message_import;
#define gpr_format_message gpr_format_message_import
-typedef gpr_slice(*gpr_slice_ref_type)(gpr_slice s);
-extern gpr_slice_ref_type gpr_slice_ref_import;
-#define gpr_slice_ref gpr_slice_ref_import
-typedef void(*gpr_slice_unref_type)(gpr_slice s);
-extern gpr_slice_unref_type gpr_slice_unref_import;
-#define gpr_slice_unref gpr_slice_unref_import
-typedef gpr_slice(*gpr_slice_new_type)(void *p, size_t len, void (*destroy)(void *));
-extern gpr_slice_new_type gpr_slice_new_import;
-#define gpr_slice_new gpr_slice_new_import
-typedef gpr_slice(*gpr_slice_new_with_user_data_type)(void *p, size_t len, void (*destroy)(void *), void *user_data);
-extern gpr_slice_new_with_user_data_type gpr_slice_new_with_user_data_import;
-#define gpr_slice_new_with_user_data gpr_slice_new_with_user_data_import
-typedef gpr_slice(*gpr_slice_new_with_len_type)(void *p, size_t len, void (*destroy)(void *, size_t));
-extern gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
-#define gpr_slice_new_with_len gpr_slice_new_with_len_import
-typedef gpr_slice(*gpr_slice_malloc_type)(size_t length);
-extern gpr_slice_malloc_type gpr_slice_malloc_import;
-#define gpr_slice_malloc gpr_slice_malloc_import
-typedef gpr_slice(*gpr_slice_from_copied_string_type)(const char *source);
-extern gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
-#define gpr_slice_from_copied_string gpr_slice_from_copied_string_import
-typedef gpr_slice(*gpr_slice_from_copied_buffer_type)(const char *source, size_t len);
-extern gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
-#define gpr_slice_from_copied_buffer gpr_slice_from_copied_buffer_import
-typedef gpr_slice(*gpr_slice_from_static_string_type)(const char *source);
-extern gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
-#define gpr_slice_from_static_string gpr_slice_from_static_string_import
-typedef gpr_slice(*gpr_slice_sub_type)(gpr_slice s, size_t begin, size_t end);
-extern gpr_slice_sub_type gpr_slice_sub_import;
-#define gpr_slice_sub gpr_slice_sub_import
-typedef gpr_slice(*gpr_slice_sub_no_ref_type)(gpr_slice s, size_t begin, size_t end);
-extern gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
-#define gpr_slice_sub_no_ref gpr_slice_sub_no_ref_import
-typedef gpr_slice(*gpr_slice_split_tail_type)(gpr_slice *s, size_t split);
-extern gpr_slice_split_tail_type gpr_slice_split_tail_import;
-#define gpr_slice_split_tail gpr_slice_split_tail_import
-typedef gpr_slice(*gpr_slice_split_head_type)(gpr_slice *s, size_t split);
-extern gpr_slice_split_head_type gpr_slice_split_head_import;
-#define gpr_slice_split_head gpr_slice_split_head_import
-typedef gpr_slice(*gpr_empty_slice_type)(void);
-extern gpr_empty_slice_type gpr_empty_slice_import;
-#define gpr_empty_slice gpr_empty_slice_import
-typedef int(*gpr_slice_cmp_type)(gpr_slice a, gpr_slice b);
-extern gpr_slice_cmp_type gpr_slice_cmp_import;
-#define gpr_slice_cmp gpr_slice_cmp_import
-typedef int(*gpr_slice_str_cmp_type)(gpr_slice a, const char *b);
-extern gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
-#define gpr_slice_str_cmp gpr_slice_str_cmp_import
-typedef void(*gpr_slice_buffer_init_type)(gpr_slice_buffer *sb);
-extern gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
-#define gpr_slice_buffer_init gpr_slice_buffer_init_import
-typedef void(*gpr_slice_buffer_destroy_type)(gpr_slice_buffer *sb);
-extern gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
-#define gpr_slice_buffer_destroy gpr_slice_buffer_destroy_import
-typedef void(*gpr_slice_buffer_add_type)(gpr_slice_buffer *sb, gpr_slice slice);
-extern gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
-#define gpr_slice_buffer_add gpr_slice_buffer_add_import
-typedef size_t(*gpr_slice_buffer_add_indexed_type)(gpr_slice_buffer *sb, gpr_slice slice);
-extern gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
-#define gpr_slice_buffer_add_indexed gpr_slice_buffer_add_indexed_import
-typedef void(*gpr_slice_buffer_addn_type)(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
-extern gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
-#define gpr_slice_buffer_addn gpr_slice_buffer_addn_import
-typedef uint8_t *(*gpr_slice_buffer_tiny_add_type)(gpr_slice_buffer *sb, size_t len);
-extern gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
-#define gpr_slice_buffer_tiny_add gpr_slice_buffer_tiny_add_import
-typedef void(*gpr_slice_buffer_pop_type)(gpr_slice_buffer *sb);
-extern gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
-#define gpr_slice_buffer_pop gpr_slice_buffer_pop_import
-typedef void(*gpr_slice_buffer_reset_and_unref_type)(gpr_slice_buffer *sb);
-extern gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
-#define gpr_slice_buffer_reset_and_unref gpr_slice_buffer_reset_and_unref_import
-typedef void(*gpr_slice_buffer_swap_type)(gpr_slice_buffer *a, gpr_slice_buffer *b);
-extern gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
-#define gpr_slice_buffer_swap gpr_slice_buffer_swap_import
-typedef void(*gpr_slice_buffer_move_into_type)(gpr_slice_buffer *src, gpr_slice_buffer *dst);
-extern gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
-#define gpr_slice_buffer_move_into gpr_slice_buffer_move_into_import
-typedef void(*gpr_slice_buffer_trim_end_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *garbage);
-extern gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
-#define gpr_slice_buffer_trim_end gpr_slice_buffer_trim_end_import
-typedef void(*gpr_slice_buffer_move_first_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *dst);
-extern gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
-#define gpr_slice_buffer_move_first gpr_slice_buffer_move_first_import
-typedef gpr_slice(*gpr_slice_buffer_take_first_type)(gpr_slice_buffer *src);
-extern gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
-#define gpr_slice_buffer_take_first gpr_slice_buffer_take_first_import
typedef char *(*gpr_strdup_type)(const char *src);
extern gpr_strdup_type gpr_strdup_import;
#define gpr_strdup gpr_strdup_import
-typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...) GPRC_PRINT_FORMAT_CHECK(2, 3);
+typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...) GPR_PRINT_FORMAT_CHECK(2, 3);
extern gpr_asprintf_type gpr_asprintf_import;
#define gpr_asprintf gpr_asprintf_import
typedef const char *(*gpr_subprocess_binary_extension_type)();
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 57f99c8ce6..00e0db71be 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -31,10 +31,133 @@ require_relative '../grpc'
require_relative 'active_call'
require_relative 'service'
require 'thread'
-require 'concurrent'
# GRPC contains the General RPC module.
module GRPC
+ # Pool is a simple thread pool.
+ class Pool
+ # Default keep alive period is 1s
+ DEFAULT_KEEP_ALIVE = 1
+
+ def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
+ fail 'pool size must be positive' unless size > 0
+ @jobs = Queue.new
+ @size = size
+ @stopped = false
+ @stop_mutex = Mutex.new # needs to be held when accessing @stopped
+ @stop_cond = ConditionVariable.new
+ @workers = []
+ @keep_alive = keep_alive
+
+ # Each worker thread has its own queue to push and pull jobs
+ # these queues are put into @ready_queues when that worker is idle
+ @ready_workers = Queue.new
+ end
+
+ # Returns the number of jobs waiting
+ def jobs_waiting
+ @jobs.size
+ end
+
+ def ready_for_work?
+ # Busy worker threads are either doing work, or have a single job
+ # waiting on them. Workers that are idle with no jobs waiting
+ # have their "queues" in @ready_workers
+ !@ready_workers.empty?
+ end
+
+ # Runs the given block on the queue with the provided args.
+ #
+ # @param args the args passed blk when it is called
+ # @param blk the block to call
+ def schedule(*args, &blk)
+ return if blk.nil?
+ @stop_mutex.synchronize do
+ if @stopped
+ GRPC.logger.warn('did not schedule job, already stopped')
+ return
+ end
+ GRPC.logger.info('schedule another job')
+ fail 'No worker threads available' if @ready_workers.empty?
+ worker_queue = @ready_workers.pop
+
+ fail 'worker already has a task waiting' unless worker_queue.empty?
+ worker_queue << [blk, args]
+ end
+ end
+
+ # Starts running the jobs in the thread pool.
+ def start
+ @stop_mutex.synchronize do
+ fail 'already stopped' if @stopped
+ end
+ until @workers.size == @size.to_i
+ new_worker_queue = Queue.new
+ @ready_workers << new_worker_queue
+ next_thread = Thread.new(new_worker_queue) do |jobs|
+ catch(:exit) do # allows { throw :exit } to kill a thread
+ loop_execute_jobs(jobs)
+ end
+ remove_current_thread
+ end
+ @workers << next_thread
+ end
+ end
+
+ # Stops the jobs in the pool
+ def stop
+ GRPC.logger.info('stopping, will wait for all the workers to exit')
+ schedule { throw :exit } while ready_for_work?
+ @stop_mutex.synchronize do # wait @keep_alive for works to stop
+ @stopped = true
+ @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
+ end
+ forcibly_stop_workers
+ GRPC.logger.info('stopped, all workers are shutdown')
+ end
+
+ protected
+
+ # Forcibly shutdown any threads that are still alive.
+ def forcibly_stop_workers
+ return unless @workers.size > 0
+ GRPC.logger.info("forcibly terminating #{@workers.size} worker(s)")
+ @workers.each do |t|
+ next unless t.alive?
+ begin
+ t.exit
+ rescue StandardError => e
+ GRPC.logger.warn('error while terminating a worker')
+ GRPC.logger.warn(e)
+ end
+ end
+ end
+
+ # removes the threads from workers, and signal when all the
+ # threads are complete.
+ def remove_current_thread
+ @stop_mutex.synchronize do
+ @workers.delete(Thread.current)
+ @stop_cond.signal if @workers.size.zero?
+ end
+ end
+
+ def loop_execute_jobs(worker_queue)
+ loop do
+ begin
+ blk, args = worker_queue.pop
+ blk.call(*args)
+ rescue StandardError => e
+ GRPC.logger.warn('Error in worker thread')
+ GRPC.logger.warn(e)
+ end
+ # there shouldn't be any work given to this thread while its busy
+ fail('received a task while busy') unless worker_queue.empty?
+ @ready_workers << worker_queue
+ end
+ end
+ end
+
# RpcServer hosts a number of services and makes them available on the
# network.
class RpcServer
@@ -44,17 +167,13 @@ module GRPC
def_delegators :@server, :add_http2_port
- # Default max size of the thread pool size is 100
- DEFAULT_MAX_POOL_SIZE = 100
-
- # Default minimum size of the thread pool is 5
- DEFAULT_MIN_POOL_SIZE = 5
+ # Default thread pool size is 30
+ DEFAULT_POOL_SIZE = 30
- # Default max_waiting_requests size is 60
- DEFAULT_MAX_WAITING_REQUESTS = 60
+ # Deprecated due to internal changes to the thread pool
+ DEFAULT_MAX_WAITING_REQUESTS = 20
# Default poll period is 1s
- # Used for grpc server shutdown and thread pool shutdown timeouts
DEFAULT_POLL_PERIOD = 1
# Signal check period is 0.25s
@@ -75,12 +194,12 @@ module GRPC
# There are some specific keyword args used to configure the RpcServer
# instance.
#
- # * pool_size: the maximum size of the thread pool that the server's
- # thread pool can reach.
+ # * pool_size: the size of the thread pool the server uses to run its
+ # threads. No more concurrent requests can be made than the size
+ # of the thread pool
#
- # * max_waiting_requests: the maximum number of requests that are not
- # being handled to allow. When this limit is exceeded, the server responds
- # with not available to new requests
+ # * max_waiting_requests: Deprecated due to internal changes to the thread
+ # pool. This is still an argument for compatibility but is ignored.
#
# * poll_period: when present, the server polls for new events with this
# period
@@ -92,8 +211,7 @@ module GRPC
#
# * server_args:
# A server arguments hash to be passed down to the underlying core server
- def initialize(pool_size:DEFAULT_MAX_POOL_SIZE,
- min_pool_size:DEFAULT_MIN_POOL_SIZE,
+ def initialize(pool_size:DEFAULT_POOL_SIZE,
max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS,
poll_period:DEFAULT_POLL_PERIOD,
connect_md_proc:nil,
@@ -101,12 +219,8 @@ module GRPC
@connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
@max_waiting_requests = max_waiting_requests
@poll_period = poll_period
-
- @pool = Concurrent::ThreadPoolExecutor.new(
- min_threads: [min_pool_size, pool_size].min,
- max_threads: pool_size,
- max_queue: max_waiting_requests,
- fallback_policy: :discard)
+ @pool_size = pool_size
+ @pool = Pool.new(@pool_size)
@run_cond = ConditionVariable.new
@run_mutex = Mutex.new
# running_state can take 4 values: :not_started, :running, :stopping, and
@@ -127,8 +241,7 @@ module GRPC
end
deadline = from_relative_time(@poll_period)
@server.close(deadline)
- @pool.shutdown
- @pool.wait_for_termination(@poll_period)
+ @pool.stop
end
def running_state
@@ -225,6 +338,7 @@ module GRPC
def run
@run_mutex.synchronize do
fail 'cannot run without registering services' if rpc_descs.size.zero?
+ @pool.start
@server.start
transition_running_state(:running)
@run_cond.broadcast
@@ -236,12 +350,8 @@ module GRPC
# Sends RESOURCE_EXHAUSTED if there are too many unprocessed jobs
def available?(an_rpc)
- jobs_count, max = @pool.queue_length, @pool.max_queue
- GRPC.logger.info("waiting: #{jobs_count}, max: #{max}")
-
- # remaining capacity for ThreadPoolExecutors is -1 if unbounded
- return an_rpc if @pool.remaining_capacity != 0
- GRPC.logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
+ return an_rpc if @pool.ready_for_work?
+ GRPC.logger.warn('no free worker threads currently')
noop = proc { |x| x }
# Create a new active call that knows that metadata hasn't been
@@ -276,7 +386,7 @@ module GRPC
break if (!an_rpc.nil?) && an_rpc.call.nil?
active_call = new_active_server_call(an_rpc)
unless active_call.nil?
- @pool.post(active_call) do |ac|
+ @pool.schedule(active_call) do |ac|
c, mth = ac
begin
rpc_descs[mth].run_server_method(c, rpc_handlers[mth])
diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb
new file mode 100644
index 0000000000..48ccaee510
--- /dev/null
+++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb
@@ -0,0 +1,144 @@
+# 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.
+
+require 'grpc'
+
+Thread.abort_on_exception = true
+
+describe GRPC::Pool do
+ Pool = GRPC::Pool
+
+ describe '#new' do
+ it 'raises if a non-positive size is used' do
+ expect { Pool.new(0) }.to raise_error
+ expect { Pool.new(-1) }.to raise_error
+ expect { Pool.new(Object.new) }.to raise_error
+ end
+
+ it 'is constructed OK with a positive size' do
+ expect { Pool.new(1) }.not_to raise_error
+ end
+ end
+
+ describe '#ready_for_work?' do
+ it 'before start it is not ready' do
+ p = Pool.new(1)
+ expect(p.ready_for_work?).to be(false)
+ end
+
+ it 'it stops being ready after all workers jobs waiting or running' do
+ p = Pool.new(5)
+ p.start
+ job = proc { sleep(3) } # sleep so workers busy when done scheduling
+ 5.times do
+ expect(p.ready_for_work?).to be(true)
+ p.schedule(&job)
+ end
+ expect(p.ready_for_work?).to be(false)
+ end
+
+ it 'it becomes ready again after jobs complete' do
+ p = Pool.new(5)
+ p.start
+ job = proc {}
+ 5.times do
+ expect(p.ready_for_work?).to be(true)
+ p.schedule(&job)
+ end
+ expect(p.ready_for_work?).to be(false)
+ sleep 5 # give the pool time do get at least one task done
+ expect(p.ready_for_work?).to be(true)
+ end
+ end
+
+ describe '#schedule' do
+ it 'return if the pool is already stopped' do
+ p = Pool.new(1)
+ p.stop
+ job = proc {}
+ expect { p.schedule(&job) }.to_not raise_error
+ end
+
+ it 'adds jobs that get run by the pool' do
+ p = Pool.new(1)
+ p.start
+ o, q = Object.new, Queue.new
+ job = proc { q.push(o) }
+ p.schedule(&job)
+ expect(q.pop).to be(o)
+ p.stop
+ end
+
+ it 'it throws an error if all of the workers have tasks to do' do
+ p = Pool.new(5)
+ p.start
+ job = proc {}
+ 5.times do
+ expect(p.ready_for_work?).to be(true)
+ p.schedule(&job)
+ end
+ expect { p.schedule(&job) }.to raise_error
+ expect { p.schedule(&job) }.to raise_error
+ end
+ end
+
+ describe '#stop' do
+ it 'works when there are no scheduled tasks' do
+ p = Pool.new(1)
+ expect { p.stop }.not_to raise_error
+ end
+
+ it 'stops jobs when there are long running jobs' do
+ p = Pool.new(1)
+ p.start
+ o, q = Object.new, Queue.new
+ job = proc do
+ sleep(5) # long running
+ q.push(o)
+ end
+ p.schedule(&job)
+ sleep(1) # should ensure the long job gets scheduled
+ expect { p.stop }.not_to raise_error
+ end
+ end
+
+ describe '#start' do
+ it 'runs jobs as they are scheduled' do
+ p = Pool.new(5)
+ o, q = Object.new, Queue.new
+ p.start
+ n = 5 # arbitrary
+ n.times do
+ p.schedule(o, &q.method(:push))
+ expect(q.pop).to be(o)
+ end
+ p.stop
+ end
+ end
+end