aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/config.h29
-rw-r--r--src/compiler/cpp_generator.cc7
-rw-r--r--src/compiler/csharp_generator.cc143
-rw-r--r--src/compiler/generator_helpers.h3
-rw-r--r--src/compiler/node_generator.cc14
-rw-r--r--src/compiler/objective_c_generator.cc46
-rw-r--r--src/compiler/python_generator.cc148
-rw-r--r--src/compiler/python_generator.h1
-rw-r--r--src/compiler/python_plugin.cc1
-rw-r--r--src/core/ext/census/grpc_filter.c10
-rw-r--r--src/core/ext/client_config/channel_connectivity.c40
-rw-r--r--src/core/ext/client_config/client_channel.c122
-rw-r--r--src/core/ext/client_config/connector.h2
-rw-r--r--src/core/ext/client_config/lb_policy.c15
-rw-r--r--src/core/ext/client_config/lb_policy.h14
-rw-r--r--src/core/ext/client_config/subchannel.c93
-rw-r--r--src/core/ext/client_config/subchannel.h5
-rw-r--r--src/core/ext/client_config/subchannel_call_holder.c52
-rw-r--r--src/core/ext/client_config/subchannel_call_holder.h3
-rw-r--r--src/core/ext/lb_policy/pick_first/pick_first.c104
-rw-r--r--src/core/ext/lb_policy/round_robin/round_robin.c125
-rw-r--r--src/core/ext/load_reporting/load_reporting.c3
-rw-r--r--src/core/ext/load_reporting/load_reporting_filter.c2
-rw-r--r--src/core/ext/resolver/dns/native/dns_resolver.c30
-rw-r--r--src/core/ext/resolver/sockaddr/sockaddr_resolver.c4
-rw-r--r--src/core/ext/resolver/zookeeper/zookeeper_resolver.c513
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create.c8
-rw-r--r--src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c95
-rw-r--r--src/core/ext/transport/chttp2/client/secure/secure_channel_create.c26
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2.c62
-rw-r--r--src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c82
-rw-r--r--src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c90
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.c232
-rw-r--r--src/core/ext/transport/chttp2/transport/bin_decoder.h66
-rw-r--r--src/core/ext/transport/chttp2/transport/chttp2_transport.c453
-rw-r--r--src/core/ext/transport/chttp2/transport/frame.h8
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.c71
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_data.h11
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.c37
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_goaway.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.c19
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_ping.h6
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.c32
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_rst_stream.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.c44
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_settings.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.c26
-rw-r--r--src/core/ext/transport/chttp2/transport/frame_window_update.h4
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.c650
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_parser.h14
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.c44
-rw-r--r--src/core/ext/transport/chttp2/transport/hpack_table.h9
-rw-r--r--src/core/ext/transport/chttp2/transport/internal.h47
-rw-r--r--src/core/ext/transport/chttp2/transport/parsing.c454
-rw-r--r--src/core/ext/transport/chttp2/transport/writing.c21
-rw-r--r--src/core/ext/transport/cronet/transport/cronet_transport.c22
-rw-r--r--src/core/lib/channel/channel_args.c26
-rw-r--r--src/core/lib/channel/channel_args.h2
-rw-r--r--src/core/lib/channel/channel_stack.c17
-rw-r--r--src/core/lib/channel/channel_stack.h28
-rw-r--r--src/core/lib/channel/channel_stack_builder.c4
-rw-r--r--src/core/lib/channel/compress_filter.c51
-rw-r--r--src/core/lib/channel/compress_filter.h6
-rw-r--r--src/core/lib/channel/connected_channel.c11
-rw-r--r--src/core/lib/channel/http_client_filter.c40
-rw-r--r--src/core/lib/channel/http_client_filter.h2
-rw-r--r--src/core/lib/channel/http_server_filter.c31
-rw-r--r--src/core/lib/compression/compression.c (renamed from src/core/lib/compression/compression_algorithm.c)44
-rw-r--r--src/core/lib/http/httpcli.c140
-rw-r--r--src/core/lib/http/httpcli.h26
-rw-r--r--src/core/lib/http/httpcli_security_connector.c6
-rw-r--r--src/core/lib/http/parser.c246
-rw-r--r--src/core/lib/http/parser.c.orig357
-rw-r--r--src/core/lib/http/parser.h17
-rw-r--r--src/core/lib/iomgr/closure.c36
-rw-r--r--src/core/lib/iomgr/closure.h34
-rw-r--r--src/core/lib/iomgr/endpoint.h2
-rw-r--r--src/core/lib/iomgr/endpoint_pair_posix.c4
-rw-r--r--src/core/lib/iomgr/error.c535
-rw-r--r--src/core/lib/iomgr/error.h192
-rw-r--r--src/core/lib/iomgr/ev_poll_and_epoll_posix.c205
-rw-r--r--src/core/lib/iomgr/ev_poll_posix.c149
-rw-r--r--src/core/lib/iomgr/ev_posix.c20
-rw-r--r--src/core/lib/iomgr/ev_posix.h18
-rw-r--r--src/core/lib/iomgr/exec_ctx.c15
-rw-r--r--src/core/lib/iomgr/exec_ctx.h6
-rw-r--r--src/core/lib/iomgr/executor.c4
-rw-r--r--src/core/lib/iomgr/executor.h2
-rw-r--r--src/core/lib/iomgr/iocp_windows.c41
-rw-r--r--src/core/lib/iomgr/iocp_windows.h8
-rw-r--r--src/core/lib/iomgr/iomgr.c9
-rw-r--r--src/core/lib/iomgr/load_file.c (renamed from src/core/lib/support/load_file.c)32
-rw-r--r--src/core/lib/iomgr/load_file.h (renamed from src/core/lib/support/load_file.h)15
-rw-r--r--src/core/lib/iomgr/polling_entity.c104
-rw-r--r--src/core/lib/iomgr/polling_entity.h81
-rw-r--r--src/core/lib/iomgr/pollset.h11
-rw-r--r--src/core/lib/iomgr/pollset_set_windows.c5
-rw-r--r--src/core/lib/iomgr/pollset_windows.c16
-rw-r--r--src/core/lib/iomgr/resolve_address.h14
-rw-r--r--src/core/lib/iomgr/resolve_address_posix.c93
-rw-r--r--src/core/lib/iomgr/resolve_address_windows.c86
-rw-r--r--src/core/lib/iomgr/socket_utils_common_posix.c137
-rw-r--r--src/core/lib/iomgr/socket_utils_posix.h31
-rw-r--r--src/core/lib/iomgr/socket_windows.c61
-rw-r--r--src/core/lib/iomgr/socket_windows.h13
-rw-r--r--src/core/lib/iomgr/tcp_client_posix.c93
-rw-r--r--src/core/lib/iomgr/tcp_client_windows.c64
-rw-r--r--src/core/lib/iomgr/tcp_posix.c74
-rw-r--r--src/core/lib/iomgr/tcp_server.h7
-rw-r--r--src/core/lib/iomgr/tcp_server_posix.c143
-rw-r--r--src/core/lib/iomgr/tcp_server_windows.c208
-rw-r--r--src/core/lib/iomgr/tcp_windows.c91
-rw-r--r--src/core/lib/iomgr/tcp_windows.h2
-rw-r--r--src/core/lib/iomgr/timer.c39
-rw-r--r--src/core/lib/iomgr/udp_server.c14
-rw-r--r--src/core/lib/iomgr/unix_sockets_posix.c15
-rw-r--r--src/core/lib/iomgr/unix_sockets_posix.h3
-rw-r--r--src/core/lib/iomgr/unix_sockets_posix_noop.c6
-rw-r--r--src/core/lib/iomgr/wakeup_fd_eventfd.c20
-rw-r--r--src/core/lib/iomgr/wakeup_fd_pipe.c22
-rw-r--r--src/core/lib/iomgr/wakeup_fd_posix.c12
-rw-r--r--src/core/lib/iomgr/wakeup_fd_posix.h15
-rw-r--r--src/core/lib/iomgr/workqueue.h7
-rw-r--r--src/core/lib/iomgr/workqueue_posix.c66
-rw-r--r--src/core/lib/profiling/basic_timers.c4
-rw-r--r--src/core/lib/security/credentials/composite/composite_credentials.c13
-rw-r--r--src/core/lib/security/credentials/credentials.c6
-rw-r--r--src/core/lib/security/credentials/credentials.h7
-rw-r--r--src/core/lib/security/credentials/fake/fake_credentials.c9
-rw-r--r--src/core/lib/security/credentials/google_default/google_default_credentials.c124
-rw-r--r--src/core/lib/security/credentials/iam/iam_credentials.c2
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_credentials.c6
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_verifier.c46
-rw-r--r--src/core/lib/security/credentials/oauth2/oauth2_credentials.c35
-rw-r--r--src/core/lib/security/credentials/oauth2/oauth2_credentials.h4
-rw-r--r--src/core/lib/security/credentials/plugin/plugin_credentials.c2
-rw-r--r--src/core/lib/security/transport/client_auth_filter.c37
-rw-r--r--src/core/lib/security/transport/handshake.c116
-rw-r--r--src/core/lib/security/transport/handshake.h12
-rw-r--r--src/core/lib/security/transport/secure_endpoint.c29
-rw-r--r--src/core/lib/security/transport/security_connector.c33
-rw-r--r--src/core/lib/security/transport/security_connector.h10
-rw-r--r--src/core/lib/security/transport/server_auth_filter.c32
-rw-r--r--src/core/lib/security/transport/tsi_error.c40
-rw-r--r--src/core/lib/security/transport/tsi_error.h42
-rw-r--r--src/core/lib/support/avl.c11
-rw-r--r--src/core/lib/support/log.c4
-rw-r--r--src/core/lib/support/log_linux.c4
-rw-r--r--src/core/lib/support/string.c10
-rw-r--r--src/core/lib/support/string.h4
-rw-r--r--src/core/lib/surface/alarm.c4
-rw-r--r--src/core/lib/surface/call.c417
-rw-r--r--src/core/lib/surface/call.h2
-rw-r--r--src/core/lib/surface/call_log_batch.c2
-rw-r--r--src/core/lib/surface/channel.c79
-rw-r--r--src/core/lib/surface/channel.h9
-rw-r--r--src/core/lib/surface/channel_ping.c6
-rw-r--r--src/core/lib/surface/completion_queue.c76
-rw-r--r--src/core/lib/surface/completion_queue.h4
-rw-r--r--src/core/lib/surface/init.c1
-rw-r--r--src/core/lib/surface/lame_client.c15
-rw-r--r--src/core/lib/surface/server.c124
-rw-r--r--src/core/lib/surface/version.c2
-rw-r--r--src/core/lib/transport/connectivity_state.c50
-rw-r--r--src/core/lib/transport/connectivity_state.h5
-rw-r--r--src/core/lib/transport/metadata.c43
-rw-r--r--src/core/lib/transport/transport.c36
-rw-r--r--src/core/lib/transport/transport.h11
-rw-r--r--src/core/lib/transport/transport_impl.h4
-rw-r--r--src/core/lib/transport/transport_op_string.c4
-rw-r--r--src/core/plugin_registry/grpc_cronet_plugin_registry.c46
-rw-r--r--src/cpp/client/client_context.cc10
-rw-r--r--src/cpp/client/create_channel_posix.cc56
-rw-r--r--src/cpp/codegen/codegen_init.cc6
-rw-r--r--src/cpp/common/core_codegen.cc2
-rw-r--r--src/cpp/common/core_codegen.h83
-rw-r--r--src/cpp/ext/proto_server_reflection.cc227
-rw-r--r--src/cpp/ext/proto_server_reflection.h94
-rw-r--r--src/cpp/ext/proto_server_reflection_plugin.cc97
-rw-r--r--src/cpp/ext/reflection.grpc.pb.cc97
-rw-r--r--src/cpp/ext/reflection.pb.cc3946
-rw-r--r--src/cpp/server/server.cc10
-rw-r--r--src/cpp/server/server_builder.cc87
-rw-r--r--src/cpp/server/server_context.cc6
-rw-r--r--src/cpp/server/server_posix.cc49
-rw-r--r--src/csharp/.gitignore2
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj1
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.project.json8
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.xproj18
-rw-r--r--src/csharp/Grpc.Auth/project.json32
-rw-r--r--src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs92
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/CompressionTest.cs26
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj5
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json8
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj18
-rw-r--r--src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs12
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitMain.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/PInvokeTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs3
-rw-r--r--src/csharp/Grpc.Core.Tests/ServerTest.cs17
-rw-r--r--src/csharp/Grpc.Core.Tests/ShutdownHookClientTest.cs57
-rw-r--r--src/csharp/Grpc.Core.Tests/ShutdownHookPendingCallTest.cs69
-rw-r--r--src/csharp/Grpc.Core.Tests/ShutdownHookServerTest.cs58
-rw-r--r--src/csharp/Grpc.Core.Tests/project.json56
-rw-r--r--src/csharp/Grpc.Core/AsyncClientStreamingCall.cs4
-rw-r--r--src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs4
-rw-r--r--src/csharp/Grpc.Core/AsyncServerStreamingCall.cs4
-rw-r--r--src/csharp/Grpc.Core/AsyncUnaryCall.cs4
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs8
-rw-r--r--src/csharp/Grpc.Core/Channel.cs55
-rw-r--r--src/csharp/Grpc.Core/ChannelState.cs2
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj5
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec13
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.project.json8
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.xproj18
-rw-r--r--src/csharp/Grpc.Core/GrpcEnvironment.cs128
-rw-r--r--src/csharp/Grpc.Core/IAsyncStreamReader.cs16
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs27
-rw-r--r--src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs28
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeExtension.cs6
-rw-r--r--src/csharp/Grpc.Core/Internal/PlatformApis.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs23
-rw-r--r--src/csharp/Grpc.Core/Logging/LogLevel.cs59
-rw-r--r--src/csharp/Grpc.Core/Logging/LogLevelFilterLogger.cs160
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs12
-rw-r--r--src/csharp/Grpc.Core/Server.cs98
-rw-r--r--src/csharp/Grpc.Core/ServerServiceDefinition.cs10
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rw-r--r--src/csharp/Grpc.Core/project.json42
-rw-r--r--src/csharp/Grpc.Dotnet.sln100
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj3
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json8
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj18
-rw-r--r--src/csharp/Grpc.Examples.MathClient/project.json53
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj3
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json8
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj18
-rw-r--r--src/csharp/Grpc.Examples.MathServer/project.json53
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj1
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json8
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj18
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs10
-rw-r--r--src/csharp/Grpc.Examples.Tests/NUnitMain.cs2
-rw-r--r--src/csharp/Grpc.Examples.Tests/project.json55
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj1
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.project.json8
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.xproj18
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs152
-rw-r--r--src/csharp/Grpc.Examples/project.json27
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj1
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json8
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj18
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/project.json55
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj1
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json8
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj18
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs49
-rw-r--r--src/csharp/Grpc.HealthCheck/project.json35
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj18
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/project.json56
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj18
-rw-r--r--src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json56
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj18
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/project.json56
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj5
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json8
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj19
-rw-r--r--src/csharp/Grpc.IntegrationTesting.StressClient/project.json56
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ClientRunners.cs6
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs12
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs3
-rw-r--r--src/csharp/Grpc.IntegrationTesting/GenericService.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json8
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj18
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs163
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs414
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs25
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs80
-rw-r--r--src/csharp/Grpc.IntegrationTesting/NUnitMain.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs226
-rw-r--r--src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/StressTestClient.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs277
-rw-r--r--src/csharp/Grpc.IntegrationTesting/project.json72
-rw-r--r--src/csharp/README.md68
-rw-r--r--src/csharp/build_packages.bat14
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c15
-rw-r--r--src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec27
-rw-r--r--src/csharp/tests.json4
-rw-r--r--src/node/ext/node_grpc.cc127
-rw-r--r--src/node/index.js43
-rw-r--r--src/node/interop/interop_server.js13
-rw-r--r--src/node/performance/benchmark_client.js50
-rw-r--r--src/node/src/common.js21
-rw-r--r--src/node/src/credentials.js4
-rw-r--r--src/node/src/server.js4
-rw-r--r--src/node/tools/package.json3
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h4
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+Cronet.h2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall+Cronet.m2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m1
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.h3
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.m8
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m9
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.m2
-rw-r--r--src/objective-c/ProtoRPC/ProtoMethod.h12
-rw-r--r--src/objective-c/ProtoRPC/ProtoMethod.m4
-rw-r--r--src/objective-c/ProtoRPC/ProtoRPC.h18
-rw-r--r--src/objective-c/ProtoRPC/ProtoRPC.m6
-rw-r--r--src/objective-c/ProtoRPC/ProtoService.h18
-rw-r--r--src/objective-c/ProtoRPC/ProtoService.m10
-rw-r--r--src/objective-c/examples/RemoteTestClient/RemoteTest.podspec4
-rw-r--r--src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj50
-rw-r--r--src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj42
-rw-r--r--src/objective-c/examples/SwiftSample/ViewController.swift5
-rw-r--r--src/objective-c/tests/GRPCClientTests.m36
-rw-r--r--src/objective-c/tests/InteropTests.m14
-rw-r--r--src/objective-c/tests/Podfile42
-rw-r--r--src/objective-c/tests/RemoteTestClient/RemoteTest.podspec4
-rw-r--r--src/objective-c/tests/Tests.xcodeproj/project.pbxproj256
-rwxr-xr-xsrc/objective-c/tests/build_tests.sh3
-rwxr-xr-x[-rw-r--r--]src/php/bin/stress_client.sh (renamed from src/python/grpcio/grpc/_adapter/_implementations.py)25
-rw-r--r--src/php/ext/grpc/call.c1
-rw-r--r--src/php/ext/grpc/channel_credentials.c33
-rw-r--r--src/php/lib/Grpc/AbstractCall.php10
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php17
-rw-r--r--src/php/lib/Grpc/BidiStreamingCall.php1
-rw-r--r--src/php/lib/Grpc/ClientStreamingCall.php4
-rw-r--r--src/php/lib/Grpc/ServerStreamingCall.php1
-rw-r--r--src/php/lib/Grpc/UnaryCall.php4
-rwxr-xr-xsrc/php/tests/interop/interop_client.php115
-rw-r--r--src/php/tests/interop/messages.proto38
-rw-r--r--src/php/tests/interop/metrics_client.php6
-rw-r--r--src/php/tests/interop/stress_client.php103
-rw-r--r--src/php/tests/interop/test.proto9
-rw-r--r--src/proto/grpc/binary_log/v1alpha/log.proto14
-rw-r--r--src/proto/grpc/testing/messages.proto53
-rw-r--r--src/proto/math/math.proto6
-rw-r--r--src/python/grpcio/commands.py4
-rw-r--r--src/python/grpcio/grpc/__init__.py224
-rw-r--r--src/python/grpcio/grpc/_adapter/_low.py76
-rw-r--r--src/python/grpcio/grpc/_adapter/_types.py2
-rw-r--r--src/python/grpcio/grpc/_auth.py (renamed from src/python/grpcio/grpc/beta/_auth.py)21
-rw-r--r--src/python/grpcio/grpc/_channel.py55
-rw-r--r--src/python/grpcio/grpc/_common.py59
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi7
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi24
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi3
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi59
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi2
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi53
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi6
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi39
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi70
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi9
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pyx1
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.c10
-rw-r--r--src/python/grpcio/grpc/_cython/imports.generated.h21
-rw-r--r--src/python/grpcio/grpc/_links/service.py6
-rw-r--r--src/python/grpcio/grpc/_server.py91
-rw-r--r--src/python/grpcio/grpc/_utilities.py26
-rw-r--r--src/python/grpcio/grpc/beta/_client_adaptations.py563
-rw-r--r--src/python/grpcio/grpc/beta/_server_adaptations.py367
-rw-r--r--src/python/grpcio/grpc/beta/implementations.py220
-rw-r--r--src/python/grpcio/grpc/beta/interfaces.py90
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py13
-rw-r--r--src/python/grpcio/grpc_version.py2
-rw-r--r--src/python/grpcio/tests/interop/client.py3
-rw-r--r--src/python/grpcio/tests/interop/methods.py13
-rw-r--r--src/python/grpcio/tests/protoc_plugin/_python_plugin_test.py583
-rw-r--r--src/python/grpcio/tests/qps/benchmark_client.py102
-rw-r--r--src/python/grpcio/tests/qps/client_runner.py14
-rw-r--r--src/python/grpcio/tests/qps/qps_worker.py4
-rw-r--r--src/python/grpcio/tests/qps/worker_server.py5
-rw-r--r--src/python/grpcio/tests/stress/client.py6
-rw-r--r--src/python/grpcio/tests/tests.json40
-rw-r--r--src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py428
-rw-r--r--src/python/grpcio/tests/unit/_adapter/_low_test.py319
-rw-r--r--src/python/grpcio/tests/unit/_api_test.py111
-rw-r--r--src/python/grpcio/tests/unit/_auth_test.py (renamed from src/python/grpcio/tests/unit/beta/_auth_test.py)2
-rw-r--r--src/python/grpcio/tests/unit/_channel_connectivity_test.py4
-rw-r--r--src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py157
-rw-r--r--src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py163
-rw-r--r--src/python/grpcio/tests/unit/_cython/_read_some_but_not_all_responses_test.py251
-rw-r--r--src/python/grpcio/tests/unit/_cython/cygrpc_test.py286
-rw-r--r--src/python/grpcio/tests/unit/_cython/test_utilities.py34
-rw-r--r--src/python/grpcio/tests/unit/_empty_message_test.py137
-rw-r--r--src/python/grpcio/tests/unit/_from_grpc_import_star.py38
-rw-r--r--src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py88
-rw-r--r--src/python/grpcio/tests/unit/_links/_transmission_test.py239
-rw-r--r--src/python/grpcio/tests/unit/_metadata_code_details_test.py523
-rw-r--r--src/python/grpcio/tests/unit/_metadata_test.py216
-rw-r--r--src/python/grpcio/tests/unit/_rpc_test.py34
-rw-r--r--src/python/grpcio/tests/unit/_thread_cleanup_test.py117
-rw-r--r--src/python/grpcio/tests/unit/beta/_beta_features_test.py4
-rw-r--r--src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py10
-rw-r--r--src/python/grpcio/tests/unit/beta/_not_found_test.py2
-rw-r--r--src/python/grpcio/tests/unit/beta/test_utilities.py13
-rw-r--r--src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py113
-rw-r--r--src/python/grpcio/tests/unit/framework/core/_base_interface_test.py96
-rw-r--r--src/python/grpcio/tests/unit/framework/foundation/_later_test.py151
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py6
-rw-r--r--src/python/grpcio/tests/unit/test_common.py4
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.c10
-rw-r--r--src/ruby/ext/grpc/rb_grpc_imports.generated.h21
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rw-r--r--src/ruby/tools/version.rb2
427 files changed, 18427 insertions, 7562 deletions
diff --git a/src/compiler/config.h b/src/compiler/config.h
index d8b95818db..1cbd842f0a 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -34,19 +34,7 @@
#ifndef SRC_COMPILER_CONFIG_H
#define SRC_COMPILER_CONFIG_H
-#include <grpc++/support/config.h>
-#include <grpc++/support/config_protobuf.h>
-
-#ifndef GRPC_CUSTOM_DESCRIPTOR
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
-#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
-#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
-#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
-#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor
-#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
-#endif
+#include <grpc++/impl/codegen/config_protobuf.h>
#ifndef GRPC_CUSTOM_CODEGENERATOR
#include <google/protobuf/compiler/code_generator.h>
@@ -75,14 +63,17 @@
#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
#endif
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
namespace protobuf {
-typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
-typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
-typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
-typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
-typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
-typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
+
namespace compiler {
typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator;
typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext;
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index e2f127094a..2288ba4163 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -73,9 +73,10 @@ void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, c
vars["l"] = params.use_system_headers ? '<' : '"';
vars["r"] = params.use_system_headers ? '>' : '"';
- if (!params.grpc_search_path.empty()) {
- vars["l"] += params.grpc_search_path;
- if (params.grpc_search_path.back() != '/') {
+ auto& s = params.grpc_search_path;
+ if (!s.empty()) {
+ vars["l"] += s;
+ if (s[s.size()-1] != '/') {
vars["l"] += '/';
}
}
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 484fa3cdcc..f5a0876cf9 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -119,18 +119,10 @@ std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
-std::string GetClientInterfaceName(const ServiceDescriptor* service) {
- return "I" + service->name() + "Client";
-}
-
std::string GetClientClassName(const ServiceDescriptor* service) {
return service->name() + "Client";
}
-std::string GetServerInterfaceName(const ServiceDescriptor* service) {
- return "I" + service->name();
-}
-
std::string GetServerClassName(const ServiceDescriptor* service) {
return service->name() + "Base";
}
@@ -302,86 +294,6 @@ void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *se
out->Print("\n");
}
-void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("/// <summary>Client for $servicename$</summary>\n",
- "servicename", GetServiceClassName(service));
- out->Print("[System.Obsolete(\"Client side interfaced will be removed "
- "in the next release. Use client class directly.\")]\n");
- out->Print("public interface $name$\n", "name",
- GetClientInterfaceName(service));
- out->Print("{\n");
- out->Indent();
- for (int i = 0; i < service->method_count(); i++) {
- const MethodDescriptor *method = service->method(i);
- MethodType method_type = GetMethodType(method);
-
- if (method_type == METHODTYPE_NO_STREAMING) {
- // unary calls have an extra synchronous stub method
- GenerateDocCommentBody(out, method);
- out->Print(
- "$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
- "methodname", method->name(), "request",
- GetClassName(method->input_type()), "response",
- GetClassName(method->output_type()));
-
- // overload taking CallOptions as a param
- GenerateDocCommentBody(out, method);
- out->Print(
- "$response$ $methodname$($request$ request, CallOptions options);\n",
- "methodname", method->name(), "request",
- GetClassName(method->input_type()), "response",
- GetClassName(method->output_type()));
- }
-
- std::string method_name = method->name();
- if (method_type == METHODTYPE_NO_STREAMING) {
- method_name += "Async"; // prevent name clash with synchronous method.
- }
- GenerateDocCommentBody(out, method);
- out->Print(
- "$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
- "methodname", method_name, "request_maybe",
- GetMethodRequestParamMaybe(method), "returntype",
- GetMethodReturnTypeClient(method));
-
- // overload taking CallOptions as a param
- GenerateDocCommentBody(out, method);
- out->Print(
- "$returntype$ $methodname$($request_maybe$CallOptions options);\n",
- "methodname", method_name, "request_maybe",
- GetMethodRequestParamMaybe(method), "returntype",
- GetMethodReturnTypeClient(method));
- }
- out->Outdent();
- out->Print("}\n");
- out->Print("\n");
-}
-
-void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
- out->Print("/// <summary>Interface of server-side implementations of $servicename$</summary>\n",
- "servicename", GetServiceClassName(service));
- out->Print("[System.Obsolete(\"Service implementations should inherit"
- " from the generated abstract base class instead.\")]\n");
- out->Print("public interface $name$\n", "name",
- GetServerInterfaceName(service));
- out->Print("{\n");
- out->Indent();
- for (int i = 0; i < service->method_count(); i++) {
- const MethodDescriptor *method = service->method(i);
- GenerateDocCommentBody(out, method);
- out->Print(
- "$returntype$ $methodname$($request$$response_stream_maybe$, "
- "ServerCallContext context);\n",
- "methodname", method->name(), "returntype",
- GetMethodReturnTypeServer(method), "request",
- GetMethodRequestParamServer(method), "response_stream_maybe",
- GetMethodResponseStreamMaybe(method));
- }
- out->Outdent();
- out->Print("}\n");
- out->Print("\n");
-}
-
void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
"servicename", GetServiceClassName(service));
@@ -414,32 +326,35 @@ 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("#pragma warning disable 0618\n");
out->Print(
- "public class $name$ : ClientBase<$name$>, $interface$\n",
- "name", GetClientClassName(service),
- "interface", GetClientInterfaceName(service));
- out->Print("#pragma warning restore 0618\n");
+ "public class $name$ : ClientBase<$name$>\n",
+ "name", GetClientClassName(service));
out->Print("{\n");
out->Indent();
// constructors
+ out->Print("/// <summary>Creates a new client for $servicename$</summary>\n"
+ "/// <param name=\"channel\">The channel to use to make remote calls.</param>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public $name$(Channel channel) : base(channel)\n",
"name", GetClientClassName(service));
out->Print("{\n");
out->Print("}\n");
+ out->Print("/// <summary>Creates a new client for $servicename$ that uses a custom <c>CallInvoker</c>.</summary>\n"
+ "/// <param name=\"callInvoker\">The callInvoker to use to make remote calls.</param>\n",
+ "servicename", GetServiceClassName(service));
out->Print("public $name$(CallInvoker callInvoker) : base(callInvoker)\n",
"name", GetClientClassName(service));
out->Print("{\n");
out->Print("}\n");
- out->Print("///<summary>Protected parameterless constructor to allow creation"
+ out->Print("/// <summary>Protected parameterless constructor to allow creation"
" of test doubles.</summary>\n");
out->Print("protected $name$() : base()\n",
"name", GetClientClassName(service));
out->Print("{\n");
out->Print("}\n");
- out->Print("///<summary>Protected constructor to allow creation of configured"
- " clients.</summary>\n");
+ out->Print("/// <summary>Protected constructor to allow creation of configured clients.</summary>\n"
+ "/// <param name=\"configuration\">The client configuration.</param>\n");
out->Print("protected $name$(ClientBaseConfiguration configuration)"
" : base(configuration)\n",
"name", GetClientClassName(service));
@@ -546,22 +461,16 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
out->Print("\n");
}
-void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
- bool use_server_class) {
+void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service) {
out->Print(
"/// <summary>Creates service definition that can be registered with a server</summary>\n");
- out->Print("#pragma warning disable 0618\n");
out->Print(
- "public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
- "interface", use_server_class ? GetServerClassName(service) :
- GetServerInterfaceName(service));
- out->Print("#pragma warning restore 0618\n");
+ "public static ServerServiceDefinition BindService($implclass$ serviceImpl)\n",
+ "implclass", GetServerClassName(service));
out->Print("{\n");
out->Indent();
- out->Print(
- "return ServerServiceDefinition.CreateBuilder($servicenamefield$)\n",
- "servicenamefield", GetServiceNameFieldName());
+ out->Print("return ServerServiceDefinition.CreateBuilder()\n");
out->Indent();
out->Indent();
for (int i = 0; i < service->method_count(); i++) {
@@ -582,20 +491,6 @@ void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
out->Print("\n");
}
-void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
- out->Print("/// <summary>Creates a new client for $servicename$</summary>\n",
- "servicename", GetServiceClassName(service));
- out->Print("public static $classname$ NewClient(Channel channel)\n",
- "classname", GetClientClassName(service));
- out->Print("{\n");
- out->Indent();
- out->Print("return new $classname$(channel);\n", "classname",
- GetClientClassName(service));
- out->Outdent();
- out->Print("}\n");
- out->Print("\n");
-}
-
void GenerateService(Printer* out, const ServiceDescriptor *service,
bool generate_client, bool generate_server,
bool internal_access) {
@@ -616,20 +511,14 @@ void GenerateService(Printer* out, const ServiceDescriptor *service,
}
GenerateServiceDescriptorProperty(out, service);
- if (generate_client) {
- GenerateClientInterface(out, service);
- }
if (generate_server) {
- GenerateServerInterface(out, service);
GenerateServerClass(out, service);
}
if (generate_client) {
GenerateClientStub(out, service);
- GenerateNewStubMethods(out, service);
}
if (generate_server) {
- GenerateBindServiceMethod(out, service, false);
- GenerateBindServiceMethod(out, service, true);
+ GenerateBindServiceMethod(out, service);
}
out->Outdent();
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 53391bc41a..9a88c2bfcc 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -253,7 +253,8 @@ inline void GetComment(const grpc::protobuf::FileDescriptor *desc,
inline grpc::string GenerateCommentsWithPrefix(
const std::vector<grpc::string> &in, const grpc::string &prefix) {
std::ostringstream oss;
- for (const grpc::string &elem : in) {
+ for (auto it = in.begin(); it != in.end(); it++) {
+ const grpc::string& elem = *it;
if (elem.empty()) {
oss << prefix << "\n";
} else if (elem[0] == ' ') {
diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc
index 986b97c26e..1fe090d17a 100644
--- a/src/compiler/node_generator.cc
+++ b/src/compiler/node_generator.cc
@@ -74,8 +74,16 @@ grpc::string GetJSMessageFilename(const grpc::string& filename) {
// Given a filename like foo/bar/baz.proto, returns the root directory
// path ../../
-grpc::string GetRootPath(const grpc::string& filename) {
- size_t slashes = std::count(filename.begin(), filename.end(), '/');
+grpc::string GetRootPath(const grpc::string& from_filename,
+ const grpc::string& to_filename) {
+ if (to_filename.find("google/protobuf") == 0) {
+ // Well-known types (.proto files in the google/protobuf directory) are
+ // assumed to come from the 'google-protobuf' npm package. We may want to
+ // generalize this exception later by letting others put generated code in
+ // their own npm packages.
+ return "google-protobuf/";
+ }
+ size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
if (slashes == 0) {
return "./";
}
@@ -90,7 +98,7 @@ grpc::string GetRootPath(const grpc::string& filename) {
// from_file, assuming that both paths are relative to the same directory
grpc::string GetRelativePath(const grpc::string& from_file,
const grpc::string& to_file) {
- return GetRootPath(from_file) + to_file;
+ return GetRootPath(from_file, to_file) + to_file;
}
/* Finds all message types used in all services in the file, and returns them
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 465491e385..4be8cb4187 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -60,9 +60,34 @@ void PrintProtoRpcDeclarationAsPragma(Printer *printer,
" returns ($server_stream$$response_type$)\n\n");
}
+template <typename DescriptorType>
+static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
+ std::vector<grpc::string> comments;
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
+ &comments);
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
+ &comments);
+ grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
+ &comments);
+ if (comments.empty()) {
+ return;
+ }
+ printer->Print("/**\n");
+ for (auto it = comments.begin(); it != comments.end(); ++it) {
+ printer->Print(" * ");
+ size_t start_pos = it->find_first_not_of(' ');
+ if (start_pos != grpc::string::npos) {
+ printer->Print(it->c_str() + start_pos);
+ }
+ printer->Print("\n");
+ }
+ printer->Print(" */\n");
+}
+
void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
const map< ::grpc::string, ::grpc::string> &vars) {
- // TODO(jcanizales): Print method comments.
+ // Print comment
+ PrintAllComments(method, printer);
printer->Print(vars, "- ($return_type$)$method_name$With");
if (method->client_streaming()) {
@@ -94,7 +119,7 @@ void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
map< ::grpc::string, ::grpc::string> vars) {
vars["method_name"] = "RPCTo" + vars["method_name"];
- vars["return_type"] = "ProtoRPC *";
+ vars["return_type"] = "GRPCProtoCall *";
PrintMethodSignature(printer, method, vars);
}
@@ -195,11 +220,13 @@ void PrintMethodImplementations(Printer *printer,
printer.Print("@end\n\n");
printer.Print(
- "// Basic service implementation, over gRPC, that only does"
- " marshalling and parsing.\n");
+ "/**\n"
+ " * Basic service implementation, over gRPC, that only does\n"
+ " * marshalling and parsing.\n"
+ " */\n");
printer.Print(vars,
"@interface $service_class$ :"
- " ProtoService<$service_class$>\n");
+ " GRPCProtoService<$service_class$>\n");
printer.Print(
"- (instancetype)initWithHost:(NSString *)host"
" NS_DESIGNATED_INITIALIZER;\n");
@@ -220,18 +247,13 @@ void PrintMethodImplementations(Printer *printer,
{"service_class", ServiceClassName(service)},
{"package", service->file()->package()}};
- printer.Print(vars,
- "static NSString *const kPackageName = @\"$package$\";\n");
- printer.Print(
- vars, "static NSString *const kServiceName = @\"$service_name$\";\n\n");
-
printer.Print(vars, "@implementation $service_class$\n\n");
printer.Print("// Designated initializer\n");
printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
- printer.Print(
+ printer.Print(vars,
" return (self = [super initWithHost:host"
- " packageName:kPackageName serviceName:kServiceName]);\n");
+ " packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
printer.Print("}\n\n");
printer.Print(
"// Override superclass initializer to disallow different"
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index cd5ddd8832..15cda474cc 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -342,7 +342,7 @@ bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
out->Print("}\n");
out->Print("method_implementations = {\n");
for (auto name_and_implementation_constructor =
- method_implementation_constructors.begin();
+ method_implementation_constructors.begin();
name_and_implementation_constructor !=
method_implementation_constructors.end();
name_and_implementation_constructor++) {
@@ -457,8 +457,149 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
return true;
}
+bool PrintStub(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
+ out->Print("\n\n");
+ out->Print("class $Service$Stub(object):\n", "Service", service->name());
+ {
+ IndentScope raii_class_indent(out);
+ PrintAllComments(service, out);
+ out->Print("\n");
+ out->Print("def __init__(self, channel):\n");
+ {
+ IndentScope raii_init_indent(out);
+ out->Print("\"\"\"Constructor.\n");
+ out->Print("\n");
+ out->Print("Args:\n");
+ {
+ IndentScope raii_args_indent(out);
+ out->Print("channel: A grpc.Channel.\n");
+ }
+ out->Print("\"\"\"\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ auto multi_callable_constructor =
+ grpc::string(method->client_streaming() ? "stream" : "unary") +
+ "_" +
+ grpc::string(method->server_streaming() ? "stream" : "unary");
+ grpc::string request_module_and_class;
+ if (!GetModuleAndMessagePath(method->input_type(), service,
+ &request_module_and_class)) {
+ return false;
+ }
+ grpc::string response_module_and_class;
+ if (!GetModuleAndMessagePath(method->output_type(), service,
+ &response_module_and_class)) {
+ return false;
+ }
+ out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
+ "Method", method->name(),
+ "MultiCallableConstructor", multi_callable_constructor);
+ {
+ IndentScope raii_first_attribute_indent(out);
+ IndentScope raii_second_attribute_indent(out);
+ out->Print(
+ "'/$PackageQualifiedService$/$Method$',\n",
+ "PackageQualifiedService", package_qualified_service_name,
+ "Method", method->name());
+ out->Print(
+ "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
+ "RequestModuleAndClass", request_module_and_class);
+ out->Print(
+ "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
+ "ResponseModuleAndClass", response_module_and_class);
+ out->Print(")\n");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool PrintServicer(const ServiceDescriptor* service, Printer* out) {
+ out->Print("\n\n");
+ out->Print("class $Service$Servicer(object):\n", "Service", service->name());
+ {
+ IndentScope raii_class_indent(out);
+ PrintAllComments(service, out);
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ grpc::string arg_name = method->client_streaming() ?
+ "request_iterator" : "request";
+ out->Print("\n");
+ out->Print("def $Method$(self, $ArgName$, context):\n",
+ "Method", method->name(), "ArgName", arg_name);
+ {
+ IndentScope raii_method_indent(out);
+ PrintAllComments(method, out);
+ out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n");
+ out->Print("context.set_details('Method not implemented!')\n");
+ out->Print("raise NotImplementedError('Method not implemented!')\n");
+ }
+ }
+ }
+ return true;
+}
+
+bool PrintAddServicerToServer(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
+ out->Print("\n\n");
+ out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
+ "Service", service->name());
+ {
+ IndentScope raii_class_indent(out);
+ out->Print("rpc_method_handlers = {\n");
+ {
+ IndentScope raii_dict_first_indent(out);
+ IndentScope raii_dict_second_indent(out);
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ auto method_handler_constructor =
+ grpc::string(method->client_streaming() ? "stream" : "unary") +
+ "_" +
+ grpc::string(method->server_streaming() ? "stream" : "unary") +
+ "_rpc_method_handler";
+ grpc::string request_module_and_class;
+ if (!GetModuleAndMessagePath(method->input_type(), service,
+ &request_module_and_class)) {
+ return false;
+ }
+ grpc::string response_module_and_class;
+ if (!GetModuleAndMessagePath(method->output_type(), service,
+ &response_module_and_class)) {
+ return false;
+ }
+ out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n",
+ "Method", method->name(),
+ "MethodHandlerConstructor", method_handler_constructor);
+ {
+ IndentScope raii_call_first_indent(out);
+ IndentScope raii_call_second_indent(out);
+ out->Print("servicer.$Method$,\n", "Method", method->name());
+ out->Print("request_deserializer=$RequestModuleAndClass$.FromString,\n",
+ "RequestModuleAndClass", request_module_and_class);
+ out->Print("response_serializer=$ResponseModuleAndClass$.SerializeToString,\n",
+ "ResponseModuleAndClass", response_module_and_class);
+ }
+ out->Print("),\n");
+ }
+ }
+ out->Print("}\n");
+ out->Print("generic_handler = grpc.method_handlers_generic_handler(\n");
+ {
+ IndentScope raii_call_first_indent(out);
+ IndentScope raii_call_second_indent(out);
+ out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
+ "PackageQualifiedServiceName", package_qualified_service_name);
+ }
+ out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
+ }
+ return true;
+}
+
bool PrintPreamble(const FileDescriptor* file,
const GeneratorConfiguration& config, Printer* out) {
+ out->Print("import $Package$\n", "Package", config.grpc_package_root);
out->Print("from $Package$ import implementations as beta_implementations\n",
"Package", config.beta_package_root);
out->Print("from $Package$ import interfaces as beta_interfaces\n",
@@ -487,7 +628,10 @@ pair<bool, grpc::string> GetServices(const FileDescriptor* file,
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
auto package_qualified_service_name = package + service->name();
- if (!(PrintBetaServicer(service, &out) &&
+ if (!(PrintStub(package_qualified_service_name, service, &out) &&
+ PrintServicer(service, &out) &&
+ PrintAddServicerToServer(package_qualified_service_name, service, &out) &&
+ PrintBetaServicer(service, &out) &&
PrintBetaStub(service, &out) &&
PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index e56b6790ef..fc51b48dae 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -43,6 +43,7 @@ namespace grpc_python_generator {
// Data pertaining to configuration of the generator with respect to anything
// that may be used internally at Google.
struct GeneratorConfiguration {
+ grpc::string grpc_package_root;
grpc::string beta_package_root;
};
diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc
index 92a07b2f80..fc76ee5ec6 100644
--- a/src/compiler/python_plugin.cc
+++ b/src/compiler/python_plugin.cc
@@ -38,6 +38,7 @@
int main(int argc, char* argv[]) {
grpc_python_generator::GeneratorConfiguration config;
+ config.grpc_package_root = "grpc";
config.beta_package_root = "grpc.beta";
grpc_python_generator::PythonGrpcGenerator generator(config);
return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index 8c4c17ad9a..72e4e5427e 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -91,14 +91,14 @@ static void client_start_transport_op(grpc_exec_ctx *exec_ctx,
}
static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
- bool success) {
+ grpc_error *error) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
extract_and_annotate_method_tag(calld->recv_initial_metadata, calld, chand);
}
- calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+ calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
}
static void server_mutate_op(grpc_call_element *elem,
@@ -180,7 +180,7 @@ const grpc_channel_filter grpc_client_census_filter = {
grpc_channel_next_op,
sizeof(call_data),
client_init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
client_destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
@@ -193,7 +193,7 @@ const grpc_channel_filter grpc_server_census_filter = {
grpc_channel_next_op,
sizeof(call_data),
server_init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
server_destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/ext/client_config/channel_connectivity.c b/src/core/ext/client_config/channel_connectivity.c
index cc60f2485a..2fd8e0e123 100644
--- a/src/core/ext/client_config/channel_connectivity.c
+++ b/src/core/ext/client_config/channel_connectivity.c
@@ -75,7 +75,6 @@ typedef enum {
typedef struct {
gpr_mu mu;
callback_phase phase;
- int success;
grpc_closure on_complete;
grpc_timer alarm;
grpc_connectivity_state state;
@@ -122,7 +121,7 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
}
static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
- int due_to_completion) {
+ bool due_to_completion, grpc_error *error) {
int delete = 0;
if (due_to_completion) {
@@ -130,14 +129,26 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
}
gpr_mu_lock(&w->mu);
+
if (due_to_completion) {
- w->success = 1;
+ if (grpc_trace_operation_failures) {
+ GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
+ }
+ GRPC_ERROR_UNREF(error);
+ error = GRPC_ERROR_NONE;
+ } else {
+ if (error == GRPC_ERROR_NONE) {
+ error =
+ GRPC_ERROR_CREATE("Timed out waiting for connection state change");
+ } else if (error == GRPC_ERROR_CANCELLED) {
+ error = GRPC_ERROR_NONE;
+ }
}
switch (w->phase) {
case WAITING:
w->phase = CALLING_BACK;
- grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->success, finished_completion,
- w, &w->completion_storage);
+ grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error),
+ finished_completion, w, &w->completion_storage);
break;
case CALLING_BACK:
w->phase = CALLING_BACK_AND_FINISHED;
@@ -153,14 +164,18 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
if (delete) {
delete_state_watcher(exec_ctx, w);
}
+
+ GRPC_ERROR_UNREF(error);
}
-static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
- partly_done(exec_ctx, pw, 1);
+static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw,
+ grpc_error *error) {
+ partly_done(exec_ctx, pw, true, GRPC_ERROR_REF(error));
}
-static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
- partly_done(exec_ctx, pw, 0);
+static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw,
+ grpc_error *error) {
+ partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error));
}
void grpc_channel_watch_connectivity_state(
@@ -174,10 +189,10 @@ void grpc_channel_watch_connectivity_state(
GRPC_API_TRACE(
"grpc_channel_watch_connectivity_state("
"channel=%p, last_observed_state=%d, "
- "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"cq=%p, tag=%p)",
- 7, (channel, (int)last_observed_state, (long long)deadline.tv_sec,
- (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
+ 7, (channel, (int)last_observed_state, deadline.tv_sec,
+ deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
grpc_cq_begin_op(cq, tag);
@@ -185,7 +200,6 @@ void grpc_channel_watch_connectivity_state(
grpc_closure_init(&w->on_complete, watch_complete, w);
w->phase = WAITING;
w->state = last_observed_state;
- w->success = 0;
w->cq = cq;
w->tag = tag;
w->channel = channel;
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 713c2c7814..1d5a7d5224 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -117,6 +117,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
channel_data *chand,
grpc_connectivity_state state,
+ grpc_error *error,
const char *reason) {
if ((state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
state == GRPC_CHANNEL_SHUTDOWN) &&
@@ -127,11 +128,13 @@ static void set_channel_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
/* mask= */ GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY,
/* check= */ 0);
}
- grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, reason);
+ grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state, error,
+ reason);
}
-static void on_lb_policy_state_changed_locked(
- grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) {
+static void on_lb_policy_state_changed_locked(grpc_exec_ctx *exec_ctx,
+ lb_policy_connectivity_watcher *w,
+ grpc_error *error) {
grpc_connectivity_state publish_state = w->state;
/* check if the notification is for a stale policy */
if (w->lb_policy != w->chand->lb_policy) return;
@@ -143,18 +146,18 @@ static void on_lb_policy_state_changed_locked(
w->chand->lb_policy = NULL;
}
set_channel_connectivity_state_locked(exec_ctx, w->chand, publish_state,
- "lb_changed");
+ GRPC_ERROR_REF(error), "lb_changed");
if (w->state != GRPC_CHANNEL_SHUTDOWN) {
watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
}
}
static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
lb_policy_connectivity_watcher *w = arg;
gpr_mu_lock(&w->chand->mu_config);
- on_lb_policy_state_changed_locked(exec_ctx, w);
+ on_lb_policy_state_changed_locked(exec_ctx, w, error);
gpr_mu_unlock(&w->chand->mu_config);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
@@ -176,19 +179,22 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
}
static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
channel_data *chand = arg;
grpc_lb_policy *lb_policy = NULL;
grpc_lb_policy *old_lb_policy;
grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
int exit_idle = 0;
+ grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
if (chand->incoming_configuration != NULL) {
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
if (lb_policy != NULL) {
GRPC_LB_POLICY_REF(lb_policy, "channel");
GRPC_LB_POLICY_REF(lb_policy, "config_change");
- state = grpc_lb_policy_check_connectivity(exec_ctx, lb_policy);
+ GRPC_ERROR_UNREF(state_error);
+ state =
+ grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
}
grpc_client_config_unref(exec_ctx, chand->incoming_configuration);
@@ -208,7 +214,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL);
} else if (chand->resolver == NULL /* disconnected */) {
- grpc_closure_list_fail_all(&chand->waiting_for_config_closures);
+ grpc_closure_list_fail_all(
+ &chand->waiting_for_config_closures,
+ GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1));
grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
NULL);
}
@@ -218,9 +226,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->exit_idle_when_lb_policy_arrives = 0;
}
- if (iomgr_success && chand->resolver) {
- set_channel_connectivity_state_locked(exec_ctx, chand, state,
- "new_lb+resolver");
+ if (error == GRPC_ERROR_NONE && chand->resolver) {
+ set_channel_connectivity_state_locked(
+ exec_ctx, chand, state, GRPC_ERROR_REF(state_error), "new_lb+resolver");
if (lb_policy != NULL) {
watch_lb_policy(exec_ctx, chand, lb_policy, state);
}
@@ -235,8 +243,12 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
chand->resolver = NULL;
}
+ grpc_error *refs[] = {error, state_error};
set_channel_connectivity_state_locked(
- exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN, "resolver_gone");
+ exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs,
+ GPR_ARRAY_SIZE(refs)),
+ "resolver_gone");
gpr_mu_unlock(&chand->mu_config);
}
@@ -256,6 +268,7 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
+ GRPC_ERROR_UNREF(state_error);
}
static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -263,7 +276,7 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_transport_op *op) {
channel_data *chand = elem->channel_data;
- grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
GPR_ASSERT(op->set_accept_stream == false);
if (op->bind_pollset != NULL) {
@@ -282,7 +295,9 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
if (op->send_ping != NULL) {
if (chand->lb_policy == NULL) {
- grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->send_ping,
+ GRPC_ERROR_CREATE("Ping with no load balancing"),
+ NULL);
} else {
grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
op->bind_pollset = NULL;
@@ -290,24 +305,29 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
op->send_ping = NULL;
}
- if (op->disconnect && chand->resolver != NULL) {
- set_channel_connectivity_state_locked(exec_ctx, chand,
- GRPC_CHANNEL_SHUTDOWN, "disconnect");
- grpc_resolver_shutdown(exec_ctx, chand->resolver);
- GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
- chand->resolver = NULL;
- if (!chand->started_resolving) {
- grpc_closure_list_fail_all(&chand->waiting_for_config_closures);
- grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
- NULL);
- }
- if (chand->lb_policy != NULL) {
- grpc_pollset_set_del_pollset_set(exec_ctx,
- chand->lb_policy->interested_parties,
- chand->interested_parties);
- GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
- chand->lb_policy = NULL;
+ if (op->disconnect_with_error != GRPC_ERROR_NONE) {
+ if (chand->resolver != NULL) {
+ set_channel_connectivity_state_locked(
+ exec_ctx, chand, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_REF(op->disconnect_with_error), "disconnect");
+ grpc_resolver_shutdown(exec_ctx, chand->resolver);
+ GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+ chand->resolver = NULL;
+ if (!chand->started_resolving) {
+ grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
+ GRPC_ERROR_REF(op->disconnect_with_error));
+ grpc_exec_ctx_enqueue_list(exec_ctx,
+ &chand->waiting_for_config_closures, NULL);
+ }
+ if (chand->lb_policy != NULL) {
+ grpc_pollset_set_del_pollset_set(exec_ctx,
+ chand->lb_policy->interested_parties,
+ chand->interested_parties);
+ GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
+ chand->lb_policy = NULL;
+ }
}
+ GRPC_ERROR_UNREF(op->disconnect_with_error);
}
gpr_mu_unlock(&chand->mu_config);
}
@@ -327,16 +347,17 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready);
-static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
continue_picking_args *cpa = arg;
if (cpa->connected_subchannel == NULL) {
/* cancelled, do nothing */
- } else if (!success) {
- grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
+ } else if (error != GRPC_ERROR_NONE) {
+ grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL);
} else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
cpa->initial_metadata_flags,
cpa->connected_subchannel, cpa->on_ready)) {
- grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
}
gpr_free(cpa);
}
@@ -361,11 +382,12 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
connected_subchannel);
}
for (closure = chand->waiting_for_config_closures.head; closure != NULL;
- closure = grpc_closure_next(closure)) {
+ closure = closure->next_data.next) {
cpa = closure->cb_arg;
if (cpa->connected_subchannel == connected_subchannel) {
cpa->connected_subchannel = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cpa->on_ready,
+ GRPC_ERROR_CREATE("Pick cancelled"), NULL);
}
}
gpr_mu_unlock(&chand->mu_config);
@@ -376,7 +398,7 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
int r;
GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel");
gpr_mu_unlock(&chand->mu_config);
- r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollset,
+ r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollent,
initial_metadata, initial_metadata_flags,
connected_subchannel, on_ready);
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel");
@@ -397,10 +419,11 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
cpa->on_ready = on_ready;
cpa->elem = elem;
grpc_closure_init(&cpa->closure, continue_picking, cpa);
- grpc_closure_list_add(&chand->waiting_for_config_closures, &cpa->closure,
- 1);
+ grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
+ GRPC_ERROR_NONE);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, on_ready, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"),
+ NULL);
}
gpr_mu_unlock(&chand->mu_config);
return 0;
@@ -461,10 +484,11 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
gpr_mu_destroy(&chand->mu_config);
}
-static void cc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_pollset *pollset) {
+static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_polling_entity *pollent) {
call_data *calld = elem->call_data;
- calld->pollset = pollset;
+ calld->pollent = pollent;
}
const grpc_channel_filter grpc_client_channel_filter = {
@@ -472,7 +496,7 @@ const grpc_channel_filter grpc_client_channel_filter = {
cc_start_transport_op,
sizeof(call_data),
init_call_elem,
- cc_set_pollset,
+ cc_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
@@ -506,7 +530,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
channel_data *chand = elem->channel_data;
grpc_connectivity_state out;
gpr_mu_lock(&chand->mu_config);
- out = grpc_connectivity_state_check(&chand->state_tracker);
+ out = grpc_connectivity_state_check(&chand->state_tracker, NULL);
if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
if (chand->lb_policy != NULL) {
grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
@@ -533,7 +557,7 @@ typedef struct {
} external_connectivity_watcher;
static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
external_connectivity_watcher *w = arg;
grpc_closure *follow_up = w->on_complete;
grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
@@ -541,7 +565,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
"external_connectivity_watcher");
gpr_free(w);
- follow_up->cb(exec_ctx, follow_up->cb_arg, iomgr_success);
+ follow_up->cb(exec_ctx, follow_up->cb_arg, error);
}
void grpc_client_channel_watch_connectivity_state(
diff --git a/src/core/ext/client_config/connector.h b/src/core/ext/client_config/connector.h
index dd85dfcb7d..ea9d23706e 100644
--- a/src/core/ext/client_config/connector.h
+++ b/src/core/ext/client_config/connector.h
@@ -64,7 +64,7 @@ typedef struct {
grpc_transport *transport;
/** channel arguments (to be passed to the filters) */
- const grpc_channel_args *channel_args;
+ grpc_channel_args *channel_args;
} grpc_connect_out_args;
struct grpc_connector_vtable {
diff --git a/src/core/ext/client_config/lb_policy.c b/src/core/ext/client_config/lb_policy.c
index a7ad9842dc..8b980b2cca 100644
--- a/src/core/ext/client_config/lb_policy.c
+++ b/src/core/ext/client_config/lb_policy.c
@@ -60,8 +60,9 @@ static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
: gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "LB_POLICY: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
- old_val + delta, reason);
+ "LB_POLICY: 0x%" PRIxPTR " %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR
+ " [%s]",
+ (intptr_t)c, purpose, old_val, old_val + delta, reason);
#endif
return old_val;
}
@@ -99,12 +100,12 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
}
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
grpc_metadata_batch *initial_metadata,
uint32_t initial_metadata_flags,
grpc_connected_subchannel **target,
grpc_closure *on_complete) {
- return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata,
+ return policy->vtable->pick(exec_ctx, policy, pollent, initial_metadata,
initial_metadata_flags, target, on_complete);
}
@@ -138,6 +139,8 @@ void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
}
grpc_connectivity_state grpc_lb_policy_check_connectivity(
- grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
- return policy->vtable->check_connectivity(exec_ctx, policy);
+ grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_error **connectivity_error) {
+ return policy->vtable->check_connectivity(exec_ctx, policy,
+ connectivity_error);
}
diff --git a/src/core/ext/client_config/lb_policy.h b/src/core/ext/client_config/lb_policy.h
index 0384e0b2eb..3cfd041d3a 100644
--- a/src/core/ext/client_config/lb_policy.h
+++ b/src/core/ext/client_config/lb_policy.h
@@ -35,6 +35,7 @@
#define GRPC_CORE_EXT_CLIENT_CONFIG_LB_POLICY_H
#include "src/core/ext/client_config/subchannel.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
/** A load balancing policy: specified by a vtable and a struct (which
@@ -59,7 +60,8 @@ struct grpc_lb_policy_vtable {
/** implement grpc_lb_policy_pick */
int (*pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
+ grpc_polling_entity *pollent,
+ grpc_metadata_batch *initial_metadata,
uint32_t initial_metadata_flags,
grpc_connected_subchannel **target, grpc_closure *on_complete);
void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
@@ -75,8 +77,9 @@ struct grpc_lb_policy_vtable {
void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
/** check the current connectivity of the lb_policy */
- grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx,
- grpc_lb_policy *policy);
+ grpc_connectivity_state (*check_connectivity)(
+ grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_error **connectivity_error);
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the policy */
@@ -124,7 +127,7 @@ void grpc_lb_policy_init(grpc_lb_policy *policy,
\a target.
Picking can be asynchronous. Any IO should be done under \a pollset. */
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
grpc_metadata_batch *initial_metadata,
uint32_t initial_metadata_flags,
grpc_connected_subchannel **target,
@@ -152,6 +155,7 @@ void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
grpc_closure *closure);
grpc_connectivity_state grpc_lb_policy_check_connectivity(
- grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+ grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_error **connectivity_error);
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_LB_POLICY_H */
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index 3a635be02f..468067ea57 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -54,7 +54,7 @@
#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1))
#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20
-#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 2
+#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
@@ -147,7 +147,7 @@ struct grpc_subchannel_call {
(((grpc_subchannel_call *)(callstack)) - 1)
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
- bool iomgr_success);
+ grpc_error *error);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
#define REF_REASON reason
@@ -177,7 +177,7 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
*/
static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
grpc_connected_subchannel *c = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
gpr_free(c);
@@ -200,7 +200,7 @@ void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
*/
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
grpc_subchannel *c = arg;
gpr_free((void *)c->filters);
grpc_channel_args_destroy(c->args);
@@ -290,8 +290,8 @@ void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
gpr_atm old_refs;
old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
if (old_refs == 1) {
- grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c),
- true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(subchannel_destroy, c),
+ GRPC_ERROR_NONE, NULL);
}
}
@@ -382,7 +382,8 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
args.initial_connect_string = c->initial_connect_string;
grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
- GRPC_CHANNEL_CONNECTING, "state_change");
+ GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
+ "state_change");
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected);
}
@@ -393,16 +394,17 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
continue_connect(exec_ctx, c);
}
-grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
+grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c,
+ grpc_error **error) {
grpc_connectivity_state state;
gpr_mu_lock(&c->mu);
- state = grpc_connectivity_state_check(&c->state_tracker);
+ state = grpc_connectivity_state_check(&c->state_tracker, error);
gpr_mu_unlock(&c->mu);
return state;
}
static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
external_state_watcher *w = arg;
grpc_closure *follow_up = w->notify;
if (w->pollset_set != NULL) {
@@ -415,7 +417,7 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&w->subchannel->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher");
gpr_free(w);
- follow_up->cb(exec_ctx, follow_up->cb_arg, success);
+ follow_up->cb(exec_ctx, follow_up->cb_arg, error);
}
void grpc_subchannel_notify_on_state_change(
@@ -469,7 +471,7 @@ void grpc_connected_subchannel_process_transport_op(
}
static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
- bool iomgr_success) {
+ grpc_error *error) {
state_watcher *sw = p;
grpc_subchannel *c = sw->subchannel;
gpr_mu *mu = &c->mu;
@@ -477,20 +479,19 @@ static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
gpr_mu_lock(mu);
/* if we failed just leave this closure */
- if (iomgr_success) {
- if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
- /* any errors on a subchannel ==> we're done, create a new one */
- sw->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
- }
- grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
- sw->connectivity_state, "reflect_child");
- if (sw->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
- grpc_connected_subchannel_notify_on_state_change(
- exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
- &sw->connectivity_state, &sw->closure);
- GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
- sw = NULL;
- }
+ if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+ /* any errors on a subchannel ==> we're done, create a new one */
+ sw->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
+ }
+ grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+ sw->connectivity_state, GRPC_ERROR_REF(error),
+ "reflect_child");
+ if (sw->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL,
+ &sw->connectivity_state, &sw->closure);
+ GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
+ sw = NULL;
}
gpr_mu_unlock(mu);
@@ -592,17 +593,20 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
/* signal completion */
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
- "connected");
+ GRPC_ERROR_NONE, "connected");
}
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_subchannel *c = arg;
gpr_mu_lock(&c->mu);
c->have_alarm = 0;
if (c->disconnected) {
- iomgr_success = 0;
+ error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
+ } else {
+ GRPC_ERROR_REF(error);
}
- if (iomgr_success) {
+ if (error == GRPC_ERROR_NONE) {
+ gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
c->next_attempt =
gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
continue_connect(exec_ctx, c);
@@ -611,11 +615,13 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
}
+ GRPC_ERROR_UNREF(error);
}
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
grpc_subchannel *c = arg;
+ grpc_channel_args *delete_channel_args = c->connecting_result.channel_args;
GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
gpr_mu_lock(&c->mu);
@@ -627,13 +633,26 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1;
- grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- "connect_failed");
+ grpc_connectivity_state_set(
+ exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1),
+ "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);
}
gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+ grpc_channel_args_destroy(delete_channel_args);
}
/*
@@ -641,7 +660,7 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
*/
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
- bool success) {
+ grpc_error *error) {
grpc_subchannel_call *c = call;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_connected_subchannel *connection = c->connection;
@@ -683,7 +702,7 @@ grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
grpc_subchannel_call *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
- grpc_pollset *pollset) {
+ grpc_polling_entity *pollent) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_subchannel_call *call =
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
@@ -692,7 +711,7 @@ grpc_subchannel_call *grpc_connected_subchannel_create_call(
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call,
NULL, NULL, callstk);
- grpc_call_stack_set_pollset(exec_ctx, callstk, pollset);
+ grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, pollent);
return call;
}
diff --git a/src/core/ext/client_config/subchannel.h b/src/core/ext/client_config/subchannel.h
index 0765a544e8..b6d39f5dc5 100644
--- a/src/core/ext/client_config/subchannel.h
+++ b/src/core/ext/client_config/subchannel.h
@@ -36,6 +36,7 @@
#include "src/core/ext/client_config/connector.h"
#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/connectivity_state.h"
/** A (sub-)channel that knows how to connect to exactly one target
@@ -109,7 +110,7 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
/** construct a subchannel call */
grpc_subchannel_call *grpc_connected_subchannel_create_call(
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
- grpc_pollset *pollset);
+ grpc_polling_entity *pollent);
/** process a transport level op */
void grpc_connected_subchannel_process_transport_op(
@@ -118,7 +119,7 @@ void grpc_connected_subchannel_process_transport_op(
/** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity(
- grpc_subchannel *channel);
+ grpc_subchannel *channel, grpc_error **error);
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the channel */
diff --git a/src/core/ext/client_config/subchannel_call_holder.c b/src/core/ext/client_config/subchannel_call_holder.c
index 91fa917661..e31800edd9 100644
--- a/src/core/ext/client_config/subchannel_call_holder.c
+++ b/src/core/ext/client_config/subchannel_call_holder.c
@@ -43,14 +43,14 @@
#define CANCELLED_CALL ((grpc_subchannel_call *)1)
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
- bool success);
+ grpc_error *error);
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
- bool success);
+ grpc_error *error);
static void add_waiting_locked(grpc_subchannel_call_holder *holder,
grpc_transport_stream_op *op);
static void fail_locked(grpc_exec_ctx *exec_ctx,
- grpc_subchannel_call_holder *holder);
+ grpc_subchannel_call_holder *holder, grpc_error *error);
static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder);
@@ -68,6 +68,7 @@ void grpc_subchannel_call_holder_init(
holder->waiting_ops_capacity = 0;
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
holder->owning_call = owning_call;
+ holder->pollent = NULL;
}
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
@@ -90,7 +91,8 @@ void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call = GET_CALL(holder);
GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0);
if (call == CANCELLED_CALL) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+ GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return;
}
@@ -106,7 +108,8 @@ retry:
call = GET_CALL(holder);
if (call == CANCELLED_CALL) {
gpr_mu_unlock(&holder->mu);
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+ GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return;
}
@@ -123,7 +126,10 @@ retry:
} else {
switch (holder->creation_phase) {
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
- fail_locked(exec_ctx, holder);
+ fail_locked(exec_ctx, holder,
+ grpc_error_set_int(GRPC_ERROR_CREATE("Cancelled"),
+ GRPC_ERROR_INT_GRPC_STATUS,
+ op->cancel_with_status));
break;
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
@@ -131,7 +137,8 @@ retry:
break;
}
gpr_mu_unlock(&holder->mu);
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+ grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+ GRPC_ERROR_CANCELLED);
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
return;
}
@@ -157,7 +164,7 @@ retry:
gpr_atm_rel_store(
&holder->subchannel_call,
(gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
- exec_ctx, holder->connected_subchannel, holder->pollset));
+ exec_ctx, holder->connected_subchannel, holder->pollent));
retry_waiting_locked(exec_ctx, holder);
goto retry;
}
@@ -167,7 +174,8 @@ retry:
GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
}
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
grpc_subchannel_call_holder *holder = arg;
gpr_mu_lock(&holder->mu);
GPR_ASSERT(holder->creation_phase ==
@@ -175,15 +183,19 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
if (holder->connected_subchannel == NULL) {
gpr_atm_no_barrier_store(&holder->subchannel_call, 1);
- fail_locked(exec_ctx, holder);
+ fail_locked(exec_ctx, holder,
+ GRPC_ERROR_CREATE_REFERENCING("Failed to create subchannel",
+ &error, 1));
} else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
/* already cancelled before subchannel became ready */
- fail_locked(exec_ctx, holder);
+ fail_locked(exec_ctx, holder,
+ GRPC_ERROR_CREATE_REFERENCING(
+ "Cancelled before creating subchannel", &error, 1));
} else {
gpr_atm_rel_store(
&holder->subchannel_call,
(gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
- exec_ctx, holder->connected_subchannel, holder->pollset));
+ exec_ctx, holder->connected_subchannel, holder->pollent));
retry_waiting_locked(exec_ctx, holder);
}
gpr_mu_unlock(&holder->mu);
@@ -204,18 +216,18 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
a->call = GET_CALL(holder);
if (a->call == CANCELLED_CALL) {
gpr_free(a);
- fail_locked(exec_ctx, holder);
+ fail_locked(exec_ctx, holder, GRPC_ERROR_CANCELLED);
return;
}
holder->waiting_ops = NULL;
holder->waiting_ops_count = 0;
holder->waiting_ops_capacity = 0;
GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
- grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a),
+ GRPC_ERROR_NONE, NULL);
}
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) {
+static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
retry_ops_args *a = args;
size_t i;
for (i = 0; i < a->nops; i++) {
@@ -240,13 +252,15 @@ static void add_waiting_locked(grpc_subchannel_call_holder *holder,
}
static void fail_locked(grpc_exec_ctx *exec_ctx,
- grpc_subchannel_call_holder *holder) {
+ grpc_subchannel_call_holder *holder,
+ grpc_error *error) {
size_t i;
for (i = 0; i < holder->waiting_ops_count; i++) {
- grpc_transport_stream_op_finish_with_failure(exec_ctx,
- &holder->waiting_ops[i]);
+ grpc_transport_stream_op_finish_with_failure(
+ exec_ctx, &holder->waiting_ops[i], GRPC_ERROR_REF(error));
}
holder->waiting_ops_count = 0;
+ GRPC_ERROR_UNREF(error);
}
char *grpc_subchannel_call_holder_get_peer(
diff --git a/src/core/ext/client_config/subchannel_call_holder.h b/src/core/ext/client_config/subchannel_call_holder.h
index 9299908788..8d2deb02f3 100644
--- a/src/core/ext/client_config/subchannel_call_holder.h
+++ b/src/core/ext/client_config/subchannel_call_holder.h
@@ -35,6 +35,7 @@
#define GRPC_CORE_EXT_CLIENT_CONFIG_SUBCHANNEL_CALL_HOLDER_H
#include "src/core/ext/client_config/subchannel.h"
+#include "src/core/lib/iomgr/polling_entity.h"
/** Pick a subchannel for grpc_subchannel_call_holder;
Return 1 if subchannel is available immediately (in which case on_ready
@@ -71,7 +72,7 @@ typedef struct grpc_subchannel_call_holder {
grpc_subchannel_call_holder_creation_phase creation_phase;
grpc_connected_subchannel *connected_subchannel;
- grpc_pollset *pollset;
+ grpc_polling_entity *pollent;
grpc_transport_stream_op *waiting_ops;
size_t waiting_ops_count;
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 b5797da832..9decf70692 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -39,7 +39,7 @@
typedef struct pending_pick {
struct pending_pick *next;
- grpc_pollset *pollset;
+ grpc_polling_entity *pollent;
uint32_t initial_metadata_flags;
grpc_connected_subchannel **target;
grpc_closure *on_complete;
@@ -103,8 +103,9 @@ static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
p->shutdown = 1;
pp = p->pending_picks;
p->pending_picks = NULL;
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_SHUTDOWN, "shutdown");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE("Channel shutdown"), "shutdown");
/* cancel subscription */
if (selected != NULL) {
grpc_connected_subchannel_notify_on_state_change(
@@ -118,9 +119,9 @@ static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
while (pp != NULL) {
pending_pick *next = pp->next;
*pp->target = NULL;
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp);
pp = next;
}
@@ -136,10 +137,11 @@ static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
while (pp != NULL) {
pending_pick *next = pp->next;
if (pp->target == target) {
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
*target = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
+ GRPC_ERROR_CREATE("Pick Cancelled"), NULL);
gpr_free(pp);
} else {
pp->next = p->pending_picks;
@@ -162,9 +164,10 @@ static void pf_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next;
if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) {
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
+ GRPC_ERROR_CREATE("Pick Cancelled"), NULL);
gpr_free(pp);
} else {
pp->next = p->pending_picks;
@@ -196,7 +199,8 @@ static void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
+ grpc_polling_entity *pollent,
+ grpc_metadata_batch *initial_metadata,
uint32_t initial_metadata_flags,
grpc_connected_subchannel **target,
grpc_closure *on_complete) {
@@ -221,10 +225,11 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if (!p->started_picking) {
start_picking(exec_ctx, p);
}
- grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset);
+ grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent,
+ p->base.interested_parties);
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
- pp->pollset = pollset;
+ pp->pollent = pollent;
pp->target = target;
pp->initial_metadata_flags = initial_metadata_flags;
pp->on_complete = on_complete;
@@ -235,7 +240,7 @@ static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
}
static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
pick_first_lb_policy *p = arg;
size_t i;
size_t num_subchannels = p->num_subchannels;
@@ -256,12 +261,14 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
}
static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
pick_first_lb_policy *p = arg;
grpc_subchannel *selected_subchannel;
pending_pick *pp;
grpc_connected_subchannel *selected;
+ GRPC_ERROR_REF(error);
+
gpr_mu_lock(&p->mu);
selected = GET_SELECTED(p);
@@ -269,6 +276,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (p->shutdown) {
gpr_mu_unlock(&p->mu);
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+ GRPC_ERROR_UNREF(error);
return;
} else if (selected != NULL) {
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
@@ -276,7 +284,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN;
}
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- p->checking_connectivity, "selected_changed");
+ p->checking_connectivity, GRPC_ERROR_REF(error),
+ "selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) {
grpc_connected_subchannel_notify_on_state_change(
exec_ctx, selected, p->base.interested_parties,
@@ -289,7 +298,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
switch (p->checking_connectivity) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_READY, "connecting_ready");
+ GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
+ "connecting_ready");
selected_subchannel = p->subchannels[p->checking_subchannel];
selected =
grpc_subchannel_get_connected_subchannel(selected_subchannel);
@@ -298,15 +308,16 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
/* drop the pick list: we are connected now */
GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
- grpc_exec_ctx_enqueue(
- exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL);
+ grpc_exec_ctx_sched(exec_ctx,
+ grpc_closure_create(destroy_subchannels, p),
+ GRPC_ERROR_NONE, NULL);
/* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = selected;
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp);
}
grpc_connected_subchannel_notify_on_state_change(
@@ -318,12 +329,13 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
(p->checking_subchannel + 1) % p->num_subchannels;
if (p->checking_subchannel == 0) {
/* only trigger transient failure when we've tried all alternatives */
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- "connecting_transient_failure");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_REF(error), "connecting_transient_failure");
}
+ GRPC_ERROR_UNREF(error);
p->checking_connectivity = grpc_subchannel_check_connectivity(
- p->subchannels[p->checking_subchannel]);
+ p->subchannels[p->checking_subchannel], &error);
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel],
@@ -335,9 +347,9 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_CONNECTING,
- "connecting_changed");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING,
+ GRPC_ERROR_REF(error), "connecting_changed");
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel],
p->base.interested_parties, &p->checking_connectivity,
@@ -350,38 +362,45 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
"pick_first");
if (p->num_subchannels == 0) {
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_SHUTDOWN,
- "no_more_channels");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels",
+ &error, 1),
+ "no_more_channels");
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
+ NULL);
gpr_free(pp);
}
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
"pick_first_connectivity");
} else {
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- "subchannel_failed");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_REF(error), "subchannel_failed");
p->checking_subchannel %= p->num_subchannels;
+ GRPC_ERROR_UNREF(error);
p->checking_connectivity = grpc_subchannel_check_connectivity(
- p->subchannels[p->checking_subchannel]);
+ p->subchannels[p->checking_subchannel], &error);
goto loop;
}
}
}
gpr_mu_unlock(&p->mu);
+
+ GRPC_ERROR_UNREF(error);
}
static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
- grpc_lb_policy *pol) {
+ grpc_lb_policy *pol,
+ grpc_error **error) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
grpc_connectivity_state st;
gpr_mu_lock(&p->mu);
- st = grpc_connectivity_state_check(&p->state_tracker);
+ st = grpc_connectivity_state_check(&p->state_tracker, error);
gpr_mu_unlock(&p->mu);
return st;
}
@@ -404,7 +423,8 @@ static void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if (selected) {
grpc_connected_subchannel_ping(exec_ctx, selected, closure);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"),
+ NULL);
}
}
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 7ab913b645..7bcf608ab9 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -31,6 +31,34 @@
*
*/
+/** Round Robin Policy.
+ *
+ * This policy keeps:
+ * - A circular list of ready (connected) subchannels, the *readylist*. An empty
+ * readylist consists solely of its root (dummy) node.
+ * - A pointer to the last element picked from the readylist, the *lastpick*.
+ * Initially set to point to the readylist's root.
+ *
+ * Behavior:
+ * - When a subchannel connects, it's *prepended* to the readylist's root node.
+ * Ie, if readylist = A <-> B <-> ROOT <-> C
+ * ^ ^
+ * |____________________|
+ * and subchannel D becomes connected, the addition of D to the readylist
+ * results in readylist = A <-> B <-> D <-> ROOT <-> C
+ * ^ ^
+ * |__________________________|
+ * - When a subchannel disconnects, it's removed from the readylist. If the
+ * subchannel being removed was the most recently picked, the *lastpick*
+ * pointer moves to the removed node's previous element. Note that if the
+ * readylist only had one element, this is still legal, as the lastpick would
+ * point to the dummy root node, for an empty readylist.
+ * - Upon picking, *lastpick* is updated to point to the returned (connected)
+ * subchannel. Note that it's possible that the selected subchannel becomes
+ * disconnected in the interim between the selection and the actual usage of
+ * the subchannel by the caller.
+ */
+
#include <string.h>
#include <grpc/support/alloc.h>
@@ -48,7 +76,7 @@ int grpc_lb_round_robin_trace = 0;
* Once a pick is available, \a target is updated and \a on_complete called. */
typedef struct pending_pick {
struct pending_pick *next;
- grpc_pollset *pollset;
+ grpc_polling_entity *pollent;
uint32_t initial_metadata_flags;
grpc_connected_subchannel **target;
grpc_closure *on_complete;
@@ -173,9 +201,7 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
return;
}
if (node == p->ready_list_last_pick) {
- /* If removing the lastly picked node, reset the last pick pointer to the
- * dummy root of the list */
- p->ready_list_last_pick = &p->ready_list;
+ p->ready_list_last_pick = p->ready_list_last_pick->prev;
}
/* removing last item */
@@ -239,11 +265,13 @@ static void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
+ GRPC_ERROR_CREATE("Channel Shutdown"), NULL);
gpr_free(pp);
}
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_SHUTDOWN, "shutdown");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+ GRPC_ERROR_CREATE("Channel Shutdown"), "shutdown");
for (i = 0; i < p->num_subchannels; i++) {
subchannel_data *sd = p->subchannels[i];
grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
@@ -262,10 +290,11 @@ static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
while (pp != NULL) {
pending_pick *next = pp->next;
if (pp->target == target) {
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
*target = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_CANCELLED,
+ NULL);
gpr_free(pp);
} else {
pp->next = p->pending_picks;
@@ -288,10 +317,11 @@ static void rr_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
pending_pick *next = pp->next;
if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
initial_metadata_flags_eq) {
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
*pp->target = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_CANCELLED,
+ NULL);
gpr_free(pp);
} else {
pp->next = p->pending_picks;
@@ -307,7 +337,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
p->started_picking = 1;
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
+ gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%" PRIuPTR, p,
p->num_subchannels);
}
@@ -331,7 +361,8 @@ static void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_pollset *pollset, grpc_metadata_batch *initial_metadata,
+ grpc_polling_entity *pollent,
+ grpc_metadata_batch *initial_metadata,
uint32_t initial_metadata_flags,
grpc_connected_subchannel **target,
grpc_closure *on_complete) {
@@ -344,8 +375,8 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
*target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
- "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
- selected->subchannel, selected);
+ "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)", *target,
+ selected);
}
/* only advance the last picked pointer if the selection was used */
advance_last_picked_locked(p);
@@ -354,10 +385,11 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
if (!p->started_picking) {
start_picking(exec_ctx, p);
}
- grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset);
+ grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent,
+ p->base.interested_parties);
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
- pp->pollset = pollset;
+ pp->pollent = pollent;
pp->target = target;
pp->on_complete = on_complete;
pp->initial_metadata_flags = initial_metadata_flags;
@@ -368,7 +400,7 @@ static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
}
static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
subchannel_data *sd = arg;
round_robin_lb_policy *p = sd->policy;
pending_pick *pp;
@@ -376,6 +408,7 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int unref = 0;
+ GRPC_ERROR_REF(error);
gpr_mu_lock(&p->mu);
if (p->shutdown) {
@@ -384,7 +417,8 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
switch (sd->connectivity_state) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_READY, "connecting_ready");
+ GRPC_CHANNEL_READY, GRPC_ERROR_REF(error),
+ "connecting_ready");
/* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */
sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
@@ -406,9 +440,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected);
}
- grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
- pp->pollset);
- grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent,
+ p->base.interested_parties);
+ grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
gpr_free(pp);
}
grpc_subchannel_notify_on_state_change(
@@ -417,9 +451,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- sd->connectivity_state,
- "connecting_changed");
+ 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);
@@ -435,9 +469,9 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
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,
- "connecting_transient_failure");
+ 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) {
@@ -454,19 +488,22 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
unref = 1;
if (p->num_subchannels == 0) {
- grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- GRPC_CHANNEL_SHUTDOWN,
- "no_more_channels");
+ 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_enqueue(exec_ctx, pp->on_complete, true, 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,
- "subchannel_failed");
+ grpc_connectivity_state_set(
+ exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_REF(error), "subchannel_failed");
}
} /* switch */
} /* !unref */
@@ -476,14 +513,17 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (unref) {
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
}
+
+ GRPC_ERROR_UNREF(error);
}
static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
- grpc_lb_policy *pol) {
+ grpc_lb_policy *pol,
+ grpc_error **error) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
grpc_connectivity_state st;
gpr_mu_lock(&p->mu);
- st = grpc_connectivity_state_check(&p->state_tracker);
+ st = grpc_connectivity_state_check(&p->state_tracker, error);
gpr_mu_unlock(&p->mu);
return st;
}
@@ -511,7 +551,8 @@ static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
grpc_connected_subchannel_ping(exec_ctx, target, closure);
} else {
gpr_mu_unlock(&p->mu);
- grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure,
+ GRPC_ERROR_CREATE("Round Robin not connected"), NULL);
}
}
@@ -524,7 +565,7 @@ static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
-static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
+static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
grpc_lb_policy_factory *factory,
grpc_lb_policy_args *args) {
GPR_ASSERT(args->addresses != NULL);
@@ -580,7 +621,7 @@ static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
}
static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
- round_robin_factory_ref, round_robin_factory_unref, create_round_robin,
+ round_robin_factory_ref, round_robin_factory_unref, round_robin_create,
"round_robin"};
static grpc_lb_policy_factory round_robin_lb_policy_factory = {
diff --git a/src/core/ext/load_reporting/load_reporting.c b/src/core/ext/load_reporting/load_reporting.c
index 60082dbaaa..9e4d32676f 100644
--- a/src/core/ext/load_reporting/load_reporting.c
+++ b/src/core/ext/load_reporting/load_reporting.c
@@ -76,7 +76,8 @@ static bool is_load_reporting_enabled(const grpc_channel_args *a) {
if (a == NULL) return false;
for (size_t i = 0; i < a->num_args; i++) {
if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_LOAD_REPORTING)) {
- return a->args[i].value.pointer.p != NULL;
+ return a->args[i].type == GRPC_ARG_POINTER &&
+ a->args[i].value.pointer.p != NULL;
}
}
return false;
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index f49730fac3..f372f88c3a 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -142,7 +142,7 @@ const grpc_channel_filter grpc_load_reporting_filter = {
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 620ba4e2aa..31ac968670 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -82,6 +82,9 @@ typedef struct {
grpc_timer retry_timer;
/** retry backoff state */
gpr_backoff backoff_state;
+
+ /** currently resolving addresses */
+ grpc_resolved_addresses *addresses;
} dns_resolver;
static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@@ -108,7 +111,8 @@ static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
}
if (r->next_completion != NULL) {
*r->target_config = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, r->next_completion,
+ GRPC_ERROR_CREATE("Resolver Shutdown"), NULL);
r->next_completion = NULL;
}
gpr_mu_unlock(&r->mu);
@@ -143,12 +147,12 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
}
static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
dns_resolver *r = arg;
gpr_mu_lock(&r->mu);
r->have_retry_timer = false;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
if (!r->resolving) {
dns_start_resolving_locked(exec_ctx, r);
}
@@ -159,13 +163,14 @@ static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
}
static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses) {
+ grpc_error *error) {
dns_resolver *r = arg;
grpc_client_config *config = NULL;
grpc_lb_policy *lb_policy;
gpr_mu_lock(&r->mu);
GPR_ASSERT(r->resolving);
r->resolving = 0;
+ grpc_resolved_addresses *addresses = r->addresses;
if (addresses != NULL) {
grpc_lb_policy_args lb_policy_args;
config = grpc_client_config_create();
@@ -183,11 +188,18 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
gpr_timespec timeout = gpr_time_sub(next_try, now);
- gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d.%09d seconds",
- timeout.tv_sec, timeout.tv_nsec);
+ const char *msg = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
+ grpc_error_free_string(msg);
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) {
+ gpr_log(GPR_DEBUG, "retrying in %" PRId64 ".%09d seconds", timeout.tv_sec,
+ timeout.tv_nsec);
+ } else {
+ gpr_log(GPR_DEBUG, "retrying immediately");
+ }
grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
now);
}
@@ -207,7 +219,9 @@ static void dns_start_resolving_locked(grpc_exec_ctx *exec_ctx,
GRPC_RESOLVER_REF(&r->base, "dns-resolving");
GPR_ASSERT(!r->resolving);
r->resolving = 1;
- grpc_resolve_address(exec_ctx, r->name, r->default_port, dns_on_resolved, r);
+ r->addresses = NULL;
+ grpc_resolve_address(exec_ctx, r->name, r->default_port,
+ grpc_closure_create(dns_on_resolved, r), &r->addresses);
}
static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
@@ -218,7 +232,7 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
if (r->resolved_config) {
grpc_client_config_ref(r->resolved_config);
}
- grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
r->published_version = r->resolved_version;
}
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index a4fa9acf22..1f7cce2f43 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -92,7 +92,7 @@ static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
gpr_mu_lock(&r->mu);
if (r->next_completion != NULL) {
*r->target_config = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
gpr_mu_unlock(&r->mu);
@@ -133,7 +133,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
r->published = 1;
*r->target_config = cfg;
- grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
r->next_completion = NULL;
}
}
diff --git a/src/core/ext/resolver/zookeeper/zookeeper_resolver.c b/src/core/ext/resolver/zookeeper/zookeeper_resolver.c
deleted file mode 100644
index deb4b9b1ef..0000000000
--- a/src/core/ext/resolver/zookeeper/zookeeper_resolver.c
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/string_util.h>
-
-#include <grpc/grpc_zookeeper.h>
-#include <zookeeper/zookeeper.h>
-
-#include "src/core/ext/client_config/lb_policy_registry.h"
-#include "src/core/ext/client_config/resolver_registry.h"
-#include "src/core/lib/iomgr/resolve_address.h"
-#include "src/core/lib/json/json.h"
-#include "src/core/lib/support/string.h"
-#include "src/core/lib/surface/api_trace.h"
-
-/** Zookeeper session expiration time in milliseconds */
-#define GRPC_ZOOKEEPER_SESSION_TIMEOUT 15000
-
-typedef struct {
- /** base class: must be first */
- grpc_resolver base;
- /** refcount */
- gpr_refcount refs;
- /** name to resolve */
- char *name;
- /** subchannel factory */
- grpc_client_channel_factory *client_channel_factory;
- /** load balancing policy name */
- char *lb_policy_name;
-
- /** mutex guarding the rest of the state */
- gpr_mu mu;
- /** are we currently resolving? */
- int resolving;
- /** which version of resolved_config have we published? */
- int published_version;
- /** which version of resolved_config is current? */
- int resolved_version;
- /** pending next completion, or NULL */
- grpc_closure *next_completion;
- /** target config address for next completion */
- grpc_client_config **target_config;
- /** current (fully resolved) config */
- grpc_client_config *resolved_config;
-
- /** zookeeper handle */
- zhandle_t *zookeeper_handle;
- /** zookeeper resolved addresses */
- grpc_resolved_addresses *resolved_addrs;
- /** total number of addresses to be resolved */
- int resolved_total;
- /** number of addresses resolved */
- int resolved_num;
-} zookeeper_resolver;
-
-static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-
-static void zookeeper_start_resolving_locked(zookeeper_resolver *r);
-static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
- zookeeper_resolver *r);
-
-static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *r);
-static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
- grpc_client_config **target_config,
- grpc_closure *on_complete);
-
-static const grpc_resolver_vtable zookeeper_resolver_vtable = {
- zookeeper_destroy, zookeeper_shutdown, zookeeper_channel_saw_error,
- zookeeper_next};
-
-static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver) {
- zookeeper_resolver *r = (zookeeper_resolver *)resolver;
- grpc_closure *call = NULL;
- gpr_mu_lock(&r->mu);
- if (r->next_completion != NULL) {
- *r->target_config = NULL;
- call = r->next_completion;
- r->next_completion = NULL;
- }
- zookeeper_close(r->zookeeper_handle);
- gpr_mu_unlock(&r->mu);
- if (call != NULL) {
- call->cb(exec_ctx, call->cb_arg, 1);
- }
-}
-
-static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver) {
- zookeeper_resolver *r = (zookeeper_resolver *)resolver;
- gpr_mu_lock(&r->mu);
- if (r->resolving == 0) {
- zookeeper_start_resolving_locked(r);
- }
- gpr_mu_unlock(&r->mu);
-}
-
-static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
- grpc_client_config **target_config,
- grpc_closure *on_complete) {
- zookeeper_resolver *r = (zookeeper_resolver *)resolver;
- gpr_mu_lock(&r->mu);
- GPR_ASSERT(r->next_completion == NULL);
- r->next_completion = on_complete;
- r->target_config = target_config;
- if (r->resolved_version == 0 && r->resolving == 0) {
- zookeeper_start_resolving_locked(r);
- } else {
- zookeeper_maybe_finish_next_locked(exec_ctx, r);
- }
- gpr_mu_unlock(&r->mu);
-}
-
-/** Zookeeper global watcher for connection management
- TODO: better connection management besides logs */
-static void zookeeper_global_watcher(zhandle_t *zookeeper_handle, int type,
- int state, const char *path,
- void *watcher_ctx) {
- if (type == ZOO_SESSION_EVENT) {
- if (state == ZOO_EXPIRED_SESSION_STATE) {
- gpr_log(GPR_ERROR, "Zookeeper session expired");
- } else if (state == ZOO_AUTH_FAILED_STATE) {
- gpr_log(GPR_ERROR, "Zookeeper authentication failed");
- }
- }
-}
-
-/** Zookeeper watcher triggered by changes to watched nodes
- Once triggered, it tries to resolve again to get updated addresses */
-static void zookeeper_watcher(zhandle_t *zookeeper_handle, int type, int state,
- const char *path, void *watcher_ctx) {
- if (watcher_ctx != NULL) {
- zookeeper_resolver *r = (zookeeper_resolver *)watcher_ctx;
- if (state == ZOO_CONNECTED_STATE) {
- gpr_mu_lock(&r->mu);
- if (r->resolving == 0) {
- zookeeper_start_resolving_locked(r);
- }
- gpr_mu_unlock(&r->mu);
- }
- }
-}
-
-/** Callback function after getting all resolved addresses
- Creates a subchannel for each address */
-static void zookeeper_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses) {
- zookeeper_resolver *r = arg;
- grpc_client_config *config = NULL;
- grpc_lb_policy *lb_policy;
-
- if (addresses != NULL) {
- grpc_lb_policy_args lb_policy_args;
- config = grpc_client_config_create();
- lb_policy_args.addresses = addresses;
- lb_policy_args.client_channel_factory = r->client_channel_factory;
- lb_policy =
- grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
-
- if (lb_policy != NULL) {
- grpc_client_config_set_lb_policy(config, lb_policy);
- GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
- }
- grpc_resolved_addresses_destroy(addresses);
- }
- gpr_mu_lock(&r->mu);
- GPR_ASSERT(r->resolving == 1);
- r->resolving = 0;
- if (r->resolved_config != NULL) {
- grpc_client_config_unref(exec_ctx, r->resolved_config);
- }
- r->resolved_config = config;
- r->resolved_version++;
- zookeeper_maybe_finish_next_locked(exec_ctx, r);
- gpr_mu_unlock(&r->mu);
-
- GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "zookeeper-resolving");
-}
-
-/** Callback function for each DNS resolved address */
-static void zookeeper_dns_resolved(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses) {
- size_t i;
- zookeeper_resolver *r = arg;
- int resolve_done = 0;
-
- gpr_mu_lock(&r->mu);
- r->resolved_num++;
- r->resolved_addrs->addrs =
- gpr_realloc(r->resolved_addrs->addrs,
- sizeof(grpc_resolved_address) *
- (r->resolved_addrs->naddrs + addresses->naddrs));
- for (i = 0; i < addresses->naddrs; i++) {
- memcpy(r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].addr,
- addresses->addrs[i].addr, addresses->addrs[i].len);
- r->resolved_addrs->addrs[i + r->resolved_addrs->naddrs].len =
- addresses->addrs[i].len;
- }
-
- r->resolved_addrs->naddrs += addresses->naddrs;
- grpc_resolved_addresses_destroy(addresses);
-
- /** Wait for all addresses to be resolved */
- resolve_done = (r->resolved_num == r->resolved_total);
- gpr_mu_unlock(&r->mu);
- if (resolve_done) {
- zookeeper_on_resolved(exec_ctx, r, r->resolved_addrs);
- }
-}
-
-/** Parses JSON format address of a zookeeper node */
-static char *zookeeper_parse_address(const char *value, size_t value_len) {
- grpc_json *json;
- grpc_json *cur;
- const char *host;
- const char *port;
- char *buffer;
- char *address = NULL;
-
- buffer = gpr_malloc(value_len);
- memcpy(buffer, value, value_len);
- json = grpc_json_parse_string_with_len(buffer, value_len);
- if (json != NULL) {
- host = NULL;
- port = NULL;
- for (cur = json->child; cur != NULL; cur = cur->next) {
- if (!strcmp(cur->key, "host")) {
- host = cur->value;
- if (port != NULL) {
- break;
- }
- } else if (!strcmp(cur->key, "port")) {
- port = cur->value;
- if (host != NULL) {
- break;
- }
- }
- }
- if (host != NULL && port != NULL) {
- gpr_asprintf(&address, "%s:%s", host, port);
- }
- grpc_json_destroy(json);
- }
- gpr_free(buffer);
-
- return address;
-}
-
-static void zookeeper_get_children_node_completion(int rc, const char *value,
- int value_len,
- const struct Stat *stat,
- const void *arg) {
- char *address = NULL;
- zookeeper_resolver *r = (zookeeper_resolver *)arg;
- int resolve_done = 0;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-
- if (rc != 0) {
- gpr_log(GPR_ERROR, "Error in getting a child node of %s", r->name);
- grpc_exec_ctx_finish(&exec_ctx);
- return;
- }
-
- address = zookeeper_parse_address(value, (size_t)value_len);
- if (address != NULL) {
- /** Further resolves address by DNS */
- grpc_resolve_address(&exec_ctx, address, NULL, zookeeper_dns_resolved, r);
- gpr_free(address);
- } else {
- gpr_log(GPR_ERROR, "Error in resolving a child node of %s", r->name);
- gpr_mu_lock(&r->mu);
- r->resolved_total--;
- resolve_done = (r->resolved_num == r->resolved_total);
- gpr_mu_unlock(&r->mu);
- if (resolve_done) {
- zookeeper_on_resolved(&exec_ctx, r, r->resolved_addrs);
- }
- }
-
- grpc_exec_ctx_finish(&exec_ctx);
-}
-
-static void zookeeper_get_children_completion(
- int rc, const struct String_vector *children, const void *arg) {
- char *path;
- int status;
- int i;
- zookeeper_resolver *r = (zookeeper_resolver *)arg;
-
- if (rc != 0) {
- gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
- return;
- }
-
- if (children->count == 0) {
- gpr_log(GPR_ERROR, "Error in resolving zookeeper address %s", r->name);
- return;
- }
-
- r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
- r->resolved_addrs->addrs = NULL;
- r->resolved_addrs->naddrs = 0;
- r->resolved_total = children->count;
-
- /** TODO: Replace expensive heap allocation with stack
- if we can get maximum length of zookeeper path */
- for (i = 0; i < children->count; i++) {
- gpr_asprintf(&path, "%s/%s", r->name, children->data[i]);
- status = zoo_awget(r->zookeeper_handle, path, zookeeper_watcher, r,
- zookeeper_get_children_node_completion, r);
- gpr_free(path);
- if (status != 0) {
- gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", path);
- }
- }
-}
-
-static void zookeeper_get_node_completion(int rc, const char *value,
- int value_len,
- const struct Stat *stat,
- const void *arg) {
- int status;
- char *address = NULL;
- zookeeper_resolver *r = (zookeeper_resolver *)arg;
- r->resolved_addrs = NULL;
- r->resolved_total = 0;
- r->resolved_num = 0;
-
- if (rc != 0) {
- gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
- return;
- }
-
- /** If zookeeper node of path r->name does not have address
- (i.e. service node), get its children */
- address = zookeeper_parse_address(value, (size_t)value_len);
- if (address != NULL) {
- r->resolved_addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
- r->resolved_addrs->addrs = NULL;
- r->resolved_addrs->naddrs = 0;
- r->resolved_total = 1;
- /** Further resolves address by DNS */
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_resolve_address(&exec_ctx, address, NULL, zookeeper_dns_resolved, r);
- gpr_free(address);
- grpc_exec_ctx_finish(&exec_ctx);
- return;
- }
-
- status = zoo_awget_children(r->zookeeper_handle, r->name, zookeeper_watcher,
- r, zookeeper_get_children_completion, r);
- if (status != 0) {
- gpr_log(GPR_ERROR, "Error in getting zookeeper children of %s", r->name);
- }
-}
-
-static void zookeeper_resolve_address(zookeeper_resolver *r) {
- int status;
- status = zoo_awget(r->zookeeper_handle, r->name, zookeeper_watcher, r,
- zookeeper_get_node_completion, r);
- if (status != 0) {
- gpr_log(GPR_ERROR, "Error in getting zookeeper node %s", r->name);
- }
-}
-
-static void zookeeper_start_resolving_locked(zookeeper_resolver *r) {
- GRPC_RESOLVER_REF(&r->base, "zookeeper-resolving");
- GPR_ASSERT(r->resolving == 0);
- r->resolving = 1;
- zookeeper_resolve_address(r);
-}
-
-static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
- zookeeper_resolver *r) {
- if (r->next_completion != NULL &&
- r->resolved_version != r->published_version) {
- *r->target_config = r->resolved_config;
- if (r->resolved_config != NULL) {
- grpc_client_config_ref(r->resolved_config);
- }
- grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
- r->next_completion = NULL;
- r->published_version = r->resolved_version;
- }
-}
-
-static void zookeeper_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
- zookeeper_resolver *r = (zookeeper_resolver *)gr;
- gpr_mu_destroy(&r->mu);
- if (r->resolved_config != NULL) {
- grpc_client_config_unref(exec_ctx, r->resolved_config);
- }
- grpc_client_channel_factory_unref(exec_ctx, r->client_channel_factory);
- gpr_free(r->name);
- gpr_free(r->lb_policy_name);
- gpr_free(r);
-}
-
-static grpc_resolver *zookeeper_create(grpc_resolver_args *args,
- const char *lb_policy_name) {
- zookeeper_resolver *r;
- size_t length;
- char *path = args->uri->path;
-
- if (0 == strcmp(args->uri->authority, "")) {
- gpr_log(GPR_ERROR, "No authority specified in zookeeper uri");
- return NULL;
- }
-
- /** Removes the trailing slash if exists */
- length = strlen(path);
- if (length > 1 && path[length - 1] == '/') {
- path[length - 1] = 0;
- }
-
- r = gpr_malloc(sizeof(zookeeper_resolver));
- memset(r, 0, sizeof(*r));
- gpr_ref_init(&r->refs, 1);
- gpr_mu_init(&r->mu);
- grpc_resolver_init(&r->base, &zookeeper_resolver_vtable);
- r->name = gpr_strdup(path);
-
- r->client_channel_factory = args->client_channel_factory;
- grpc_client_channel_factory_ref(r->client_channel_factory);
-
- r->lb_policy_name = gpr_strdup(lb_policy_name);
-
- /** Initializes zookeeper client */
- zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
- r->zookeeper_handle =
- zookeeper_init(args->uri->authority, zookeeper_global_watcher,
- GRPC_ZOOKEEPER_SESSION_TIMEOUT, 0, 0, 0);
- if (r->zookeeper_handle == NULL) {
- gpr_log(GPR_ERROR, "Unable to connect to zookeeper server");
- return NULL;
- }
-
- return &r->base;
-}
-
-/*
- * FACTORY
- */
-
-static void zookeeper_factory_ref(grpc_resolver_factory *factory) {}
-
-static void zookeeper_factory_unref(grpc_resolver_factory *factory) {}
-
-static char *zookeeper_factory_get_default_hostname(
- grpc_resolver_factory *factory, grpc_uri *uri) {
- return NULL;
-}
-
-static grpc_resolver *zookeeper_factory_create_resolver(
- grpc_resolver_factory *factory, grpc_resolver_args *args) {
- return zookeeper_create(args, "pick_first");
-}
-
-static const grpc_resolver_factory_vtable zookeeper_factory_vtable = {
- zookeeper_factory_ref, zookeeper_factory_unref,
- zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname,
- "zookeeper"};
-
-static grpc_resolver_factory zookeeper_resolver_factory = {
- &zookeeper_factory_vtable};
-
-static grpc_resolver_factory *zookeeper_resolver_factory_create() {
- return &zookeeper_resolver_factory;
-}
-
-static void zookeeper_plugin_init() {
- grpc_register_resolver_type(zookeeper_resolver_factory_create());
-}
-
-void grpc_zookeeper_register() {
- GRPC_API_TRACE("grpc_zookeeper_register(void)", 0, ());
- grpc_register_plugin(zookeeper_plugin_init, NULL);
-}
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 c5d3d8d9cc..85f9efb3b6 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -79,11 +79,11 @@ static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
connector_unref(exec_ctx, arg);
}
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->tcp;
@@ -103,13 +103,13 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
GPR_ASSERT(c->result->transport);
- c->result->channel_args = c->args.channel_args;
+ c->result->channel_args = grpc_channel_args_copy(c->args.channel_args);
} else {
memset(c->result, 0, sizeof(*c->result));
}
notify = c->notify;
c->notify = NULL;
- notify->cb(exec_ctx, notify->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
}
static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
new file mode 100644
index 0000000000..ca435c25ce
--- /dev/null
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
@@ -0,0 +1,95 @@
+/*
+ *
+ * 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 <grpc/grpc.h>
+#include <grpc/grpc_posix.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+#include <fcntl.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/transport/transport.h"
+
+grpc_channel *grpc_insecure_channel_create_from_fd(
+ const char *target, int fd, const grpc_channel_args *args) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GRPC_API_TRACE("grpc_insecure_channel_create(target=%p, fd=%d, args=%p)", 3,
+ (target, fd, args));
+
+ grpc_arg default_authority_arg;
+ default_authority_arg.type = GRPC_ARG_STRING;
+ default_authority_arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
+ default_authority_arg.value.string = "test.authority";
+ grpc_channel_args *final_args =
+ grpc_channel_args_copy_and_add(args, &default_authority_arg, 1);
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ GPR_ASSERT(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0);
+
+ grpc_endpoint *client =
+ grpc_tcp_create(grpc_fd_create(fd, "client"),
+ GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "fd-client");
+
+ grpc_transport *transport =
+ grpc_create_chttp2_transport(&exec_ctx, final_args, client, 1);
+ GPR_ASSERT(transport);
+ grpc_channel *channel = grpc_channel_create(
+ &exec_ctx, target, final_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
+ grpc_channel_args_destroy(final_args);
+ grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+
+ grpc_exec_ctx_finish(&exec_ctx);
+
+ return channel != NULL ? channel : grpc_lame_client_channel_create(
+ target, GRPC_STATUS_INTERNAL,
+ "Failed to create client channel");
+}
+
+#else // !GPR_SUPPORT_CHANNELS_FROM_FD
+
+grpc_channel *grpc_insecure_channel_create_from_fd(
+ const char *target, int fd, const grpc_channel_args *args) {
+ GPR_ASSERT(0);
+ return NULL;
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
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 a262306085..721ba82d8f 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
@@ -90,7 +90,6 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_auth_context *auth_context) {
connector *c = arg;
grpc_closure *notify;
- grpc_channel_args *args_copy = NULL;
gpr_mu_lock(&c->mu);
if (c->connecting_endpoint == NULL) {
memset(c->result, 0, sizeof(*c->result));
@@ -109,26 +108,23 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
auth_context_arg = grpc_auth_context_to_arg(auth_context);
- args_copy = grpc_channel_args_copy_and_add(c->args.channel_args,
- &auth_context_arg, 1);
- c->result->channel_args = args_copy;
+ c->result->channel_args = grpc_channel_args_copy_and_add(
+ c->args.channel_args, &auth_context_arg, 1);
}
notify = c->notify;
c->notify = NULL;
- /* look at c->args which are connector args. */
- notify->cb(exec_ctx, notify->cb_arg, 1);
- if (args_copy != NULL) grpc_channel_args_destroy(args_copy);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_NONE, NULL);
}
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
connector *c = arg;
- grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector,
- c->connecting_endpoint,
- on_secure_handshake_done, c);
+ grpc_channel_security_connector_do_handshake(
+ exec_ctx, c->security_connector, c->connecting_endpoint, c->args.deadline,
+ on_secure_handshake_done, c);
}
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
connector *c = arg;
grpc_closure *notify;
grpc_endpoint *tcp = c->newly_connecting_endpoint;
@@ -147,13 +143,14 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
&c->initial_string_sent);
} else {
grpc_channel_security_connector_do_handshake(
- exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c);
+ exec_ctx, c->security_connector, tcp, c->args.deadline,
+ on_secure_handshake_done, c);
}
} else {
memset(c->result, 0, sizeof(*c->result));
notify = c->notify;
c->notify = NULL;
- notify->cb(exec_ctx, notify->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
}
}
@@ -175,7 +172,6 @@ static void connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *con,
grpc_closure *notify) {
connector *c = (connector *)con;
GPR_ASSERT(c->notify == NULL);
- GPR_ASSERT(notify->cb);
c->notify = notify;
c->args = *args;
c->result = result;
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 0428bb1e3d..9bae3a94f9 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -35,6 +35,7 @@
#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/lib/channel/http_server_filter.h"
@@ -74,34 +75,40 @@ static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
grpc_closure *destroy_done) {
grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_unref(exec_ctx, tcp);
- grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_NONE, NULL);
}
int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL;
size_t i;
- unsigned count = 0;
+ 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;
GRPC_API_TRACE("grpc_server_add_insecure_http2_port(server=%p, addr=%s)", 2,
(server, addr));
- resolved = grpc_blocking_resolve_address(addr, "http");
- if (!resolved) {
+ grpc_error **errors = NULL;
+ err = grpc_blocking_resolve_address(addr, "https", &resolved);
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
- tcp = grpc_tcp_server_create(NULL);
- GPR_ASSERT(tcp);
+ err = grpc_tcp_server_create(NULL, &tcp);
+ if (err != GRPC_ERROR_NONE) {
+ goto error;
+ }
- for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ 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, (struct sockaddr *)&resolved->addrs[i].addr,
- resolved->addrs[i].len);
- if (port_temp > 0) {
+ resolved->addrs[i].len, &port_temp);
+ if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
@@ -111,13 +118,24 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %d resolved",
- resolved->naddrs);
+ 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;
- }
- if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
- count, resolved->naddrs);
+ } 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);
@@ -127,6 +145,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
/* Error path: cleanup and return */
error:
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
@@ -135,7 +154,18 @@ error:
}
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/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
new file mode 100644
index 0000000000..96bf4d6f30
--- /dev/null
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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 <grpc/grpc.h>
+#include <grpc/grpc_posix.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_posix.h"
+#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/surface/server.h"
+
+void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
+ grpc_completion_queue *cq,
+ int fd) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+ char *name;
+ gpr_asprintf(&name, "fd:%d", fd);
+
+ grpc_endpoint *server_endpoint = grpc_tcp_create(
+ grpc_fd_create(fd, name), GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
+
+ gpr_free(name);
+
+ const grpc_channel_args *server_args = grpc_server_get_channel_args(server);
+ grpc_transport *transport = grpc_create_chttp2_transport(
+ &exec_ctx, server_args, server_endpoint, 0 /* is_client */);
+ grpc_endpoint_add_to_pollset(&exec_ctx, server_endpoint, grpc_cq_pollset(cq));
+ grpc_server_setup_transport(&exec_ctx, server, transport, NULL, server_args);
+ grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+#else // !GPR_SUPPORT_CHANNELS_FROM_FD
+
+void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
+ grpc_completion_queue *cq,
+ int fd) {
+ GPR_ASSERT(0);
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
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 ebbefbcd89..ead8a4d566 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
@@ -37,6 +37,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>
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
@@ -128,9 +129,11 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
state->state = statep;
state_ref(state->state);
state->accepting_pollset = accepting_pollset;
- grpc_server_security_connector_do_handshake(exec_ctx, state->state->sc,
- acceptor, tcp,
- on_secure_handshake_done, state);
+ grpc_server_security_connector_do_handshake(
+ exec_ctx, state->state->sc, acceptor, tcp,
+ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_time_from_seconds(120, GPR_TIMESPAN)),
+ on_secure_handshake_done, state);
}
/* Server callback: start listening on our ports */
@@ -141,11 +144,12 @@ static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *statep,
on_accept, state);
}
-static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
+static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep,
+ grpc_error *error) {
server_secure_state *state = statep;
if (state->destroy_callback != NULL) {
state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
- success);
+ GRPC_ERROR_REF(error));
}
grpc_server_security_connector_shutdown(exec_ctx, state->sc);
state_unref(state);
@@ -171,12 +175,14 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
grpc_tcp_server *tcp = NULL;
server_secure_state *state = NULL;
size_t i;
- unsigned count = 0;
+ 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_API_TRACE(
"grpc_server_add_secure_http2_port("
@@ -184,26 +190,34 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
3, (server, addr, creds));
/* create security context */
- if (creds == NULL) goto error;
+ if (creds == NULL) {
+ err = GRPC_ERROR_CREATE(
+ "No credentials specified for secure server port (creds==NULL)");
+ goto error;
+ }
status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) {
- gpr_log(GPR_ERROR,
- "Unable to create secure server with credentials of type %s.",
- creds->type);
+ char *msg;
+ gpr_asprintf(&msg,
+ "Unable to create secure server with credentials of type %s.",
+ creds->type);
+ err = grpc_error_set_int(GRPC_ERROR_CREATE(msg),
+ GRPC_ERROR_INT_SECURITY_STATUS, status);
+ gpr_free(msg);
goto error;
}
sc->channel_args = grpc_server_get_channel_args(server);
/* resolve address */
- resolved = grpc_blocking_resolve_address(addr, "https");
- if (!resolved) {
+ 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->destroy_closure, destroy_done, state);
- tcp = grpc_tcp_server_create(&state->destroy_closure);
- if (!tcp) {
+ err = grpc_tcp_server_create(&state->destroy_closure, &tcp);
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
@@ -215,11 +229,12 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1);
+ errors = gpr_malloc(sizeof(*errors) * resolved->naddrs);
for (i = 0; i < resolved->naddrs; i++) {
- port_temp = grpc_tcp_server_add_port(
+ errors[i] = grpc_tcp_server_add_port(
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
- resolved->addrs[i].len);
- if (port_temp > 0) {
+ resolved->addrs[i].len, &port_temp);
+ if (errors[i] == GRPC_ERROR_NONE) {
if (port_num == -1) {
port_num = port_temp;
} else {
@@ -229,15 +244,31 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
}
}
if (count == 0) {
- gpr_log(GPR_ERROR, "No address added out of total %d resolved",
- resolved->naddrs);
+ 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]);
+ }
}
- if (count != resolved->naddrs) {
- gpr_log(GPR_ERROR, "Only %d addresses added out of total %d resolved",
- count, resolved->naddrs);
- /* if it's an error, don't we want to goto error; here ? */
- }
+ gpr_free(errors);
+ errors = NULL;
grpc_resolved_addresses_destroy(resolved);
/* Register with the server only upon success */
@@ -248,6 +279,13 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
/* Error path: cleanup and return */
error:
+ 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);
}
@@ -262,5 +300,9 @@ error:
}
}
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
new file mode 100644
index 0000000000..2d90b01cd8
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -0,0 +1,232 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "src/core/lib/support/string.h"
+
+static uint8_t decode_table[] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62, 0x40, 0x40, 0x40, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40};
+
+static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
+
+static bool input_is_valid(uint8_t *input_ptr, size_t length) {
+ size_t i;
+
+ for (i = 0; i < length; ++i) {
+ if ((decode_table[input_ptr[i]] & 0xC0) != 0) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, invalid character '%c' in base64 "
+ "input.\n",
+ (char)(*input_ptr));
+ return false;
+ }
+ }
+ return true;
+}
+
+#define COMPOSE_OUTPUT_BYTE_0(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[0]] << 2) | \
+ (decode_table[input_ptr[1]] >> 4))
+
+#define COMPOSE_OUTPUT_BYTE_1(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[1]] << 4) | \
+ (decode_table[input_ptr[2]] >> 2))
+
+#define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
+ (uint8_t)((decode_table[input_ptr[2]] << 6) | decode_table[input_ptr[3]])
+
+bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx) {
+ size_t input_tail;
+
+ if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
+ return false;
+ }
+
+ // Process a block of 4 input characters and 3 output bytes
+ while (ctx->input_end >= ctx->input_cur + 4 &&
+ ctx->output_end >= ctx->output_cur + 3) {
+ if (!input_is_valid(ctx->input_cur, 4)) return false;
+ ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
+ ctx->output_cur += 3;
+ ctx->input_cur += 4;
+ }
+
+ // Process the tail of input data
+ input_tail = (size_t)(ctx->input_end - ctx->input_cur);
+ if (input_tail == 4) {
+ // Process the input data with pad chars
+ if (ctx->input_cur[3] == '=') {
+ if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
+ if (!input_is_valid(ctx->input_cur, 2)) return false;
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ ctx->input_cur += 4;
+ } else if (ctx->output_end >= ctx->output_cur + 2) {
+ if (!input_is_valid(ctx->input_cur, 3)) return false;
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ ;
+ ctx->input_cur += 4;
+ }
+ }
+
+ } else if (ctx->contains_tail && input_tail > 1) {
+ // Process the input data without pad chars, but constains_tail is set
+ if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
+ if (!input_is_valid(ctx->input_cur, input_tail)) return false;
+ switch (input_tail) {
+ case 3:
+ ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
+ case 2:
+ ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
+ }
+ ctx->output_cur += tail_xtra[input_tail];
+ ctx->input_cur += input_tail;
+ }
+ }
+
+ return true;
+}
+
+gpr_slice grpc_chttp2_base64_decode(gpr_slice input) {
+ size_t input_length = GPR_SLICE_LENGTH(input);
+ size_t output_length = input_length / 4 * 3;
+ struct grpc_base64_decode_context ctx;
+ gpr_slice output;
+
+ if (input_length % 4 != 0) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, input of "
+ "grpc_chttp2_base64_decode has a length of %d, which is not a "
+ "multiple of 4.\n",
+ (int)input_length);
+ return gpr_empty_slice();
+ }
+
+ if (input_length > 0) {
+ uint8_t *input_end = GPR_SLICE_END_PTR(input);
+ if (*(--input_end) == '=') {
+ output_length--;
+ if (*(--input_end) == '=') {
+ output_length--;
+ }
+ }
+ }
+ output = gpr_slice_malloc(output_length);
+
+ ctx.input_cur = GPR_SLICE_START_PTR(input);
+ ctx.input_end = GPR_SLICE_END_PTR(input);
+ ctx.output_cur = GPR_SLICE_START_PTR(output);
+ ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.contains_tail = false;
+
+ if (!grpc_base64_decode_partial(&ctx)) {
+ char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+ gpr_free(s);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+ GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur == GPR_SLICE_END_PTR(input));
+ return output;
+}
+
+gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
+ size_t output_length) {
+ size_t input_length = GPR_SLICE_LENGTH(input);
+ gpr_slice output = gpr_slice_malloc(output_length);
+ struct grpc_base64_decode_context ctx;
+
+ // The length of a base64 string cannot be 4 * n + 1
+ if (input_length % 4 == 1) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, input of "
+ "grpc_chttp2_base64_decode_with_length has a length of %d, which "
+ "has a tail of 1 byte.\n",
+ (int)input_length);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+
+ if (output_length > input_length / 4 * 3 + tail_xtra[input_length % 4]) {
+ gpr_log(GPR_ERROR,
+ "Base64 decoding failed, output_length %d is longer "
+ "than the max possible output length %d.\n",
+ (int)output_length,
+ (int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+
+ ctx.input_cur = GPR_SLICE_START_PTR(input);
+ ctx.input_end = GPR_SLICE_END_PTR(input);
+ ctx.output_cur = GPR_SLICE_START_PTR(output);
+ ctx.output_end = GPR_SLICE_END_PTR(output);
+ ctx.contains_tail = true;
+
+ if (!grpc_base64_decode_partial(&ctx)) {
+ char *s = gpr_dump_slice(input, GPR_DUMP_ASCII);
+ gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
+ gpr_free(s);
+ gpr_slice_unref(output);
+ return gpr_empty_slice();
+ }
+ GPR_ASSERT(ctx.output_cur == GPR_SLICE_END_PTR(output));
+ GPR_ASSERT(ctx.input_cur <= GPR_SLICE_END_PTR(input));
+ return output;
+}
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
new file mode 100644
index 0000000000..b9d40c9b74
--- /dev/null
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
+#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H
+
+#include <grpc/support/slice.h>
+#include <stdbool.h>
+
+struct grpc_base64_decode_context {
+ /* input/output: */
+ uint8_t *input_cur;
+ uint8_t *input_end;
+ uint8_t *output_cur;
+ uint8_t *output_end;
+ /* Indicate if the decoder should handle the tail of input data*/
+ bool contains_tail;
+};
+
+/* base64 decode a grpc_base64_decode_context util either input_end is reached
+ or output_end is reached. When input_end is reached, (input_end - input_cur)
+ is less than 4. When output_end is reached, (output_end - output_cur) is less
+ than 3. Returns false if decoding is failed. */
+bool grpc_base64_decode_partial(struct grpc_base64_decode_context *ctx);
+
+/* base64 decode a slice with pad chars. Returns a new slice, does not take
+ ownership of the input. Returns an empty slice if decoding is failed. */
+gpr_slice grpc_chttp2_base64_decode(gpr_slice input);
+
+/* base64 decode a slice without pad chars, data length is needed. Returns a new
+ slice, does not take ownership of the input. Returns an empty slice if
+ decoding is failed. */
+gpr_slice grpc_chttp2_base64_decode_with_length(gpr_slice input,
+ size_t output_length);
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index b0da0578f5..9c125566d4 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -47,6 +47,7 @@
#include "src/core/ext/transport/chttp2/transport/internal.h"
#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/http/parser.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
@@ -84,19 +85,17 @@ int grpc_flowctl_trace = 0;
static const grpc_transport_vtable vtable;
/* forward declarations of various callbacks that we'll build closures around */
-static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
-static void reading_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *t,
- bool iomgr_success_ignored);
+static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
+static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
/** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value);
/** Start disconnection chain */
-static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
+static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_error *error);
/** Perform a transport_op */
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
@@ -107,7 +106,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
- grpc_status_code status);
+ grpc_status_code status,
+ gpr_slice *optional_message);
static void close_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
@@ -133,7 +133,7 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_connectivity_state state, const char *reason);
+ grpc_connectivity_state state, grpc_error *error, const char *reason);
static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
@@ -147,7 +147,9 @@ static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s,
void *byte_stream);
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global);
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global,
+ grpc_error *error);
/*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
@@ -161,6 +163,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(t->ep == NULL);
+ gpr_slice_unref(t->optional_drop_message);
+
gpr_slice_buffer_destroy(&t->global.qbuf);
gpr_slice_buffer_destroy(&t->writing.outbuf);
@@ -190,7 +194,8 @@ static void destruct_transport(grpc_exec_ctx *exec_ctx,
and maybe they hold resources that need to be freed */
while (t->global.pings.next != &t->global.pings) {
grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
- grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, ping->on_recv,
+ GRPC_ERROR_CREATE("Transport closed"), NULL);
ping->next->prev = ping->prev;
ping->prev->next = ping->next;
gpr_free(ping);
@@ -259,7 +264,9 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->parsing.is_client = is_client;
t->parsing.deframe_state =
is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
+ t->parsing.is_first_frame = true;
t->writing.is_client = is_client;
+ t->optional_drop_message = gpr_empty_slice();
grpc_connectivity_state_init(
&t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
is_client ? "client_transport" : "server_transport");
@@ -404,7 +411,7 @@ static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_ignored,
void *arg_ignored) {
t->destroying = 1;
- drop_connection(exec_ctx, t);
+ drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed"));
}
static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
@@ -440,12 +447,11 @@ static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
static void close_transport_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
- grpc_chttp2_stream *s_ignored,
- void *arg_ignored) {
+ grpc_error *error) {
if (!t->closed) {
t->closed = 1;
connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
- "close_transport");
+ GRPC_ERROR_REF(error), "close_transport");
if (t->ep) {
allow_endpoint_shutdown_locked(exec_ctx, t);
}
@@ -458,6 +464,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
}
+ GRPC_ERROR_UNREF(error);
}
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
@@ -546,7 +553,9 @@ static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
s->global.id == 0);
GPR_ASSERT(!s->global.in_stream_map);
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ close_transport_locked(
+ exec_ctx, t,
+ GRPC_ERROR_CREATE("Last stream closed after sending goaway"));
}
if (!t->executor.parsing_active && s->global.id) {
GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
@@ -635,12 +644,11 @@ static void finish_global_actions(grpc_exec_ctx *exec_ctx,
for (;;) {
if (!t->executor.writing_active && !t->closed &&
- grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
- t->executor.parsing_active)) {
+ grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
t->executor.writing_active = 1;
REF_TRANSPORT(t, "writing");
prevent_endpoint_shutdown(t);
- grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
}
check_read_ops(exec_ctx, &t->global);
@@ -751,12 +759,12 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_ignored,
void *a) {
- bool success = (bool)(uintptr_t)a;
+ grpc_error *error = a;
allow_endpoint_shutdown_locked(exec_ctx, t);
- if (!success) {
- drop_connection(exec_ctx, t);
+ if (error != GRPC_ERROR_NONE) {
+ drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
}
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
@@ -764,7 +772,8 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global;
while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
&stream_global)) {
- fail_pending_writes(exec_ctx, stream_global);
+ fail_pending_writes(exec_ctx, &t->global, stream_global,
+ GRPC_ERROR_REF(error));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
}
@@ -777,18 +786,18 @@ static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
}
UNREF_TRANSPORT(exec_ctx, t, "writing");
+ GRPC_ERROR_UNREF(error);
}
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing, bool success) {
+ void *transport_writing, grpc_error *error) {
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
- grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL,
- terminate_writing_with_lock,
- (void *)(uintptr_t)success, 0);
+ grpc_chttp2_run_with_global_lock(
+ exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0);
}
static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
- bool iomgr_success_ignored) {
+ grpc_error *error) {
grpc_chttp2_transport *t = gt;
GPR_TIMER_BEGIN("writing_action", 0);
grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
@@ -801,11 +810,19 @@ void grpc_chttp2_add_incoming_goaway(
char *msg = gpr_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_free(msg);
gpr_slice_unref(goaway_text);
transport_global->seen_goaway = 1;
- connectivity_state_set(exec_ctx, transport_global, GRPC_CHANNEL_SHUTDOWN,
- "got_goaway");
+ /* lie: use transient failure from the transport to indicate goaway has been
+ * received */
+ connectivity_state_set(
+ exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ grpc_error_set_str(
+ grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ (intptr_t)goaway_error),
+ GRPC_ERROR_STR_RAW_BYTES, msg),
+ "got_goaway");
+ gpr_free(msg);
}
static void maybe_start_some_streams(
@@ -834,9 +851,9 @@ static void maybe_start_some_streams(
transport_global->next_stream_id += 2;
if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
- connectivity_state_set(exec_ctx, transport_global,
- GRPC_CHANNEL_TRANSIENT_FAILURE,
- "no_more_stream_ids");
+ connectivity_state_set(
+ exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
+ GRPC_ERROR_CREATE("Stream IDs exhausted"), "no_more_stream_ids");
}
stream_global->outgoing_window =
@@ -859,39 +876,45 @@ static void maybe_start_some_streams(
grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
&stream_global)) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_UNAVAILABLE);
+ GRPC_STATUS_UNAVAILABLE, NULL);
}
}
#define CLOSURE_BARRIER_STATS_BIT (1 << 0)
-#define CLOSURE_BARRIER_FAILURE_BIT (1 << 1)
#define CLOSURE_BARRIER_FIRST_REF_BIT (1 << 16)
static grpc_closure *add_closure_barrier(grpc_closure *closure) {
- closure->final_data += CLOSURE_BARRIER_FIRST_REF_BIT;
+ closure->next_data.scratch += CLOSURE_BARRIER_FIRST_REF_BIT;
return closure;
}
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global,
- grpc_closure **pclosure, int success) {
+void grpc_chttp2_complete_closure_step(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
+ grpc_error *error) {
grpc_closure *closure = *pclosure;
if (closure == NULL) {
+ GRPC_ERROR_UNREF(error);
return;
}
- closure->final_data -= CLOSURE_BARRIER_FIRST_REF_BIT;
- if (!success) {
- closure->final_data |= CLOSURE_BARRIER_FAILURE_BIT;
+ closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
+ if (error != GRPC_ERROR_NONE) {
+ if (closure->error == GRPC_ERROR_NONE) {
+ closure->error =
+ GRPC_ERROR_CREATE("Error in HTTP transport completing operation");
+ closure->error = grpc_error_set_str(
+ closure->error, GRPC_ERROR_STR_TARGET_ADDRESS,
+ TRANSPORT_FROM_GLOBAL(transport_global)->peer_string);
+ }
+ closure->error = grpc_error_add_child(closure->error, error);
}
- if (closure->final_data < CLOSURE_BARRIER_FIRST_REF_BIT) {
- if (closure->final_data & CLOSURE_BARRIER_STATS_BIT) {
+ if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) {
+ if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) {
grpc_transport_move_stats(&stream_global->stats,
stream_global->collecting_stats);
stream_global->collecting_stats = NULL;
}
- grpc_exec_ctx_enqueue(
- exec_ctx, closure,
- (closure->final_data & CLOSURE_BARRIER_FAILURE_BIT) == 0, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, closure->error, NULL);
}
*pclosure = NULL;
}
@@ -909,7 +932,7 @@ static int contains_non_ok_status(
return 0;
}
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
@@ -926,17 +949,18 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
/* use final_data as a barrier until enqueue time; the inital counter is
dropped at the end of this function */
- on_complete->final_data = CLOSURE_BARRIER_FIRST_REF_BIT;
+ on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
+ on_complete->error = GRPC_ERROR_NONE;
if (op->collect_stats != NULL) {
GPR_ASSERT(stream_global->collecting_stats == NULL);
stream_global->collecting_stats = op->collect_stats;
- on_complete->final_data |= CLOSURE_BARRIER_STATS_BIT;
+ on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT;
}
if (op->cancel_with_status != GRPC_STATUS_OK) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- op->cancel_with_status);
+ op->cancel_with_status, op->optional_close_message);
}
if (op->close_with_status != GRPC_STATUS_OK) {
@@ -957,10 +981,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG,
"to-be-sent initial metadata size exceeds peer limit "
- "(%lu vs. %lu)",
+ "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
} else {
if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
stream_global->seen_error = true;
@@ -978,8 +1002,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
} else {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_initial_metadata_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished,
+ GRPC_ERROR_CREATE(
+ "Attempt to send initial metadata after stream was closed"));
}
}
}
@@ -990,7 +1016,9 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
stream_global->send_message_finished = add_closure_barrier(on_complete);
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_message_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished,
+ GRPC_ERROR_CREATE("Attempt to send message after stream was closed"));
} else {
stream_global->send_message = op->send_message;
if (stream_global->id != 0) {
@@ -1012,10 +1040,10 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
if (metadata_size > metadata_peer_limit) {
gpr_log(GPR_DEBUG,
"to-be-sent trailing metadata size exceeds peer limit "
- "(%lu vs. %lu)",
+ "(%" PRIuPTR " vs. %" PRIuPTR ")",
metadata_size, metadata_peer_limit);
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
} else {
if (contains_non_ok_status(transport_global,
op->send_trailing_metadata)) {
@@ -1024,9 +1052,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
}
if (stream_global->write_closed) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
+ exec_ctx, transport_global, stream_global,
&stream_global->send_trailing_metadata_finished,
- grpc_metadata_batch_is_empty(op->send_trailing_metadata));
+ grpc_metadata_batch_is_empty(op->send_trailing_metadata)
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
+ "stream was closed"));
} else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */
@@ -1062,10 +1093,12 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
stream_global->recv_trailing_metadata_finished =
add_closure_barrier(on_complete);
stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
+ stream_global->final_metadata_requested = true;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- grpc_chttp2_complete_closure_step(exec_ctx, stream_global, &on_complete, 1);
+ grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
+ &on_complete, GRPC_ERROR_NONE);
GPR_TIMER_END("perform_stream_op_locked", 0);
}
@@ -1102,7 +1135,7 @@ static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
for (ping = transport_global->pings.next; ping != &transport_global->pings;
ping = ping->next) {
if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
- grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL);
ping->next->prev = ping->prev;
ping->prev->next = ping->next;
gpr_free(ping);
@@ -1124,7 +1157,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused,
void *stream_op) {
grpc_transport_op *op = stream_op;
- bool close_transport = op->disconnect;
+ grpc_error *close_transport = op->disconnect_with_error;
/* If there's a set_accept_stream ensure that we're not parsing
to avoid changing things out from underneath */
@@ -1135,7 +1168,7 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
return;
}
- grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change(
@@ -1149,7 +1182,9 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
t->global.last_incoming_stream_id,
(uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
- close_transport = !grpc_chttp2_has_streams(t);
+ close_transport = grpc_chttp2_has_streams(t)
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE("GOAWAY sent");
}
if (op->set_accept_stream) {
@@ -1170,8 +1205,8 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
send_ping_locked(t, op->send_ping);
}
- if (close_transport) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ if (close_transport != GRPC_ERROR_NONE) {
+ close_transport_locked(exec_ctx, t, close_transport);
}
}
@@ -1201,18 +1236,19 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
}
if (stream_global->exceeded_metadata_size) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
}
}
grpc_chttp2_incoming_metadata_buffer_publish(
&stream_global->received_initial_metadata,
stream_global->recv_initial_metadata);
- grpc_exec_ctx_enqueue(
- exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_initial_metadata_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_initial_metadata_ready = NULL;
}
if (stream_global->recv_message_ready != NULL) {
- while (stream_global->seen_error &&
+ while (stream_global->final_metadata_requested &&
+ stream_global->seen_error &&
(bs = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames)) != NULL) {
incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
@@ -1221,13 +1257,13 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
*stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
&stream_global->incoming_frames);
GPR_ASSERT(*stream_global->recv_message != NULL);
- grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL;
} else if (stream_global->published_trailing_metadata) {
*stream_global->recv_message = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
+ GRPC_ERROR_NONE, NULL);
stream_global->recv_message_ready = NULL;
}
}
@@ -1240,7 +1276,7 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
}
if (stream_global->exceeded_metadata_size) {
cancel_from_api(exec_ctx, transport_global, stream_global,
- GRPC_STATUS_RESOURCE_EXHAUSTED);
+ GRPC_STATUS_RESOURCE_EXHAUSTED, NULL);
}
}
if (stream_global->all_incoming_byte_streams_finished) {
@@ -1248,8 +1284,8 @@ static void check_read_ops(grpc_exec_ctx *exec_ctx,
&stream_global->received_trailing_metadata,
stream_global->recv_trailing_metadata);
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->recv_trailing_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->recv_trailing_metadata_finished, GRPC_ERROR_NONE);
}
}
}
@@ -1265,7 +1301,7 @@ static void decrement_active_streams_locked(
}
static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
- uint32_t id) {
+ uint32_t id, grpc_error *error) {
size_t new_stream_count;
grpc_chttp2_stream *s =
grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
@@ -1280,12 +1316,15 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
}
if (s->parsing.data_parser.parsing_frame != NULL) {
grpc_chttp2_incoming_byte_stream_finished(
- exec_ctx, s->parsing.data_parser.parsing_frame, 0, 0);
+ exec_ctx, s->parsing.data_parser.parsing_frame,
+ GRPC_ERROR_CREATE_REFERENCING("Stream removed", &error, 1), 0);
s->parsing.data_parser.parsing_frame = NULL;
}
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+ close_transport_locked(
+ exec_ctx, t,
+ GRPC_ERROR_CREATE("Last stream closed after sending GOAWAY"));
}
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
@@ -1298,12 +1337,14 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->global.concurrent_stream_count = (uint32_t)new_stream_count;
maybe_start_some_streams(exec_ctx, &t->global);
}
+ GRPC_ERROR_UNREF(error);
}
static void cancel_from_api(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global,
- grpc_status_code status) {
+ grpc_status_code status,
+ gpr_slice *optional_message) {
if (!stream_global->read_closed || !stream_global->write_closed) {
if (stream_global->id != 0) {
gpr_slice_buffer_add(
@@ -1313,15 +1354,21 @@ static void cancel_from_api(grpc_exec_ctx *exec_ctx,
(uint32_t)grpc_chttp2_grpc_status_to_http2_error(status),
&stream_global->stats.outgoing));
}
+
+ if (optional_message) {
+ gpr_slice_ref(*optional_message);
+ }
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
- NULL);
+ optional_message);
}
if (status != GRPC_STATUS_OK && !stream_global->seen_error) {
stream_global->seen_error = true;
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
- 1);
+ grpc_chttp2_mark_stream_closed(
+ exec_ctx, transport_global, stream_global, 1, 1,
+ grpc_error_set_int(GRPC_ERROR_CREATE("Cancelled"),
+ GRPC_ERROR_INT_GRPC_STATUS, status));
}
void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
@@ -1362,23 +1409,27 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
}
static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global) {
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global,
+ grpc_error *error) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_initial_metadata_finished,
- 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_trailing_metadata_finished,
- 0);
- grpc_chttp2_complete_closure_step(exec_ctx, stream_global,
- &stream_global->send_message_finished, 0);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_trailing_metadata_finished, GRPC_ERROR_REF(error));
+ grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished,
+ error);
}
void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, int close_reads,
- int close_writes) {
+ grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
+ grpc_error *error) {
if (stream_global->read_closed && stream_global->write_closed) {
/* already closed */
+ GRPC_ERROR_UNREF(error);
return;
}
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
@@ -1395,7 +1446,8 @@ void grpc_chttp2_mark_stream_closed(
grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
stream_global);
} else {
- fail_pending_writes(exec_ctx, stream_global);
+ fail_pending_writes(exec_ctx, transport_global, stream_global,
+ GRPC_ERROR_REF(error));
}
}
if (stream_global->read_closed && stream_global->write_closed) {
@@ -1406,11 +1458,12 @@ void grpc_chttp2_mark_stream_closed(
} else {
if (stream_global->id != 0) {
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
- stream_global->id);
+ stream_global->id, GRPC_ERROR_REF(error));
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
}
+ GRPC_ERROR_UNREF(error);
}
static void close_from_api(grpc_exec_ctx *exec_ctx,
@@ -1515,15 +1568,27 @@ static void close_from_api(grpc_exec_ctx *exec_ctx,
}
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global, status,
optional_message);
+ grpc_error *err = GRPC_ERROR_CREATE("Stream closed");
+ err = grpc_error_set_int(err, GRPC_ERROR_INT_GRPC_STATUS, status);
+ if (optional_message) {
+ char *str =
+ gpr_dump_slice(*optional_message, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ err = grpc_error_set_str(err, GRPC_ERROR_STR_GRPC_MESSAGE, str);
+ gpr_free(str);
+ }
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
- 1);
+ 1, err);
}
static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
void *user_data,
grpc_chttp2_stream_global *stream_global) {
+ grpc_chttp2_transport *transport = TRANSPORT_FROM_GLOBAL(transport_global);
cancel_from_api(user_data, transport_global, stream_global,
- GRPC_STATUS_UNAVAILABLE);
+ GRPC_STATUS_UNAVAILABLE,
+ GPR_SLICE_IS_EMPTY(transport->optional_drop_message)
+ ? NULL
+ : &transport->optional_drop_message);
}
static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
@@ -1531,8 +1596,9 @@ static void end_all_the_calls(grpc_exec_ctx *exec_ctx,
grpc_chttp2_for_all_streams(&t->global, exec_ctx, cancel_stream_cb);
}
-static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
- close_transport_locked(exec_ctx, t, NULL, NULL);
+static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+ grpc_error *error) {
+ close_transport_locked(exec_ctx, t, error);
end_all_the_calls(exec_ctx, t);
}
@@ -1563,20 +1629,22 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error);
static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused, void *arg);
-static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
+static void reading_action(grpc_exec_ctx *exec_ctx, void *tp,
+ grpc_error *error) {
/* Control flow:
reading_action_locked ->
(parse_unlocked -> post_parse_locked)? ->
post_reading_action_locked */
grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
- (void *)(uintptr_t)success, 0);
+ GRPC_ERROR_REF(error), 0);
}
static void reading_action_locked(grpc_exec_ctx *exec_ctx,
@@ -1584,7 +1652,7 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream *s_unused, void *arg) {
grpc_chttp2_transport_global *transport_global = &t->global;
grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
- bool success = (bool)(uintptr_t)arg;
+ grpc_error *error = arg;
GPR_ASSERT(!t->executor.parsing_active);
if (!t->closed) {
@@ -1593,27 +1661,73 @@ static void reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_map_move_into(&t->new_stream_map,
&t->parsing_stream_map);
grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
- grpc_exec_ctx_enqueue(exec_ctx, &t->parsing_action, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL);
} else {
post_reading_action_locked(exec_ctx, t, s_unused, arg);
}
}
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport *t) {
+ grpc_http_parser parser;
+ size_t i = 0;
+ grpc_error *error = GRPC_ERROR_NONE;
+ grpc_http_response response;
+ memset(&response, 0, sizeof(response));
+
+ grpc_http_parser_init(&parser, GRPC_HTTP_RESPONSE, &response);
+
+ grpc_error *parse_error = GRPC_ERROR_NONE;
+ for (; i < t->read_buffer.count && parse_error == GRPC_ERROR_NONE; i++) {
+ parse_error = grpc_http_parser_parse(&parser, t->read_buffer.slices[i]);
+ }
+ if (parse_error == GRPC_ERROR_NONE &&
+ (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
+ error = grpc_error_set_int(
+ GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
+ GRPC_ERROR_INT_HTTP_STATUS, response.status);
+ }
+ GRPC_ERROR_UNREF(parse_error);
+
+ grpc_http_parser_destroy(&parser);
+ grpc_http_response_destroy(&response);
+ return error;
+}
+
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
grpc_chttp2_transport *t = arg;
GPR_TIMER_BEGIN("reading_action.parse", 0);
size_t i = 0;
- for (; i < t->read_buffer.count &&
- grpc_chttp2_perform_read(exec_ctx, &t->parsing,
- t->read_buffer.slices[i]);
- i++)
- ;
+ grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
+ GRPC_ERROR_NONE};
+ for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
+ errors[1] = grpc_chttp2_perform_read(exec_ctx, &t->parsing,
+ t->read_buffer.slices[i]);
+ };
if (i != t->read_buffer.count) {
- success = false;
+ gpr_slice_unref(t->optional_drop_message);
+ errors[2] = try_http_parsing(exec_ctx, t);
+ if (errors[2] != GRPC_ERROR_NONE) {
+ t->optional_drop_message = gpr_slice_from_copied_string(
+ "Connection dropped: received http1.x response");
+ } else {
+ t->optional_drop_message = gpr_slice_from_copied_string(
+ "Connection dropped: received unparseable response");
+ }
+ }
+ grpc_error *err =
+ errors[0] == GRPC_ERROR_NONE && errors[1] == GRPC_ERROR_NONE &&
+ errors[2] == GRPC_ERROR_NONE
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
+ GPR_ARRAY_SIZE(errors));
+ for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
+ GRPC_ERROR_UNREF(errors[i]);
}
GPR_TIMER_END("reading_action.parse", 0);
- grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked,
- (void *)(uintptr_t)success, 0);
+ grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err,
+ 0);
}
static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -1650,7 +1764,8 @@ static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
GPR_ASSERT(stream_global->in_stream_map);
GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed);
- remove_stream(exec_ctx, t, stream_global->id);
+ remove_stream(exec_ctx, t, stream_global->id,
+ GRPC_ERROR_CREATE("Stream removed"));
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
@@ -1661,10 +1776,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t,
grpc_chttp2_stream *s_unused,
void *arg) {
- bool success = (bool)(uintptr_t)arg;
+ grpc_error *error = arg;
bool keep_reading = false;
- if (!success || t->closed) {
- drop_connection(exec_ctx, t);
+ if (error == GRPC_ERROR_NONE && t->closed) {
+ error = GRPC_ERROR_CREATE("Transport closed");
+ }
+ if (error != GRPC_ERROR_NONE) {
+ drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
t->endpoint_reading = 0;
if (!t->executor.writing_active && t->ep) {
grpc_endpoint_destroy(exec_ctx, t->ep);
@@ -1686,6 +1804,8 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
} else {
UNREF_TRANSPORT(exec_ctx, t, "reading_action");
}
+
+ GRPC_LOG_IF_ERROR("close_transport", error);
}
/*******************************************************************************
@@ -1694,13 +1814,13 @@ static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
static void connectivity_state_set(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_connectivity_state state, const char *reason) {
+ grpc_connectivity_state state, grpc_error *error, const char *reason) {
GRPC_CHTTP2_IF_TRACING(
gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
grpc_connectivity_state_set(
exec_ctx,
&TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
- state, reason);
+ state, error, reason);
}
/*******************************************************************************
@@ -1732,6 +1852,13 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
add_to_pollset_locked, pollset, 0);
}
+static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+ grpc_stream *gs, grpc_pollset_set *pollset_set) {
+ grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
+ (grpc_chttp2_stream *)gs,
+ add_to_pollset_set_locked, pollset_set, 0);
+}
+
/*******************************************************************************
* BYTE STREAM
*/
@@ -1739,6 +1866,7 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
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);
gpr_free(bs);
}
@@ -1807,9 +1935,10 @@ static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
}
if (bs->slices.count > 0) {
*arg->slice = gpr_slice_buffer_take_first(&bs->slices);
- grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, true, NULL);
- } else if (bs->failed) {
- grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL);
+ } else if (bs->error != GRPC_ERROR_NONE) {
+ grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_REF(bs->error),
+ NULL);
} else {
bs->on_next = arg->on_complete;
bs->next = arg->slice;
@@ -1866,7 +1995,7 @@ static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
if (bs->on_next != NULL) {
*bs->next = arg->slice;
- grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
bs->on_next = NULL;
} else {
gpr_slice_buffer_add(&bs->slices, arg->slice);
@@ -1884,13 +2013,30 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
sizeof(arg));
}
+typedef struct {
+ grpc_chttp2_incoming_byte_stream *bs;
+ grpc_error *error;
+} bs_fail_args;
+
+static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error) {
+ bs_fail_args *a = gpr_malloc(sizeof(*a));
+ a->bs = bs;
+ a->error = error;
+ return a;
+}
+
static void incoming_byte_stream_finished_failed_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
void *argp) {
- grpc_chttp2_incoming_byte_stream *bs = argp;
- grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
+ bs_fail_args *a = argp;
+ grpc_chttp2_incoming_byte_stream *bs = a->bs;
+ grpc_error *error = a->error;
+ gpr_free(a);
+ grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
bs->on_next = NULL;
- bs->failed = 1;
+ GRPC_ERROR_UNREF(bs->error);
+ bs->error = error;
incoming_byte_stream_unref(exec_ctx, bs);
}
@@ -1903,25 +2049,26 @@ static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
}
void grpc_chttp2_incoming_byte_stream_finished(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
- int from_parsing_thread) {
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error, int from_parsing_thread) {
if (from_parsing_thread) {
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
incoming_byte_stream_finished_ok_locked,
bs, 0);
} else {
- incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
- bs->stream, bs);
- }
- } else {
- if (success) {
grpc_chttp2_run_with_global_lock(
exec_ctx, bs->transport, bs->stream,
- incoming_byte_stream_finished_failed_locked, bs, 0);
+ incoming_byte_stream_finished_failed_locked,
+ make_bs_fail_args(bs, error), 0);
+ }
+ } else {
+ if (error == GRPC_ERROR_NONE) {
+ incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
+ bs->stream, bs);
} else {
- incoming_byte_stream_finished_failed_locked(exec_ctx, bs->transport,
- bs->stream, bs);
+ incoming_byte_stream_finished_failed_locked(
+ exec_ctx, bs->transport, bs->stream, make_bs_fail_args(bs, error));
}
}
}
@@ -1944,7 +2091,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
gpr_slice_buffer_init(&incoming_byte_stream->slices);
incoming_byte_stream->on_next = NULL;
incoming_byte_stream->is_tail = 1;
- incoming_byte_stream->failed = 0;
+ incoming_byte_stream->error = GRPC_ERROR_NONE;
if (add_to_queue->head == NULL) {
add_to_queue->head = incoming_byte_stream;
} else {
@@ -1963,10 +2110,13 @@ static char *format_flowctl_context_var(const char *context, const char *var,
int64_t val, uint32_t id,
char **scope) {
char *underscore_pos;
+ char *buf;
char *result;
if (context == NULL) {
*scope = NULL;
- gpr_asprintf(&result, "%s(%lld)", var, val);
+ gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
+ result = gpr_leftpad(buf, ' ', 40);
+ gpr_free(buf);
return result;
}
underscore_pos = strchr(context, '_');
@@ -1977,7 +2127,9 @@ static char *format_flowctl_context_var(const char *context, const char *var,
gpr_asprintf(scope, "%s[%d]", tmp, id);
gpr_free(tmp);
}
- gpr_asprintf(&result, "%s.%s(%lld)", underscore_pos + 1, var, val);
+ gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
+ result = gpr_leftpad(buf, ' ', 40);
+ gpr_free(buf);
return result;
}
@@ -1998,6 +2150,8 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
uint32_t stream_id, int64_t val1, int64_t val2) {
char *scope1;
char *scope2;
+ char *tmp_phase;
+ char *tmp_scope1;
char *label1 =
format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
char *label2 =
@@ -2005,14 +2159,18 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
char *clisvr = is_client ? "client" : "server";
char *prefix;
- gpr_asprintf(&prefix, "FLOW % 8s: %s % 11s ", phase, clisvr, scope1);
+ tmp_phase = gpr_leftpad(phase, ' ', 8);
+ tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
+ gpr_asprintf(&prefix, "FLOW %s: %s %s ", phase, clisvr, scope1);
+ gpr_free(tmp_phase);
+ gpr_free(tmp_scope1);
switch (op) {
case GRPC_CHTTP2_FLOWCTL_MOVE:
GPR_ASSERT(samestr(scope1, scope2));
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sMOVE % 40s <- % 40s giving %d", prefix, label1, label2,
+ "%sMOVE %s <- %s giving %" PRId64, prefix, label1, label2,
val1 + val2);
}
break;
@@ -2020,7 +2178,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0);
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sCREDIT % 40s by % 40s giving %d", prefix, label1, label2,
+ "%sCREDIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 + val2);
}
break;
@@ -2028,7 +2186,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
GPR_ASSERT(val2 >= 0);
if (val2 != 0) {
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
- "%sDEBIT % 40s by % 40s giving %d", prefix, label1, label2,
+ "%sDEBIT %s by %s giving %" PRId64, prefix, label1, label2,
val1 - val2);
}
break;
@@ -2053,6 +2211,7 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
"chttp2",
init_stream,
set_pollset,
+ set_pollset_set,
perform_stream_op,
perform_transport_op,
destroy_stream,
@@ -2073,5 +2232,5 @@ void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
- reading_action(exec_ctx, t, 1);
+ reading_action(exec_ctx, t, GRPC_ERROR_NONE);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index 5c72d91c2a..7776609367 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -37,13 +37,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/support/slice.h>
-/* Common definitions for frame handling in the chttp2 transport */
-
-typedef enum {
- GRPC_CHTTP2_PARSE_OK,
- GRPC_CHTTP2_STREAM_ERROR,
- GRPC_CHTTP2_CONNECTION_ERROR
-} grpc_chttp2_parse_error;
+#include "src/core/lib/iomgr/error.h"
/* defined in internal.h */
typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing;
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
index 3a6d80e0a3..9046fbc453 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.c
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -37,24 +37,25 @@
#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/internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/transport.h"
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
- grpc_chttp2_data_parser *parser) {
+grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser) {
parser->state = GRPC_CHTTP2_DATA_FH_0;
parser->parsing_frame = NULL;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser) {
grpc_byte_stream *bs;
if (parser->parsing_frame) {
- grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame,
- 0, 1);
+ grpc_chttp2_incoming_byte_stream_finished(
+ exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"),
+ 1);
}
while (
(bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
@@ -62,11 +63,16 @@ void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
}
}
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser *parser, uint8_t flags) {
+grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
+ uint8_t flags,
+ uint32_t stream_id) {
if (flags & ~GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
- gpr_log(GPR_ERROR, "unsupported data flags: 0x%02x", flags);
- return GRPC_CHTTP2_STREAM_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "unsupported data flags: 0x%02x", flags);
+ grpc_error *err = grpc_error_set_int(
+ GRPC_ERROR_CREATE(msg), GRPC_ERROR_INT_STREAM_ID, (intptr_t)stream_id);
+ gpr_free(msg);
+ return err;
}
if (flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) {
@@ -75,7 +81,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
parser->is_last_frame = 0;
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_incoming_frame_queue_merge(
@@ -139,7 +145,7 @@ void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
stats->data_bytes += write_bytes;
}
-grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -149,19 +155,20 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_data_parser *p = parser;
uint32_t message_flags;
grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
+ char *msg;
if (is_last && p->is_last_frame) {
stream_parsing->received_close = 1;
}
if (cur == end) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
switch (p->state) {
case GRPC_CHTTP2_DATA_ERROR:
p->state = GRPC_CHTTP2_DATA_ERROR;
- return GRPC_CHTTP2_STREAM_ERROR;
+ return GRPC_ERROR_REF(p->error);
fh_0:
case GRPC_CHTTP2_DATA_FH_0:
stream_parsing->stats.incoming.framing_bytes++;
@@ -174,13 +181,23 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->is_frame_compressed = 1; /* GPR_TRUE */
break;
default:
- gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
+ gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
+ p->error = GRPC_ERROR_CREATE(msg);
+ p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
+ (intptr_t)stream_parsing->id);
+ gpr_free(msg);
+ msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ p->error =
+ grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, msg);
+ gpr_free(msg);
+ p->error =
+ grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg);
p->state = GRPC_CHTTP2_DATA_ERROR;
- return GRPC_CHTTP2_STREAM_ERROR;
+ return GRPC_ERROR_REF(p->error);
}
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_1:
@@ -188,7 +205,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size = ((uint32_t)*cur) << 24;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_2:
@@ -196,7 +213,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 16;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_3:
@@ -204,7 +221,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
p->frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) {
p->state = GRPC_CHTTP2_DATA_FH_4;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_CHTTP2_DATA_FH_4:
@@ -225,7 +242,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
stream_parsing);
if (cur == end) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
uint32_t remaining = (uint32_t)(end - cur);
if (remaining == p->frame_size) {
@@ -233,19 +250,19 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_incoming_byte_stream_push(
exec_ctx, p->parsing_frame,
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
- grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
- 1);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
+ GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL;
p->state = GRPC_CHTTP2_DATA_FH_0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else if (remaining > p->frame_size) {
stream_parsing->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_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
- 1);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
+ GRPC_ERROR_NONE, 1);
p->parsing_frame = NULL;
cur += p->frame_size;
goto fh_0; /* loop */
@@ -256,9 +273,9 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
p->frame_size -= remaining;
stream_parsing->stats.incoming.data_bytes += remaining;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
}
- GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index af71f483a2..a21a7942b9 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -66,6 +66,7 @@ typedef struct {
uint8_t is_last_frame;
uint8_t frame_type;
uint32_t frame_size;
+ grpc_error *error;
int is_frame_compressed;
grpc_chttp2_incoming_frame_queue incoming_frames;
@@ -79,19 +80,19 @@ grpc_byte_stream *grpc_chttp2_incoming_frame_queue_pop(
grpc_chttp2_incoming_frame_queue *q);
/* initialize per-stream state for data frame parsing */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_init(
- grpc_chttp2_data_parser *parser);
+grpc_error *grpc_chttp2_data_parser_init(grpc_chttp2_data_parser *parser);
void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
grpc_chttp2_data_parser *parser);
/* start processing a new data frame */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
- grpc_chttp2_data_parser *parser, uint8_t flags);
+grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
+ uint8_t flags,
+ uint32_t stream_id);
/* handle a slice of a data frame - is_last indicates the last slice of a
frame */
-grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
+grpc_error *grpc_chttp2_data_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c
index 827e7a6977..299e27ad70 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.c
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p) {
p->debug_data = NULL;
@@ -47,11 +48,15 @@ void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p) {
gpr_free(p->debug_data);
}
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
- grpc_chttp2_goaway_parser *p, uint32_t length, uint8_t flags) {
+grpc_error *grpc_chttp2_goaway_parser_begin_frame(grpc_chttp2_goaway_parser *p,
+ uint32_t length,
+ uint8_t flags) {
if (length < 8) {
- gpr_log(GPR_ERROR, "goaway frame too short (%d bytes)", length);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "goaway frame too short (%d bytes)", length);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
gpr_free(p->debug_data);
@@ -59,10 +64,10 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
p->debug_data = gpr_malloc(p->debug_length);
p->debug_pos = 0;
p->state = GRPC_CHTTP2_GOAWAY_LSI0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -75,7 +80,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI0:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id = ((uint32_t)*cur) << 24;
++cur;
@@ -83,7 +88,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI1:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur) << 16;
++cur;
@@ -91,7 +96,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI2:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur) << 8;
++cur;
@@ -99,7 +104,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_LSI3:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_LSI3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->last_stream_id |= ((uint32_t)*cur);
++cur;
@@ -107,7 +112,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR0:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code = ((uint32_t)*cur) << 24;
++cur;
@@ -115,7 +120,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR1:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur) << 16;
++cur;
@@ -123,7 +128,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR2:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur) << 8;
++cur;
@@ -131,7 +136,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
case GRPC_CHTTP2_GOAWAY_ERR3:
if (cur == end) {
p->state = GRPC_CHTTP2_GOAWAY_ERR3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
p->error_code |= ((uint32_t)*cur);
++cur;
@@ -151,9 +156,9 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
p->debug_data = NULL;
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
- GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index 7c38b26a39..eb4303405a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -63,9 +63,9 @@ typedef struct {
void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser *p);
void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
+grpc_error *grpc_chttp2_goaway_parser_begin_frame(
grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
+grpc_error *grpc_chttp2_goaway_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 7e1815f0fe..1f814ab1bd 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
gpr_slice slice = gpr_slice_malloc(9 + 8);
@@ -57,18 +58,22 @@ gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes) {
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
- grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags) {
+grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
+ uint32_t length,
+ uint8_t flags) {
if (flags & 0xfe || length != 8) {
- gpr_log(GPR_ERROR, "invalid ping: length=%d, flags=%02x", length, flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid ping: length=%d, flags=%02x", length, flags);
+ grpc_error *error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return error;
}
parser->byte = 0;
parser->is_ack = flags;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+grpc_error *grpc_chttp2_ping_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -93,5 +98,5 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
}
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 4f7fcc1305..5a8723421c 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -46,9 +46,9 @@ typedef struct {
gpr_slice grpc_chttp2_ping_create(uint8_t ack, uint8_t *opaque_8bytes);
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
- grpc_chttp2_ping_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
+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_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
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 7f01105e3e..e3a3c9e4a7 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_rst_stream.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include "src/core/ext/transport/chttp2/transport/frame.h"
@@ -67,18 +69,21 @@ gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags) {
if (length != 4) {
- gpr_log(GPR_ERROR, "invalid rst_stream: length=%d, flags=%02x", length,
- flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid rst_stream: length=%d, flags=%02x", length,
+ flags);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
parser->byte = 0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -97,12 +102,15 @@ grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
if (p->byte == 4) {
GPR_ASSERT(is_last);
stream_parsing->received_close = 1;
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = (((uint32_t)p->reason_bytes[0]) << 24) |
- (((uint32_t)p->reason_bytes[1]) << 16) |
- (((uint32_t)p->reason_bytes[2]) << 8) |
- (((uint32_t)p->reason_bytes[3]));
+ if (stream_parsing->forced_close_error == GRPC_ERROR_NONE) {
+ stream_parsing->forced_close_error = grpc_error_set_int(
+ GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
+ (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
+ (((uint32_t)p->reason_bytes[1]) << 16) |
+ (((uint32_t)p->reason_bytes[2]) << 8) |
+ (((uint32_t)p->reason_bytes[3]))));
+ }
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
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 9c1e756a94..11cf94f3ea 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -47,9 +47,9 @@ typedef struct {
gpr_slice grpc_chttp2_rst_stream_create(uint32_t stream_id, uint32_t code,
grpc_transport_one_way_stats *stats);
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
+grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
+grpc_error *grpc_chttp2_rst_stream_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index a3c1e15f35..04b96c4cd9 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -36,7 +36,9 @@
#include <string.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"
@@ -118,7 +120,7 @@ gpr_slice grpc_chttp2_settings_ack_create(void) {
return output;
}
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings) {
parser->target_settings = settings;
@@ -129,31 +131,29 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
if (flags == GRPC_CHTTP2_FLAG_ACK) {
parser->is_ack = 1;
if (length != 0) {
- gpr_log(GPR_ERROR, "non-empty settings ack frame received");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("non-empty settings ack frame received");
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else if (flags != 0) {
- gpr_log(GPR_ERROR, "invalid flags on settings frame");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("invalid flags on settings frame");
} else if (length % 6 != 0) {
- gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
} else {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
}
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *p,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_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);
+ char *msg;
if (parser->is_ack) {
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
for (;;) {
@@ -168,7 +168,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
gpr_slice_buffer_add(&transport_parsing->qbuf,
grpc_chttp2_settings_ack_create());
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->id = (uint16_t)(((uint16_t)*cur) << 8);
cur++;
@@ -176,7 +176,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_ID1:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_ID1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->id = (uint16_t)(parser->id | (*cur));
cur++;
@@ -184,7 +184,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL0:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value = ((uint32_t)*cur) << 24;
cur++;
@@ -192,7 +192,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL1:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL1;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value |= ((uint32_t)*cur) << 16;
cur++;
@@ -200,7 +200,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL2:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL2;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
parser->value |= ((uint32_t)*cur) << 8;
cur++;
@@ -208,7 +208,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
case GRPC_CHTTP2_SPS_VAL3:
if (cur == end) {
parser->state = GRPC_CHTTP2_SPS_VAL3;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
} else {
parser->state = GRPC_CHTTP2_SPS_ID0;
}
@@ -229,9 +229,11 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->last_incoming_stream_id, sp->error_value,
gpr_slice_from_static_string("HTTP2 settings error"),
&transport_parsing->qbuf);
- gpr_log(GPR_ERROR, "invalid value %u passed for %s",
- parser->value, sp->name);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ gpr_asprintf(&msg, "invalid value %u passed for %s",
+ parser->value, sp->name);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
}
if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
@@ -249,7 +251,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
transport_parsing->is_client ? "CLI" : "SVR", parser->id,
parser->value);
}
- } else {
+ } else if (grpc_http_trace) {
gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
parser->id, parser->value);
}
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index d9e30f1ed0..f654c598c8 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -92,10 +92,10 @@ gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new,
/* Create an ack settings frame */
gpr_slice grpc_chttp2_settings_ack_create(void);
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
+grpc_error *grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
uint32_t *settings);
-grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
+grpc_error *grpc_chttp2_settings_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
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 90243418bd..3cf848fd5c 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.c
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -34,7 +34,9 @@
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/internal.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
gpr_slice grpc_chttp2_window_update_create(
uint32_t id, uint32_t window_update, grpc_transport_one_way_stats *stats) {
@@ -62,19 +64,22 @@ gpr_slice grpc_chttp2_window_update_create(
return slice;
}
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags) {
if (flags || length != 4) {
- gpr_log(GPR_ERROR, "invalid window update: length=%d, flags=%02x", length,
- flags);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid window update: length=%d, flags=%02x", length,
+ flags);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
parser->byte = 0;
parser->amount = 0;
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -96,8 +101,11 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
if (p->byte == 4) {
uint32_t received_update = p->amount;
if (received_update == 0 || (received_update & 0x80000000u)) {
- gpr_log(GPR_ERROR, "invalid window update bytes: %d", p->amount);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "invalid window update bytes: %d", p->amount);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
GPR_ASSERT(is_last);
@@ -115,5 +123,5 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
}
}
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
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 d6e87b9329..1bcbbf9247 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -48,9 +48,9 @@ typedef struct {
gpr_slice grpc_chttp2_window_update_create(uint32_t id, uint32_t window_delta,
grpc_transport_one_way_stats *stats);
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
+grpc_error *grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
-grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
+grpc_error *grpc_chttp2_window_update_parser_parse(
grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index ed45bc9cb3..522455f7dc 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -46,6 +46,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
@@ -77,63 +78,70 @@ typedef enum {
a set of indirect jumps, and so not waste stack space. */
/* forward declarations for parsing states */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end);
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end);
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end);
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end, grpc_error *error);
+static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+
+static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_value_string_with_indexed_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_value_string_with_literal_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end);
+
+static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
const uint8_t *end);
+static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+
+static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end);
+static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
+static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end);
/* we translate the first byte of a hpack field into one of these decoding
cases, then use a lookup table to jump directly to the appropriate parser.
@@ -631,19 +639,18 @@ static const uint8_t inverse_base64[256] = {
};
/* emission helpers */
-static int on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
- int add_to_table) {
+static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
+ int add_to_table) {
if (add_to_table) {
- if (!grpc_chttp2_hptbl_add(&p->table, md)) {
- return 0;
- }
+ grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md);
+ if (err != GRPC_ERROR_NONE) return err;
}
if (p->on_header == NULL) {
GRPC_MDELEM_UNREF(md);
- return 0;
+ return GRPC_ERROR_CREATE("on_header callback not set");
}
p->on_header(p->on_header_user_data, md);
- return 1;
+ return GRPC_ERROR_NONE;
}
static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
@@ -654,70 +661,70 @@ static grpc_mdstr *take_string(grpc_chttp2_hpack_parser *p,
}
/* jump to the next state */
-static int parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
p->state = *p->next_state++;
return p->state(p, cur, end);
}
/* begin parsing a header: all functionality is encoded into lookup tables
above */
-static int parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_begin;
- return 1;
+ return GRPC_ERROR_NONE;
}
return first_byte_action[first_byte_lut[*cur]](p, cur, end);
}
/* stream dependency and prioritization data: we just skip it */
-static int parse_stream_weight(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_weight(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_weight;
- return 1;
+ return GRPC_ERROR_NONE;
}
return p->after_prioritization(p, cur + 1, end);
}
-static int parse_stream_dep3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep3(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep3;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_weight(p, cur + 1, end);
}
-static int parse_stream_dep2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep2(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep2;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep3(p, cur + 1, end);
}
-static int parse_stream_dep1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep1(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep1;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep2(p, cur + 1, end);
}
-static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_stream_dep0(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_stream_dep0;
- return 1;
+ return GRPC_ERROR_NONE;
}
return parse_stream_dep1(p, cur + 1, end);
@@ -725,30 +732,34 @@ static int parse_stream_dep0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* emit an indexed field; for now just logs it to console; jumps to
begin the next field on completion */
-static int finish_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
if (md == NULL) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
- }
- return 0;
+ return grpc_error_set_int(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
+ GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
+ GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
GRPC_MDELEM_REF(md);
- return on_hdr(p, md, 0) && parse_begin(p, cur, end);
+ grpc_error *err = on_hdr(p, md, 0);
+ if (err != GRPC_ERROR_NONE) return err;
+ return parse_begin(p, cur, end);
}
/* parse an indexed field with index < 127 */
-static int parse_indexed_field(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
p->dynamic_table_update_allowed = 0;
p->index = (*cur) & 0x7f;
return finish_indexed_field(p, cur + 1, end);
}
/* parse an indexed field with index >= 127 */
-static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_indexed_field};
p->dynamic_table_update_allowed = 0;
@@ -760,28 +771,34 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
/* finish a literal header with incremental indexing: just log, and jump to '
begin */
-static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 1) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 1);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header with incremental indexing with no index */
-static int finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 1) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 1);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header with incremental indexing; index < 63 */
-static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_incidx};
p->dynamic_table_update_allowed = 0;
@@ -791,8 +808,9 @@ static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header with incremental indexing; index >= 63 */
-static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_incidx};
@@ -804,8 +822,9 @@ static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header with incremental indexing; index = 0 */
-static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_incidx_v};
@@ -815,28 +834,34 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
}
/* finish a literal header without incremental indexing */
-static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header without incremental indexing with index = 0 */
-static int finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header without incremental indexing; index < 15 */
-static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_notidx};
p->dynamic_table_update_allowed = 0;
@@ -846,8 +871,9 @@ static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header without incremental indexing; index >= 15 */
-static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_notidx};
@@ -859,8 +885,9 @@ static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header without incremental indexing; index == 0 */
-static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_notidx_v};
@@ -870,28 +897,34 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
}
/* finish a literal header that is never indexed */
-static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
GPR_ASSERT(md != NULL); /* handled in string parsing */
- return on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* finish a literal header that is never indexed with an extra value */
-static int finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
- return on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
- take_string(p, &p->value)),
- 0) &&
- parse_begin(p, cur, end);
+static grpc_error *finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
+ grpc_error *err =
+ on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+ take_string(p, &p->value)),
+ 0);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a literal header that is never indexed; index < 15 */
-static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_value_string_with_indexed_key, finish_lithdr_nvridx};
p->dynamic_table_update_allowed = 0;
@@ -901,8 +934,9 @@ static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a literal header that is never indexed; index >= 15 */
-static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_nvridx};
@@ -914,8 +948,9 @@ static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
}
/* parse a literal header that is never indexed; index == 0 */
-static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur, const uint8_t *end) {
+static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_key_string, parse_string_prefix,
parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
@@ -925,20 +960,25 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
}
/* finish parsing a max table size change */
-static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (grpc_http_trace) {
gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
}
- return grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index) &&
- parse_begin(p, cur, end);
+ grpc_error *err =
+ grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_begin(p, cur, end);
}
/* parse a max table size change, max size < 15 */
-static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (p->dynamic_table_update_allowed == 0) {
- return 0;
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE(
+ "More than two max table size changes in a single frame"));
}
p->dynamic_table_update_allowed--;
p->index = (*cur) & 0x1f;
@@ -946,12 +986,16 @@ static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a max table size change, max size >= 15 */
-static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur,
+ const uint8_t *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size};
if (p->dynamic_table_update_allowed == 0) {
- return 0;
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE(
+ "More than two max table size changes in a single frame"));
}
p->dynamic_table_update_allowed--;
p->next_state = and_then;
@@ -961,28 +1005,38 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* a parse error: jam the parse state into parse_error, and return error */
-static int parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
- p->state = parse_error;
- return 0;
+static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end, grpc_error *err) {
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
+ if (p->last_error == GRPC_ERROR_NONE) {
+ p->last_error = GRPC_ERROR_REF(err);
+ }
+ p->state = still_parse_error;
+ return err;
+}
+
+static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
+ return GRPC_ERROR_REF(p->last_error);
}
-static int parse_illegal_op(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
GPR_ASSERT(cur != end);
- if (grpc_http_trace) {
- gpr_log(GPR_DEBUG, "Illegal hpack op code %d", *cur);
- }
- return parse_error(p, cur, end);
+ char *msg;
+ gpr_asprintf(&msg, "Illegal hpack op code %d", *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* parse the 1st byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value0;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (*cur) & 0x7f;
@@ -996,11 +1050,11 @@ static int parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 2nd byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value1;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
@@ -1014,11 +1068,11 @@ static int parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 3rd byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value2;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
@@ -1032,11 +1086,11 @@ static int parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 4th byte of a varint into p->parsing.value
no overflow is possible */
-static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
if (cur == end) {
p->state = parse_value3;
- return 1;
+ return GRPC_ERROR_NONE;
}
*p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
@@ -1050,15 +1104,16 @@ static int parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
/* parse the 5th byte of a varint into p->parsing.value
depending on the byte, we may overflow, and care must be taken */
-static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
uint8_t c;
uint32_t cur_value;
uint32_t add_value;
+ char *msg;
if (cur == end) {
p->state = parse_value4;
- return 1;
+ return GRPC_ERROR_NONE;
}
c = (*cur) & 0x7f;
@@ -1081,48 +1136,49 @@ static int parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
error:
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x on byte 5",
- *p->parsing.value, *cur);
- }
- return parse_error(p, cur, end);
+ gpr_asprintf(&msg,
+ "integer overflow in hpack integer decoding: have 0x%08x, "
+ "got byte 0x%02x on byte 5",
+ *p->parsing.value, *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* parse any trailing bytes in a varint: it's possible to append an arbitrary
number of 0x80's and not affect the value - a zero will terminate - and
anything else will overflow */
-static int parse_value5up(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
while (cur != end && *cur == 0x80) {
++cur;
}
if (cur == end) {
p->state = parse_value5up;
- return 1;
+ return GRPC_ERROR_NONE;
}
if (*cur == 0) {
return parse_next(p, cur + 1, end);
}
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x sometime after byte 5",
- *p->parsing.value, *cur);
- }
- return parse_error(p, cur, end);
+ char *msg;
+ gpr_asprintf(&msg,
+ "integer overflow in hpack integer decoding: have 0x%08x, "
+ "got byte 0x%02x sometime after byte 5",
+ *p->parsing.value, *cur);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
/* parse a string prefix */
-static int parse_string_prefix(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (cur == end) {
p->state = parse_string_prefix;
- return 1;
+ return GRPC_ERROR_NONE;
}
p->strlen = (*cur) & 0x7f;
@@ -1149,25 +1205,26 @@ static void append_bytes(grpc_chttp2_hpack_parser_string *str,
str->length += (uint32_t)length;
}
-static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
grpc_chttp2_hpack_parser_string *str = p->parsing.str;
uint32_t bits;
uint8_t decoded[3];
switch ((binary_state)p->binary) {
case NOT_BINARY:
append_bytes(str, cur, (size_t)(end - cur));
- return 1;
+ return GRPC_ERROR_NONE;
b64_byte0:
case B64_BYTE0:
if (cur == end) {
p->binary = B64_BYTE0;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte0;
p->base64_buffer = bits << 18;
@@ -1176,12 +1233,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE1:
if (cur == end) {
p->binary = B64_BYTE1;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte1;
p->base64_buffer |= bits << 12;
@@ -1190,12 +1248,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE2:
if (cur == end) {
p->binary = B64_BYTE2;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte2;
p->base64_buffer |= bits << 6;
@@ -1204,12 +1263,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
case B64_BYTE3:
if (cur == end) {
p->binary = B64_BYTE3;
- return 1;
+ return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
++cur;
if (bits == 255)
- return 0;
+ return parse_error(p, cur, end,
+ GRPC_ERROR_CREATE("Illegal base64 character"));
else if (bits == 64)
goto b64_byte3;
p->base64_buffer |= bits;
@@ -1220,11 +1280,13 @@ static int append_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
append_bytes(str, decoded, 3);
goto b64_byte0;
}
- GPR_UNREACHABLE_CODE(return 1);
+ GPR_UNREACHABLE_CODE(return parse_error(
+ p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
}
/* append a null terminator to a string */
-static int finish_str(grpc_chttp2_hpack_parser *p) {
+static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
uint8_t terminator = 0;
uint8_t decoded[2];
uint32_t bits;
@@ -1235,14 +1297,18 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
case B64_BYTE0:
break;
case B64_BYTE1:
- gpr_log(GPR_ERROR, "illegal base64 encoding");
- return 0; /* illegal encoding */
+ return parse_error(
+ p, cur, end,
+ GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */
case B64_BYTE2:
bits = p->base64_buffer;
if (bits & 0xffff) {
- gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%04x",
- bits & 0xffff);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%04x",
+ bits & 0xffff);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
decoded[0] = (uint8_t)(bits >> 16);
append_bytes(str, decoded, 1);
@@ -1250,9 +1316,12 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
case B64_BYTE3:
bits = p->base64_buffer;
if (bits & 0xff) {
- gpr_log(GPR_ERROR, "trailing bits in base64 encoding: 0x%02x",
- bits & 0xff);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "trailing bits in base64 encoding: 0x%02x",
+ bits & 0xff);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return parse_error(p, cur, end, err);
}
decoded[0] = (uint8_t)(bits >> 16);
decoded[1] = (uint8_t)(bits >> 8);
@@ -1261,38 +1330,42 @@ static int finish_str(grpc_chttp2_hpack_parser *p) {
}
append_bytes(str, &terminator, 1);
p->parsing.str->length--; /* don't actually count the null terminator */
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode a nibble from a huffman encoded stream */
-static int huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
+static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
if (emit != -1) {
if (emit >= 0 && emit < 256) {
uint8_t c = (uint8_t)emit;
- if (!append_string(p, &c, (&c) + 1)) return 0;
+ grpc_error *err = append_string(p, &c, (&c) + 1);
+ if (err != GRPC_ERROR_NONE) return err;
} else {
assert(emit == 256);
}
}
p->huff_state = next;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode full bytes from a huffman encoded stream */
-static int add_huff_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *add_huff_bytes(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
for (; cur != end; ++cur) {
- if (!huff_nibble(p, *cur >> 4) || !huff_nibble(p, *cur & 0xf)) return 0;
+ grpc_error *err = huff_nibble(p, *cur >> 4);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ err = huff_nibble(p, *cur & 0xf);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
/* decode some string bytes based on the current decoding mode
(huffman or not) */
-static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *add_str_bytes(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
if (p->huff) {
return add_huff_bytes(p, cur, end);
} else {
@@ -1301,26 +1374,31 @@ static int add_str_bytes(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse a string - tries to do large chunks at a time */
-static int parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+ const uint8_t *end) {
size_t remaining = p->strlen - p->strgot;
size_t given = (size_t)(end - cur);
if (remaining <= given) {
- return add_str_bytes(p, cur, cur + remaining) && finish_str(p) &&
- parse_next(p, cur + remaining, end);
+ grpc_error *err = add_str_bytes(p, cur, cur + remaining);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ err = finish_str(p, cur + remaining, end);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_next(p, cur + remaining, end);
} else {
- if (!add_str_bytes(p, cur, cur + given)) return 0;
+ grpc_error *err = add_str_bytes(p, cur, cur + given);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
GPR_ASSERT(given <= UINT32_MAX - p->strgot);
p->strgot += (uint32_t)given;
p->state = parse_string;
- return 1;
+ return GRPC_ERROR_NONE;
}
}
/* begin parsing a string - performs setup, calls parse_string */
-static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end, uint8_t binary,
- grpc_chttp2_hpack_parser_string *str) {
+static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end,
+ uint8_t binary,
+ grpc_chttp2_hpack_parser_string *str) {
p->strgot = 0;
str->length = 0;
p->parsing.str = str;
@@ -1330,58 +1408,50 @@ static int begin_parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
}
/* parse the key string */
-static int parse_key_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end) {
return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
}
/* check if a key represents a binary header or not */
-typedef enum { BINARY_HEADER, PLAINTEXT_HEADER, ERROR_HEADER } is_binary_header;
-static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
- return grpc_is_binary_header(p->key.str, p->key.length) ? BINARY_HEADER
- : PLAINTEXT_HEADER;
+static bool is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
+ return grpc_is_binary_header(p->key.str, p->key.length);
}
-static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
+static grpc_error *is_binary_indexed_header(grpc_chttp2_hpack_parser *p,
+ bool *is) {
grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
if (!elem) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
- }
- return ERROR_HEADER;
+ return grpc_error_set_int(
+ grpc_error_set_int(GRPC_ERROR_CREATE("Invalid HPACK index received"),
+ GRPC_ERROR_INT_INDEX, (intptr_t)p->index),
+ GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
}
- return grpc_is_binary_header(
- (const char *)GPR_SLICE_START_PTR(elem->key->slice),
- GPR_SLICE_LENGTH(elem->key->slice))
- ? BINARY_HEADER
- : PLAINTEXT_HEADER;
+ *is =
+ grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(elem->key->slice),
+ GPR_SLICE_LENGTH(elem->key->slice));
+ return GRPC_ERROR_NONE;
}
/* parse the value string */
-static int parse_value_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
- const uint8_t *end, is_binary_header type) {
- switch (type) {
- case BINARY_HEADER:
- return begin_parse_string(p, cur, end, B64_BYTE0, &p->value);
- case PLAINTEXT_HEADER:
- return begin_parse_string(p, cur, end, NOT_BINARY, &p->value);
- case ERROR_HEADER:
- return 0;
- }
- /* Add code to prevent return without value error */
- GPR_UNREACHABLE_CODE(return 0);
+static grpc_error *parse_value_string(grpc_chttp2_hpack_parser *p,
+ const uint8_t *cur, const uint8_t *end,
+ bool is_binary) {
+ return begin_parse_string(p, cur, end, is_binary ? B64_BYTE0 : NOT_BINARY,
+ &p->value);
}
-static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end) {
- return parse_value_string(p, cur, end, is_binary_indexed_header(p));
+static grpc_error *parse_value_string_with_indexed_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
+ bool is_binary = false;
+ grpc_error *err = is_binary_indexed_header(p, &is_binary);
+ if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+ return parse_value_string(p, cur, end, is_binary);
}
-static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
- const uint8_t *cur,
- const uint8_t *end) {
+static grpc_error *parse_value_string_with_literal_key(
+ grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
return parse_value_string(p, cur, end, is_binary_literal_header(p));
}
@@ -1398,6 +1468,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
p->value.capacity = 0;
p->value.length = 0;
p->dynamic_table_update_allowed = 2;
+ p->last_error = GRPC_ERROR_NONE;
grpc_chttp2_hptbl_init(&p->table);
}
@@ -1408,12 +1479,14 @@ void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
grpc_chttp2_hptbl_destroy(&p->table);
+ GRPC_ERROR_UNREF(p->last_error);
gpr_free(p->key.str);
gpr_free(p->value.str);
}
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg, const uint8_t *end) {
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+ const uint8_t *beg,
+ const uint8_t *end) {
/* TODO(ctiller): limit the distance of end from beg, and perform multiple
steps in the event of a large chunk of data to limit
stack space usage when no tail call optimization is
@@ -1421,7 +1494,7 @@ int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
return p->state(p, beg, end);
}
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+grpc_error *grpc_chttp2_header_parser_parse(
grpc_exec_ctx *exec_ctx, void *hpack_parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
@@ -1430,17 +1503,17 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
if (stream_parsing != NULL) {
stream_parsing->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
}
- if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
- GPR_SLICE_END_PTR(slice))) {
+ grpc_error *error = grpc_chttp2_hpack_parser_parse(
+ parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
+ if (error != GRPC_ERROR_NONE) {
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return error;
}
if (is_last) {
if (parser->is_boundary && parser->state != parse_begin) {
- gpr_log(GPR_ERROR,
- "end of header frame not aligned with a hpack record boundary");
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE(
+ "end of header frame not aligned with a hpack record boundary");
}
/* need to check for null stream: this can occur if we receive an invalid
stream id on a header */
@@ -1448,8 +1521,7 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
if (parser->is_boundary) {
if (stream_parsing->header_frames_received ==
GPR_ARRAY_SIZE(stream_parsing->got_metadata_on_parse)) {
- gpr_log(GPR_ERROR, "too many trailer frames");
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ return GRPC_ERROR_CREATE("Too many trailer frames");
}
stream_parsing
->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
@@ -1468,5 +1540,5 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
parser->dynamic_table_update_allowed = 2;
}
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 855d6c5d52..78eb38db5e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -44,9 +44,8 @@
typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
-typedef int (*grpc_chttp2_hpack_parser_state)(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg,
- const uint8_t *end);
+typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
+ grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end);
typedef struct {
char *str;
@@ -59,6 +58,8 @@ struct grpc_chttp2_hpack_parser {
void (*on_header)(void *user_data, grpc_mdelem *md);
void *on_header_user_data;
+ grpc_error *last_error;
+
/* current parse state - or a function that implements it */
grpc_chttp2_hpack_parser_state state;
/* future states dependent on the opening op code */
@@ -103,12 +104,13 @@ void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
/* returns 1 on success, 0 on error */
-int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
- const uint8_t *beg, const uint8_t *end);
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+ const uint8_t *beg,
+ const uint8_t *end);
/* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
the transport */
-grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
+grpc_error *grpc_chttp2_header_parser_parse(
grpc_exec_ctx *exec_ctx, void *hpack_parser,
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 295f31c44f..2b73ec969e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include "src/core/lib/support/murmur_hash.h"
@@ -262,18 +263,19 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
tbl->max_bytes = max_bytes;
}
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
- uint32_t bytes) {
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ uint32_t bytes) {
if (tbl->current_table_bytes == bytes) {
- return 1;
+ return GRPC_ERROR_NONE;
}
if (bytes > tbl->max_bytes) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "Attempt to make hpack table %d bytes when max is %d bytes",
- bytes, tbl->max_bytes);
- }
- return 0;
+ char *msg;
+ gpr_asprintf(&msg,
+ "Attempt to make hpack table %d bytes when max is %d bytes",
+ bytes, tbl->max_bytes);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
@@ -291,23 +293,25 @@ int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
rebuild_ents(tbl, new_cap);
}
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
if (tbl->current_table_bytes > tbl->max_bytes) {
- if (grpc_http_trace) {
- gpr_log(GPR_ERROR,
- "HPACK max table size reduced to %d but not reflected by hpack "
- "stream (still at %d)",
- tbl->max_bytes, tbl->current_table_bytes);
- }
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "HPACK max table size reduced to %d but not reflected by hpack "
+ "stream (still at %d)",
+ tbl->max_bytes, tbl->current_table_bytes);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
/* we can't add elements bigger than the max table size */
@@ -324,7 +328,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) {
evict1(tbl);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
/* evict entries to ensure no overflow */
@@ -339,7 +343,7 @@ int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* update accounting values */
tbl->num_ents++;
tbl->mem_used += (uint32_t)elem_bytes;
- return 1;
+ return GRPC_ERROR_NONE;
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 074fea36d8..45bd9255bf 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -36,6 +36,7 @@
#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"
/* HPACK header table */
@@ -87,15 +88,15 @@ void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
uint32_t max_bytes);
-int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
- uint32_t bytes);
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+ uint32_t bytes);
/* lookup a table entry based on its hpack index */
grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
uint32_t index);
/* add a table entry to the index */
-int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
- grpc_mdelem *md) GRPC_MUST_USE_RESULT;
+grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
+ grpc_mdelem *md) GRPC_MUST_USE_RESULT;
/* Find a key/value pair in the table... returns the index in the table of the
most similar entry, or 0 if the value was not found */
typedef struct {
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 5872fd8e0a..d63170e350 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -156,7 +156,7 @@ struct grpc_chttp2_incoming_byte_stream {
grpc_byte_stream base;
gpr_refcount refs;
struct grpc_chttp2_incoming_byte_stream *next_message;
- int failed;
+ grpc_error *error;
grpc_chttp2_transport *transport;
grpc_chttp2_stream *stream;
@@ -265,6 +265,7 @@ struct grpc_chttp2_transport_parsing {
uint8_t incoming_frame_type;
uint8_t incoming_frame_flags;
uint8_t header_eof;
+ bool is_first_frame;
uint32_t expect_continuation_stream_id;
uint32_t incoming_frame_size;
uint32_t incoming_stream_id;
@@ -275,10 +276,10 @@ struct grpc_chttp2_transport_parsing {
/* active parser */
void *parser_data;
grpc_chttp2_stream_parsing *incoming_stream;
- grpc_chttp2_parse_error (*parser)(
- grpc_exec_ctx *exec_ctx, void *parser_user_data,
- grpc_chttp2_transport_parsing *transport_parsing,
- grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+ grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ grpc_chttp2_stream_parsing *stream_parsing,
+ gpr_slice slice, int is_last);
/* received settings */
uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
@@ -383,6 +384,9 @@ struct grpc_chttp2_transport {
/** Transport op to be applied post-parsing */
grpc_transport_op *post_parsing_op;
+
+ /** Message explaining the reason of dropping connection */
+ gpr_slice optional_drop_message;
};
typedef struct {
@@ -437,6 +441,7 @@ typedef struct {
bool published_initial_metadata;
bool published_trailing_metadata;
+ bool final_metadata_requested;
grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@@ -468,12 +473,12 @@ typedef struct {
} grpc_chttp2_stream_writing;
struct grpc_chttp2_stream_parsing {
+ /** saw some stream level error */
+ grpc_error *forced_close_error;
/** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id;
/** has this stream received a close */
uint8_t received_close;
- /** saw a rst_stream */
- uint8_t saw_rst_stream;
/** how many header frames have we received? */
uint8_t header_frames_received;
/** which metadata did we get (on this parse) */
@@ -485,8 +490,6 @@ struct grpc_chttp2_stream_parsing {
int64_t incoming_window;
/** parsing state for data frames */
grpc_chttp2_data_parser data_parser;
- /** reason give to rst_stream */
- uint32_t rst_stream_reason;
/** amount of window given */
int64_t outgoing_window;
/** number of bytes received - reset at end of parse thread execution */
@@ -523,13 +526,12 @@ struct grpc_chttp2_stream {
are required, and schedule them if so */
int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
- grpc_chttp2_transport_writing *writing,
- int is_parsing);
+ grpc_chttp2_transport_writing *writing);
void grpc_chttp2_perform_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
grpc_endpoint *endpoint);
void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
- void *transport_writing, bool success);
+ void *transport_writing, grpc_error *error);
void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing);
@@ -538,9 +540,9 @@ void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing);
/** 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 */
-int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice);
+grpc_error *grpc_chttp2_perform_read(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice);
void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing);
@@ -670,9 +672,10 @@ void grpc_chttp2_for_all_streams(
void grpc_chttp2_parsing_become_skip_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_stream_global *stream_global,
- grpc_closure **pclosure, int success);
+void grpc_chttp2_complete_closure_step(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
+ grpc_error *error);
void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport *transport,
@@ -775,8 +778,8 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
grpc_status_code status, gpr_slice *details);
void grpc_chttp2_mark_stream_closed(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global, int close_reads,
- int close_writes);
+ grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
+ grpc_error *error);
void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
@@ -808,8 +811,8 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
grpc_chttp2_incoming_byte_stream *bs,
gpr_slice slice);
void grpc_chttp2_incoming_byte_stream_finished(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
- int from_parsing_thread);
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+ grpc_error *error, int from_parsing_thread);
void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *parsing,
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 4bd374b7fa..991d7729af 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -49,30 +49,30 @@
((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
parsing)))
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_header_frame_parser(
+static grpc_error *init_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation);
-static int init_data_frame_parser(
+static grpc_error *init_data_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_rst_stream_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
+static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_rst_stream_parser(
+static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_settings_frame_parser(
+static grpc_error *init_ping_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_window_update_frame_parser(
+static grpc_error *init_goaway_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static int init_ping_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_goaway_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing);
-static int init_skip_frame_parser(
+static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header);
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice, int is_last);
+static grpc_error *parse_frame_slice(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice, int is_last);
void grpc_chttp2_prepare_to_read(
grpc_chttp2_transport_global *transport_global,
@@ -230,38 +230,42 @@ void grpc_chttp2_publish_reads(
grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
}
- if (stream_parsing->saw_rst_stream) {
- if (stream_parsing->rst_stream_reason != GRPC_CHTTP2_NO_ERROR) {
- grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
- (grpc_chttp2_error_code)stream_parsing->rst_stream_reason);
- char *status_details;
- gpr_slice slice_details;
- gpr_asprintf(&status_details, "Received RST_STREAM err=%d",
- stream_parsing->rst_stream_reason);
- slice_details = gpr_slice_from_copied_string(status_details);
- gpr_free(status_details);
+ if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
+ intptr_t reason;
+ bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
+ GRPC_ERROR_INT_HTTP2_ERROR, &reason);
+ if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
+ grpc_status_code status_code =
+ has_reason ? grpc_chttp2_http2_error_to_grpc_status(
+ (grpc_chttp2_error_code)reason)
+ : GRPC_STATUS_INTERNAL;
+ const char *status_details =
+ grpc_error_string(stream_parsing->forced_close_error);
+ gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
+ grpc_error_free_string(status_details);
grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
status_code, &slice_details);
}
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- 1, 1);
+ 1, 1, stream_parsing->forced_close_error);
}
if (stream_parsing->received_close) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- 1, 0);
+ 1, 0, GRPC_ERROR_NONE);
}
}
}
-int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice) {
+grpc_error *grpc_chttp2_perform_read(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice) {
uint8_t *beg = GPR_SLICE_START_PTR(slice);
uint8_t *end = GPR_SLICE_END_PTR(slice);
uint8_t *cur = beg;
+ grpc_error *err;
- if (cur == end) return 1;
+ if (cur == end) return GRPC_ERROR_NONE;
switch (transport_parsing->deframe_state) {
case GRPC_DTS_CLIENT_PREFIX_0:
@@ -291,21 +295,25 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
->deframe_state]) {
- gpr_log(GPR_INFO,
- "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
- "at byte %d",
- GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
- ->deframe_state],
- (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
- [transport_parsing->deframe_state],
- *cur, (int)*cur, transport_parsing->deframe_state);
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
+ "at byte %d",
+ GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
+ ->deframe_state],
+ (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
+ [transport_parsing->deframe_state],
+ *cur, (int)*cur, transport_parsing->deframe_state);
+ err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
++cur;
++transport_parsing->deframe_state;
}
if (cur == end) {
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
dts_fh_0:
@@ -314,7 +322,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_1;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_1:
@@ -322,7 +330,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_2;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_2:
@@ -330,7 +338,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size |= *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_3;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_3:
@@ -338,7 +346,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_type = *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_4;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_4:
@@ -346,7 +354,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_flags = *cur;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_5;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_5:
@@ -354,7 +362,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_6;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_6:
@@ -362,7 +370,7 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_7;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_7:
@@ -370,15 +378,16 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_8;
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FH_8:
GPR_ASSERT(cur < end);
transport_parsing->incoming_stream_id |= ((uint32_t)*cur);
transport_parsing->deframe_state = GRPC_DTS_FRAME;
- if (!init_frame_parser(exec_ctx, transport_parsing)) {
- return 0;
+ err = init_frame_parser(exec_ctx, transport_parsing);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
if (transport_parsing->incoming_stream_id != 0 &&
transport_parsing->incoming_stream_id >
@@ -387,62 +396,69 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_stream_id;
}
if (transport_parsing->incoming_frame_size == 0) {
- if (!parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
- 1)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->incoming_stream = NULL;
if (++cur == end) {
transport_parsing->deframe_state = GRPC_DTS_FH_0;
- return 1;
+ return GRPC_ERROR_NONE;
}
goto dts_fh_0; /* loop */
} else if (transport_parsing->incoming_frame_size >
transport_parsing->max_frame_size) {
- gpr_log(GPR_DEBUG, "Frame size %d is larger than max frame size %d",
- transport_parsing->incoming_frame_size,
- transport_parsing->max_frame_size);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
+ transport_parsing->incoming_frame_size,
+ transport_parsing->max_frame_size);
+ err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (++cur == end) {
- return 1;
+ return GRPC_ERROR_NONE;
}
/* fallthrough */
case GRPC_DTS_FRAME:
GPR_ASSERT(cur < end);
if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
- if (!parse_frame_slice(exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 1)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->deframe_state = GRPC_DTS_FH_0;
transport_parsing->incoming_stream = NULL;
- return 1;
+ return GRPC_ERROR_NONE;
} else if ((uint32_t)(end - cur) >
transport_parsing->incoming_frame_size) {
size_t cur_offset = (size_t)(cur - beg);
- if (!parse_frame_slice(
- exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(
- slice, cur_offset,
- cur_offset + transport_parsing->incoming_frame_size),
- 1)) {
- return 0;
+ err = parse_frame_slice(
+ exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(
+ slice, cur_offset,
+ cur_offset + transport_parsing->incoming_frame_size),
+ 1);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
cur += transport_parsing->incoming_frame_size;
transport_parsing->incoming_stream = NULL;
goto dts_fh_0; /* loop */
} else {
- if (!parse_frame_slice(exec_ctx, transport_parsing,
- gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
- (size_t)(end - beg)),
- 0)) {
- return 0;
+ err = parse_frame_slice(exec_ctx, transport_parsing,
+ gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
+ (size_t)(end - beg)),
+ 0);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
- return 1;
+ return GRPC_ERROR_NONE;
}
GPR_UNREACHABLE_CODE(return 0);
}
@@ -450,23 +466,41 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
GPR_UNREACHABLE_CODE(return 0);
}
-static int init_frame_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_frame_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+ if (transport_parsing->is_first_frame &&
+ transport_parsing->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
+ char *msg;
+ gpr_asprintf(
+ &msg, "Expected SETTINGS frame as the first frame, got frame type %d",
+ transport_parsing->incoming_frame_type);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
+ }
+ transport_parsing->is_first_frame = false;
if (transport_parsing->expect_continuation_stream_id != 0) {
if (transport_parsing->incoming_frame_type !=
GRPC_CHTTP2_FRAME_CONTINUATION) {
- gpr_log(GPR_ERROR, "Expected CONTINUATION frame, got frame type %02x",
- transport_parsing->incoming_frame_type);
- return 0;
+ char *msg;
+ gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
+ transport_parsing->incoming_frame_type);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (transport_parsing->expect_continuation_stream_id !=
transport_parsing->incoming_stream_id) {
- gpr_log(GPR_ERROR,
- "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
- "grpc_chttp2_stream %08x",
- transport_parsing->expect_continuation_stream_id,
- transport_parsing->incoming_stream_id);
- return 0;
+ char *msg;
+ gpr_asprintf(
+ &msg,
+ "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
+ "grpc_chttp2_stream %08x",
+ transport_parsing->expect_continuation_stream_id,
+ transport_parsing->incoming_stream_id);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
return init_header_frame_parser(exec_ctx, transport_parsing, 1);
}
@@ -476,8 +510,7 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_HEADER:
return init_header_frame_parser(exec_ctx, transport_parsing, 0);
case GRPC_CHTTP2_FRAME_CONTINUATION:
- gpr_log(GPR_ERROR, "Unexpected CONTINUATION frame");
- return 0;
+ return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame");
case GRPC_CHTTP2_FRAME_RST_STREAM:
return init_rst_stream_parser(exec_ctx, transport_parsing);
case GRPC_CHTTP2_FRAME_SETTINGS:
@@ -489,22 +522,24 @@ static int init_frame_parser(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_FRAME_GOAWAY:
return init_goaway_parser(exec_ctx, transport_parsing);
default:
- gpr_log(GPR_ERROR, "Unknown frame type %02x",
- transport_parsing->incoming_frame_type);
+ if (grpc_http_trace) {
+ gpr_log(GPR_ERROR, "Unknown frame type %02x",
+ transport_parsing->incoming_frame_type);
+ }
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
}
-static grpc_chttp2_parse_error skip_parser(
- grpc_exec_ctx *exec_ctx, void *parser,
- grpc_chttp2_transport_parsing *transport_parsing,
- grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
- return GRPC_CHTTP2_PARSE_OK;
+static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ grpc_chttp2_stream_parsing *stream_parsing,
+ gpr_slice slice, int is_last) {
+ return GRPC_ERROR_NONE;
}
static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
-static int init_skip_frame_parser(
+static grpc_error *init_skip_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_header) {
if (is_header) {
@@ -519,7 +554,7 @@ static int init_skip_frame_parser(
} else {
transport_parsing->parser = skip_parser;
}
- return 1;
+ return GRPC_ERROR_NONE;
}
void grpc_chttp2_parsing_become_skip_parser(
@@ -529,22 +564,28 @@ void grpc_chttp2_parsing_become_skip_parser(
transport_parsing->parser == grpc_chttp2_header_parser_parse);
}
-static grpc_chttp2_parse_error update_incoming_window(
+static grpc_error *update_incoming_window(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing) {
uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
if (incoming_frame_size > transport_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_window);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_window);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
if (incoming_frame_size > stream_parsing->incoming_window) {
- gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
- transport_parsing->incoming_frame_size,
- stream_parsing->incoming_window);
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ char *msg;
+ gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
+ transport_parsing->incoming_frame_size,
+ stream_parsing->incoming_window);
+ grpc_error *err = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
+ return err;
}
GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
@@ -555,15 +596,15 @@ static grpc_chttp2_parse_error update_incoming_window(
grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
- return GRPC_CHTTP2_PARSE_OK;
+ return GRPC_ERROR_NONE;
}
-static int init_data_frame_parser(
+static grpc_error *init_data_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
grpc_chttp2_stream_parsing *stream_parsing =
grpc_chttp2_parsing_lookup_stream(transport_parsing,
transport_parsing->incoming_stream_id);
- grpc_chttp2_parse_error err = GRPC_CHTTP2_PARSE_OK;
+ grpc_error *err = GRPC_ERROR_NONE;
if (stream_parsing == NULL) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
@@ -571,33 +612,32 @@ static int init_data_frame_parser(
if (stream_parsing->received_close) {
return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
}
- if (err == GRPC_CHTTP2_PARSE_OK) {
+ if (err == GRPC_ERROR_NONE) {
err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing);
}
- if (err == GRPC_CHTTP2_PARSE_OK) {
+ if (err == GRPC_ERROR_NONE) {
err = grpc_chttp2_data_parser_begin_frame(
- &stream_parsing->data_parser, transport_parsing->incoming_frame_flags);
- }
- switch (err) {
- case GRPC_CHTTP2_PARSE_OK:
- transport_parsing->incoming_stream = stream_parsing;
- transport_parsing->parser = grpc_chttp2_data_parser_parse;
- transport_parsing->parser_data = &stream_parsing->data_parser;
- return 1;
- case GRPC_CHTTP2_STREAM_ERROR:
- stream_parsing->received_close = 1;
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
- gpr_slice_buffer_add(
- &transport_parsing->qbuf,
- grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
- &stream_parsing->stats.outgoing));
- return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
- case GRPC_CHTTP2_CONNECTION_ERROR:
- return 0;
+ &stream_parsing->data_parser, transport_parsing->incoming_frame_flags,
+ stream_parsing->id);
+ }
+ if (err == GRPC_ERROR_NONE) {
+ transport_parsing->incoming_stream = stream_parsing;
+ transport_parsing->parser = grpc_chttp2_data_parser_parse;
+ transport_parsing->parser_data = &stream_parsing->data_parser;
+ return GRPC_ERROR_NONE;
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
+ /* handle stream errors by closing the stream */
+ stream_parsing->received_close = 1;
+ stream_parsing->forced_close_error = err;
+ gpr_slice_buffer_add(
+ &transport_parsing->qbuf,
+ grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+ GRPC_CHTTP2_PROTOCOL_ERROR,
+ &stream_parsing->stats.outgoing));
+ return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+ } else {
+ return err;
}
- GPR_UNREACHABLE_CODE(return 0);
}
static void free_timeout(void *p) { gpr_free(p); }
@@ -649,7 +689,8 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG,
- "received initial metadata size exceeds limit (%lu vs. %lu)",
+ "received initial metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true;
@@ -695,7 +736,8 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
if (new_size > metadata_size_limit) {
if (!stream_parsing->exceeded_metadata_size) {
gpr_log(GPR_DEBUG,
- "received trailing metadata size exceeds limit (%lu vs. %lu)",
+ "received trailing metadata size exceeds limit (%" PRIuPTR
+ " vs. %" PRIuPTR ")",
new_size, metadata_size_limit);
stream_parsing->seen_error = true;
stream_parsing->exceeded_metadata_size = true;
@@ -711,7 +753,7 @@ static void on_trailing_header(void *tp, grpc_mdelem *md) {
GPR_TIMER_END("on_trailing_header", 0);
}
-static int init_header_frame_parser(
+static grpc_error *init_header_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
int is_continuation) {
uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
@@ -806,15 +848,16 @@ static int init_header_frame_parser(
GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int init_window_update_frame_parser(
+static grpc_error *init_window_update_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_window_update_parser_begin_frame(
- &transport_parsing->simple.window_update,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_window_update_parser_begin_frame(
+ &transport_parsing->simple.window_update,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
if (transport_parsing->incoming_stream_id != 0) {
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
@@ -826,26 +869,27 @@ static int init_window_update_frame_parser(
}
transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.window_update;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_ping_parser(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_ping_parser_begin_frame(
- &transport_parsing->simple.ping,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+static grpc_error *init_ping_parser(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+ grpc_error *err = grpc_chttp2_ping_parser_begin_frame(
+ &transport_parsing->simple.ping, transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_ping_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.ping;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_rst_stream_parser(
+static grpc_error *init_rst_stream_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_rst_stream_parser_begin_frame(
- &transport_parsing->simple.rst_stream,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_rst_stream_parser_begin_frame(
+ &transport_parsing->simple.rst_stream,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
transport_parsing, transport_parsing->incoming_stream_id);
@@ -855,37 +899,32 @@ static int init_rst_stream_parser(
stream_parsing->stats.incoming.framing_bytes += 9;
transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_goaway_parser(
+static grpc_error *init_goaway_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_goaway_parser_begin_frame(
- &transport_parsing->goaway_parser,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags);
+ grpc_error *err = grpc_chttp2_goaway_parser_begin_frame(
+ &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags);
+ if (err != GRPC_ERROR_NONE) return err;
transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
transport_parsing->parser_data = &transport_parsing->goaway_parser;
- return ok;
+ return GRPC_ERROR_NONE;
}
-static int init_settings_frame_parser(
+static grpc_error *init_settings_frame_parser(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
- int ok;
-
if (transport_parsing->incoming_stream_id != 0) {
- gpr_log(GPR_ERROR, "settings frame received for grpc_chttp2_stream %d",
- transport_parsing->incoming_stream_id);
- return 0;
+ return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream");
}
- ok = GRPC_CHTTP2_PARSE_OK == grpc_chttp2_settings_parser_begin_frame(
- &transport_parsing->simple.settings,
- transport_parsing->incoming_frame_size,
- transport_parsing->incoming_frame_flags,
- transport_parsing->settings);
- if (!ok) {
- return 0;
+ grpc_error *err = grpc_chttp2_settings_parser_begin_frame(
+ &transport_parsing->simple.settings,
+ transport_parsing->incoming_frame_size,
+ transport_parsing->incoming_frame_flags, transport_parsing->settings);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
transport_parsing->settings_ack_received = 1;
@@ -899,7 +938,7 @@ static int init_settings_frame_parser(
}
transport_parsing->parser = grpc_chttp2_settings_parser_parse;
transport_parsing->parser_data = &transport_parsing->simple.settings;
- return ok;
+ return GRPC_ERROR_NONE;
}
/*
@@ -908,34 +947,37 @@ static int is_window_update_legal(int64_t window_update, int64_t window) {
}
*/
-static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
- grpc_chttp2_transport_parsing *transport_parsing,
- gpr_slice slice, int is_last) {
+static grpc_error *parse_frame_slice(
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
+ gpr_slice slice, int is_last) {
grpc_chttp2_stream_parsing *stream_parsing =
transport_parsing->incoming_stream;
- switch (transport_parsing->parser(exec_ctx, transport_parsing->parser_data,
- transport_parsing, stream_parsing, slice,
- is_last)) {
- case GRPC_CHTTP2_PARSE_OK:
- if (stream_parsing) {
- grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
- stream_parsing);
- }
- return 1;
- case GRPC_CHTTP2_STREAM_ERROR:
- grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
- if (stream_parsing) {
- stream_parsing->saw_rst_stream = 1;
- stream_parsing->rst_stream_reason = GRPC_CHTTP2_PROTOCOL_ERROR;
- gpr_slice_buffer_add(
- &transport_parsing->qbuf,
- grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
- GRPC_CHTTP2_PROTOCOL_ERROR,
- &stream_parsing->stats.outgoing));
- }
- return 1;
- case GRPC_CHTTP2_CONNECTION_ERROR:
- return 0;
+ grpc_error *err = transport_parsing->parser(
+ exec_ctx, transport_parsing->parser_data, transport_parsing,
+ stream_parsing, slice, is_last);
+ if (err == GRPC_ERROR_NONE) {
+ if (stream_parsing) {
+ grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+ stream_parsing);
+ }
+ return GRPC_ERROR_NONE;
+ } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
+ if (grpc_http_trace) {
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "%s", msg);
+ grpc_error_free_string(msg);
+ }
+ grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
+ if (stream_parsing) {
+ stream_parsing->forced_close_error = err;
+ gpr_slice_buffer_add(
+ &transport_parsing->qbuf,
+ grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
+ GRPC_CHTTP2_PROTOCOL_ERROR,
+ &stream_parsing->stats.outgoing));
+ } else {
+ GRPC_ERROR_UNREF(err);
+ }
}
- GPR_UNREACHABLE_CODE(return 0);
+ return err;
}
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index a8fb463939..b19f5f068d 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -45,7 +45,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
int grpc_chttp2_unlocking_check_writes(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_transport_writing *transport_writing, int is_parsing) {
+ grpc_chttp2_transport_writing *transport_writing) {
grpc_chttp2_stream_global *stream_global;
grpc_chttp2_stream_writing *stream_writing;
@@ -61,7 +61,7 @@ int grpc_chttp2_unlocking_check_writes(
[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
if (transport_global->dirtied_local_settings &&
- !transport_global->sent_local_settings && !is_parsing) {
+ !transport_global->sent_local_settings) {
gpr_slice_buffer_add(
&transport_writing->outbuf,
grpc_chttp2_settings_create(
@@ -187,7 +187,8 @@ void grpc_chttp2_perform_writes(
grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
&transport_writing->done_cb);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &transport_writing->done_cb, GRPC_ERROR_NONE,
+ NULL);
}
}
@@ -334,25 +335,27 @@ void grpc_chttp2_cleanup_writing(
transport_global, transport_writing, &stream_global, &stream_writing)) {
if (stream_writing->sent_initial_metadata) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_initial_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_initial_metadata_finished, GRPC_ERROR_NONE);
}
grpc_transport_move_one_way_stats(&stream_writing->stats,
&stream_global->stats.outgoing);
if (stream_writing->sent_message) {
GPR_ASSERT(stream_writing->send_message == NULL);
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global, &stream_global->send_message_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_message_finished, GRPC_ERROR_NONE);
stream_writing->sent_message = 0;
}
if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_complete_closure_step(
- exec_ctx, stream_global,
- &stream_global->send_trailing_metadata_finished, 1);
+ exec_ctx, transport_global, stream_global,
+ &stream_global->send_trailing_metadata_finished, GRPC_ERROR_NONE);
}
if (stream_writing->sent_trailing_metadata) {
grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- !transport_global->is_client, 1);
+ !transport_global->is_client, 1,
+ GRPC_ERROR_NONE);
}
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index df160aaaf6..25d8aca250 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -152,14 +152,18 @@ static void next_recv_step(stream_obj *s, enum e_caller caller);
static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_stream *gs, grpc_pollset *pollset) {}
+static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
+ grpc_transport *gt, grpc_stream *gs,
+ grpc_pollset_set *pollset_set) {}
+
static void enqueue_callbacks(grpc_closure *callback_list[]) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
if (callback_list[0]) {
- grpc_exec_ctx_enqueue(&exec_ctx, callback_list[0], true, NULL);
+ grpc_exec_ctx_sched(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL);
callback_list[0] = NULL;
}
if (callback_list[1]) {
- grpc_exec_ctx_enqueue(&exec_ctx, callback_list[1], true, NULL);
+ grpc_exec_ctx_sched(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL);
callback_list[1] = NULL;
}
grpc_exec_ctx_finish(&exec_ctx);
@@ -646,7 +650,13 @@ static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
}
}
-const grpc_transport_vtable grpc_cronet_vtable = {
- sizeof(stream_obj), "cronet_http", init_stream,
- set_pollset_do_nothing, perform_stream_op, NULL,
- destroy_stream, destroy_transport, NULL};
+const grpc_transport_vtable grpc_cronet_vtable = {sizeof(stream_obj),
+ "cronet_http",
+ init_stream,
+ set_pollset_do_nothing,
+ set_pollset_set_do_nothing,
+ perform_stream_op,
+ NULL,
+ destroy_stream,
+ destroy_transport,
+ NULL};
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 569be4dc28..79ceeb66b3 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -35,6 +35,7 @@
#include <grpc/grpc.h>
#include "src/core/lib/support/string.h"
+#include <grpc/compression.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
@@ -148,6 +149,7 @@ grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) {
void grpc_channel_args_destroy(grpc_channel_args *a) {
size_t i;
+ if (!a) return;
for (i = 0; i < a->num_args; i++) {
switch (a->args[i].type) {
case GRPC_ARG_STRING:
@@ -181,6 +183,7 @@ grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
grpc_channel_args *grpc_channel_args_set_compression_algorithm(
grpc_channel_args *a, grpc_compression_algorithm algorithm) {
+ GPR_ASSERT(algorithm < GRPC_COMPRESS_ALGORITHMS_COUNT);
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM;
@@ -200,7 +203,8 @@ static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
!strcmp(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
a->args[i].key)) {
*states_arg = &a->args[i].value.integer;
- return 1; /* GPR_TRUE */
+ **states_arg |= 0x1; /* forcefully enable support for no compression */
+ return 1;
}
}
}
@@ -209,15 +213,23 @@ static int find_compression_algorithm_states_bitset(const grpc_channel_args *a,
grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
- int *states_arg;
+ int *states_arg = NULL;
grpc_channel_args *result = *a;
const int states_arg_found =
find_compression_algorithm_states_bitset(*a, &states_arg);
- if (states_arg_found) {
+ if (grpc_channel_args_get_compression_algorithm(*a) == algorithm &&
+ state == 0) {
+ char *algo_name = NULL;
+ GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name) != 0);
+ gpr_log(GPR_ERROR,
+ "Tried to disable default compression algorithm '%s'. The "
+ "operation has been ignored.",
+ algo_name);
+ } else if (states_arg_found) {
if (state != 0) {
GPR_BITSET((unsigned *)states_arg, algorithm);
- } else {
+ } else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned *)states_arg, algorithm);
}
} else {
@@ -229,7 +241,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
if (state != 0) {
GPR_BITSET((unsigned *)&tmp.value.integer, algorithm);
- } else {
+ } else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
}
result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
@@ -239,11 +251,11 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
return result;
}
-int grpc_channel_args_compression_algorithm_get_states(
+uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args *a) {
int *states_arg;
if (find_compression_algorithm_states_bitset(a, &states_arg)) {
- return *states_arg;
+ return (uint32_t)*states_arg;
} else {
return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 23c7b7b897..653d04f427 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -81,7 +81,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
*
* The i-th bit of the returned bitset corresponds to the i-th entry in the
* grpc_compression_algorithm enum. */
-int grpc_channel_args_compression_algorithm_get_states(
+uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args *a);
int grpc_channel_args_compare(const grpc_channel_args *a,
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 4892ed283d..bbba85d80b 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -106,6 +106,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
const grpc_channel_filter **filters,
size_t filter_count,
const grpc_channel_args *channel_args,
+ grpc_transport *optional_transport,
const char *name, grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
@@ -127,6 +128,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
for (i = 0; i < filter_count; i++) {
args.channel_stack = stack;
args.channel_args = channel_args;
+ args.optional_transport = optional_transport;
args.is_first = i == 0;
args.is_last = i == (filter_count - 1);
elems[i].filter = filters[i];
@@ -189,9 +191,9 @@ void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
}
}
-void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_call_stack *call_stack,
- grpc_pollset *pollset) {
+void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_call_stack *call_stack,
+ grpc_polling_entity *pollent) {
size_t count = call_stack->count;
grpc_call_element *call_elems;
char *user_data;
@@ -203,15 +205,16 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
/* init per-filter data */
for (i = 0; i < count; i++) {
- call_elems[i].filter->set_pollset(exec_ctx, &call_elems[i], pollset);
+ call_elems[i].filter->set_pollset_or_pollset_set(exec_ctx, &call_elems[i],
+ pollent);
user_data +=
ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
}
}
-void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_pollset *pollset) {}
+void grpc_call_stack_ignore_set_pollset_or_pollset_set(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_polling_entity *pollent) {}
void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_stats *call_stats,
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 2040002269..41dd4a0d8a 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -48,6 +48,7 @@
#include <grpc/support/time.h>
#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/transport/transport.h"
typedef struct grpc_channel_element grpc_channel_element;
@@ -59,6 +60,8 @@ typedef struct grpc_call_stack grpc_call_stack;
typedef struct {
grpc_channel_stack *channel_stack;
const grpc_channel_args *channel_args;
+ /** Transport, iff it is known */
+ grpc_transport *optional_transport;
int is_first;
int is_last;
} grpc_channel_element_args;
@@ -109,8 +112,9 @@ typedef struct {
argument. */
void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args);
- void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_pollset *pollset);
+ void (*set_pollset_or_pollset_set)(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_polling_entity *pollent);
/* Destroy per call data.
The filter does not need to do any chaining.
The bottom filter of a stack will be passed a non-NULL pointer to
@@ -196,6 +200,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
grpc_iomgr_cb_func destroy, void *destroy_arg,
const grpc_channel_filter **filters,
size_t filter_count, const grpc_channel_args *args,
+ grpc_transport *optional_transport,
const char *name, grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
@@ -210,10 +215,11 @@ void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
grpc_call_context_element *context,
const void *transport_server_data,
grpc_call_stack *call_stack);
-/* Set a pollset for a call stack: must occur before the first op is started */
-void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_call_stack *call_stack,
- grpc_pollset *pollset);
+/* 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,
+ grpc_call_stack *call_stack,
+ grpc_polling_entity *pollent);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
#define GRPC_CALL_STACK_REF(call_stack, reason) \
@@ -240,11 +246,11 @@ void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
const grpc_call_stats *call_stats,
void *and_free_memory);
-/* Ignore set pollset - used by filters to implement the set_pollset method
- if they don't care about pollsets at all. Does nothing. */
-void grpc_call_stack_ignore_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_pollset *pollset);
+/* Ignore set pollset{_set} - used by filters if they don't care about pollsets
+ * at all. Does nothing. */
+void grpc_call_stack_ignore_set_pollset_or_pollset_set(
+ grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+ grpc_polling_entity *pollent);
/* Call the next operation in a call stack */
void grpc_call_next_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_transport_stream_op *op);
diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c
index a8646c9565..eda4968f48 100644
--- a/src/core/lib/channel/channel_stack_builder.c
+++ b/src/core/lib/channel/channel_stack_builder.c
@@ -257,8 +257,8 @@ void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
// and initialize it
grpc_channel_stack_init(exec_ctx, initial_refs, destroy,
destroy_arg == NULL ? result : destroy_arg, filters,
- num_filters, builder->args, builder->name,
- channel_stack);
+ num_filters, builder->args, builder->transport,
+ builder->name, channel_stack);
// run post-initialization functions
i = 0;
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 30b18a7274..32ebe53ee6 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -73,8 +73,8 @@ typedef struct call_data {
typedef struct channel_data {
/** The default, channel-level, compression algorithm */
grpc_compression_algorithm default_compression_algorithm;
- /** Compression options for the channel */
- grpc_compression_options compression_options;
+ /** Bitset of enabled algorithms */
+ uint32_t enabled_algorithms_bitset;
/** Supported compression algorithms */
uint32_t supported_compression_algorithms;
} channel_data;
@@ -96,9 +96,8 @@ static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
md_c_str);
calld->compression_algorithm = GRPC_COMPRESS_NONE;
}
- if (grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options, calld->compression_algorithm) ==
- 0) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
+ calld->compression_algorithm)) {
gpr_log(GPR_ERROR,
"Invalid compression algorithm: '%s' (previously disabled). "
"Ignoring.",
@@ -155,11 +154,11 @@ static void process_send_initial_metadata(
static void continue_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem);
-static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
+static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
gpr_slice_buffer_reset_and_unref(&calld->slices);
- calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, success);
+ calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
}
static void finish_send_message(grpc_exec_ctx *exec_ctx,
@@ -178,8 +177,8 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
const float savings_ratio = 1.0f - (float)after_size / (float)before_size;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
- gpr_log(GPR_DEBUG,
- "Compressed[%s] %d bytes vs. %d bytes (%.2f%% savings)",
+ gpr_log(GPR_DEBUG, "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
+ " bytes (%.2f%% savings)",
algo_name, before_size, after_size, 100 * savings_ratio);
}
gpr_slice_buffer_swap(&calld->slices, &tmp);
@@ -189,10 +188,10 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
char *algo_name;
GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
&algo_name));
- gpr_log(
- GPR_DEBUG,
- "Algorithm '%s' enabled but decided not to compress. Input size: %d",
- algo_name, calld->slices.length);
+ gpr_log(GPR_DEBUG,
+ "Algorithm '%s' enabled but decided not to compress. Input size: "
+ "%" PRIuPTR,
+ algo_name, calld->slices.length);
}
}
@@ -207,7 +206,7 @@ static void finish_send_message(grpc_exec_ctx *exec_ctx,
grpc_call_next_op(exec_ctx, elem, &calld->send_op);
}
-static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
+static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
grpc_call_element *elem = elemp;
call_data *calld = elem->call_data;
gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
@@ -282,32 +281,26 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
channel_data *channeld = elem->channel_data;
- grpc_compression_algorithm algo_idx;
- grpc_compression_options_init(&channeld->compression_options);
- channeld->compression_options.enabled_algorithms_bitset =
- (uint32_t)grpc_channel_args_compression_algorithm_get_states(
- args->channel_args);
+ channeld->enabled_algorithms_bitset =
+ grpc_channel_args_compression_algorithm_get_states(args->channel_args);
channeld->default_compression_algorithm =
grpc_channel_args_get_compression_algorithm(args->channel_args);
/* Make sure the default isn't disabled. */
- if (!grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options,
- channeld->default_compression_algorithm)) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset,
+ channeld->default_compression_algorithm)) {
gpr_log(GPR_DEBUG,
"compression algorithm %d not enabled: switching to none",
channeld->default_compression_algorithm);
channeld->default_compression_algorithm = GRPC_COMPRESS_NONE;
}
- channeld->compression_options.default_compression_algorithm =
- channeld->default_compression_algorithm;
- channeld->supported_compression_algorithms = 0;
- for (algo_idx = 0; algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
+ channeld->supported_compression_algorithms = 1; /* always support identity */
+ for (grpc_compression_algorithm algo_idx = 1;
+ algo_idx < GRPC_COMPRESS_ALGORITHMS_COUNT; ++algo_idx) {
/* skip disabled algorithms */
- if (grpc_compression_options_is_algorithm_enabled(
- &channeld->compression_options, algo_idx) == 0) {
+ if (!GPR_BITGET(channeld->enabled_algorithms_bitset, algo_idx)) {
continue;
}
channeld->supported_compression_algorithms |= 1u << algo_idx;
@@ -325,7 +318,7 @@ const grpc_channel_filter grpc_compress_filter = {
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/lib/channel/compress_filter.h b/src/core/lib/channel/compress_filter.h
index 0ce5d08837..e4a2a829d5 100644
--- a/src/core/lib/channel/compress_filter.h
+++ b/src/core/lib/channel/compress_filter.h
@@ -34,9 +34,9 @@
#ifndef GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
#define GRPC_CORE_LIB_CHANNEL_COMPRESS_FILTER_H
-#include "src/core/lib/channel/channel_stack.h"
+#include <grpc/impl/codegen/compression_types.h>
-#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request"
+#include "src/core/lib/channel/channel_stack.h"
extern int grpc_compression_trace;
@@ -48,7 +48,7 @@ extern int grpc_compression_trace;
* - Channel configuration, as established at channel creation time.
* - The metadata accompanying the outgoing data to be compressed. This is
* taken as a request only. We may choose not to honor it. The metadata key
- * is given by \a GRPC_COMPRESS_REQUEST_ALGORITHM_KEY.
+ * is given by \a GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY.
*
* Compression can be disabled for concrete messages (for instance in order to
* prevent CRIME/BEAST type attacks) by having the GRPC_WRITE_NO_COMPRESS set in
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 06e87b005f..0a7d27a1dc 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -93,12 +93,13 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
GPR_ASSERT(r == 0);
}
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_pollset *pollset) {
+static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_polling_entity *pollent) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
- grpc_transport_set_pollset(exec_ctx, chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollset);
+ grpc_transport_set_pops(exec_ctx, chand->transport,
+ TRANSPORT_STREAM_FROM_CALL_DATA(calld), pollent);
}
/* Destructor for call_data */
@@ -138,7 +139,7 @@ static const grpc_channel_filter connected_channel_filter = {
con_start_transport_op,
sizeof(call_data),
init_call_elem,
- set_pollset,
+ set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index cd9e6e894b..ab6c6c9ef0 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -38,6 +38,10 @@
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/transport_impl.h"
+
+#define EXPECTED_CONTENT_TYPE "application/grpc"
+#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
typedef struct call_data {
grpc_linked_mdelem method;
@@ -74,13 +78,31 @@ static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
} else if (md->key == GRPC_MDSTR_STATUS) {
grpc_call_element_send_cancel(a->exec_ctx, a->elem);
return NULL;
+ } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
+ return NULL;
} else if (md->key == GRPC_MDSTR_CONTENT_TYPE) {
+ const char *value_str = grpc_mdstr_as_c_string(md->value);
+ if (strncmp(value_str, EXPECTED_CONTENT_TYPE,
+ EXPECTED_CONTENT_TYPE_LENGTH) == 0 &&
+ (value_str[EXPECTED_CONTENT_TYPE_LENGTH] == '+' ||
+ value_str[EXPECTED_CONTENT_TYPE_LENGTH] == ';')) {
+ /* Although the C implementation doesn't (currently) generate them,
+ any custom +-suffix is explicitly valid. */
+ /* TODO(klempner): We should consider preallocating common values such
+ as +proto or +json, or at least stashing them if we see them. */
+ /* TODO(klempner): Should we be surfacing this to application code? */
+ } else {
+ /* TODO(klempner): We're currently allowing this, but we shouldn't
+ see it without a proxy so log for now. */
+ gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str);
+ }
return NULL;
}
return md;
}
-static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
client_recv_filter_args a;
@@ -88,7 +110,7 @@ static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
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, success);
+ calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
}
static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
@@ -179,7 +201,8 @@ static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
return GRPC_MDELEM_SCHEME_HTTP;
}
-static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
+static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
+ const char *transport_name) {
gpr_strvec v;
size_t i;
int is_first = 1;
@@ -201,8 +224,8 @@ static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args) {
}
}
- gpr_asprintf(&tmp, "%sgrpc-c/%s (%s)", is_first ? "" : " ",
- grpc_version_string(), GPR_PLATFORM_STRING);
+ gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s)", is_first ? "" : " ",
+ grpc_version_string(), GPR_PLATFORM_STRING, transport_name);
is_first = 0;
gpr_strvec_add(&v, tmp);
@@ -233,9 +256,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element_args *args) {
channel_data *chand = elem->channel_data;
GPR_ASSERT(!args->is_last);
+ GPR_ASSERT(args->optional_transport != NULL);
chand->static_scheme = scheme_from_args(args->channel_args);
chand->user_agent = grpc_mdelem_from_metadata_strings(
- GRPC_MDSTR_USER_AGENT, user_agent_from_args(args->channel_args));
+ GRPC_MDSTR_USER_AGENT,
+ user_agent_from_args(args->channel_args,
+ args->optional_transport->vtable->name));
}
/* Destructor for channel data */
@@ -250,7 +276,7 @@ const grpc_channel_filter grpc_http_client_filter = {
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h
index a884b36318..47081175ea 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/core/lib/channel/http_client_filter.h
@@ -1,5 +1,4 @@
/*
- *
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -39,6 +38,7 @@
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_client_filter;
+/* Channel arg to override the http2 :scheme header */
#define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
#endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 43d71af473..d0beebd817 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -108,7 +108,7 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
} else {
/* TODO(klempner): We're currently allowing this, but we shouldn't
see it without a proxy so log for now. */
- gpr_log(GPR_INFO, "Unexpected content-type %s", value_str);
+ gpr_log(GPR_INFO, "Unexpected content-type '%s'", value_str);
}
return NULL;
} else if (md->key == GRPC_MDSTR_TE || md->key == GRPC_MDSTR_METHOD ||
@@ -142,10 +142,11 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
}
}
-static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *err) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- if (success) {
+ if (err == GRPC_ERROR_NONE) {
server_filter_args a;
a.elem = elem;
a.exec_ctx = exec_ctx;
@@ -157,27 +158,35 @@ static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
calld->seen_path && calld->seen_authority) {
/* do nothing */
} else {
+ err = GRPC_ERROR_CREATE("Bad incoming HTTP headers");
if (!calld->seen_path) {
- gpr_log(GPR_ERROR, "Missing :path header");
+ err = grpc_error_add_child(err,
+ GRPC_ERROR_CREATE("Missing :path header"));
}
if (!calld->seen_authority) {
- gpr_log(GPR_ERROR, "Missing :authority header");
+ err = grpc_error_add_child(
+ err, GRPC_ERROR_CREATE("Missing :authority header"));
}
if (!calld->seen_method) {
- gpr_log(GPR_ERROR, "Missing :method header");
+ err = grpc_error_add_child(err,
+ GRPC_ERROR_CREATE("Missing :method header"));
}
if (!calld->seen_scheme) {
- gpr_log(GPR_ERROR, "Missing :scheme header");
+ err = grpc_error_add_child(err,
+ GRPC_ERROR_CREATE("Missing :scheme header"));
}
if (!calld->seen_te_trailers) {
- gpr_log(GPR_ERROR, "Missing te trailers header");
+ err = grpc_error_add_child(
+ err, GRPC_ERROR_CREATE("Missing te: trailers header"));
}
/* Error this call out */
- success = 0;
grpc_call_element_send_cancel(exec_ctx, elem);
}
+ } else {
+ GRPC_ERROR_REF(err);
}
- calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+ calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, err);
+ GRPC_ERROR_UNREF(err);
}
static void hs_mutate_op(grpc_call_element *elem,
@@ -244,7 +253,7 @@ const grpc_channel_filter grpc_http_server_filter = {
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/lib/compression/compression_algorithm.c b/src/core/lib/compression/compression.c
index 820871d579..54efb5e855 100644
--- a/src/core/lib/compression/compression_algorithm.c
+++ b/src/core/lib/compression/compression.c
@@ -125,6 +125,28 @@ grpc_mdelem *grpc_compression_encoding_mdelem(
return NULL;
}
+void grpc_compression_options_init(grpc_compression_options *opts) {
+ memset(opts, 0, sizeof(*opts));
+ /* all enabled by default */
+ opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
+}
+
+void grpc_compression_options_enable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+void grpc_compression_options_disable_algorithm(
+ grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
+ GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
+}
+
+int grpc_compression_options_is_algorithm_enabled(
+ const grpc_compression_options *opts,
+ grpc_compression_algorithm algorithm) {
+ return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
+}
+
/* TODO(dgq): Add the ability to specify parameters to the individual
* compression algorithms */
grpc_compression_algorithm grpc_compression_algorithm_for_level(
@@ -180,25 +202,3 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
abort();
};
}
-
-void grpc_compression_options_init(grpc_compression_options *opts) {
- opts->enabled_algorithms_bitset = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
- opts->default_compression_algorithm = GRPC_COMPRESS_NONE;
-}
-
-void grpc_compression_options_enable_algorithm(
- grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
- GPR_BITSET(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-void grpc_compression_options_disable_algorithm(
- grpc_compression_options *opts, grpc_compression_algorithm algorithm) {
- GPR_BITCLEAR(&opts->enabled_algorithms_bitset, algorithm);
-}
-
-int grpc_compression_options_is_algorithm_enabled(
- const grpc_compression_options *opts,
- grpc_compression_algorithm algorithm) {
- if (algorithm >= GRPC_COMPRESS_ALGORITHMS_COUNT) return 0;
- return GPR_BITGET(opts->enabled_algorithms_bitset, algorithm);
-}
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index f22721ac8f..18135bcb58 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -39,12 +39,14 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
#include "src/core/lib/http/format_request.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/support/string.h"
@@ -59,16 +61,16 @@ typedef struct {
gpr_timespec deadline;
int have_read_byte;
const grpc_httpcli_handshaker *handshaker;
- grpc_httpcli_response_cb on_response;
- void *user_data;
+ grpc_closure *on_done;
grpc_httpcli_context *context;
- grpc_pollset *pollset;
+ grpc_polling_entity *pollent;
grpc_iomgr_object iomgr_obj;
gpr_slice_buffer incoming;
gpr_slice_buffer outgoing;
grpc_closure on_read;
grpc_closure done_write;
grpc_closure connected;
+ grpc_error *overall_error;
} internal_request;
static grpc_httpcli_get_override g_get_override = NULL;
@@ -76,6 +78,7 @@ static grpc_httpcli_post_override g_post_override = NULL;
static void plaintext_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint, const char *host,
+ gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx,
void *arg,
grpc_endpoint *endpoint)) {
@@ -93,14 +96,14 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
grpc_pollset_set_destroy(context->pollset_set);
}
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req);
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
+ grpc_error *due_to_error);
static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
- int success) {
- grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set,
- req->pollset);
- req->on_response(exec_ctx, req->user_data,
- success ? &req->parser.http.response : NULL);
+ grpc_error *error) {
+ grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent,
+ req->context->pollset_set);
+ grpc_exec_ctx_sched(exec_ctx, req->on_done, error, NULL);
grpc_http_parser_destroy(&req->parser);
if (req->addresses != NULL) {
grpc_resolved_addresses_destroy(req->addresses);
@@ -114,39 +117,49 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_iomgr_unregister_object(&req->iomgr_obj);
gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing);
+ GRPC_ERROR_UNREF(req->overall_error);
gpr_free(req);
}
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success);
+static void append_error(internal_request *req, grpc_error *error) {
+ if (req->overall_error == GRPC_ERROR_NONE) {
+ req->overall_error = GRPC_ERROR_CREATE("Failed HTTP/1 client request");
+ }
+ grpc_resolved_address *addr = &req->addresses->addrs[req->next_address - 1];
+ char *addr_text = grpc_sockaddr_to_uri((struct sockaddr *)addr->addr);
+ req->overall_error = grpc_error_add_child(
+ req->overall_error,
+ grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text));
+ gpr_free(addr_text);
+}
static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
}
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *error) {
internal_request *req = user_data;
size_t i;
for (i = 0; i < req->incoming.count; i++) {
if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
req->have_read_byte = 1;
- if (!grpc_http_parser_parse(&req->parser, req->incoming.slices[i])) {
- finish(exec_ctx, req, 0);
+ grpc_error *err =
+ grpc_http_parser_parse(&req->parser, req->incoming.slices[i]);
+ if (err != GRPC_ERROR_NONE) {
+ finish(exec_ctx, req, err);
return;
}
}
}
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
do_read(exec_ctx, req);
} else if (!req->have_read_byte) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
} else {
- int parse_success = grpc_http_parser_eof(&req->parser);
- if (parse_success && (req->parser.type != GRPC_HTTP_RESPONSE)) {
- parse_success = 0;
- }
- finish(exec_ctx, req, parse_success);
+ finish(exec_ctx, req, grpc_http_parser_eof(&req->parser));
}
}
@@ -154,12 +167,12 @@ static void on_written(grpc_exec_ctx *exec_ctx, internal_request *req) {
do_read(exec_ctx, req);
}
-static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void done_write(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
on_written(exec_ctx, req);
} else {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
}
}
@@ -174,7 +187,8 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
internal_request *req = arg;
if (!ep) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req,
+ GRPC_ERROR_CREATE("Unexplained handshake failure"));
return;
}
@@ -182,23 +196,30 @@ static void on_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
start_write(exec_ctx, req);
}
-static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void on_connected(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
internal_request *req = arg;
if (!req->ep) {
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_REF(error));
return;
}
req->handshaker->handshake(
exec_ctx, req, req->ep,
req->ssl_host_override ? req->ssl_host_override : req->host,
- on_handshake_done);
+ req->deadline, on_handshake_done);
}
-static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
+static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
+ grpc_error *error) {
grpc_resolved_address *addr;
+ if (error != GRPC_ERROR_NONE) {
+ append_error(req, error);
+ }
if (req->next_address == req->addresses->naddrs) {
- finish(exec_ctx, req, 0);
+ finish(exec_ctx, req,
+ GRPC_ERROR_CREATE_REFERENCING("Failed HTTP requests to all targets",
+ &req->overall_error, 1));
return;
}
addr = &req->addresses->addrs[req->next_address++];
@@ -208,34 +229,34 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
(struct sockaddr *)&addr->addr, addr->len, req->deadline);
}
-static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses) {
+static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg;
- if (!addresses) {
- finish(exec_ctx, req, 0);
+ if (error != GRPC_ERROR_NONE) {
+ finish(exec_ctx, req, error);
return;
}
- req->addresses = addresses;
req->next_address = 0;
- next_address(exec_ctx, req);
+ next_address(exec_ctx, req, GRPC_ERROR_NONE);
}
-static void internal_request_begin(
- grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_pollset *pollset, const grpc_httpcli_request *request,
- gpr_timespec deadline, grpc_httpcli_response_cb on_response,
- void *user_data, const char *name, gpr_slice request_text) {
+static void internal_request_begin(grpc_exec_ctx *exec_ctx,
+ grpc_httpcli_context *context,
+ grpc_polling_entity *pollent,
+ const grpc_httpcli_request *request,
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response,
+ const char *name, gpr_slice request_text) {
internal_request *req = gpr_malloc(sizeof(internal_request));
memset(req, 0, sizeof(*req));
req->request_text = request_text;
- grpc_http_parser_init(&req->parser);
- req->on_response = on_response;
- req->user_data = user_data;
+ grpc_http_parser_init(&req->parser, GRPC_HTTP_RESPONSE, response);
+ req->on_done = on_done;
req->deadline = deadline;
req->handshaker =
request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
req->context = context;
- req->pollset = pollset;
+ req->pollent = pollent;
+ req->overall_error = GRPC_ERROR_NONE;
grpc_closure_init(&req->on_read, on_read, req);
grpc_closure_init(&req->done_write, done_write, req);
gpr_slice_buffer_init(&req->incoming);
@@ -244,45 +265,46 @@ static void internal_request_begin(
req->host = gpr_strdup(request->host);
req->ssl_host_override = gpr_strdup(request->ssl_host_override);
- grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set,
- req->pollset);
+ GPR_ASSERT(pollent);
+ grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent,
+ req->context->pollset_set);
grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port,
- on_resolved, req);
+ grpc_closure_create(on_resolved, req), &req->addresses);
}
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data) {
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response) {
char *name;
if (g_get_override &&
- g_get_override(exec_ctx, request, deadline, on_response, user_data)) {
+ g_get_override(exec_ctx, request, deadline, on_done, response)) {
return;
}
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->http.path);
- internal_request_begin(exec_ctx, context, pollset, request, deadline,
- on_response, user_data, name,
+ internal_request_begin(exec_ctx, context, pollent, request, deadline, on_done,
+ response, name,
grpc_httpcli_format_get_request(request));
gpr_free(name);
}
void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data) {
+ gpr_timespec deadline, grpc_closure *on_done,
+ grpc_httpcli_response *response) {
char *name;
if (g_post_override &&
g_post_override(exec_ctx, request, body_bytes, body_size, deadline,
- on_response, user_data)) {
+ on_done, response)) {
return;
}
gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->http.path);
internal_request_begin(
- exec_ctx, context, pollset, request, deadline, on_response, user_data,
- name, grpc_httpcli_format_post_request(request, body_bytes, body_size));
+ exec_ctx, context, pollent, request, deadline, on_done, response, name,
+ grpc_httpcli_format_post_request(request, body_bytes, body_size));
gpr_free(name);
}
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index 11a32a125c..662e176f4c 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -41,6 +41,7 @@
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/iomgr/pollset_set.h"
/* User agent this library reports */
@@ -56,7 +57,7 @@ typedef struct grpc_httpcli_context {
typedef struct {
const char *default_port;
void (*handshake)(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *endpoint,
- const char *host,
+ const char *host, gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint));
} grpc_httpcli_handshaker;
@@ -81,11 +82,6 @@ typedef struct grpc_httpcli_request {
/* Expose the parser response type as a httpcli response too */
typedef struct grpc_http_response grpc_httpcli_response;
-/* Callback for grpc_httpcli_get and grpc_httpcli_post. */
-typedef void (*grpc_httpcli_response_cb)(grpc_exec_ctx *exec_ctx,
- void *user_data,
- const grpc_http_response *response);
-
void grpc_httpcli_context_init(grpc_httpcli_context *context);
void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
@@ -100,10 +96,10 @@ void grpc_httpcli_context_destroy(grpc_httpcli_context *context);
'on_response' is a callback to report results to (and 'user_data' is a user
supplied pointer to pass to said call) */
void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ gpr_timespec deadline, grpc_closure *on_complete,
+ grpc_httpcli_response *response);
/* Asynchronously perform a HTTP POST.
'context' specifies the http context under which to do the post
@@ -121,22 +117,22 @@ void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
supplied pointer to pass to said call)
Does not support ?var1=val1&var2=val2 in the path. */
void grpc_httpcli_post(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size,
- gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ gpr_timespec deadline, grpc_closure *on_complete,
+ grpc_httpcli_response *response);
/* override functions return 1 if they handled the request, 0 otherwise */
typedef int (*grpc_httpcli_get_override)(grpc_exec_ctx *exec_ctx,
const grpc_httpcli_request *request,
gpr_timespec deadline,
- grpc_httpcli_response_cb on_response,
- void *user_data);
+ grpc_closure *on_complete,
+ grpc_httpcli_response *response);
typedef int (*grpc_httpcli_post_override)(
grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
const char *body_bytes, size_t body_size, gpr_timespec deadline,
- grpc_httpcli_response_cb on_response, void *user_data);
+ grpc_closure *on_complete, grpc_httpcli_response *response);
void grpc_httpcli_set_override(grpc_httpcli_get_override get,
grpc_httpcli_post_override post);
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 5590928968..a57d93bb7b 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -61,6 +61,7 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
+ gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_httpcli_ssl_channel_security_connector *c =
@@ -79,7 +80,7 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
- nonsecure_endpoint, cb, user_data);
+ nonsecure_endpoint, deadline, cb, user_data);
}
}
@@ -163,6 +164,7 @@ static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *tcp, const char *host,
+ gpr_timespec deadline,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint)) {
grpc_channel_security_connector *sc = NULL;
@@ -181,7 +183,7 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK);
grpc_channel_security_connector_do_handshake(
- exec_ctx, sc, tcp, on_secure_transport_setup_done, c);
+ exec_ctx, sc, tcp, deadline, on_secure_transport_setup_done, c);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
}
diff --git a/src/core/lib/http/parser.c b/src/core/lib/http/parser.c
index 09b2ed40d1..92ed08ae51 100644
--- a/src/core/lib/http/parser.c
+++ b/src/core/lib/http/parser.c
@@ -48,37 +48,38 @@ static char *buf2str(void *buffer, size_t length) {
return out;
}
-static int handle_response_line(grpc_http_parser *parser) {
+static grpc_error *handle_response_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
- if (cur == end || *cur++ != 'H') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'P') goto error;
- if (cur == end || *cur++ != '/') goto error;
- if (cur == end || *cur++ != '1') goto error;
- if (cur == end || *cur++ != '.') goto error;
- if (cur == end || *cur < '0' || *cur++ > '1') goto error;
- if (cur == end || *cur++ != ' ') goto error;
- if (cur == end || *cur < '1' || *cur++ > '9') goto error;
- if (cur == end || *cur < '0' || *cur++ > '9') goto error;
- if (cur == end || *cur < '0' || *cur++ > '9') goto error;
- parser->http.response.status =
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
+ if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
+ if (cur == end || *cur < '0' || *cur++ > '1') {
+ return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
+ }
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+ if (cur == end || *cur < '1' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ parser->http.response->status =
(cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
- if (cur == end || *cur++ != ' ') goto error;
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
/* we don't really care about the status code message */
- return 1;
-
-error:
- if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing response line");
- return 0;
+ return GRPC_ERROR_NONE;
}
-static int handle_request_line(grpc_http_parser *parser) {
+static grpc_error *handle_request_line(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
@@ -87,84 +88,81 @@ static int handle_request_line(grpc_http_parser *parser) {
while (cur != end && *cur++ != ' ')
;
- if (cur == end) goto error;
- parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1));
+ if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
+ parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
beg = cur;
while (cur != end && *cur++ != ' ')
;
- if (cur == end) goto error;
- parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1));
-
- if (cur == end || *cur++ != 'H') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'T') goto error;
- if (cur == end || *cur++ != 'P') goto error;
- if (cur == end || *cur++ != '/') goto error;
+ if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
+ parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
vers_major = (uint8_t)(*cur++ - '1' + 1);
++cur;
- if (cur == end) goto error;
+ if (cur == end)
+ return GRPC_ERROR_CREATE("End of line in HTTP version string");
vers_minor = (uint8_t)(*cur++ - '1' + 1);
if (vers_major == 1) {
if (vers_minor == 0) {
- parser->http.request.version = GRPC_HTTP_HTTP10;
+ parser->http.request->version = GRPC_HTTP_HTTP10;
} else if (vers_minor == 1) {
- parser->http.request.version = GRPC_HTTP_HTTP11;
+ parser->http.request->version = GRPC_HTTP_HTTP11;
} else {
- goto error;
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else if (vers_major == 2) {
if (vers_minor == 0) {
- parser->http.request.version = GRPC_HTTP_HTTP20;
+ parser->http.request->version = GRPC_HTTP_HTTP20;
} else {
- goto error;
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
} else {
- goto error;
+ return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
}
- return 1;
-
-error:
- if (grpc_http1_trace) gpr_log(GPR_ERROR, "Failed parsing request line");
- return 0;
+ return GRPC_ERROR_NONE;
}
-static int handle_first_line(grpc_http_parser *parser) {
- if (parser->cur_line[0] == 'H') {
- parser->type = GRPC_HTTP_RESPONSE;
- return handle_response_line(parser);
- } else {
- parser->type = GRPC_HTTP_REQUEST;
- return handle_request_line(parser);
+static grpc_error *handle_first_line(grpc_http_parser *parser) {
+ switch (parser->type) {
+ case GRPC_HTTP_REQUEST:
+ return handle_request_line(parser);
+ case GRPC_HTTP_RESPONSE:
+ return handle_response_line(parser);
}
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
-static int add_header(grpc_http_parser *parser) {
+static grpc_error *add_header(grpc_http_parser *parser) {
uint8_t *beg = parser->cur_line;
uint8_t *cur = beg;
uint8_t *end = beg + parser->cur_line_length;
size_t *hdr_count = NULL;
grpc_http_header **hdrs = NULL;
grpc_http_header hdr = {NULL, NULL};
+ grpc_error *error = GRPC_ERROR_NONE;
GPR_ASSERT(cur != end);
if (*cur == ' ' || *cur == '\t') {
- if (grpc_http1_trace)
- gpr_log(GPR_ERROR, "Continued header lines not supported yet");
- goto error;
+ error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
+ goto done;
}
while (cur != end && *cur != ':') {
cur++;
}
if (cur == end) {
- if (grpc_http1_trace) {
- gpr_log(GPR_ERROR, "Didn't find ':' in header string");
- }
- goto error;
+ error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
+ goto done;
}
GPR_ASSERT(cur >= beg);
hdr.key = buf2str(beg, (size_t)(cur - beg));
@@ -176,14 +174,15 @@ static int add_header(grpc_http_parser *parser) {
GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
- if (parser->type == GRPC_HTTP_RESPONSE) {
- hdr_count = &parser->http.response.hdr_count;
- hdrs = &parser->http.response.hdrs;
- } else if (parser->type == GRPC_HTTP_REQUEST) {
- hdr_count = &parser->http.request.hdr_count;
- hdrs = &parser->http.request.hdrs;
- } else {
- return 0;
+ switch (parser->type) {
+ case GRPC_HTTP_RESPONSE:
+ hdr_count = &parser->http.response->hdr_count;
+ hdrs = &parser->http.response->hdrs;
+ break;
+ case GRPC_HTTP_REQUEST:
+ hdr_count = &parser->http.request->hdr_count;
+ hdrs = &parser->http.request->hdrs;
+ break;
}
if (*hdr_count == parser->hdr_capacity) {
@@ -192,20 +191,21 @@ static int add_header(grpc_http_parser *parser) {
*hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
}
(*hdrs)[(*hdr_count)++] = hdr;
- return 1;
-error:
- gpr_free(hdr.key);
- gpr_free(hdr.value);
- return 0;
+done:
+ if (error != GRPC_ERROR_NONE) {
+ gpr_free(hdr.key);
+ gpr_free(hdr.value);
+ }
+ return error;
}
-static int finish_line(grpc_http_parser *parser) {
+static grpc_error *finish_line(grpc_http_parser *parser) {
+ grpc_error *err;
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
- if (!handle_first_line(parser)) {
- return 0;
- }
+ err = handle_first_line(parser);
+ if (err != GRPC_ERROR_NONE) return err;
parser->state = GRPC_HTTP_HEADERS;
break;
case GRPC_HTTP_HEADERS:
@@ -213,30 +213,31 @@ static int finish_line(grpc_http_parser *parser) {
parser->state = GRPC_HTTP_BODY;
break;
}
- if (!add_header(parser)) {
- return 0;
+ err = add_header(parser);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
}
break;
case GRPC_HTTP_BODY:
- GPR_UNREACHABLE_CODE(return 0);
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
parser->cur_line_length = 0;
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
+static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
size_t *body_length = NULL;
char **body = NULL;
if (parser->type == GRPC_HTTP_RESPONSE) {
- body_length = &parser->http.response.body_length;
- body = &parser->http.response.body;
+ body_length = &parser->http.response->body_length;
+ body = &parser->http.response->body;
} else if (parser->type == GRPC_HTTP_REQUEST) {
- body_length = &parser->http.request.body_length;
- body = &parser->http.request.body;
+ body_length = &parser->http.request->body_length;
+ body = &parser->http.request->body;
} else {
- return 0;
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
}
if (*body_length == parser->body_capacity) {
@@ -246,34 +247,34 @@ static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
(*body)[*body_length] = (char)byte;
(*body_length)++;
- return 1;
+ return GRPC_ERROR_NONE;
}
-static int check_line(grpc_http_parser *parser) {
+static bool check_line(grpc_http_parser *parser) {
if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\r' &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
- return 1;
+ return true;
}
// HTTP request with \n\r line termiantors.
else if (parser->cur_line_length >= 2 &&
parser->cur_line[parser->cur_line_length - 2] == '\n' &&
parser->cur_line[parser->cur_line_length - 1] == '\r') {
- return 1;
+ return true;
}
// HTTP request with only \n line terminators.
else if (parser->cur_line_length >= 1 &&
parser->cur_line[parser->cur_line_length - 1] == '\n') {
parser->cur_line_end_length = 1;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
-static int addbyte(grpc_http_parser *parser, uint8_t byte) {
+static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
switch (parser->state) {
case GRPC_HTTP_FIRST_LINE:
case GRPC_HTTP_HEADERS:
@@ -288,7 +289,7 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
if (check_line(parser)) {
return finish_line(parser);
} else {
- return 1;
+ return GRPC_ERROR_NONE;
}
GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTP_BODY:
@@ -297,46 +298,53 @@ static int addbyte(grpc_http_parser *parser, uint8_t byte) {
GPR_UNREACHABLE_CODE(return 0);
}
-void grpc_http_parser_init(grpc_http_parser *parser) {
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response) {
memset(parser, 0, sizeof(*parser));
parser->state = GRPC_HTTP_FIRST_LINE;
- parser->type = GRPC_HTTP_UNKNOWN;
+ parser->type = type;
+ parser->http.request_or_response = request_or_response;
parser->cur_line_end_length = 2;
}
-void grpc_http_parser_destroy(grpc_http_parser *parser) {
+void grpc_http_parser_destroy(grpc_http_parser *parser) {}
+
+void grpc_http_request_destroy(grpc_http_request *request) {
size_t i;
- if (parser->type == GRPC_HTTP_RESPONSE) {
- gpr_free(parser->http.response.body);
- for (i = 0; i < parser->http.response.hdr_count; i++) {
- gpr_free(parser->http.response.hdrs[i].key);
- gpr_free(parser->http.response.hdrs[i].value);
- }
- gpr_free(parser->http.response.hdrs);
- } else if (parser->type == GRPC_HTTP_REQUEST) {
- gpr_free(parser->http.request.body);
- for (i = 0; i < parser->http.request.hdr_count; i++) {
- gpr_free(parser->http.request.hdrs[i].key);
- gpr_free(parser->http.request.hdrs[i].value);
- }
- gpr_free(parser->http.request.hdrs);
- gpr_free(parser->http.request.method);
- gpr_free(parser->http.request.path);
+ gpr_free(request->body);
+ for (i = 0; i < request->hdr_count; i++) {
+ gpr_free(request->hdrs[i].key);
+ gpr_free(request->hdrs[i].value);
}
+ gpr_free(request->hdrs);
+ gpr_free(request->method);
+ gpr_free(request->path);
}
-int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
+void grpc_http_response_destroy(grpc_http_response *response) {
+ size_t i;
+ gpr_free(response->body);
+ for (i = 0; i < response->hdr_count; i++) {
+ gpr_free(response->hdrs[i].key);
+ gpr_free(response->hdrs[i].value);
+ }
+ gpr_free(response->hdrs);
+}
+
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
size_t i;
for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
- if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
- return 0;
- }
+ grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
+ if (err != GRPC_ERROR_NONE) return err;
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-int grpc_http_parser_eof(grpc_http_parser *parser) {
- return parser->state == GRPC_HTTP_BODY;
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
+ if (parser->state != GRPC_HTTP_BODY) {
+ return GRPC_ERROR_CREATE("Did not finish headers");
+ }
+ return GRPC_ERROR_NONE;
}
diff --git a/src/core/lib/http/parser.c.orig b/src/core/lib/http/parser.c.orig
new file mode 100644
index 0000000000..74d90fd8bf
--- /dev/null
+++ b/src/core/lib/http/parser.c.orig
@@ -0,0 +1,357 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/http/parser.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+int grpc_http1_trace = 0;
+
+static char *buf2str(void *buffer, size_t length) {
+ char *out = gpr_malloc(length + 1);
+ memcpy(out, buffer, length);
+ out[length] = 0;
+ return out;
+}
+
+static grpc_error *handle_response_line(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'");
+ if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'");
+ if (cur == end || *cur < '0' || *cur++ > '1') {
+ return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1");
+ }
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+ if (cur == end || *cur < '1' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ if (cur == end || *cur < '0' || *cur++ > '9')
+ return GRPC_ERROR_CREATE("Expected status code");
+ parser->http.response->status =
+ (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
+ if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '");
+
+ /* we don't really care about the status code message */
+
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *handle_request_line(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+ uint8_t vers_major = 0;
+ uint8_t vers_minor = 0;
+
+ while (cur != end && *cur++ != ' ')
+ ;
+ if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line");
+ parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1));
+
+ beg = cur;
+ while (cur != end && *cur++ != ' ')
+ ;
+ if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line");
+ parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1));
+
+ if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'");
+ if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'");
+ if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'");
+ vers_major = (uint8_t)(*cur++ - '1' + 1);
+ ++cur;
+ if (cur == end)
+ return GRPC_ERROR_CREATE("End of line in HTTP version string");
+ vers_minor = (uint8_t)(*cur++ - '1' + 1);
+
+ if (vers_major == 1) {
+ if (vers_minor == 0) {
+ parser->http.request->version = GRPC_HTTP_HTTP10;
+ } else if (vers_minor == 1) {
+ parser->http.request->version = GRPC_HTTP_HTTP11;
+ } else {
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+ } else if (vers_major == 2) {
+ if (vers_minor == 0) {
+ parser->http.request->version = GRPC_HTTP_HTTP20;
+ } else {
+ return GRPC_ERROR_CREATE(
+ "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+ } else {
+ return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0");
+ }
+
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *handle_first_line(grpc_http_parser *parser) {
+ switch (parser->type) {
+ case GRPC_HTTP_REQUEST:
+ return handle_request_line(parser);
+ case GRPC_HTTP_RESPONSE:
+ return handle_response_line(parser);
+ }
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+}
+
+static grpc_error *add_header(grpc_http_parser *parser) {
+ uint8_t *beg = parser->cur_line;
+ uint8_t *cur = beg;
+ uint8_t *end = beg + parser->cur_line_length;
+ size_t *hdr_count = NULL;
+ grpc_http_header **hdrs = NULL;
+ grpc_http_header hdr = {NULL, NULL};
+ grpc_error *error = GRPC_ERROR_NONE;
+
+ GPR_ASSERT(cur != end);
+
+ if (*cur == ' ' || *cur == '\t') {
+ error = GRPC_ERROR_CREATE("Continued header lines not supported yet");
+ goto done;
+ }
+
+ while (cur != end && *cur != ':') {
+ cur++;
+ }
+ if (cur == end) {
+<<<<<<< HEAD
+ error = GRPC_ERROR_CREATE("Didn't find ':' in header string");
+ goto done;
+=======
+ if (grpc_http1_trace) {
+ gpr_log(GPR_ERROR, "Didn't find ':' in header string");
+ }
+ goto error;
+>>>>>>> a709afe241d8b264a1c326315f757b4a8d330207
+ }
+ GPR_ASSERT(cur >= beg);
+ hdr.key = buf2str(beg, (size_t)(cur - beg));
+ cur++; /* skip : */
+
+ while (cur != end && (*cur == ' ' || *cur == '\t')) {
+ cur++;
+ }
+ GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length);
+ hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length);
+
+ switch (parser->type) {
+ case GRPC_HTTP_RESPONSE:
+ hdr_count = &parser->http.response->hdr_count;
+ hdrs = &parser->http.response->hdrs;
+ break;
+ case GRPC_HTTP_REQUEST:
+ hdr_count = &parser->http.request->hdr_count;
+ hdrs = &parser->http.request->hdrs;
+ break;
+ }
+
+ if (*hdr_count == parser->hdr_capacity) {
+ parser->hdr_capacity =
+ GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
+ *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
+ }
+ (*hdrs)[(*hdr_count)++] = hdr;
+
+done:
+ if (error != GRPC_ERROR_NONE) {
+ gpr_free(hdr.key);
+ gpr_free(hdr.value);
+ }
+ return error;
+}
+
+static grpc_error *finish_line(grpc_http_parser *parser) {
+ grpc_error *err;
+ switch (parser->state) {
+ case GRPC_HTTP_FIRST_LINE:
+ err = handle_first_line(parser);
+ if (err != GRPC_ERROR_NONE) return err;
+ parser->state = GRPC_HTTP_HEADERS;
+ break;
+ case GRPC_HTTP_HEADERS:
+ if (parser->cur_line_length == parser->cur_line_end_length) {
+ parser->state = GRPC_HTTP_BODY;
+ break;
+ }
+ err = add_header(parser);
+ if (err != GRPC_ERROR_NONE) {
+ return err;
+ }
+ break;
+ case GRPC_HTTP_BODY:
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+ }
+
+ parser->cur_line_length = 0;
+ return GRPC_ERROR_NONE;
+}
+
+static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) {
+ size_t *body_length = NULL;
+ char **body = NULL;
+
+ if (parser->type == GRPC_HTTP_RESPONSE) {
+ body_length = &parser->http.response->body_length;
+ body = &parser->http.response->body;
+ } else if (parser->type == GRPC_HTTP_REQUEST) {
+ body_length = &parser->http.request->body_length;
+ body = &parser->http.request->body;
+ } else {
+ GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
+ }
+
+ if (*body_length == parser->body_capacity) {
+ parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
+ *body = gpr_realloc((void *)*body, parser->body_capacity);
+ }
+ (*body)[*body_length] = (char)byte;
+ (*body_length)++;
+
+ return GRPC_ERROR_NONE;
+}
+
+static bool check_line(grpc_http_parser *parser) {
+ if (parser->cur_line_length >= 2 &&
+ parser->cur_line[parser->cur_line_length - 2] == '\r' &&
+ parser->cur_line[parser->cur_line_length - 1] == '\n') {
+ return true;
+ }
+
+ // HTTP request with \n\r line termiantors.
+ else if (parser->cur_line_length >= 2 &&
+ parser->cur_line[parser->cur_line_length - 2] == '\n' &&
+ parser->cur_line[parser->cur_line_length - 1] == '\r') {
+ return true;
+ }
+
+ // HTTP request with only \n line terminators.
+ else if (parser->cur_line_length >= 1 &&
+ parser->cur_line[parser->cur_line_length - 1] == '\n') {
+ parser->cur_line_end_length = 1;
+ return true;
+ }
+
+ return false;
+}
+
+static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) {
+ switch (parser->state) {
+ case GRPC_HTTP_FIRST_LINE:
+ case GRPC_HTTP_HEADERS:
+ if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
+ if (grpc_http1_trace)
+ gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
+ GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
+ return 0;
+ }
+ parser->cur_line[parser->cur_line_length] = byte;
+ parser->cur_line_length++;
+ if (check_line(parser)) {
+ return finish_line(parser);
+ } else {
+ return GRPC_ERROR_NONE;
+ }
+ GPR_UNREACHABLE_CODE(return 0);
+ case GRPC_HTTP_BODY:
+ return addbyte_body(parser, byte);
+ }
+ GPR_UNREACHABLE_CODE(return 0);
+}
+
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response) {
+ memset(parser, 0, sizeof(*parser));
+ parser->state = GRPC_HTTP_FIRST_LINE;
+ parser->type = type;
+ parser->http.request_or_response = request_or_response;
+ parser->cur_line_end_length = 2;
+}
+
+void grpc_http_parser_destroy(grpc_http_parser *parser) {}
+
+void grpc_http_request_destroy(grpc_http_request *request) {
+ size_t i;
+ gpr_free(request->body);
+ for (i = 0; i < request->hdr_count; i++) {
+ gpr_free(request->hdrs[i].key);
+ gpr_free(request->hdrs[i].value);
+ }
+ gpr_free(request->hdrs);
+ gpr_free(request->method);
+ gpr_free(request->path);
+}
+
+void grpc_http_response_destroy(grpc_http_response *response) {
+ size_t i;
+ gpr_free(response->body);
+ for (i = 0; i < response->hdr_count; i++) {
+ gpr_free(response->hdrs[i].key);
+ gpr_free(response->hdrs[i].value);
+ }
+ gpr_free(response->hdrs);
+}
+
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
+ size_t i;
+
+ for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
+ grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]);
+ if (err != GRPC_ERROR_NONE) return err;
+ }
+
+ return GRPC_ERROR_NONE;
+}
+
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) {
+ if (parser->state != GRPC_HTTP_BODY) {
+ return GRPC_ERROR_CREATE("Did not finish headers");
+ }
+ return GRPC_ERROR_NONE;
+}
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
index 536637e9a2..6df3cc8b13 100644
--- a/src/core/lib/http/parser.h
+++ b/src/core/lib/http/parser.h
@@ -36,6 +36,7 @@
#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' */
#define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096
@@ -61,7 +62,6 @@ typedef enum {
typedef enum {
GRPC_HTTP_RESPONSE,
GRPC_HTTP_REQUEST,
- GRPC_HTTP_UNKNOWN
} grpc_http_type;
/* A request */
@@ -97,8 +97,9 @@ typedef struct {
grpc_http_type type;
union {
- grpc_http_response response;
- grpc_http_request request;
+ grpc_http_response *response;
+ grpc_http_request *request;
+ void *request_or_response;
} http;
size_t body_capacity;
size_t hdr_capacity;
@@ -108,11 +109,15 @@ typedef struct {
size_t cur_line_end_length;
} grpc_http_parser;
-void grpc_http_parser_init(grpc_http_parser *parser);
+void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type,
+ void *request_or_response);
void grpc_http_parser_destroy(grpc_http_parser *parser);
-int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
-int grpc_http_parser_eof(grpc_http_parser *parser);
+grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice);
+grpc_error *grpc_http_parser_eof(grpc_http_parser *parser);
+
+void grpc_http_request_destroy(grpc_http_request *request);
+void grpc_http_response_destroy(grpc_http_response *response);
extern int grpc_http1_trace;
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index 27793c32e4..0b6c3b2539 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -39,25 +39,32 @@ void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg) {
closure->cb = cb;
closure->cb_arg = cb_arg;
- closure->final_data = 0;
}
-void grpc_closure_list_add(grpc_closure_list *closure_list,
- grpc_closure *closure, bool success) {
- if (closure == NULL) return;
- closure->final_data = (success != 0);
+void grpc_closure_list_append(grpc_closure_list *closure_list,
+ grpc_closure *closure, grpc_error *error) {
+ if (closure == NULL) {
+ GRPC_ERROR_UNREF(error);
+ return;
+ }
+ closure->error = error;
+ closure->next_data.next = NULL;
if (closure_list->head == NULL) {
closure_list->head = closure;
} else {
- closure_list->tail->final_data |= (uintptr_t)closure;
+ closure_list->tail->next_data.next = closure;
}
closure_list->tail = closure;
}
-void grpc_closure_list_fail_all(grpc_closure_list *list) {
- for (grpc_closure *c = list->head; c != NULL; c = grpc_closure_next(c)) {
- c->final_data &= ~(uintptr_t)1;
+void grpc_closure_list_fail_all(grpc_closure_list *list,
+ grpc_error *forced_failure) {
+ for (grpc_closure *c = list->head; c != NULL; c = c->next_data.next) {
+ if (c->error == GRPC_ERROR_NONE) {
+ c->error = GRPC_ERROR_REF(forced_failure);
+ }
}
+ GRPC_ERROR_UNREF(forced_failure);
}
bool grpc_closure_list_empty(grpc_closure_list closure_list) {
@@ -71,7 +78,7 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) {
if (dst->head == NULL) {
*dst = *src;
} else {
- dst->tail->final_data |= (uintptr_t)src->head;
+ dst->tail->next_data.next = src->head;
dst->tail = src->tail;
}
src->head = src->tail = NULL;
@@ -83,12 +90,13 @@ typedef struct {
grpc_closure wrapper;
} wrapped_closure;
-static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
wrapped_closure *wc = arg;
grpc_iomgr_cb_func cb = wc->cb;
void *cb_arg = wc->cb_arg;
gpr_free(wc);
- cb(exec_ctx, cb_arg, success);
+ cb(exec_ctx, cb_arg, error);
}
grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
@@ -98,7 +106,3 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
return &wc->wrapper;
}
-
-grpc_closure *grpc_closure_next(grpc_closure *closure) {
- return (grpc_closure *)(closure->final_data & ~(uintptr_t)1);
-}
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index fdc2daed9d..08e59a168e 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -36,6 +36,7 @@
#include <grpc/support/port_platform.h>
#include <stdbool.h>
+#include "src/core/lib/iomgr/error.h"
struct grpc_closure;
typedef struct grpc_closure grpc_closure;
@@ -52,10 +53,10 @@ typedef struct grpc_closure_list {
/** gRPC Callback definition.
*
* \param arg Arbitrary input.
- * \param success An indication on the state of the iomgr. On false, cleanup
- * actions should be taken (eg, shutdown). */
+ * \param error GRPC_ERROR_NONE if no error occurred, otherwise some grpc_error
+ * describing what went wrong */
typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
- bool success);
+ grpc_error *error);
/** A closure over a grpc_iomgr_cb_func. */
struct grpc_closure {
@@ -65,10 +66,15 @@ struct grpc_closure {
/** Arguments to be passed to "cb". */
void *cb_arg;
- /** Once enqueued, contains in the lower bit the success of the closure,
- and in the upper bits the pointer to the next closure in the list.
- Before enqueing for execution, this is usable for scratch data. */
- uintptr_t final_data;
+ /** Once queued, the result of the closure. Before then: scratch space */
+ grpc_error *error;
+
+ /** Once queued, next indicates the next queued closure; before then, scratch
+ * space */
+ union {
+ grpc_closure *next;
+ uintptr_t scratch;
+ } next_data;
};
/** Initializes \a closure with \a cb and \a cb_arg. */
@@ -81,13 +87,14 @@ grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
#define GRPC_CLOSURE_LIST_INIT \
{ NULL, NULL }
-/** add \a closure to the end of \a list and set \a closure's success to \a
- * success */
-void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure,
- bool success);
+/** add \a closure to the end of \a list
+ and set \a closure's result to \a error */
+void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
+ grpc_error *error);
/** force all success bits in \a list to false */
-void grpc_closure_list_fail_all(grpc_closure_list *list);
+void grpc_closure_list_fail_all(grpc_closure_list *list,
+ grpc_error *forced_failure);
/** append all closures from \a src to \a dst and empty \a src. */
void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
@@ -95,7 +102,4 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
/** return whether \a list is empty. */
bool grpc_closure_list_empty(grpc_closure_list list);
-/** return the next pointer for a queued closure list */
-grpc_closure *grpc_closure_next(grpc_closure *closure);
-
#endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 3877ceb1e2..f9808bbda1 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -82,7 +82,7 @@ char *grpc_endpoint_get_peer(grpc_endpoint *ep);
void grpc_endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer *slices, grpc_closure *cb);
-/* Causes any pending read/write callbacks to run immediately with
+/* Causes any pending and future read/write callbacks to run immediately with
success==0 */
void grpc_endpoint_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
void grpc_endpoint_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep);
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c
index e0ce47c773..e295fb4867 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.c
+++ b/src/core/lib/iomgr/endpoint_pair_posix.c
@@ -58,8 +58,8 @@ static void create_sockets(int sv[2]) {
GPR_ASSERT(fcntl(sv[0], F_SETFL, flags | O_NONBLOCK) == 0);
flags = fcntl(sv[1], F_GETFL, 0);
GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
- GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]));
- GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]));
+ GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[0]) == GRPC_ERROR_NONE);
+ GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
new file mode 100644
index 0000000000..540fb4fa7e
--- /dev/null
+++ b/src/core/lib/iomgr/error.c
@@ -0,0 +1,535 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/error.h"
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/avl.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
+
+#ifdef GPR_WINDOWS
+#include <grpc/support/log_windows.h>
+#endif
+
+static void destroy_integer(void *key) {}
+
+static void *copy_integer(void *key) { return key; }
+
+static long compare_integers(void *key1, void *key2) {
+ return GPR_ICMP((uintptr_t)key1, (uintptr_t)key2);
+}
+
+static void destroy_string(void *str) { gpr_free(str); }
+
+static void *copy_string(void *str) { return gpr_strdup(str); }
+
+static void destroy_err(void *err) { GRPC_ERROR_UNREF(err); }
+
+static void *copy_err(void *err) { return GRPC_ERROR_REF(err); }
+
+static void destroy_time(void *tm) { gpr_free(tm); }
+
+static gpr_timespec *box_time(gpr_timespec tm) {
+ gpr_timespec *out = gpr_malloc(sizeof(*out));
+ *out = tm;
+ return out;
+}
+
+static void *copy_time(void *tm) { return box_time(*(gpr_timespec *)tm); }
+
+static const gpr_avl_vtable avl_vtable_ints = {destroy_integer, copy_integer,
+ compare_integers,
+ destroy_integer, copy_integer};
+
+static const gpr_avl_vtable avl_vtable_strs = {destroy_integer, copy_integer,
+ compare_integers, destroy_string,
+ copy_string};
+
+static const gpr_avl_vtable avl_vtable_times = {
+ destroy_integer, copy_integer, compare_integers, destroy_time, copy_time};
+
+static const gpr_avl_vtable avl_vtable_errs = {
+ destroy_integer, copy_integer, compare_integers, destroy_err, copy_err};
+
+static const char *error_int_name(grpc_error_ints key) {
+ switch (key) {
+ case GRPC_ERROR_INT_ERRNO:
+ return "errno";
+ case GRPC_ERROR_INT_FILE_LINE:
+ return "file_line";
+ case GRPC_ERROR_INT_STREAM_ID:
+ return "stream_id";
+ case GRPC_ERROR_INT_GRPC_STATUS:
+ return "grpc_status";
+ case GRPC_ERROR_INT_OFFSET:
+ return "offset";
+ case GRPC_ERROR_INT_INDEX:
+ return "index";
+ case GRPC_ERROR_INT_SIZE:
+ return "size";
+ case GRPC_ERROR_INT_HTTP2_ERROR:
+ return "http2_error";
+ case GRPC_ERROR_INT_TSI_CODE:
+ return "tsi_code";
+ case GRPC_ERROR_INT_SECURITY_STATUS:
+ return "security_status";
+ case GRPC_ERROR_INT_FD:
+ return "fd";
+ case GRPC_ERROR_INT_WSA_ERROR:
+ return "wsa_error";
+ case GRPC_ERROR_INT_HTTP_STATUS:
+ return "http_status";
+ }
+ GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+static const char *error_str_name(grpc_error_strs key) {
+ switch (key) {
+ case GRPC_ERROR_STR_DESCRIPTION:
+ return "description";
+ case GRPC_ERROR_STR_OS_ERROR:
+ return "os_error";
+ case GRPC_ERROR_STR_TARGET_ADDRESS:
+ return "target_address";
+ case GRPC_ERROR_STR_SYSCALL:
+ return "syscall";
+ case GRPC_ERROR_STR_FILE:
+ return "file";
+ case GRPC_ERROR_STR_GRPC_MESSAGE:
+ return "grpc_message";
+ case GRPC_ERROR_STR_RAW_BYTES:
+ return "raw_bytes";
+ case GRPC_ERROR_STR_TSI_ERROR:
+ return "tsi_error";
+ case GRPC_ERROR_STR_FILENAME:
+ return "filename";
+ }
+ GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+static const char *error_time_name(grpc_error_times key) {
+ switch (key) {
+ case GRPC_ERROR_TIME_CREATED:
+ return "created";
+ }
+ GPR_UNREACHABLE_CODE(return "unknown");
+}
+
+struct grpc_error {
+ gpr_refcount refs;
+ gpr_avl ints;
+ gpr_avl strs;
+ gpr_avl times;
+ gpr_avl errs;
+ uintptr_t next_err;
+};
+
+static bool is_special(grpc_error *err) {
+ return err == GRPC_ERROR_NONE || err == GRPC_ERROR_OOM ||
+ err == GRPC_ERROR_CANCELLED;
+}
+
+#ifdef GRPC_ERROR_REFCOUNT_DEBUG
+grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
+ const char *func) {
+ if (is_special(err)) return err;
+ gpr_log(GPR_DEBUG, "%p: %d -> %d [%s:%d %s]", err, err->refs.count,
+ err->refs.count + 1, file, line, func);
+ gpr_ref(&err->refs);
+ return err;
+}
+#else
+grpc_error *grpc_error_ref(grpc_error *err) {
+ if (is_special(err)) return err;
+ gpr_ref(&err->refs);
+ return err;
+}
+#endif
+
+static void error_destroy(grpc_error *err) {
+ GPR_ASSERT(!is_special(err));
+ gpr_avl_unref(err->ints);
+ gpr_avl_unref(err->strs);
+ gpr_avl_unref(err->errs);
+ gpr_avl_unref(err->times);
+ gpr_free(err);
+}
+
+#ifdef GRPC_ERROR_REFCOUNT_DEBUG
+void grpc_error_unref(grpc_error *err, const char *file, int line,
+ const char *func) {
+ if (is_special(err)) return;
+ gpr_log(GPR_DEBUG, "%p: %d -> %d [%s:%d %s]", err, err->refs.count,
+ err->refs.count - 1, file, line, func);
+ if (gpr_unref(&err->refs)) {
+ error_destroy(err);
+ }
+}
+#else
+void grpc_error_unref(grpc_error *err) {
+ if (is_special(err)) return;
+ if (gpr_unref(&err->refs)) {
+ error_destroy(err);
+ }
+}
+#endif
+
+grpc_error *grpc_error_create(const char *file, int line, const char *desc,
+ grpc_error **referencing,
+ size_t num_referencing) {
+ grpc_error *err = gpr_malloc(sizeof(*err));
+ if (err == NULL) { // TODO(ctiller): make gpr_malloc return NULL
+ return GRPC_ERROR_OOM;
+ }
+#ifdef GRPC_ERROR_REFCOUNT_DEBUG
+ gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
+#endif
+ err->ints = gpr_avl_add(gpr_avl_create(&avl_vtable_ints),
+ (void *)(uintptr_t)GRPC_ERROR_INT_FILE_LINE,
+ (void *)(uintptr_t)line);
+ err->strs = gpr_avl_add(
+ gpr_avl_add(gpr_avl_create(&avl_vtable_strs),
+ (void *)(uintptr_t)GRPC_ERROR_STR_FILE, gpr_strdup(file)),
+ (void *)(uintptr_t)GRPC_ERROR_STR_DESCRIPTION, gpr_strdup(desc));
+ err->errs = gpr_avl_create(&avl_vtable_errs);
+ err->next_err = 0;
+ for (size_t i = 0; i < num_referencing; i++) {
+ if (referencing[i] == GRPC_ERROR_NONE) continue;
+ err->errs = gpr_avl_add(err->errs, (void *)(err->next_err++),
+ GRPC_ERROR_REF(referencing[i]));
+ }
+ err->times = gpr_avl_add(gpr_avl_create(&avl_vtable_times),
+ (void *)(uintptr_t)GRPC_ERROR_TIME_CREATED,
+ box_time(gpr_now(GPR_CLOCK_REALTIME)));
+ gpr_ref_init(&err->refs, 1);
+ return err;
+}
+
+static grpc_error *copy_error_and_unref(grpc_error *in) {
+ if (is_special(in)) {
+ if (in == GRPC_ERROR_NONE) return GRPC_ERROR_CREATE("no error");
+ if (in == GRPC_ERROR_OOM) return GRPC_ERROR_CREATE("oom");
+ if (in == GRPC_ERROR_CANCELLED) return GRPC_ERROR_CREATE("cancelled");
+ return GRPC_ERROR_CREATE("unknown");
+ }
+ grpc_error *out = gpr_malloc(sizeof(*out));
+#ifdef GRPC_ERROR_REFCOUNT_DEBUG
+ gpr_log(GPR_DEBUG, "%p create copying", out);
+#endif
+ out->ints = gpr_avl_ref(in->ints);
+ out->strs = gpr_avl_ref(in->strs);
+ out->errs = gpr_avl_ref(in->errs);
+ out->times = gpr_avl_ref(in->times);
+ out->next_err = in->next_err;
+ gpr_ref_init(&out->refs, 1);
+ GRPC_ERROR_UNREF(in);
+ return out;
+}
+
+grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
+ intptr_t value) {
+ grpc_error *new = copy_error_and_unref(src);
+ new->ints = gpr_avl_add(new->ints, (void *)(uintptr_t)which, (void *)value);
+ return new;
+}
+
+bool grpc_error_get_int(grpc_error *err, grpc_error_ints which, intptr_t *p) {
+ void *pp;
+ if (gpr_avl_maybe_get(err->ints, (void *)(uintptr_t)which, &pp)) {
+ if (p != NULL) *p = (intptr_t)pp;
+ return true;
+ }
+ return false;
+}
+
+grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
+ const char *value) {
+ grpc_error *new = copy_error_and_unref(src);
+ new->strs =
+ gpr_avl_add(new->strs, (void *)(uintptr_t)which, gpr_strdup(value));
+ return new;
+}
+
+grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child) {
+ grpc_error *new = copy_error_and_unref(src);
+ new->errs = gpr_avl_add(new->errs, (void *)(new->next_err++), child);
+ return new;
+}
+
+static const char *no_error_string = "null";
+static const char *oom_error_string = "\"Out of memory\"";
+static const char *cancelled_error_string = "\"Cancelled\"";
+
+typedef struct {
+ char *key;
+ char *value;
+} kv_pair;
+
+typedef struct {
+ kv_pair *kvs;
+ size_t num_kvs;
+ size_t cap_kvs;
+} kv_pairs;
+
+static void append_kv(kv_pairs *kvs, char *key, char *value) {
+ if (kvs->num_kvs == kvs->cap_kvs) {
+ kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
+ kvs->kvs = gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs);
+ }
+ kvs->kvs[kvs->num_kvs].key = key;
+ kvs->kvs[kvs->num_kvs].value = value;
+ kvs->num_kvs++;
+}
+
+static void collect_kvs(gpr_avl_node *node, char *key(void *k),
+ char *fmt(void *v), kv_pairs *kvs) {
+ if (node == NULL) return;
+ append_kv(kvs, key(node->key), fmt(node->value));
+ collect_kvs(node->left, key, fmt, kvs);
+ collect_kvs(node->right, key, fmt, kvs);
+}
+
+static char *key_int(void *p) {
+ return gpr_strdup(error_int_name((grpc_error_ints)(uintptr_t)p));
+}
+
+static char *key_str(void *p) {
+ return gpr_strdup(error_str_name((grpc_error_strs)(uintptr_t)p));
+}
+
+static char *key_time(void *p) {
+ return gpr_strdup(error_time_name((grpc_error_times)(uintptr_t)p));
+}
+
+static char *fmt_int(void *p) {
+ char *s;
+ gpr_asprintf(&s, "%" PRIdPTR, (intptr_t)p);
+ return s;
+}
+
+static void append_chr(char c, char **s, size_t *sz, size_t *cap) {
+ if (*sz == *cap) {
+ *cap = GPR_MAX(8, 3 * *cap / 2);
+ *s = gpr_realloc(*s, *cap);
+ }
+ (*s)[(*sz)++] = c;
+}
+
+static void append_str(const char *str, char **s, size_t *sz, size_t *cap) {
+ for (const char *c = str; *c; c++) {
+ append_chr(*c, s, sz, cap);
+ }
+}
+
+static void append_esc_str(const char *str, char **s, size_t *sz, size_t *cap) {
+ static const char *hex = "0123456789abcdef";
+ append_chr('"', s, sz, cap);
+ for (const uint8_t *c = (const uint8_t *)str; *c; c++) {
+ if (*c < 32 || *c >= 127) {
+ append_chr('\\', s, sz, cap);
+ switch (*c) {
+ case '\b':
+ append_chr('b', s, sz, cap);
+ break;
+ case '\f':
+ append_chr('f', s, sz, cap);
+ break;
+ case '\n':
+ append_chr('n', s, sz, cap);
+ break;
+ case '\r':
+ append_chr('r', s, sz, cap);
+ break;
+ case '\t':
+ append_chr('t', s, sz, cap);
+ break;
+ default:
+ append_chr('u', s, sz, cap);
+ append_chr('0', s, sz, cap);
+ append_chr('0', s, sz, cap);
+ append_chr(hex[*c >> 4], s, sz, cap);
+ append_chr(hex[*c & 0x0f], s, sz, cap);
+ break;
+ }
+ } else {
+ append_chr((char)*c, s, sz, cap);
+ }
+ }
+ append_chr('"', s, sz, cap);
+}
+
+static char *fmt_str(void *p) {
+ char *s = NULL;
+ size_t sz = 0;
+ size_t cap = 0;
+ append_esc_str(p, &s, &sz, &cap);
+ append_chr(0, &s, &sz, &cap);
+ return s;
+}
+
+static char *fmt_time(void *p) {
+ gpr_timespec tm = *(gpr_timespec *)p;
+ char *out;
+ char *pfx = "!!";
+ switch (tm.clock_type) {
+ case GPR_CLOCK_MONOTONIC:
+ pfx = "@monotonic:";
+ break;
+ case GPR_CLOCK_REALTIME:
+ pfx = "@";
+ break;
+ case GPR_CLOCK_PRECISE:
+ pfx = "@precise:";
+ break;
+ case GPR_TIMESPAN:
+ pfx = "";
+ break;
+ }
+ gpr_asprintf(&out, "\"%s%" PRId64 ".%09d\"", pfx, tm.tv_sec, tm.tv_nsec);
+ return out;
+}
+
+static void add_errs(gpr_avl_node *n, char **s, size_t *sz, size_t *cap) {
+ if (n == NULL) return;
+ add_errs(n->left, s, sz, cap);
+ const char *e = grpc_error_string(n->value);
+ append_str(e, s, sz, cap);
+ grpc_error_free_string(e);
+ add_errs(n->right, s, sz, cap);
+}
+
+static char *errs_string(grpc_error *err) {
+ char *s = NULL;
+ size_t sz = 0;
+ size_t cap = 0;
+ append_chr('[', &s, &sz, &cap);
+ add_errs(err->errs.root, &s, &sz, &cap);
+ append_chr(']', &s, &sz, &cap);
+ append_chr(0, &s, &sz, &cap);
+ return s;
+}
+
+static int cmp_kvs(const void *a, const void *b) {
+ const kv_pair *ka = a;
+ const kv_pair *kb = b;
+ return strcmp(ka->key, kb->key);
+}
+
+static const char *finish_kvs(kv_pairs *kvs) {
+ char *s = NULL;
+ size_t sz = 0;
+ size_t cap = 0;
+
+ append_chr('{', &s, &sz, &cap);
+ for (size_t i = 0; i < kvs->num_kvs; i++) {
+ if (i != 0) append_chr(',', &s, &sz, &cap);
+ append_esc_str(kvs->kvs[i].key, &s, &sz, &cap);
+ gpr_free(kvs->kvs[i].key);
+ append_chr(':', &s, &sz, &cap);
+ append_str(kvs->kvs[i].value, &s, &sz, &cap);
+ gpr_free(kvs->kvs[i].value);
+ }
+ append_chr('}', &s, &sz, &cap);
+ append_chr(0, &s, &sz, &cap);
+
+ gpr_free(kvs->kvs);
+ return s;
+}
+
+void grpc_error_free_string(const char *str) {
+ if (str == no_error_string) return;
+ if (str == oom_error_string) return;
+ if (str == cancelled_error_string) return;
+ gpr_free((char *)str);
+}
+
+const char *grpc_error_string(grpc_error *err) {
+ if (err == GRPC_ERROR_NONE) return no_error_string;
+ if (err == GRPC_ERROR_OOM) return oom_error_string;
+ if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
+
+ kv_pairs kvs;
+ memset(&kvs, 0, sizeof(kvs));
+
+ collect_kvs(err->ints.root, key_int, fmt_int, &kvs);
+ collect_kvs(err->strs.root, key_str, fmt_str, &kvs);
+ collect_kvs(err->times.root, key_time, fmt_time, &kvs);
+ if (!gpr_avl_is_empty(err->errs)) {
+ append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
+ }
+
+ qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
+
+ return finish_kvs(&kvs);
+}
+
+grpc_error *grpc_os_error(const char *file, int line, int err,
+ const char *call_name) {
+ return grpc_error_set_str(
+ grpc_error_set_str(
+ grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
+ GRPC_ERROR_INT_ERRNO, err),
+ GRPC_ERROR_STR_OS_ERROR, strerror(err)),
+ GRPC_ERROR_STR_SYSCALL, call_name);
+}
+
+#ifdef GPR_WINDOWS
+grpc_error *grpc_wsa_error(const char *file, int line, int err,
+ const char *call_name) {
+ char *utf8_message = gpr_format_message(err);
+ grpc_error *error = grpc_error_set_str(
+ grpc_error_set_str(
+ grpc_error_set_int(grpc_error_create(file, line, "OS Error", NULL, 0),
+ GRPC_ERROR_INT_WSA_ERROR, err),
+ GRPC_ERROR_STR_OS_ERROR, utf8_message),
+ GRPC_ERROR_STR_SYSCALL, call_name);
+ gpr_free(utf8_message);
+ return error;
+}
+#endif
+
+bool grpc_log_if_error(const char *what, grpc_error *error, const char *file,
+ int line) {
+ if (error == GRPC_ERROR_NONE) return true;
+ const char *msg = grpc_error_string(error);
+ gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(error);
+ return false;
+}
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
new file mode 100644
index 0000000000..69cdf3028e
--- /dev/null
+++ b/src/core/lib/iomgr/error.h
@@ -0,0 +1,192 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_ERROR_H
+#define GRPC_CORE_LIB_IOMGR_ERROR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <grpc/support/time.h>
+
+/// Opaque representation of an error.
+/// Errors are refcounted objects that represent the result of an operation.
+/// Ownership laws:
+/// if a grpc_error is returned by a function, the caller owns a ref to that
+/// instance
+/// if a grpc_error is passed to a grpc_closure callback function (functions
+/// with the signature:
+/// void (*f)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error))
+/// then those functions do not automatically own a ref to error
+/// if a grpc_error is passed to *ANY OTHER FUNCTION* then that function takes
+/// ownership of the error
+/// Errors have:
+/// a set of ints, strings, and timestamps that describe the error
+/// always present are:
+/// GRPC_ERROR_STR_FILE, GRPC_ERROR_INT_FILE_LINE - source location the error
+/// was generated
+/// GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error
+/// GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened
+/// an error can also have children; these are other errors that are believed
+/// to have contributed to this one. By accumulating children, we can begin
+/// to root cause high level failures from low level failures, without having
+/// to derive execution paths from log lines
+typedef struct grpc_error grpc_error;
+
+typedef enum {
+ /// 'errno' from the operating system
+ GRPC_ERROR_INT_ERRNO,
+ /// __LINE__ from the call site creating the error
+ GRPC_ERROR_INT_FILE_LINE,
+ /// stream identifier: for errors that are associated with an individual
+ /// wire stream
+ GRPC_ERROR_INT_STREAM_ID,
+ /// grpc status code representing this error
+ GRPC_ERROR_INT_GRPC_STATUS,
+ /// offset into some binary blob (usually represented by
+ /// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
+ GRPC_ERROR_INT_OFFSET,
+ /// context sensitive index associated with the error
+ GRPC_ERROR_INT_INDEX,
+ /// context sensitive size associated with the error
+ GRPC_ERROR_INT_SIZE,
+ /// http2 error code associated with the error (see the HTTP2 RFC)
+ GRPC_ERROR_INT_HTTP2_ERROR,
+ /// TSI status code associated with the error
+ GRPC_ERROR_INT_TSI_CODE,
+ /// grpc_security_status associated with the error
+ GRPC_ERROR_INT_SECURITY_STATUS,
+ /// WSAGetLastError() reported when this error occurred
+ GRPC_ERROR_INT_WSA_ERROR,
+ /// File descriptor associated with this error
+ GRPC_ERROR_INT_FD,
+ /// HTTP status (i.e. 404)
+ GRPC_ERROR_INT_HTTP_STATUS,
+} grpc_error_ints;
+
+typedef enum {
+ /// top-level textual description of this error
+ GRPC_ERROR_STR_DESCRIPTION,
+ /// source file in which this error occurred
+ GRPC_ERROR_STR_FILE,
+ /// operating system description of this error
+ GRPC_ERROR_STR_OS_ERROR,
+ /// syscall that generated this error
+ GRPC_ERROR_STR_SYSCALL,
+ /// peer that we were trying to communicate when this error occurred
+ GRPC_ERROR_STR_TARGET_ADDRESS,
+ /// grpc status message associated with this error
+ GRPC_ERROR_STR_GRPC_MESSAGE,
+ /// hex dump (or similar) with the data that generated this error
+ GRPC_ERROR_STR_RAW_BYTES,
+ /// tsi error string associated with this error
+ GRPC_ERROR_STR_TSI_ERROR,
+ /// filename that we were trying to read/write when this error occurred
+ GRPC_ERROR_STR_FILENAME,
+} grpc_error_strs;
+
+typedef enum {
+ /// timestamp of error creation
+ GRPC_ERROR_TIME_CREATED,
+} grpc_error_times;
+
+#define GRPC_ERROR_NONE ((grpc_error *)NULL)
+#define GRPC_ERROR_OOM ((grpc_error *)1)
+#define GRPC_ERROR_CANCELLED ((grpc_error *)2)
+
+const char *grpc_error_string(grpc_error *error);
+void grpc_error_free_string(const char *str);
+
+/// Create an error - but use GRPC_ERROR_CREATE instead
+grpc_error *grpc_error_create(const char *file, int line, const char *desc,
+ grpc_error **referencing, size_t num_referencing);
+/// Create an error (this is the preferred way of generating an error that is
+/// not due to a system call - for system calls, use GRPC_OS_ERROR or
+/// GRPC_WSA_ERROR as appropriate)
+/// \a referencing is an array of num_referencing elements indicating one or
+/// more errors that are believed to have contributed to this one
+/// err = grpc_error_create(x, y, z, r, nr) is equivalent to:
+/// err = grpc_error_create(x, y, z, NULL, 0);
+/// for (i=0; i<nr; i++) err = grpc_error_add_child(err, r[i]);
+#define GRPC_ERROR_CREATE(desc) \
+ grpc_error_create(__FILE__, __LINE__, desc, NULL, 0)
+
+// Create an error that references some other errors. This function adds a
+// reference to each error in errs - it does not consume an existing reference
+#define GRPC_ERROR_CREATE_REFERENCING(desc, errs, count) \
+ grpc_error_create(__FILE__, __LINE__, desc, errs, count)
+
+//#define GRPC_ERROR_REFCOUNT_DEBUG
+#ifdef GRPC_ERROR_REFCOUNT_DEBUG
+grpc_error *grpc_error_ref(grpc_error *err, const char *file, int line,
+ const char *func);
+void grpc_error_unref(grpc_error *err, const char *file, int line,
+ const char *func);
+#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__, __func__)
+#define GRPC_ERROR_UNREF(err) \
+ grpc_error_unref(err, __FILE__, __LINE__, __func__)
+#else
+grpc_error *grpc_error_ref(grpc_error *err);
+void grpc_error_unref(grpc_error *err);
+#define GRPC_ERROR_REF(err) grpc_error_ref(err)
+#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
+#endif
+
+grpc_error *grpc_error_set_int(grpc_error *src, grpc_error_ints which,
+ intptr_t value);
+bool grpc_error_get_int(grpc_error *error, grpc_error_ints which, intptr_t *p);
+grpc_error *grpc_error_set_time(grpc_error *src, grpc_error_times which,
+ gpr_timespec value);
+grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
+ const char *value);
+/// Add a child error: an error that is believed to have contributed to this
+/// error occurring. Allows root causing high level errors from lower level
+/// errors that contributed to them.
+grpc_error *grpc_error_add_child(grpc_error *src, grpc_error *child);
+grpc_error *grpc_os_error(const char *file, int line, int err,
+ const char *call_name);
+/// create an error associated with errno!=0 (an 'operating system' error)
+#define GRPC_OS_ERROR(err, call_name) \
+ grpc_os_error(__FILE__, __LINE__, err, call_name)
+grpc_error *grpc_wsa_error(const char *file, int line, int err,
+ const char *call_name);
+/// windows only: create an error associated with WSAGetLastError()!=0
+#define GRPC_WSA_ERROR(err, call_name) \
+ grpc_wsa_error(__FILE__, __LINE__, err, call_name)
+
+bool grpc_log_if_error(const char *what, grpc_error *error, const char *file,
+ int line);
+#define GRPC_LOG_IF_ERROR(what, error) \
+ grpc_log_if_error((what), (error), __FILE__, __LINE__)
+
+#endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */
diff --git a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c b/src/core/lib/iomgr/ev_poll_and_epoll_posix.c
index 943c404f91..9e306af5fa 100644
--- a/src/core/lib/iomgr/ev_poll_and_epoll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_and_epoll_posix.c
@@ -221,9 +221,10 @@ struct grpc_pollset {
struct grpc_pollset_vtable {
void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd, int and_unlock_pollset);
- void (*maybe_work_and_unlock)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker *worker,
- gpr_timespec deadline, gpr_timespec now);
+ 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);
};
@@ -251,9 +252,9 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
#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 void pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags);
+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,
@@ -420,12 +421,13 @@ static bool fd_is_orphaned(grpc_fd *fd) {
return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
}
-static void pollset_kick_locked(grpc_fd_watcher *watcher) {
+static grpc_error *pollset_kick_locked(grpc_fd_watcher *watcher) {
gpr_mu_lock(&watcher->pollset->mu);
GPR_ASSERT(watcher->worker);
- pollset_kick_ext(watcher->pollset, watcher->worker,
- GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+ 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) {
@@ -464,7 +466,7 @@ static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
} else {
remove_fd_from_all_epoll_sets(fd->fd);
}
- grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
}
static int fd_wrapped_fd(grpc_fd *fd) {
@@ -513,15 +515,27 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#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 (*st == CLOSURE_NOT_READY) {
+ if (fd->shutdown) {
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
+ NULL);
+ } else if (*st == CLOSURE_NOT_READY) {
/* not ready ==> switch to a waiting state by setting the closure */
*st = closure;
} else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY;
- grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
+ NULL);
maybe_wake_one_watcher_locked(fd);
} else {
/* upcallptr was set to a different closure. This is an error! */
@@ -544,7 +558,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0;
} else {
/* waiting ==> queue closure */
- grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL);
+ grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
*st = CLOSURE_NOT_READY;
return 1;
}
@@ -557,11 +571,22 @@ static void set_read_notifier_pollset_locked(
static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
- GPR_ASSERT(!fd->shutdown);
- fd->shutdown = 1;
- set_ready_locked(exec_ctx, fd, &fd->read_closure);
- set_ready_locked(exec_ctx, fd, &fd->write_closure);
+ /* 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,
@@ -744,10 +769,19 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker;
}
-static void pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags) {
+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) {
@@ -757,25 +791,28 @@ static void pollset_kick_ext(grpc_pollset *p,
for (specific_worker = p->root_worker.next;
specific_worker != &p->root_worker;
specific_worker = specific_worker->next) {
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ kick_append_error(
+ &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
- p->kicked_without_pollers = 1;
+ p->kicked_without_pollers = true;
GPR_TIMER_END("pollset_kick_ext.broadcast", 0);
} 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 = 1;
+ specific_worker->reevaluate_polling_on_wakeup = true;
}
- specific_worker->kicked_specifically = 1;
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ 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 = 1;
+ specific_worker->reevaluate_polling_on_wakeup = true;
}
- specific_worker->kicked_specifically = 1;
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ 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);
@@ -783,14 +820,9 @@ static void pollset_kick_ext(grpc_pollset *p,
specific_worker = pop_front_worker(p);
if (specific_worker != NULL) {
if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
- /* Prefer not to kick self. Push the worker to the end of the list and
- * pop the one from front */
GPR_TIMER_MARK("kick_anonymous_not_self", 0);
push_back_worker(p, specific_worker);
specific_worker = pop_front_worker(p);
- /* If there was only one worker on the pollset, we would get the same
- * worker we pushed (the one set on current thread local) back. If so,
- * kick it only if GRPC_POLLSET_CAN_KICK_SELF flag is set */
if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
gpr_tls_get(&g_current_thread_worker) ==
(intptr_t)specific_worker) {
@@ -801,28 +833,30 @@ static void pollset_kick_ext(grpc_pollset *p,
if (specific_worker != NULL) {
GPR_TIMER_MARK("finally_kick", 0);
push_back_worker(p, specific_worker);
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ kick_append_error(
+ &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
} else {
GPR_TIMER_MARK("kicked_no_pollers", 0);
- p->kicked_without_pollers = 1;
+ p->kicked_without_pollers = true;
}
}
GPR_TIMER_END("pollset_kick_ext", 0);
+ return error;
}
-static void pollset_kick(grpc_pollset *p,
- grpc_pollset_worker *specific_worker) {
- pollset_kick_ext(p, specific_worker, 0);
+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 void pollset_global_init(void) {
+static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker);
- grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
}
static void pollset_global_shutdown(void) {
@@ -831,7 +865,9 @@ static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_worker);
}
-static void kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); }
+static grpc_error *kick_poller(void) {
+ return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
+}
/* main interface */
@@ -894,14 +930,23 @@ static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
pollset->vtable->finish_shutdown(pollset);
- grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
+}
+
+static void 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 void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker_hdl, gpr_timespec now,
- gpr_timespec deadline) {
+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;
@@ -917,7 +962,10 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
pollset->local_wakeup_cache = worker.wakeup_fd->next;
} else {
worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
- grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
+ error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
+ }
}
worker.kicked_specifically = 0;
/* If there's work waiting for the pollset to be idle, and the
@@ -954,8 +1002,9 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
- pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker,
- deadline, now);
+ 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);
@@ -1017,6 +1066,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
*worker_hdl = NULL;
GPR_TIMER_END("pollset_work", 0);
+ return error;
}
static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@@ -1065,7 +1115,7 @@ typedef struct grpc_unary_promote_args {
} grpc_unary_promote_args;
static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
- bool success) {
+ 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;
@@ -1167,7 +1217,8 @@ static void basic_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
up_args->promotion_closure.cb = basic_do_promote;
up_args->promotion_closure.cb_arg = up_args;
- grpc_closure_list_add(&pollset->idle_jobs, &up_args->promotion_closure, 1);
+ grpc_closure_list_append(&pollset->idle_jobs, &up_args->promotion_closure,
+ GRPC_ERROR_NONE);
pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
exit:
@@ -1176,11 +1227,9 @@ exit:
}
}
-static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_pollset_worker *worker,
- gpr_timespec deadline,
- gpr_timespec now) {
+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)
@@ -1190,6 +1239,7 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
int timeout;
int r;
nfds_t nfds;
+ grpc_error *error = GRPC_ERROR_NONE;
fd = pollset->data.ptr;
if (fd && fd_is_orphaned(fd)) {
@@ -1230,7 +1280,7 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
if (r < 0) {
if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
}
if (fd) {
fd_end_poll(exec_ctx, &fd_watcher, 0, 0, NULL);
@@ -1241,10 +1291,12 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
}
} else {
if (pfd[0].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
}
if (pfd[1].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
}
if (nfds > 2) {
fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
@@ -1257,6 +1309,8 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
if (fd) {
GRPC_FD_UNREF(fd, "basicpoll_begin");
}
+
+ return error;
}
static void basic_pollset_destroy(grpc_pollset *pollset) {
@@ -1317,7 +1371,7 @@ exit:
}
}
-static void multipoll_with_poll_pollset_maybe_work_and_unlock(
+static grpc_error *multipoll_with_poll_pollset_maybe_work_and_unlock(
grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now) {
#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
@@ -1331,6 +1385,7 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
/* TODO(ctiller): inline some elements to avoid an allocation */
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);
@@ -1383,7 +1438,7 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
if (r < 0) {
if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
}
for (i = 2; i < pfd_count; i++) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
@@ -1394,10 +1449,12 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
}
} else {
if (pfds[0].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
}
if (pfds[1].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
}
for (i = 2; i < pfd_count; i++) {
if (watchers[i].fd == NULL) {
@@ -1411,6 +1468,8 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
gpr_free(pfds);
gpr_free(watchers);
+
+ return error;
}
static void multipoll_with_poll_pollset_finish_shutdown(grpc_pollset *pollset) {
@@ -1601,7 +1660,7 @@ static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_status) {
+ grpc_error *error) {
delayed_add *da = arg;
if (!fd_is_orphaned(da->fd)) {
@@ -1614,7 +1673,8 @@ static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
/* We don't care about this pollset anymore. */
if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
da->pollset->called_shutdown = 1;
- grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, da->pollset->shutdown_done, GRPC_ERROR_NONE,
+ NULL);
}
}
gpr_mu_unlock(&da->pollset->mu);
@@ -1638,14 +1698,14 @@ static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
GRPC_FD_REF(fd, "delayed_add");
grpc_closure_init(&da->closure, perform_delayed_add, da);
pollset->in_flight_cbs++;
- grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &da->closure, GRPC_ERROR_NONE, NULL);
}
}
/* TODO(klempner): We probably want to turn this down a bit */
#define GRPC_EPOLL_MAX_EVENTS 1000
-static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
+static grpc_error *multipoll_with_epoll_pollset_maybe_work_and_unlock(
grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now) {
struct epoll_event ep_ev[GRPC_EPOLL_MAX_EVENTS];
@@ -1654,6 +1714,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
epoll_hdr *h = pollset->data.ptr;
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
@@ -1682,13 +1743,14 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
if (poll_rv < 0) {
if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
}
} else if (poll_rv == 0) {
/* do nothing */
} else {
if (pfds[0].revents) {
- grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd);
+ work_combine_error(&error,
+ grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd->fd));
}
if (pfds[1].revents) {
do {
@@ -1696,7 +1758,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, 0);
if (ep_rv < 0) {
if (errno != EINTR) {
- gpr_log(GPR_ERROR, "epoll_wait() failed: %s", strerror(errno));
+ work_combine_error(&error, GRPC_OS_ERROR(errno, "epoll_wait"));
}
} else {
int i;
@@ -1708,7 +1770,8 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
int read_ev = ep_ev[i].events & (EPOLLIN | EPOLLPRI);
int write_ev = ep_ev[i].events & EPOLLOUT;
if (fd == NULL) {
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+ work_combine_error(&error, grpc_wakeup_fd_consume_wakeup(
+ &grpc_global_wakeup_fd));
} else {
if (read_ev || cancel) {
fd_become_readable(exec_ctx, fd, pollset);
@@ -1722,6 +1785,7 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
} while (ep_rv == GRPC_EPOLL_MAX_EVENTS);
}
}
+ return error;
}
static void multipoll_with_epoll_pollset_finish_shutdown(
@@ -1938,6 +2002,7 @@ static const grpc_event_engine_vtable vtable = {
.fd_wrapped_fd = fd_wrapped_fd,
.fd_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,
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index 0167999dad..45c0a5e954 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015-2016, Google Inc.
+ * Copyright 2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,9 +217,9 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
/* As per pollset_kick, with an extended set of flags (defined above)
-- mostly for fd_posix's use. */
-static void pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags);
+static grpc_error *pollset_kick_ext(grpc_pollset *p,
+ grpc_pollset_worker *specific_worker,
+ uint32_t flags) GRPC_MUST_USE_RESULT;
/* Return 1 if the pollset has active threads in pollset_work (pollset must
* be locked) */
@@ -328,12 +328,13 @@ static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
return notifier;
}
-static void pollset_kick_locked(grpc_fd_watcher *watcher) {
+static grpc_error *pollset_kick_locked(grpc_fd_watcher *watcher) {
gpr_mu_lock(&watcher->pollset->mu);
GPR_ASSERT(watcher->worker);
- pollset_kick_ext(watcher->pollset, watcher->worker,
- GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+ 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) {
@@ -370,7 +371,7 @@ static void close_fd_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
if (!fd->released) {
close(fd->fd);
}
- grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
}
static int fd_wrapped_fd(grpc_fd *fd) {
@@ -419,15 +420,27 @@ static void fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
static void fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#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 (*st == CLOSURE_NOT_READY) {
+ if (fd->shutdown) {
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
+ NULL);
+ } else if (*st == CLOSURE_NOT_READY) {
/* not ready ==> switch to a waiting state by setting the closure */
*st = closure;
} else if (*st == CLOSURE_READY) {
/* already ready ==> queue the closure to run immediately */
*st = CLOSURE_NOT_READY;
- grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
+ NULL);
maybe_wake_one_watcher_locked(fd);
} else {
/* upcallptr was set to a different closure. This is an error! */
@@ -450,7 +463,7 @@ static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
return 0;
} else {
/* waiting ==> queue closure */
- grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL);
+ grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
*st = CLOSURE_NOT_READY;
return 1;
}
@@ -463,13 +476,24 @@ static void set_read_notifier_pollset_locked(
static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
gpr_mu_lock(&fd->mu);
- GPR_ASSERT(!fd->shutdown);
- fd->shutdown = 1;
- set_ready_locked(exec_ctx, fd, &fd->read_closure);
- set_ready_locked(exec_ctx, fd, &fd->write_closure);
+ /* 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);
@@ -631,10 +655,19 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker;
}
-static void pollset_kick_ext(grpc_pollset *p,
- grpc_pollset_worker *specific_worker,
- uint32_t flags) {
+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) {
@@ -644,25 +677,28 @@ static void pollset_kick_ext(grpc_pollset *p,
for (specific_worker = p->root_worker.next;
specific_worker != &p->root_worker;
specific_worker = specific_worker->next) {
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ kick_append_error(
+ &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
- p->kicked_without_pollers = 1;
+ p->kicked_without_pollers = true;
GPR_TIMER_END("pollset_kick_ext.broadcast", 0);
} 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 = 1;
+ specific_worker->reevaluate_polling_on_wakeup = true;
}
- specific_worker->kicked_specifically = 1;
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ 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 = 1;
+ specific_worker->reevaluate_polling_on_wakeup = true;
}
- specific_worker->kicked_specifically = 1;
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ 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);
@@ -683,28 +719,31 @@ static void pollset_kick_ext(grpc_pollset *p,
if (specific_worker != NULL) {
GPR_TIMER_MARK("finally_kick", 0);
push_back_worker(p, specific_worker);
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd);
+ kick_append_error(
+ &error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
} else {
GPR_TIMER_MARK("kicked_no_pollers", 0);
- p->kicked_without_pollers = 1;
+ p->kicked_without_pollers = true;
}
}
GPR_TIMER_END("pollset_kick_ext", 0);
+ GRPC_LOG_IF_ERROR("pollset_kick_ext", GRPC_ERROR_REF(error));
+ return error;
}
-static void pollset_kick(grpc_pollset *p,
- grpc_pollset_worker *specific_worker) {
- pollset_kick_ext(p, specific_worker, 0);
+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 void pollset_global_init(void) {
+static grpc_error *pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker);
- grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
+ return grpc_wakeup_fd_init(&grpc_global_wakeup_fd);
}
static void pollset_global_shutdown(void) {
@@ -713,7 +752,9 @@ static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_worker);
}
-static void kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); }
+static grpc_error *kick_poller(void) {
+ return grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd);
+}
/* main interface */
@@ -783,14 +824,23 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
GRPC_FD_UNREF(pollset->fds[i], "multipoller");
}
pollset->fd_count = 0;
- grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
}
-static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker_hdl, gpr_timespec now,
- gpr_timespec deadline) {
+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;
@@ -806,7 +856,11 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
pollset->local_wakeup_cache = worker.wakeup_fd->next;
} else {
worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
- grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
+ error = grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
+ if (error != GRPC_ERROR_NONE) {
+ GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
+ return error;
+ }
}
worker.kicked_specifically = 0;
/* If there's work waiting for the pollset to be idle, and the
@@ -890,7 +944,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
if (r < 0) {
if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ work_combine_error(&error, GRPC_OS_ERROR(errno, "poll"));
}
for (i = 2; i < pfd_count; i++) {
fd_end_poll(exec_ctx, &watchers[i], 0, 0, NULL);
@@ -901,10 +955,12 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
} else {
if (pfds[0].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
+ work_combine_error(
+ &error, grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd));
}
if (pfds[1].revents & POLLIN_CHECK) {
- grpc_wakeup_fd_consume_wakeup(&worker.wakeup_fd->fd);
+ work_combine_error(
+ &error, grpc_wakeup_fd_consume_wakeup(&worker.wakeup_fd->fd));
}
for (i = 2; i < pfd_count; i++) {
if (watchers[i].fd == NULL) {
@@ -937,7 +993,7 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
/* If we're forced to re-evaluate polling (via pollset_kick with
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
a loop */
- if (worker.reevaluate_polling_on_wakeup) {
+ if (worker.reevaluate_polling_on_wakeup && error == GRPC_ERROR_NONE) {
worker.reevaluate_polling_on_wakeup = 0;
pollset->kicked_without_pollers = 0;
if (queued_work || worker.kicked_specifically) {
@@ -982,6 +1038,8 @@ static void pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
*worker_hdl = NULL;
GPR_TIMER_END("pollset_work", 0);
+ GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
+ return error;
}
static void pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@@ -1172,6 +1230,7 @@ static const grpc_event_engine_vtable vtable = {
.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,
@@ -1199,7 +1258,9 @@ static const grpc_event_engine_vtable vtable = {
};
const grpc_event_engine_vtable *grpc_init_poll_posix(void) {
- pollset_global_init();
+ if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
+ return NULL;
+ }
return &vtable;
}
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index 6477b05dcd..4c360f13a3 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -153,6 +153,10 @@ void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
g_event_engine->fd_shutdown(exec_ctx, fd);
}
+bool grpc_fd_is_shutdown(grpc_fd *fd) {
+ return g_event_engine->fd_is_shutdown(fd);
+}
+
void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) {
g_event_engine->fd_notify_on_read(exec_ctx, fd, closure);
@@ -187,15 +191,15 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
g_event_engine->pollset_destroy(pollset);
}
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker, gpr_timespec now,
- gpr_timespec deadline) {
- g_event_engine->pollset_work(exec_ctx, pollset, worker, now, deadline);
+grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+ grpc_pollset_worker **worker, gpr_timespec now,
+ gpr_timespec deadline) {
+ return g_event_engine->pollset_work(exec_ctx, pollset, worker, now, deadline);
}
-void grpc_pollset_kick(grpc_pollset *pollset,
- grpc_pollset_worker *specific_worker) {
- g_event_engine->pollset_kick(pollset, specific_worker);
+grpc_error *grpc_pollset_kick(grpc_pollset *pollset,
+ grpc_pollset_worker *specific_worker) {
+ return g_event_engine->pollset_kick(pollset, specific_worker);
}
void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@@ -245,6 +249,6 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
g_event_engine->pollset_set_del_fd(exec_ctx, pollset_set, fd);
}
-void grpc_kick_poller(void) { g_event_engine->kick_poller(); }
+grpc_error *grpc_kick_poller(void) { return g_event_engine->kick_poller(); }
#endif // GPR_POSIX_SOCKET
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 344bf63438..87e9bc4d46 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -55,6 +55,7 @@ typedef struct grpc_event_engine_vtable {
grpc_closure *closure);
void (*fd_notify_on_write)(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure);
+ bool (*fd_is_shutdown)(grpc_fd *fd);
grpc_pollset *(*fd_get_read_notifier_pollset)(grpc_exec_ctx *exec_ctx,
grpc_fd *fd);
@@ -63,11 +64,11 @@ typedef struct grpc_event_engine_vtable {
grpc_closure *closure);
void (*pollset_reset)(grpc_pollset *pollset);
void (*pollset_destroy)(grpc_pollset *pollset);
- void (*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker, gpr_timespec now,
- gpr_timespec deadline);
- void (*pollset_kick)(grpc_pollset *pollset,
- grpc_pollset_worker *specific_worker);
+ grpc_error *(*pollset_work)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+ grpc_pollset_worker **worker, gpr_timespec now,
+ gpr_timespec deadline);
+ grpc_error *(*pollset_kick)(grpc_pollset *pollset,
+ grpc_pollset_worker *specific_worker);
void (*pollset_add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd);
@@ -90,7 +91,7 @@ typedef struct grpc_event_engine_vtable {
void (*pollset_set_del_fd)(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_fd *fd);
- void (*kick_poller)(void);
+ grpc_error *(*kick_poller)(void);
void (*shutdown_engine)(void);
} grpc_event_engine_vtable;
@@ -116,7 +117,10 @@ int grpc_fd_wrapped_fd(grpc_fd *fd);
void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
int *release_fd, const char *reason);
-/* Cause any current callbacks to error out with GRPC_CALLBACK_CANCELLED. */
+/* Has grpc_fd_shutdown been called on an fd? */
+bool grpc_fd_is_shutdown(grpc_fd *fd);
+
+/* Cause any current and future callbacks to fail. */
void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
/* Register read interest, causing read_cb to be called once when fd becomes
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
index e451479073..c44aafcddf 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -63,11 +63,12 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
grpc_closure *c = exec_ctx->closure_list.head;
exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
while (c != NULL) {
- bool success = (bool)(c->final_data & 1);
- grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1);
+ grpc_closure *next = c->next_data.next;
+ grpc_error *error = c->error;
did_something = true;
GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
- c->cb(exec_ctx, c->cb_arg, success);
+ c->cb(exec_ctx, c->cb_arg, error);
+ GRPC_ERROR_UNREF(error);
GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
c = next;
}
@@ -81,11 +82,11 @@ void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {
grpc_exec_ctx_flush(exec_ctx);
}
-void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
- bool success,
- grpc_workqueue *offload_target_or_null) {
+void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+ grpc_error *error,
+ grpc_workqueue *offload_target_or_null) {
GPR_ASSERT(offload_target_or_null == NULL);
- grpc_closure_list_add(&exec_ctx->closure_list, closure, success);
+ grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
}
void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 9d47a262f8..38f27d9b13 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -94,9 +94,9 @@ bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
* the instance is destroyed, or work may be lost. */
void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
/** Add a closure to be executed at the next flush/finish point */
-void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
- bool success,
- grpc_workqueue *offload_target_or_null);
+void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+ grpc_error *error,
+ grpc_workqueue *offload_target_or_null);
/** Returns true if we'd like to leave this execution context as soon as
possible: useful for deciding whether to do something more or not depending
on outside context */
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
index 36e22e4271..8d7535d6fe 100644
--- a/src/core/lib/iomgr/executor.c
+++ b/src/core/lib/iomgr/executor.c
@@ -112,10 +112,10 @@ static void maybe_spawn_locked() {
g_executor.pending_join = 1;
}
-void grpc_executor_enqueue(grpc_closure *closure, bool success) {
+void grpc_executor_push(grpc_closure *closure, grpc_error *error) {
gpr_mu_lock(&g_executor.mu);
if (g_executor.shutting_down == 0) {
- grpc_closure_list_add(&g_executor.closures, closure, success);
+ grpc_closure_list_append(&g_executor.closures, closure, error);
maybe_spawn_locked();
}
gpr_mu_unlock(&g_executor.mu);
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
index b7e6f51aa5..da9dcd07d0 100644
--- a/src/core/lib/iomgr/executor.h
+++ b/src/core/lib/iomgr/executor.h
@@ -45,7 +45,7 @@ void grpc_executor_init();
/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate
* thread */
-void grpc_executor_enqueue(grpc_closure *closure, bool success);
+void grpc_executor_push(grpc_closure *closure, grpc_error *error);
/** Shutdown the executor, running all pending work as part of the call */
void grpc_executor_shutdown();
diff --git a/src/core/lib/iomgr/iocp_windows.c b/src/core/lib/iomgr/iocp_windows.c
index 708232295e..2532e52e48 100644
--- a/src/core/lib/iomgr/iocp_windows.c
+++ b/src/core/lib/iomgr/iocp_windows.c
@@ -104,7 +104,6 @@ grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
} else if (overlapped == &socket->read_info.overlapped) {
info = &socket->read_info;
} else {
- gpr_log(GPR_ERROR, "Unknown IOCP operation");
abort();
}
success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
@@ -112,16 +111,7 @@ grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
info->bytes_transfered = bytes;
info->wsa_error = success ? 0 : WSAGetLastError();
GPR_ASSERT(overlapped == &info->overlapped);
- GPR_ASSERT(!info->has_pending_iocp);
- gpr_mu_lock(&socket->state_mu);
- if (info->closure) {
- closure = info->closure;
- info->closure = NULL;
- } else {
- info->has_pending_iocp = 1;
- }
- gpr_mu_unlock(&socket->state_mu);
- grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+ grpc_socket_become_ready(exec_ctx, socket, info);
return GRPC_IOCP_WORK_WORK;
}
@@ -176,33 +166,4 @@ void grpc_iocp_add_socket(grpc_winsocket *socket) {
GPR_ASSERT(ret == g_iocp);
}
-/* Calling notify_on_read or write means either of two things:
- -) The IOCP already completed in the background, and we need to call
- the callback now.
- -) The IOCP hasn't completed yet, and we're queuing it for later. */
-static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
- grpc_winsocket *socket, grpc_closure *closure,
- grpc_winsocket_callback_info *info) {
- GPR_ASSERT(info->closure == NULL);
- gpr_mu_lock(&socket->state_mu);
- if (info->has_pending_iocp) {
- info->has_pending_iocp = 0;
- grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
- } else {
- info->closure = closure;
- }
- gpr_mu_unlock(&socket->state_mu);
-}
-
-void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
- grpc_winsocket *socket,
- grpc_closure *closure) {
- socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info);
-}
-
-void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
- grpc_closure *closure) {
- socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info);
-}
-
#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h
index ae210fa7d7..011fee38ff 100644
--- a/src/core/lib/iomgr/iocp_windows.h
+++ b/src/core/lib/iomgr/iocp_windows.h
@@ -52,12 +52,4 @@ void grpc_iocp_flush(void);
void grpc_iocp_shutdown(void);
void grpc_iocp_add_socket(grpc_winsocket *);
-void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
- grpc_winsocket *winsocket,
- grpc_closure *closure);
-
-void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx,
- grpc_winsocket *winsocket,
- grpc_closure *closure);
-
#endif /* GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 60cef8ba77..89292a153e 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -96,7 +96,8 @@ void grpc_iomgr_shutdown(void) {
gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
gpr_time_from_seconds(1, GPR_TIMESPAN)) >= 0) {
if (g_root_object.next != &g_root_object) {
- gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
+ gpr_log(GPR_DEBUG,
+ "Waiting for %" PRIuPTR " iomgr objects to be destroyed",
count_objects());
}
last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
@@ -114,9 +115,9 @@ void grpc_iomgr_shutdown(void) {
if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline)) {
if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
if (g_root_object.next != &g_root_object) {
- gpr_log(GPR_DEBUG,
- "Failed to free %d iomgr objects before shutdown deadline: "
- "memory leaks are likely",
+ gpr_log(GPR_DEBUG, "Failed to free %" PRIuPTR
+ " iomgr objects before shutdown deadline: "
+ "memory leaks are likely",
count_objects());
dump_objects("LEAKED");
if (grpc_iomgr_abort_on_leaks()) {
diff --git a/src/core/lib/support/load_file.c b/src/core/lib/iomgr/load_file.c
index f30aacdd4f..b62ecbc534 100644
--- a/src/core/lib/support/load_file.c
+++ b/src/core/lib/iomgr/load_file.c
@@ -31,7 +31,7 @@
*
*/
-#include "src/core/lib/support/load_file.h"
+#include "src/core/lib/iomgr/load_file.h"
#include <errno.h>
#include <string.h>
@@ -43,21 +43,19 @@
#include "src/core/lib/support/block_annotate.h"
#include "src/core/lib/support/string.h"
-gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
- int *success) {
+grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
+ gpr_slice *output) {
unsigned char *contents = NULL;
size_t contents_size = 0;
- char *error_msg = NULL;
gpr_slice result = gpr_empty_slice();
FILE *file;
size_t bytes_read = 0;
+ grpc_error *error = GRPC_ERROR_NONE;
GRPC_SCHEDULING_START_BLOCKING_REGION;
file = fopen(filename, "rb");
if (file == NULL) {
- gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
- strerror(errno));
- GPR_ASSERT(error_msg != NULL);
+ error = GRPC_OS_ERROR(errno, "fopen");
goto end;
}
fseek(file, 0, SEEK_END);
@@ -67,25 +65,25 @@ gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
bytes_read = fread(contents, 1, contents_size, file);
if (bytes_read < contents_size) {
+ error = GRPC_OS_ERROR(errno, "fread");
GPR_ASSERT(ferror(file));
- gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
- strerror(errno), filename);
- GPR_ASSERT(error_msg != NULL);
goto end;
}
- if (success != NULL) *success = 1;
if (add_null_terminator) {
contents[contents_size++] = 0;
}
result = gpr_slice_new(contents, contents_size, gpr_free);
end:
- if (error_msg != NULL) {
- gpr_log(GPR_ERROR, "%s", error_msg);
- gpr_free(error_msg);
- if (success != NULL) *success = 0;
- }
+ *output = result;
if (file != NULL) fclose(file);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_error *error_out = grpc_error_set_str(
+ GRPC_ERROR_CREATE_REFERENCING("Failed to load file", &error, 1),
+ GRPC_ERROR_STR_FILENAME, filename);
+ GRPC_ERROR_UNREF(error);
+ error = error_out;
+ }
GRPC_SCHEDULING_END_BLOCKING_REGION;
- return result;
+ return error;
}
diff --git a/src/core/lib/support/load_file.h b/src/core/lib/iomgr/load_file.h
index 9a4b27942e..9aac2225d1 100644
--- a/src/core/lib/support/load_file.h
+++ b/src/core/lib/iomgr/load_file.h
@@ -31,25 +31,26 @@
*
*/
-#ifndef GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H
-#define GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H
+#ifndef GRPC_CORE_LIB_IOMGR_LOAD_FILE_H
+#define GRPC_CORE_LIB_IOMGR_LOAD_FILE_H
#include <stdio.h>
#include <grpc/support/slice.h>
+#include "src/core/lib/iomgr/error.h"
+
#ifdef __cplusplus
extern "C" {
#endif
/* Loads the content of a file into a slice. add_null_terminator will add
- a NULL terminator if non-zero. The success parameter, if not NULL,
- will be set to 1 in case of success and 0 in case of failure. */
-gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
- int *success);
+ a NULL terminator if non-zero. */
+grpc_error *grpc_load_file(const char *filename, int add_null_terminator,
+ gpr_slice *slice);
#ifdef __cplusplus
}
#endif
-#endif /* GRPC_CORE_LIB_SUPPORT_LOAD_FILE_H */
+#endif /* GRPC_CORE_LIB_IOMGR_LOAD_FILE_H */
diff --git a/src/core/lib/iomgr/polling_entity.c b/src/core/lib/iomgr/polling_entity.c
new file mode 100644
index 0000000000..d1686aa12f
--- /dev/null
+++ b/src/core/lib/iomgr/polling_entity.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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 <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/polling_entity.h"
+
+grpc_polling_entity grpc_polling_entity_create_from_pollset_set(
+ grpc_pollset_set *pollset_set) {
+ grpc_polling_entity pollent;
+ pollent.pollent.pollset_set = pollset_set;
+ pollent.tag = POPS_POLLSET_SET;
+ return pollent;
+}
+
+grpc_polling_entity grpc_polling_entity_create_from_pollset(
+ grpc_pollset *pollset) {
+ grpc_polling_entity pollent;
+ pollent.pollent.pollset = pollset;
+ pollent.tag = POPS_POLLSET;
+ return pollent;
+}
+
+grpc_pollset *grpc_polling_entity_pollset(grpc_polling_entity *pollent) {
+ if (pollent->tag == POPS_POLLSET) {
+ return pollent->pollent.pollset;
+ }
+ return NULL;
+}
+
+grpc_pollset_set *grpc_polling_entity_pollset_set(
+ grpc_polling_entity *pollent) {
+ if (pollent->tag == POPS_POLLSET_SET) {
+ return pollent->pollent.pollset_set;
+ }
+ return NULL;
+}
+
+bool grpc_polling_entity_is_empty(const grpc_polling_entity *pollent) {
+ return pollent->tag == POPS_NONE;
+}
+
+void grpc_polling_entity_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_polling_entity *pollent,
+ grpc_pollset_set *pss_dst) {
+ if (pollent->tag == POPS_POLLSET) {
+ GPR_ASSERT(pollent->pollent.pollset != NULL);
+ grpc_pollset_set_add_pollset(exec_ctx, pss_dst, pollent->pollent.pollset);
+ } else if (pollent->tag == POPS_POLLSET_SET) {
+ GPR_ASSERT(pollent->pollent.pollset_set != NULL);
+ grpc_pollset_set_add_pollset_set(exec_ctx, pss_dst,
+ pollent->pollent.pollset_set);
+ } else {
+ gpr_log(GPR_ERROR, "Invalid grpc_polling_entity tag '%d'", pollent->tag);
+ abort();
+ }
+}
+
+void grpc_polling_entity_del_from_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_polling_entity *pollent,
+ grpc_pollset_set *pss_dst) {
+ if (pollent->tag == POPS_POLLSET) {
+ GPR_ASSERT(pollent->pollent.pollset != NULL);
+ grpc_pollset_set_del_pollset(exec_ctx, pss_dst, pollent->pollent.pollset);
+ } else if (pollent->tag == POPS_POLLSET_SET) {
+ GPR_ASSERT(pollent->pollent.pollset_set != NULL);
+ grpc_pollset_set_del_pollset_set(exec_ctx, pss_dst,
+ pollent->pollent.pollset_set);
+ } else {
+ gpr_log(GPR_ERROR, "Invalid grpc_polling_entity tag '%d'", pollent->tag);
+ abort();
+ }
+}
diff --git a/src/core/lib/iomgr/polling_entity.h b/src/core/lib/iomgr/polling_entity.h
new file mode 100644
index 0000000000..e81531053c
--- /dev/null
+++ b/src/core/lib/iomgr/polling_entity.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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_POLLING_ENTITY_H
+#define GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H
+
+#include "src/core/lib/iomgr/pollset.h"
+#include "src/core/lib/iomgr/pollset_set.h"
+
+/* A grpc_polling_entity is a pollset-or-pollset_set container. It allows
+ * functions that
+ * accept a pollset XOR a pollset_set to do so through an abstract interface.
+ * No ownership is taken. */
+
+typedef struct grpc_polling_entity {
+ union {
+ grpc_pollset *pollset;
+ grpc_pollset_set *pollset_set;
+ } pollent;
+ enum pops_tag { POPS_NONE, POPS_POLLSET, POPS_POLLSET_SET } tag;
+} grpc_polling_entity;
+
+grpc_polling_entity grpc_polling_entity_create_from_pollset_set(
+ grpc_pollset_set *pollset_set);
+grpc_polling_entity grpc_polling_entity_create_from_pollset(
+ grpc_pollset *pollset);
+
+/** If \a pollent contains a pollset, return it. Otherwise, return NULL */
+grpc_pollset *grpc_polling_entity_pollset(grpc_polling_entity *pollent);
+
+/** If \a pollent contains a pollset_set, return it. Otherwise, return NULL */
+grpc_pollset_set *grpc_polling_entity_pollset_set(grpc_polling_entity *pollent);
+
+bool grpc_polling_entity_is_empty(const grpc_polling_entity *pollent);
+
+/** Add the pollset or pollset_set in \a pollent to the destination pollset_set
+ * \a
+ * pss_dst */
+void grpc_polling_entity_add_to_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_polling_entity *pollent,
+ grpc_pollset_set *pss_dst);
+
+/** Delete the pollset or pollset_set in \a pollent from the destination
+ * pollset_set \a
+ * pss_dst */
+void grpc_polling_entity_del_from_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_polling_entity *pollent,
+ grpc_pollset_set *pss_dst);
+/* pollset_set specific */
+
+#endif /* GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H */
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index c40a474877..8d9edc8406 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -81,14 +81,15 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
May call grpc_closure_list_run on grpc_closure_list, without holding the
pollset
lock */
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker, gpr_timespec now,
- gpr_timespec deadline);
+grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
+ grpc_pollset_worker **worker, gpr_timespec now,
+ gpr_timespec deadline) GRPC_MUST_USE_RESULT;
/* Break one polling thread out of polling work for this pollset.
If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers.
Otherwise, if specific_worker is non-NULL, then kick that worker. */
-void grpc_pollset_kick(grpc_pollset *pollset,
- grpc_pollset_worker *specific_worker);
+grpc_error *grpc_pollset_kick(grpc_pollset *pollset,
+ grpc_pollset_worker *specific_worker)
+ GRPC_MUST_USE_RESULT;
#endif /* GRPC_CORE_LIB_IOMGR_POLLSET_H */
diff --git a/src/core/lib/iomgr/pollset_set_windows.c b/src/core/lib/iomgr/pollset_set_windows.c
index 89f60b92fb..a35a9766fc 100644
--- a/src/core/lib/iomgr/pollset_set_windows.c
+++ b/src/core/lib/iomgr/pollset_set_windows.c
@@ -32,12 +32,15 @@
*/
#include <grpc/support/port_platform.h>
+#include <stdint.h>
#ifdef GPR_WINSOCK_SOCKET
#include "src/core/lib/iomgr/pollset_set_windows.h"
-grpc_pollset_set* grpc_pollset_set_create(void) { return NULL; }
+grpc_pollset_set* grpc_pollset_set_create(void) {
+ return (grpc_pollset_set*)((intptr_t)0xdeafbeef);
+}
void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}
diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c
index bff5c586f8..626dd784b3 100644
--- a/src/core/lib/iomgr/pollset_windows.c
+++ b/src/core/lib/iomgr/pollset_windows.c
@@ -109,7 +109,7 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
pollset->shutting_down = 1;
grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
if (!pollset->is_iocp_worker) {
- grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
} else {
pollset->on_shutdown = closure;
}
@@ -127,9 +127,9 @@ void grpc_pollset_reset(grpc_pollset *pollset) {
pollset->on_shutdown = NULL;
}
-void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_pollset_worker **worker_hdl, gpr_timespec now,
- gpr_timespec deadline) {
+grpc_error *grpc_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;
@@ -167,7 +167,8 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
}
if (pollset->shutting_down && pollset->on_shutdown != NULL) {
- grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, pollset->on_shutdown, GRPC_ERROR_NONE,
+ NULL);
pollset->on_shutdown = NULL;
}
goto done;
@@ -197,9 +198,11 @@ done:
}
gpr_cv_destroy(&worker.cv);
*worker_hdl = NULL;
+ return GRPC_ERROR_NONE;
}
-void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
+grpc_error *grpc_pollset_kick(grpc_pollset *p,
+ grpc_pollset_worker *specific_worker) {
if (specific_worker != NULL) {
if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
for (specific_worker =
@@ -233,6 +236,7 @@ void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
p->kicked_without_pollers = 1;
}
}
+ return GRPC_ERROR_NONE;
}
void grpc_kick_poller(void) { grpc_iocp_kick(); }
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index ef198fe0f6..ddbe375755 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -50,24 +50,20 @@ typedef struct {
grpc_resolved_address *addrs;
} grpc_resolved_addresses;
-/* Async result callback:
- On success: addresses is the result, and the callee must call
- grpc_resolved_addresses_destroy when it's done with them
- On failure: addresses is NULL */
-typedef void (*grpc_resolve_cb)(grpc_exec_ctx *exec_ctx, void *arg,
- grpc_resolved_addresses *addresses);
/* Asynchronously resolve addr. Use default_port if a port isn't designated
in addr, otherwise use the port in addr. */
/* TODO(ctiller): add a timeout here */
extern void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *addr,
const char *default_port,
- grpc_resolve_cb cb, void *arg);
+ grpc_closure *on_done,
+ grpc_resolved_addresses **addresses);
/* Destroy resolved addresses */
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
/* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
result must be freed with grpc_resolved_addresses_destroy. */
-extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
- const char *name, const char *default_port);
+extern grpc_error *(*grpc_blocking_resolve_address)(
+ const char *name, const char *default_port,
+ grpc_resolved_addresses **addresses);
#endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/lib/iomgr/resolve_address_posix.c b/src/core/lib/iomgr/resolve_address_posix.c
index cae91eec20..4e9f978584 100644
--- a/src/core/lib/iomgr/resolve_address_posix.c
+++ b/src/core/lib/iomgr/resolve_address_posix.c
@@ -54,38 +54,33 @@
#include "src/core/lib/support/block_annotate.h"
#include "src/core/lib/support/string.h"
-typedef struct {
- char *name;
- char *default_port;
- grpc_resolve_cb cb;
- grpc_closure request_closure;
- void *arg;
-} request;
-
-static grpc_resolved_addresses *blocking_resolve_address_impl(
- const char *name, const char *default_port) {
+static grpc_error *blocking_resolve_address_impl(
+ const char *name, const char *default_port,
+ grpc_resolved_addresses **addresses) {
struct addrinfo hints;
struct addrinfo *result = NULL, *resp;
char *host;
char *port;
int s;
size_t i;
- grpc_resolved_addresses *addrs = NULL;
+ grpc_error *err;
if (name[0] == 'u' && name[1] == 'n' && name[2] == 'i' && name[3] == 'x' &&
name[4] == ':' && name[5] != 0) {
- return grpc_resolve_unix_domain_address(name + 5);
+ return grpc_resolve_unix_domain_address(name + 5, addresses);
}
/* parse name, splitting it into host and port parts */
gpr_split_host_port(name, &host, &port);
if (host == NULL) {
- gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
+ err = grpc_error_set_str(GRPC_ERROR_CREATE("unparseable host:port"),
+ GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto done;
}
if (port == NULL) {
if (default_port == NULL) {
- gpr_log(GPR_ERROR, "no port in name '%s'", name);
+ err = grpc_error_set_str(GRPC_ERROR_CREATE("no port in name"),
+ GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto done;
}
port = gpr_strdup(default_port);
@@ -115,23 +110,31 @@ static grpc_resolved_addresses *blocking_resolve_address_impl(
}
if (s != 0) {
- gpr_log(GPR_ERROR, "getaddrinfo: %s", gai_strerror(s));
+ err = grpc_error_set_str(
+ grpc_error_set_str(
+ grpc_error_set_str(grpc_error_set_int(GRPC_ERROR_CREATE("OS Error"),
+ GRPC_ERROR_INT_ERRNO, s),
+ GRPC_ERROR_STR_OS_ERROR, gai_strerror(s)),
+ GRPC_ERROR_STR_SYSCALL, "getaddrinfo"),
+ GRPC_ERROR_STR_TARGET_ADDRESS, name);
goto done;
}
/* Success path: set addrs non-NULL, fill it in */
- addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
- addrs->naddrs = 0;
+ *addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
+ (*addresses)->naddrs = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
- addrs->naddrs++;
+ (*addresses)->naddrs++;
}
- addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
+ (*addresses)->addrs =
+ gpr_malloc(sizeof(grpc_resolved_address) * (*addresses)->naddrs);
i = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
- memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
- addrs->addrs[i].len = resp->ai_addrlen;
+ memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+ (*addresses)->addrs[i].len = resp->ai_addrlen;
i++;
}
+ err = GRPC_ERROR_NONE;
done:
gpr_free(host);
@@ -139,45 +142,59 @@ done:
if (result) {
freeaddrinfo(result);
}
- return addrs;
+ return err;
}
-grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
- const char *name, const char *default_port) = blocking_resolve_address_impl;
+grpc_error *(*grpc_blocking_resolve_address)(
+ const char *name, const char *default_port,
+ grpc_resolved_addresses **addresses) = blocking_resolve_address_impl;
+
+typedef struct {
+ char *name;
+ char *default_port;
+ grpc_closure *on_done;
+ grpc_resolved_addresses **addrs_out;
+ grpc_closure request_closure;
+ void *arg;
+} request;
/* Callback to be passed to grpc_executor to asynch-ify
* grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp,
+ grpc_error *error) {
request *r = rp;
- grpc_resolved_addresses *resolved =
- grpc_blocking_resolve_address(r->name, r->default_port);
- void *arg = r->arg;
- grpc_resolve_cb cb = r->cb;
+ grpc_exec_ctx_sched(
+ exec_ctx, r->on_done,
+ grpc_blocking_resolve_address(r->name, r->default_port, r->addrs_out),
+ NULL);
gpr_free(r->name);
gpr_free(r->default_port);
- cb(exec_ctx, arg, resolved);
gpr_free(r);
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
- gpr_free(addrs->addrs);
+ if (addrs != NULL) {
+ gpr_free(addrs->addrs);
+ }
gpr_free(addrs);
}
static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
- const char *default_port, grpc_resolve_cb cb,
- void *arg) {
+ const char *default_port,
+ grpc_closure *on_done,
+ grpc_resolved_addresses **addrs) {
request *r = gpr_malloc(sizeof(request));
grpc_closure_init(&r->request_closure, do_request_thread, r);
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
- r->cb = cb;
- r->arg = arg;
- grpc_executor_enqueue(&r->request_closure, 1);
+ r->on_done = on_done;
+ r->addrs_out = addrs;
+ grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE);
}
void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *name,
- const char *default_port, grpc_resolve_cb cb,
- void *arg) = resolve_address_impl;
+ const char *default_port, grpc_closure *on_done,
+ grpc_resolved_addresses **addrs) =
+ resolve_address_impl;
#endif
diff --git a/src/core/lib/iomgr/resolve_address_windows.c b/src/core/lib/iomgr/resolve_address_windows.c
index c1bbb3db6b..2af8af82dc 100644
--- a/src/core/lib/iomgr/resolve_address_windows.c
+++ b/src/core/lib/iomgr/resolve_address_windows.c
@@ -56,30 +56,37 @@
typedef struct {
char *name;
char *default_port;
- grpc_resolve_cb cb;
grpc_closure request_closure;
- void *arg;
+ grpc_closure *on_done;
+ grpc_resolved_addresses **addresses;
} request;
-static grpc_resolved_addresses *blocking_resolve_address_impl(
- const char *name, const char *default_port) {
+static grpc_error *blocking_resolve_address_impl(
+ const char *name, const char *default_port,
+ grpc_resolved_addresses **addresses) {
struct addrinfo hints;
struct addrinfo *result = NULL, *resp;
char *host;
char *port;
int s;
size_t i;
- grpc_resolved_addresses *addrs = NULL;
+ grpc_error *error = GRPC_ERROR_NONE;
/* parse name, splitting it into host and port parts */
gpr_split_host_port(name, &host, &port);
if (host == NULL) {
- gpr_log(GPR_ERROR, "unparseable host:port: '%s'", name);
+ char *msg;
+ gpr_asprintf(&msg, "unparseable host:port: '%s'", name);
+ error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
goto done;
}
if (port == NULL) {
if (default_port == NULL) {
- gpr_log(GPR_ERROR, "no port in name '%s'", name);
+ char *msg;
+ gpr_asprintf(&msg, "no port in name '%s'", name);
+ error = GRPC_ERROR_CREATE(msg);
+ gpr_free(msg);
goto done;
}
port = gpr_strdup(default_port);
@@ -95,31 +102,30 @@ static grpc_resolved_addresses *blocking_resolve_address_impl(
s = getaddrinfo(host, port, &hints, &result);
GRPC_SCHEDULING_END_BLOCKING_REGION;
if (s != 0) {
- char *error_message = gpr_format_message(s);
- gpr_log(GPR_ERROR, "getaddrinfo: %s", error_message);
- gpr_free(error_message);
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "getaddrinfo");
goto done;
}
/* Success path: set addrs non-NULL, fill it in */
- addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
- addrs->naddrs = 0;
+ (*addresses) = gpr_malloc(sizeof(grpc_resolved_addresses));
+ (*addresses)->naddrs = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
- addrs->naddrs++;
+ (*addresses)->naddrs++;
}
- addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address) * addrs->naddrs);
+ (*addresses)->addrs =
+ gpr_malloc(sizeof(grpc_resolved_address) * (*addresses)->naddrs);
i = 0;
for (resp = result; resp != NULL; resp = resp->ai_next) {
- memcpy(&addrs->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
- addrs->addrs[i].len = resp->ai_addrlen;
+ memcpy(&(*addresses)->addrs[i].addr, resp->ai_addr, resp->ai_addrlen);
+ (*addresses)->addrs[i].len = resp->ai_addrlen;
i++;
}
{
- for (i = 0; i < addrs->naddrs; i++) {
+ for (i = 0; i < (*addresses)->naddrs; i++) {
char *buf;
- grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
- 0);
+ grpc_sockaddr_to_string(
+ &buf, (struct sockaddr *)&(*addresses)->addrs[i].addr, 0);
gpr_free(buf);
}
}
@@ -130,45 +136,53 @@ done:
if (result) {
freeaddrinfo(result);
}
- return addrs;
+ return error;
}
-grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
- const char *name, const char *default_port) = blocking_resolve_address_impl;
+grpc_error *(*grpc_blocking_resolve_address)(
+ const char *name, const char *default_port,
+ grpc_resolved_addresses **addresses) = blocking_resolve_address_impl;
/* Callback to be passed to grpc_executor to asynch-ify
* grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp,
+ grpc_error *error) {
request *r = rp;
- grpc_resolved_addresses *resolved =
- grpc_blocking_resolve_address(r->name, r->default_port);
- void *arg = r->arg;
- grpc_resolve_cb cb = r->cb;
+ if (error == GRPC_ERROR_NONE) {
+ error =
+ grpc_blocking_resolve_address(r->name, r->default_port, r->addresses);
+ } else {
+ GRPC_ERROR_REF(error);
+ }
+ grpc_exec_ctx_sched(exec_ctx, r->on_done, error, NULL);
gpr_free(r->name);
gpr_free(r->default_port);
- cb(exec_ctx, arg, resolved);
gpr_free(r);
}
void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addrs) {
- gpr_free(addrs->addrs);
+ if (addrs != NULL) {
+ gpr_free(addrs->addrs);
+ }
gpr_free(addrs);
}
static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
- const char *default_port, grpc_resolve_cb cb,
- void *arg) {
+ const char *default_port,
+ grpc_closure *on_done,
+ grpc_resolved_addresses **addresses) {
request *r = gpr_malloc(sizeof(request));
grpc_closure_init(&r->request_closure, do_request_thread, r);
r->name = gpr_strdup(name);
r->default_port = gpr_strdup(default_port);
- r->cb = cb;
- r->arg = arg;
- grpc_executor_enqueue(&r->request_closure, 1);
+ r->on_done = on_done;
+ r->addresses = addresses;
+ grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE);
}
void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *name,
- const char *default_port, grpc_resolve_cb cb,
- void *arg) = resolve_address_impl;
+ const char *default_port, grpc_closure *on_done,
+ grpc_resolved_addresses **addresses) =
+ resolve_address_impl;
#endif
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.c b/src/core/lib/iomgr/socket_utils_common_posix.c
index fa83ceef30..3a1371617e 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.c
+++ b/src/core/lib/iomgr/socket_utils_common_posix.c
@@ -49,6 +49,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
@@ -57,10 +58,10 @@
#include "src/core/lib/support/string.h"
/* set a socket to non blocking mode */
-int grpc_set_socket_nonblocking(int fd, int non_blocking) {
+grpc_error *grpc_set_socket_nonblocking(int fd, int non_blocking) {
int oldflags = fcntl(fd, F_GETFL, 0);
if (oldflags < 0) {
- return 0;
+ return GRPC_OS_ERROR(errno, "fcntl");
}
if (non_blocking) {
@@ -70,52 +71,71 @@ int grpc_set_socket_nonblocking(int fd, int non_blocking) {
}
if (fcntl(fd, F_SETFL, oldflags) != 0) {
- return 0;
+ return GRPC_OS_ERROR(errno, "fcntl");
}
- return 1;
+ return GRPC_ERROR_NONE;
}
-int grpc_set_socket_no_sigpipe_if_possible(int fd) {
+grpc_error *grpc_set_socket_no_sigpipe_if_possible(int fd) {
#ifdef GPR_HAVE_SO_NOSIGPIPE
int val = 1;
int newval;
socklen_t intlen = sizeof(newval);
- return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) &&
- 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) &&
- (newval != 0) == val;
-#else
- return 1;
+ if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(SO_NOSIGPIPE)");
+ }
+ if (0 != getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen)) {
+ return GRPC_OS_ERROR(errno, "getsockopt(SO_NOSIGPIPE)");
+ }
+ if ((newval != 0) != (val != 0)) {
+ return GRPC_ERROR_CREATE("Failed to set SO_NOSIGPIPE");
+ }
#endif
+ return GRPC_ERROR_NONE;
}
-int grpc_set_socket_ip_pktinfo_if_possible(int fd) {
+grpc_error *grpc_set_socket_ip_pktinfo_if_possible(int fd) {
#ifdef GPR_HAVE_IP_PKTINFO
int get_local_ip = 1;
- return 0 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
- sizeof(get_local_ip));
-#else
- (void)fd;
- return 1;
+ if (0 != setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &get_local_ip,
+ sizeof(get_local_ip))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(IP_PKTINFO)");
+ }
#endif
+ return GRPC_ERROR_NONE;
}
-int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
+grpc_error *grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd) {
#ifdef GPR_HAVE_IPV6_RECVPKTINFO
int get_local_ip = 1;
- return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
- sizeof(get_local_ip));
-#else
- (void)fd;
- return 1;
+ if (0 != setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &get_local_ip,
+ sizeof(get_local_ip))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(IPV6_RECVPKTINFO)");
+ }
#endif
+ return GRPC_ERROR_NONE;
+}
+
+grpc_error *grpc_set_socket_sndbuf(int fd, int buffer_size_bytes) {
+ return 0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size_bytes,
+ sizeof(buffer_size_bytes))
+ ? GRPC_ERROR_NONE
+ : GRPC_OS_ERROR(errno, "setsockopt(SO_SNDBUF)");
+}
+
+grpc_error *grpc_set_socket_rcvbuf(int fd, int buffer_size_bytes) {
+ return 0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size_bytes,
+ sizeof(buffer_size_bytes))
+ ? GRPC_ERROR_NONE
+ : GRPC_OS_ERROR(errno, "setsockopt(SO_RCVBUF)");
}
/* set a socket to close on exec */
-int grpc_set_socket_cloexec(int fd, int close_on_exec) {
+grpc_error *grpc_set_socket_cloexec(int fd, int close_on_exec) {
int oldflags = fcntl(fd, F_GETFD, 0);
if (oldflags < 0) {
- return 0;
+ return GRPC_OS_ERROR(errno, "fcntl");
}
if (close_on_exec) {
@@ -125,30 +145,45 @@ int grpc_set_socket_cloexec(int fd, int close_on_exec) {
}
if (fcntl(fd, F_SETFD, oldflags) != 0) {
- return 0;
+ return GRPC_OS_ERROR(errno, "fcntl");
}
- return 1;
+ return GRPC_ERROR_NONE;
}
/* set a socket to reuse old addresses */
-int grpc_set_socket_reuse_addr(int fd, int reuse) {
+grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse) {
int val = (reuse != 0);
int newval;
socklen_t intlen = sizeof(newval);
- return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
- 0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
- (newval != 0) == val;
+ if (0 != setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(SO_REUSEADDR)");
+ }
+ if (0 != getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen)) {
+ return GRPC_OS_ERROR(errno, "getsockopt(SO_REUSEADDR)");
+ }
+ if ((newval != 0) != val) {
+ return GRPC_ERROR_CREATE("Failed to set SO_REUSEADDR");
+ }
+
+ return GRPC_ERROR_NONE;
}
/* disable nagle */
-int grpc_set_socket_low_latency(int fd, int low_latency) {
+grpc_error *grpc_set_socket_low_latency(int fd, int low_latency) {
int val = (low_latency != 0);
int newval;
socklen_t intlen = sizeof(newval);
- return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
- 0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
- (newval != 0) == val;
+ if (0 != setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) {
+ return GRPC_OS_ERROR(errno, "setsockopt(TCP_NODELAY)");
+ }
+ if (0 != getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen)) {
+ return GRPC_OS_ERROR(errno, "getsockopt(TCP_NODELAY)");
+ }
+ if ((newval != 0) != val) {
+ return GRPC_ERROR_CREATE("Failed to set TCP_NODELAY");
+ }
+ return GRPC_ERROR_NONE;
}
static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
@@ -196,35 +231,47 @@ static int set_socket_dualstack(int fd) {
}
}
-int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
- int protocol, grpc_dualstack_mode *dsmode) {
+static grpc_error *error_for_fd(int fd, const struct sockaddr *addr) {
+ if (fd >= 0) return GRPC_ERROR_NONE;
+ char *addr_str;
+ grpc_sockaddr_to_string(&addr_str, addr, 0);
+ grpc_error *err = grpc_error_set_str(GRPC_OS_ERROR(errno, "socket"),
+ GRPC_ERROR_STR_TARGET_ADDRESS, addr_str);
+ gpr_free(addr_str);
+ return err;
+}
+
+grpc_error *grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
+ int protocol,
+ grpc_dualstack_mode *dsmode,
+ int *newfd) {
int family = addr->sa_family;
if (family == AF_INET6) {
- int fd;
if (grpc_ipv6_loopback_available()) {
- fd = socket(family, type, protocol);
+ *newfd = socket(family, type, protocol);
} else {
- fd = -1;
+ *newfd = -1;
errno = EAFNOSUPPORT;
}
/* Check if we've got a valid dualstack socket. */
- if (fd >= 0 && set_socket_dualstack(fd)) {
+ if (*newfd >= 0 && set_socket_dualstack(*newfd)) {
*dsmode = GRPC_DSMODE_DUALSTACK;
- return fd;
+ return GRPC_ERROR_NONE;
}
/* If this isn't an IPv4 address, then return whatever we've got. */
if (!grpc_sockaddr_is_v4mapped(addr, NULL)) {
*dsmode = GRPC_DSMODE_IPV6;
- return fd;
+ return error_for_fd(*newfd, addr);
}
/* Fall back to AF_INET. */
- if (fd >= 0) {
- close(fd);
+ if (*newfd >= 0) {
+ close(*newfd);
}
family = AF_INET;
}
*dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
- return socket(family, type, protocol);
+ *newfd = socket(family, type, protocol);
+ return error_for_fd(*newfd, addr);
}
#endif
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index a8f6e5e658..30ff39dfa3 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -37,21 +37,23 @@
#include <sys/socket.h>
#include <unistd.h>
+#include "src/core/lib/iomgr/error.h"
+
/* a wrapper for accept or accept4 */
int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
int nonblock, int cloexec);
/* set a socket to non blocking mode */
-int grpc_set_socket_nonblocking(int fd, int non_blocking);
+grpc_error *grpc_set_socket_nonblocking(int fd, int non_blocking);
/* set a socket to close on exec */
-int grpc_set_socket_cloexec(int fd, int close_on_exec);
+grpc_error *grpc_set_socket_cloexec(int fd, int close_on_exec);
/* set a socket to reuse old addresses */
-int grpc_set_socket_reuse_addr(int fd, int reuse);
+grpc_error *grpc_set_socket_reuse_addr(int fd, int reuse);
/* disable nagle */
-int grpc_set_socket_low_latency(int fd, int low_latency);
+grpc_error *grpc_set_socket_low_latency(int fd, int low_latency);
/* Returns true if this system can create AF_INET6 sockets bound to ::1.
The value is probed once, and cached for the life of the process.
@@ -64,19 +66,22 @@ int grpc_set_socket_low_latency(int fd, int low_latency);
int grpc_ipv6_loopback_available(void);
/* Tries to set SO_NOSIGPIPE if available on this platform.
- Returns 1 on success, 0 on failure.
If SO_NO_SIGPIPE is not available, returns 1. */
-int grpc_set_socket_no_sigpipe_if_possible(int fd);
+grpc_error *grpc_set_socket_no_sigpipe_if_possible(int fd);
/* Tries to set IP_PKTINFO if available on this platform.
- Returns 1 on success, 0 on failure.
If IP_PKTINFO is not available, returns 1. */
-int grpc_set_socket_ip_pktinfo_if_possible(int fd);
+grpc_error *grpc_set_socket_ip_pktinfo_if_possible(int fd);
/* Tries to set IPV6_RECVPKTINFO if available on this platform.
- Returns 1 on success, 0 on failure.
If IPV6_RECVPKTINFO is not available, returns 1. */
-int grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+grpc_error *grpc_set_socket_ipv6_recvpktinfo_if_possible(int fd);
+
+/* Tries to set the socket's send buffer to given size. */
+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);
/* An enum to keep track of IPv4/IPv6 socket modes.
@@ -117,7 +122,9 @@ extern int grpc_forbid_dualstack_sockets_for_testing;
IPv4, so that bind() or connect() see the correct family.
Also, it's important to distinguish between DUALSTACK and IPV6 when
listening on the [::] wildcard address. */
-int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
- int protocol, grpc_dualstack_mode *dsmode);
+grpc_error *grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
+ int protocol,
+ grpc_dualstack_mode *dsmode,
+ int *newfd);
#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */
diff --git a/src/core/lib/iomgr/socket_windows.c b/src/core/lib/iomgr/socket_windows.c
index 7d8f9f761d..d7d5f6f157 100644
--- a/src/core/lib/iomgr/socket_windows.c
+++ b/src/core/lib/iomgr/socket_windows.c
@@ -91,10 +91,69 @@ void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
closesocket(winsocket->socket);
}
-void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
+static void destroy(grpc_winsocket *winsocket) {
grpc_iomgr_unregister_object(&winsocket->iomgr_object);
gpr_mu_destroy(&winsocket->state_mu);
gpr_free(winsocket);
}
+static bool check_destroyable(grpc_winsocket *winsocket) {
+ return winsocket->destroy_called == true &&
+ winsocket->write_info.closure == NULL &&
+ winsocket->read_info.closure == NULL;
+}
+
+void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
+ gpr_mu_lock(&winsocket->state_mu);
+ GPR_ASSERT(!winsocket->destroy_called);
+ winsocket->destroy_called = true;
+ bool should_destroy = check_destroyable(winsocket);
+ gpr_mu_unlock(&winsocket->state_mu);
+ if (should_destroy) destroy(winsocket);
+}
+
+/* Calling notify_on_read or write means either of two things:
+-) The IOCP already completed in the background, and we need to call
+the callback now.
+-) The IOCP hasn't completed yet, and we're queuing it for later. */
+static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
+ grpc_winsocket *socket, grpc_closure *closure,
+ grpc_winsocket_callback_info *info) {
+ GPR_ASSERT(info->closure == NULL);
+ gpr_mu_lock(&socket->state_mu);
+ if (info->has_pending_iocp) {
+ info->has_pending_iocp = 0;
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
+ } else {
+ info->closure = closure;
+ }
+ gpr_mu_unlock(&socket->state_mu);
+}
+
+void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
+ grpc_winsocket *socket,
+ grpc_closure *closure) {
+ socket_notify_on_iocp(exec_ctx, socket, closure, &socket->write_info);
+}
+
+void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+ grpc_closure *closure) {
+ socket_notify_on_iocp(exec_ctx, socket, closure, &socket->read_info);
+}
+
+void grpc_socket_become_ready(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+ grpc_winsocket_callback_info *info) {
+ GPR_ASSERT(!info->has_pending_iocp);
+ gpr_mu_lock(&socket->state_mu);
+ if (info->closure) {
+ grpc_exec_ctx_sched(exec_ctx, info->closure, GRPC_ERROR_NONE, NULL);
+ info->closure = NULL;
+ } else {
+ info->has_pending_iocp = 1;
+ }
+ bool should_destroy = check_destroyable(socket);
+ gpr_mu_unlock(&socket->state_mu);
+ if (should_destroy) destroy(socket);
+}
+
#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h
index 73c4384987..490d0e0a06 100644
--- a/src/core/lib/iomgr/socket_windows.h
+++ b/src/core/lib/iomgr/socket_windows.h
@@ -81,6 +81,7 @@ typedef struct grpc_winsocket_callback_info {
is closer to what happens in posix world. */
typedef struct grpc_winsocket {
SOCKET socket;
+ bool destroy_called;
grpc_winsocket_callback_info write_info;
grpc_winsocket_callback_info read_info;
@@ -108,4 +109,16 @@ void grpc_winsocket_shutdown(grpc_winsocket *socket);
/* Destroy a socket. Should only be called if there's no pending operation. */
void grpc_winsocket_destroy(grpc_winsocket *socket);
+void grpc_socket_notify_on_write(grpc_exec_ctx *exec_ctx,
+ grpc_winsocket *winsocket,
+ grpc_closure *closure);
+
+void grpc_socket_notify_on_read(grpc_exec_ctx *exec_ctx,
+ grpc_winsocket *winsocket,
+ grpc_closure *closure);
+
+void grpc_socket_become_ready(grpc_exec_ctx *exec_ctx,
+ grpc_winsocket *winsocket,
+ grpc_winsocket_callback_info *ci);
+
#endif /* GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index e93d5734a0..80c7a3f128 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -71,33 +71,39 @@ typedef struct {
grpc_closure *closure;
} async_connect;
-static int prepare_socket(const struct sockaddr *addr, int fd) {
- if (fd < 0) {
- goto error;
+static grpc_error *prepare_socket(const struct sockaddr *addr, int fd) {
+ grpc_error *err = GRPC_ERROR_NONE;
+
+ GPR_ASSERT(fd >= 0);
+
+ err = grpc_set_socket_nonblocking(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_cloexec(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ if (!grpc_is_unix_socket(addr)) {
+ err = grpc_set_socket_low_latency(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
}
-
- if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
- (!grpc_is_unix_socket(addr) && !grpc_set_socket_low_latency(fd, 1)) ||
- !grpc_set_socket_no_sigpipe_if_possible(fd)) {
- gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
- strerror(errno));
- goto error;
- }
- return 1;
+ err = grpc_set_socket_no_sigpipe_if_possible(fd);
+ if (err != GRPC_ERROR_NONE) goto error;
+ goto done;
error:
if (fd >= 0) {
close(fd);
}
- return 0;
+done:
+ return err;
}
-static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
+static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
int done;
async_connect *ac = acp;
if (grpc_tcp_trace) {
- gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: success=%d", ac->addr_str,
- success);
+ const char *str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
+ str);
+ grpc_error_free_string(str);
}
gpr_mu_lock(&ac->mu);
if (ac->fd != NULL) {
@@ -112,7 +118,7 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
}
}
-static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
+static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
async_connect *ac = acp;
int so_error = 0;
socklen_t so_error_size;
@@ -122,9 +128,13 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
grpc_closure *closure = ac->closure;
grpc_fd *fd;
+ GRPC_ERROR_REF(error);
+
if (grpc_tcp_trace) {
- gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: success=%d",
- ac->addr_str, success);
+ const char *str = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s",
+ ac->addr_str, str);
+ grpc_error_free_string(str);
}
gpr_mu_lock(&ac->mu);
@@ -136,15 +146,14 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
grpc_timer_cancel(exec_ctx, &ac->alarm);
gpr_mu_lock(&ac->mu);
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
do {
so_error_size = sizeof(so_error);
err = getsockopt(grpc_fd_wrapped_fd(fd), SOL_SOCKET, SO_ERROR, &so_error,
&so_error_size);
} while (err < 0 && errno == EINTR);
if (err < 0) {
- gpr_log(GPR_ERROR, "failed to connect to '%s': getsockopt(ERROR): %s",
- ac->addr_str, strerror(errno));
+ error = GRPC_OS_ERROR(errno, "getsockopt");
goto finish;
} else if (so_error != 0) {
if (so_error == ENOBUFS) {
@@ -169,14 +178,12 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
} else {
switch (so_error) {
case ECONNREFUSED:
- gpr_log(
- GPR_ERROR,
- "failed to connect to '%s': socket error: connection refused",
- ac->addr_str);
+ error = grpc_error_set_int(error, GRPC_ERROR_INT_ERRNO, errno);
+ error = grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
+ "Connection refused");
break;
default:
- gpr_log(GPR_ERROR, "failed to connect to '%s': socket error: %d",
- ac->addr_str, so_error);
+ error = GRPC_OS_ERROR(errno, "getsockopt(SO_ERROR)");
break;
}
goto finish;
@@ -188,8 +195,8 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
goto finish;
}
} else {
- gpr_log(GPR_ERROR, "failed to connect to '%s': timeout occurred",
- ac->addr_str);
+ error =
+ grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, "Timeout occurred");
goto finish;
}
@@ -203,12 +210,18 @@ 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");
+ error =
+ grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, ac->addr_str);
+ }
if (done) {
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_str);
gpr_free(ac);
}
- grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
}
static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
@@ -225,6 +238,7 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
grpc_fd *fdobj;
char *name;
char *addr_str;
+ grpc_error *error;
*ep = NULL;
@@ -234,9 +248,10 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
addr_len = sizeof(addr6_v4mapped);
}
- fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
- if (fd < 0) {
- gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
+ error = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
+ if (error != GRPC_ERROR_NONE) {
+ grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+ return;
}
if (dsmode == GRPC_DSMODE_IPV4) {
/* If we got an AF_INET socket, map the address back to IPv4. */
@@ -244,8 +259,8 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
- if (!prepare_socket(addr, fd)) {
- grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+ if ((error = prepare_socket(addr, fd)) != GRPC_ERROR_NONE) {
+ grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
return;
}
@@ -261,14 +276,14 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
if (err >= 0) {
*ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
- grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
goto done;
}
if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
- gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
- grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect"),
+ NULL);
goto done;
}
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index efa0140f54..562cb9c6bf 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -75,23 +75,25 @@ static void async_connect_unlock_and_cleanup(async_connect *ac,
if (socket != NULL) grpc_winsocket_destroy(socket);
}
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) {
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
async_connect *ac = acp;
gpr_mu_lock(&ac->mu);
- if (ac->socket != NULL) {
- grpc_winsocket_shutdown(ac->socket);
+ grpc_winsocket *socket = ac->socket;
+ ac->socket = NULL;
+ if (socket != NULL) {
+ grpc_winsocket_shutdown(socket);
}
- async_connect_unlock_and_cleanup(ac, ac->socket);
+ async_connect_unlock_and_cleanup(ac, socket);
}
-static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
+static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
async_connect *ac = acp;
- SOCKET sock = ac->socket->socket;
grpc_endpoint **ep = ac->endpoint;
GPR_ASSERT(*ep == NULL);
- grpc_winsocket_callback_info *info = &ac->socket->write_info;
grpc_closure *on_done = ac->on_done;
+ GRPC_ERROR_REF(error);
+
gpr_mu_lock(&ac->mu);
grpc_winsocket *socket = ac->socket;
ac->socket = NULL;
@@ -101,17 +103,15 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
gpr_mu_lock(&ac->mu);
- if (from_iocp && socket != NULL) {
+ if (error == GRPC_ERROR_NONE && socket != NULL) {
DWORD transfered_bytes = 0;
DWORD flags;
- BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
- &transfered_bytes, FALSE, &flags);
+ BOOL wsa_success =
+ WSAGetOverlappedResult(socket->socket, &socket->write_info.overlapped,
+ &transfered_bytes, FALSE, &flags);
GPR_ASSERT(transfered_bytes == 0);
if (!wsa_success) {
- char *utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, "on_connect error connecting to '%s': %s",
- ac->addr_name, utf8_message);
- gpr_free(utf8_message);
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
} else {
*ep = grpc_tcp_create(socket, ac->addr_name);
socket = NULL;
@@ -121,7 +121,7 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
async_connect_unlock_and_cleanup(ac, socket);
/* If the connection was aborted, the callback was already called when
the deadline was met. */
- on_done->cb(exec_ctx, on_done->cb_arg, *ep != NULL);
+ grpc_exec_ctx_sched(exec_ctx, on_done, error, NULL);
}
/* Tries to issue one async connection, then schedules both an IOCP
@@ -141,10 +141,8 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
LPFN_CONNECTEX ConnectEx;
GUID guid = WSAID_CONNECTEX;
DWORD ioctl_num_bytes;
- const char *message = NULL;
- char *utf8_message;
grpc_winsocket_callback_info *info;
- int last_error;
+ grpc_error *error = GRPC_ERROR_NONE;
*endpoint = NULL;
@@ -157,12 +155,12 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) {
- message = "Unable to create socket: %s";
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
goto failure;
}
- if (!grpc_tcp_prepare_socket(sock)) {
- message = "Unable to set socket options: %s";
+ error = grpc_tcp_prepare_socket(sock);
+ if (error != GRPC_ERROR_NONE) {
goto failure;
}
@@ -173,7 +171,8 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
&ConnectEx, sizeof(ConnectEx), &ioctl_num_bytes, NULL, NULL);
if (status != 0) {
- message = "Unable to retrieve ConnectEx pointer: %s";
+ error = GRPC_WSA_ERROR(WSAGetLastError(),
+ "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
goto failure;
}
@@ -181,7 +180,7 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
status = bind(sock, (struct sockaddr *)&local_address, sizeof(local_address));
if (status != 0) {
- message = "Unable to bind socket: %s";
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
goto failure;
}
@@ -193,9 +192,9 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
/* It wouldn't be unusual to get a success immediately. But we'll still get
an IOCP notification, so let's ignore it. */
if (!success) {
- int error = WSAGetLastError();
- if (error != ERROR_IO_PENDING) {
- message = "ConnectEx failed: %s";
+ int last_error = WSAGetLastError();
+ if (last_error != ERROR_IO_PENDING) {
+ error = GRPC_WSA_ERROR(last_error, "ConnectEx");
goto failure;
}
}
@@ -215,17 +214,18 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
return;
failure:
- last_error = WSAGetLastError();
- utf8_message = gpr_format_message(last_error);
- gpr_log(GPR_ERROR, message, utf8_message);
- gpr_log(GPR_ERROR, "last error = %d", last_error);
- gpr_free(utf8_message);
+ GPR_ASSERT(error != GRPC_ERROR_NONE);
+ char *target_uri = grpc_sockaddr_to_uri(addr);
+ grpc_error *final_error = grpc_error_set_str(
+ GRPC_ERROR_CREATE_REFERENCING("Failed to connect", &error, 1),
+ GRPC_ERROR_STR_TARGET_ADDRESS, target_uri);
+ GRPC_ERROR_UNREF(error);
if (socket != NULL) {
grpc_winsocket_destroy(socket);
} else if (sock != INVALID_SOCKET) {
closesocket(sock);
}
- grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, on_done, final_error, NULL);
}
#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index e2869224f1..1046b60bcc 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -38,6 +38,7 @@
#include "src/core/lib/iomgr/tcp_posix.h"
#include <errno.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
@@ -74,7 +75,7 @@ typedef struct {
grpc_endpoint base;
grpc_fd *em_fd;
int fd;
- int finished_edge;
+ bool finished_edge;
msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
size_t slice_size;
gpr_refcount refcount;
@@ -101,9 +102,9 @@ typedef struct {
} grpc_tcp;
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- bool success);
+ grpc_error *error);
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- bool success);
+ grpc_error *error);
static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
@@ -155,12 +156,15 @@ static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
TCP_UNREF(exec_ctx, tcp, "destroy");
}
-static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) {
+static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp,
+ grpc_error *error) {
grpc_closure *cb = tcp->read_cb;
if (grpc_tcp_trace) {
size_t i;
- gpr_log(GPR_DEBUG, "read: success=%d", success);
+ const char *str = grpc_error_string(error);
+ 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);
@@ -171,7 +175,7 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp, int success) {
tcp->read_cb = NULL;
tcp->incoming_buffer = NULL;
- cb->cb(exec_ctx, cb->cb_arg, success);
+ grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
#define MAX_READ_IOVEC 4
@@ -219,15 +223,14 @@ static void tcp_continue_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 {
- /* TODO(klempner): Log interesting errors */
gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
- call_read_cb(exec_ctx, tcp, 0);
+ 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);
- call_read_cb(exec_ctx, tcp, 0);
+ call_read_cb(exec_ctx, tcp, GRPC_ERROR_CREATE("EOF"));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
@@ -240,7 +243,7 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
++tcp->iov_size;
}
GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
- call_read_cb(exec_ctx, tcp, 1);
+ call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE);
TCP_UNREF(exec_ctx, tcp, "read");
}
@@ -248,13 +251,13 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
}
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- bool success) {
+ grpc_error *error) {
grpc_tcp *tcp = (grpc_tcp *)arg;
GPR_ASSERT(!tcp->finished_edge);
- if (!success) {
+ if (error != GRPC_ERROR_NONE) {
gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
- call_read_cb(exec_ctx, tcp, 0);
+ call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
TCP_UNREF(exec_ctx, tcp, "read");
} else {
tcp_continue_read(exec_ctx, tcp);
@@ -271,17 +274,16 @@ static void tcp_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
TCP_REF(tcp, "read");
if (tcp->finished_edge) {
- tcp->finished_edge = 0;
+ tcp->finished_edge = false;
grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &tcp->read_closure, GRPC_ERROR_NONE, NULL);
}
}
-typedef enum { FLUSH_DONE, FLUSH_PENDING, FLUSH_ERROR } flush_result;
-
+/* returns true if done, false if pending; if returning true, *error is set */
#define MAX_WRITE_IOVEC 16
-static flush_result tcp_flush(grpc_tcp *tcp) {
+static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
msg_iovlen_type iov_size;
@@ -331,10 +333,10 @@ static flush_result tcp_flush(grpc_tcp *tcp) {
if (errno == EAGAIN) {
tcp->outgoing_slice_idx = unwind_slice_idx;
tcp->outgoing_byte_idx = unwind_byte_idx;
- return FLUSH_PENDING;
+ return false;
} else {
- /* TODO(klempner): Log some of these */
- return FLUSH_ERROR;
+ *error = GRPC_OS_ERROR(errno, "sendmsg");
+ return true;
}
}
@@ -355,42 +357,42 @@ static flush_result tcp_flush(grpc_tcp *tcp) {
}
if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
- return FLUSH_DONE;
+ *error = GRPC_ERROR_NONE;
+ return true;
}
};
}
static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
- bool success) {
+ grpc_error *error) {
grpc_tcp *tcp = (grpc_tcp *)arg;
- flush_result status;
grpc_closure *cb;
- if (!success) {
+ if (error != GRPC_ERROR_NONE) {
cb = tcp->write_cb;
tcp->write_cb = NULL;
- cb->cb(exec_ctx, cb->cb_arg, 0);
+ cb->cb(exec_ctx, cb->cb_arg, error);
TCP_UNREF(exec_ctx, tcp, "write");
return;
}
- status = tcp_flush(tcp);
- if (status == FLUSH_PENDING) {
+ if (!tcp_flush(tcp, &error)) {
grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
} else {
cb = tcp->write_cb;
tcp->write_cb = NULL;
GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
- cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE);
+ cb->cb(exec_ctx, cb->cb_arg, error);
GPR_TIMER_END("tcp_handle_write.cb", 0);
TCP_UNREF(exec_ctx, tcp, "write");
+ GRPC_ERROR_UNREF(error);
}
}
static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
gpr_slice_buffer *buf, grpc_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- flush_result status;
+ grpc_error *error = GRPC_ERROR_NONE;
if (grpc_tcp_trace) {
size_t i;
@@ -408,20 +410,22 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
if (buf->length == 0) {
GPR_TIMER_END("tcp_write", 0);
- grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cb, grpc_fd_is_shutdown(tcp->em_fd)
+ ? GRPC_ERROR_CREATE("EOF")
+ : GRPC_ERROR_NONE,
+ NULL);
return;
}
tcp->outgoing_buffer = buf;
tcp->outgoing_slice_idx = 0;
tcp->outgoing_byte_idx = 0;
- status = tcp_flush(tcp);
- if (status == FLUSH_PENDING) {
+ if (!tcp_flush(tcp, &error)) {
TCP_REF(tcp, "write");
tcp->write_cb = cb;
grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
} else {
- grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
GPR_TIMER_END("tcp_write", 0);
@@ -461,7 +465,7 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
tcp->incoming_buffer = NULL;
tcp->slice_size = slice_size;
tcp->iov_size = 1;
- tcp->finished_edge = 1;
+ tcp->finished_edge = true;
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);
tcp->em_fd = em_fd;
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index fee14ae661..1d6e70dbe9 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -58,7 +58,8 @@ typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
/* Create a server, initially not bound to any ports. The caller owns one ref.
If shutdown_complete is not NULL, it will be used by
grpc_tcp_server_unref() when the ref count reaches zero. */
-grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete);
+grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
+ grpc_tcp_server **server);
/* Start listening to bound ports */
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
@@ -74,8 +75,8 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *server,
but not dualstack sockets. */
/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
all of the multiple socket port matching logic in one place */
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len);
+grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+ size_t addr_len, int *out_port);
/* Number of fds at the given port_index, or 0 if port_index is out of
bounds. */
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 909e34abc7..6fb547bb36 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -59,6 +59,8 @@
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/sockaddr_utils.h"
#include "src/core/lib/iomgr/socket_utils_posix.h"
@@ -133,7 +135,8 @@ struct grpc_tcp_server {
size_t next_pollset_to_assign;
};
-grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
+grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
+ grpc_tcp_server **server) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
gpr_ref_init(&s->refs, 1);
gpr_mu_init(&s->mu);
@@ -149,12 +152,13 @@ grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
s->tail = NULL;
s->nports = 0;
s->next_pollset_to_assign = 0;
- return s;
+ *server = s;
+ 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_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
}
gpr_mu_destroy(&s->mu);
@@ -169,7 +173,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
}
static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
- bool success) {
+ grpc_error *error) {
grpc_tcp_server *s = server;
gpr_mu_lock(&s->mu);
s->destroyed_ports++;
@@ -263,61 +267,68 @@ static int get_max_accept_queue_size(void) {
}
/* Prepare a recently-created socket for listening. */
-static int prepare_socket(int fd, const struct sockaddr *addr,
- size_t addr_len) {
+static grpc_error *prepare_socket(int fd, const struct sockaddr *addr,
+ size_t addr_len, int *port) {
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
-
- if (fd < 0) {
- goto error;
- }
-
- if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
- (!grpc_is_unix_socket(addr) && (!grpc_set_socket_low_latency(fd, 1) ||
- !grpc_set_socket_reuse_addr(fd, 1))) ||
- !grpc_set_socket_no_sigpipe_if_possible(fd)) {
- gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
- strerror(errno));
- goto error;
+ grpc_error *err = GRPC_ERROR_NONE;
+
+ GPR_ASSERT(fd >= 0);
+
+ err = grpc_set_socket_nonblocking(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_cloexec(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ if (!grpc_is_unix_socket(addr)) {
+ err = grpc_set_socket_low_latency(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
+ err = grpc_set_socket_reuse_addr(fd, 1);
+ if (err != GRPC_ERROR_NONE) goto error;
}
+ err = grpc_set_socket_no_sigpipe_if_possible(fd);
+ if (err != GRPC_ERROR_NONE) goto error;
GPR_ASSERT(addr_len < ~(socklen_t)0);
if (bind(fd, addr, (socklen_t)addr_len) < 0) {
- char *addr_str;
- grpc_sockaddr_to_string(&addr_str, addr, 0);
- gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, strerror(errno));
- gpr_free(addr_str);
+ err = GRPC_OS_ERROR(errno, "bind");
goto error;
}
if (listen(fd, get_max_accept_queue_size()) < 0) {
- gpr_log(GPR_ERROR, "listen: %s", strerror(errno));
+ err = GRPC_OS_ERROR(errno, "listen");
goto error;
}
sockname_len = sizeof(sockname_temp);
if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+ err = GRPC_OS_ERROR(errno, "getsockname");
goto error;
}
- return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ *port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ return GRPC_ERROR_NONE;
error:
+ GPR_ASSERT(err != GRPC_ERROR_NONE);
if (fd >= 0) {
close(fd);
}
- return -1;
+ grpc_error *ret = grpc_error_set_int(
+ GRPC_ERROR_CREATE_REFERENCING("Unable to configure socket", &err, 1),
+ GRPC_ERROR_INT_FD, fd);
+ GRPC_ERROR_UNREF(err);
+ return ret;
}
/* event manager callback when reads are ready */
-static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
grpc_tcp_listener *sp = arg;
grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index,
sp->fd_index};
grpc_pollset *read_notifier_pollset = NULL;
grpc_fd *fdobj;
- if (!success) {
+ if (err != GRPC_ERROR_NONE) {
goto error;
}
@@ -386,18 +397,19 @@ error:
}
}
-static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
- const struct sockaddr *addr,
- size_t addr_len,
- unsigned port_index,
- unsigned fd_index) {
+static grpc_error *add_socket_to_server(grpc_tcp_server *s, int fd,
+ const struct sockaddr *addr,
+ size_t addr_len, unsigned port_index,
+ unsigned fd_index,
+ grpc_tcp_listener **listener) {
grpc_tcp_listener *sp = NULL;
- int port;
+ int port = -1;
char *addr_str;
char *name;
- port = prepare_socket(fd, addr, addr_len);
- if (port >= 0) {
+ grpc_error *err = prepare_socket(fd, addr, addr_len, &port);
+ if (err == GRPC_ERROR_NONE) {
+ GPR_ASSERT(port > 0);
grpc_sockaddr_to_string(&addr_str, (struct sockaddr *)&addr, 1);
gpr_asprintf(&name, "tcp-server-listener:%s", addr_str);
gpr_mu_lock(&s->mu);
@@ -427,11 +439,12 @@ static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
gpr_free(name);
}
- return sp;
+ *listener = sp;
+ return err;
}
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len) {
+grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+ size_t addr_len, int *out_port) {
grpc_tcp_listener *sp;
grpc_tcp_listener *sp2 = NULL;
int fd;
@@ -446,6 +459,7 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
int port;
unsigned port_index = 0;
unsigned fd_index = 0;
+ grpc_error *errs[2] = {GRPC_ERROR_NONE, GRPC_ERROR_NONE};
if (s->tail != NULL) {
port_index = s->tail->port_index + 1;
}
@@ -484,33 +498,35 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
/* Try listening on IPv6 first. */
addr = (struct sockaddr *)&wild6;
addr_len = sizeof(wild6);
- fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
- sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
- if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
- goto done;
- }
- if (sp != NULL) {
- ++fd_index;
- }
- /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
- if (port == 0 && sp != NULL) {
- grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port);
+ errs[0] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
+ if (errs[0] == GRPC_ERROR_NONE) {
+ errs[0] = add_socket_to_server(s, fd, addr, addr_len, port_index,
+ fd_index, &sp);
+ if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
+ goto done;
+ }
+ if (sp != NULL) {
+ ++fd_index;
+ }
+ /* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+ if (port == 0 && sp != NULL) {
+ grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port);
+ }
}
addr = (struct sockaddr *)&wild4;
addr_len = sizeof(wild4);
}
- fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
- if (fd < 0) {
- gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
- } else {
+ errs[1] = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
+ if (errs[1] == GRPC_ERROR_NONE) {
if (dsmode == GRPC_DSMODE_IPV4 &&
grpc_sockaddr_is_v4mapped(addr, &addr4_copy)) {
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
sp2 = sp;
- sp = add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index);
+ errs[1] =
+ add_socket_to_server(s, fd, addr, addr_len, port_index, fd_index, &sp);
if (sp2 != NULL && sp != NULL) {
sp2->sibling = sp;
sp->is_sibling = 1;
@@ -520,9 +536,21 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
done:
gpr_free(allocated_addr);
if (sp != NULL) {
- return sp->port;
+ *out_port = sp->port;
+ GRPC_ERROR_UNREF(errs[0]);
+ GRPC_ERROR_UNREF(errs[1]);
+ return GRPC_ERROR_NONE;
} else {
- return -1;
+ *out_port = -1;
+ char *addr_str = grpc_sockaddr_to_uri(addr);
+ grpc_error *err = grpc_error_set_str(
+ GRPC_ERROR_CREATE_REFERENCING("Failed to add port to server", errs,
+ GPR_ARRAY_SIZE(errs)),
+ GRPC_ERROR_STR_TARGET_ADDRESS, addr_str);
+ GRPC_ERROR_UNREF(errs[0]);
+ GRPC_ERROR_UNREF(errs[1]);
+ gpr_free(addr_str);
+ return err;
}
}
@@ -591,7 +619,8 @@ grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
grpc_closure *shutdown_starting) {
gpr_mu_lock(&s->mu);
- grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
+ grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
+ GRPC_ERROR_NONE);
gpr_mu_unlock(&s->mu);
}
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 8a21d930c8..86982bc183 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -102,7 +102,8 @@ struct grpc_tcp_server {
/* Public function. Allocates the proper data structures to hold a
grpc_tcp_server. */
-grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
+grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
+ grpc_tcp_server **server) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
gpr_ref_init(&s->refs, 1);
gpr_mu_init(&s->mu);
@@ -114,12 +115,13 @@ grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete) {
s->shutdown_starting.head = NULL;
s->shutdown_starting.tail = NULL;
s->shutdown_complete = shutdown_complete;
- return s;
+ *server = s;
+ 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_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
}
/* Now that the accepts have been aborted, we can destroy the sockets.
@@ -143,7 +145,8 @@ grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
grpc_closure *shutdown_starting) {
gpr_mu_lock(&s->mu);
- grpc_closure_list_add(&s->shutdown_starting, shutdown_starting, 1);
+ grpc_closure_list_append(&s->shutdown_starting, shutdown_starting,
+ GRPC_ERROR_NONE);
gpr_mu_unlock(&s->mu);
}
@@ -187,51 +190,49 @@ void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
}
/* Prepare (bind) a recently-created socket for listening. */
-static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
- size_t addr_len) {
+static grpc_error *prepare_socket(SOCKET sock, const struct sockaddr *addr,
+ size_t addr_len, int *port) {
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
+ grpc_error *error = GRPC_ERROR_NONE;
- if (sock == INVALID_SOCKET) goto error;
-
- if (!grpc_tcp_prepare_socket(sock)) {
- char *utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, "Unable to prepare socket: %s", utf8_message);
- gpr_free(utf8_message);
- goto error;
+ error = grpc_tcp_prepare_socket(sock);
+ if (error != GRPC_ERROR_NONE) {
+ goto failure;
}
if (bind(sock, addr, (int)addr_len) == SOCKET_ERROR) {
- char *addr_str;
- char *utf8_message = gpr_format_message(WSAGetLastError());
- grpc_sockaddr_to_string(&addr_str, addr, 0);
- gpr_log(GPR_ERROR, "bind addr=%s: %s", addr_str, utf8_message);
- gpr_free(utf8_message);
- gpr_free(addr_str);
- goto error;
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "bind");
+ goto failure;
}
if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
- char *utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, "listen: %s", utf8_message);
- gpr_free(utf8_message);
- goto error;
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "listen");
+ goto failure;
}
sockname_len = sizeof(sockname_temp);
if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
SOCKET_ERROR) {
- char *utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
- gpr_free(utf8_message);
- goto error;
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname");
+ goto failure;
}
- return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ *port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ return GRPC_ERROR_NONE;
-error:
+failure:
+ GPR_ASSERT(error != GRPC_ERROR_NONE);
+ char *tgtaddr = grpc_sockaddr_to_uri(addr);
+ grpc_error *final_error = grpc_error_set_int(
+ grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING(
+ "Failed to prepare server socket", &error, 1),
+ GRPC_ERROR_STR_TARGET_ADDRESS, tgtaddr),
+ GRPC_ERROR_INT_FD, (intptr_t)sock);
+ gpr_free(tgtaddr);
+ GRPC_ERROR_UNREF(error);
if (sock != INVALID_SOCKET) closesocket(sock);
- return -1;
+ return error;
}
static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
@@ -251,26 +252,23 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
/* 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 void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
+static grpc_error *start_accept(grpc_exec_ctx *exec_ctx,
+ grpc_tcp_listener *port) {
SOCKET sock = INVALID_SOCKET;
- char *message;
- char *utf8_message;
BOOL success;
DWORD addrlen = sizeof(struct sockaddr_in6) + 16;
DWORD bytes_received = 0;
+ grpc_error *error = GRPC_ERROR_NONE;
sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
-
if (sock == INVALID_SOCKET) {
- message = "Unable to create socket: %s";
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
goto failure;
}
- if (!grpc_tcp_prepare_socket(sock)) {
- message = "Unable to prepare socket: %s";
- goto failure;
- }
+ error = grpc_tcp_prepare_socket(sock);
+ if (error != GRPC_ERROR_NONE) goto failure;
/* Start the "accept" asynchronously. */
success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
@@ -280,9 +278,9 @@ static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
/* It is possible to get an accept immediately without delay. However, we
will still get an IOCP notification for it. So let's just ignore it. */
if (!success) {
- int error = WSAGetLastError();
- if (error != ERROR_IO_PENDING) {
- message = "AcceptEx failed: %s";
+ int last_error = WSAGetLastError();
+ if (last_error != ERROR_IO_PENDING) {
+ error = GRPC_WSA_ERROR(last_error, "AcceptEx");
goto failure;
}
}
@@ -291,9 +289,10 @@ static void start_accept(grpc_exec_ctx *exec_ctx, grpc_tcp_listener *port) {
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);
- return;
+ 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
@@ -301,16 +300,15 @@ failure:
but we fail there because the listening port has been closed in the
meantime. */
decrement_active_ports_and_notify(exec_ctx, port);
- return;
+ GRPC_ERROR_UNREF(error);
+ return GRPC_ERROR_NONE;
}
- utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, message, utf8_message);
- gpr_free(utf8_message);
if (sock != INVALID_SOCKET) closesocket(sock);
+ return error;
}
/* Event manager callback when reads are ready. */
-static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
+static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_tcp_listener *sp = arg;
grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0};
SOCKET sock = sp->new_socket;
@@ -328,7 +326,10 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
/* The general mechanism for shutting down is to queue abortion calls. While
this is necessary in the read/write case, it's useless for the accept
case. We only need to adjust the pending callback count */
- if (!from_iocp) {
+ if (error != GRPC_ERROR_NONE) {
+ const char *msg = grpc_error_string(error);
+ gpr_log(GPR_INFO, "Skipping on_accept due to error: %s", msg);
+ grpc_error_free_string(msg);
return;
}
@@ -387,21 +388,20 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
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. */
- start_accept(exec_ctx, sp);
+ GPR_ASSERT(GRPC_LOG_IF_ERROR("start_accept", start_accept(exec_ctx, sp)));
}
-static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
- const struct sockaddr *addr,
- size_t addr_len,
- unsigned port_index) {
+static grpc_error *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
+ const struct sockaddr *addr,
+ size_t addr_len, unsigned port_index,
+ grpc_tcp_listener **listener) {
grpc_tcp_listener *sp = NULL;
- int port;
+ int port = -1;
int status;
GUID guid = WSAID_ACCEPTEX;
DWORD ioctl_num_bytes;
LPFN_ACCEPTEX AcceptEx;
-
- if (sock == INVALID_SOCKET) return NULL;
+ grpc_error *error = GRPC_ERROR_NONE;
/* We need to grab the AcceptEx pointer for that port, as it may be
interface-dependent. We'll cache it to avoid doing that again. */
@@ -417,44 +417,49 @@ static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
return NULL;
}
- port = prepare_socket(sock, addr, addr_len);
- if (port >= 0) {
- gpr_mu_lock(&s->mu);
- GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
- sp = gpr_malloc(sizeof(grpc_tcp_listener));
- sp->next = NULL;
- if (s->head == NULL) {
- s->head = sp;
- } else {
- s->tail->next = sp;
- }
- s->tail = sp;
- sp->server = s;
- sp->socket = grpc_winsocket_create(sock, "listener");
- sp->shutting_down = 0;
- sp->AcceptEx = AcceptEx;
- sp->new_socket = INVALID_SOCKET;
- sp->port = port;
- sp->port_index = port_index;
- grpc_closure_init(&sp->on_accept, on_accept, sp);
- GPR_ASSERT(sp->socket);
- gpr_mu_unlock(&s->mu);
+ error = prepare_socket(sock, addr, addr_len, &port);
+ if (error != GRPC_ERROR_NONE) {
+ return error;
}
- return sp;
+ GPR_ASSERT(port >= 0);
+ gpr_mu_lock(&s->mu);
+ GPR_ASSERT(!s->on_accept_cb && "must add ports before starting server");
+ sp = gpr_malloc(sizeof(grpc_tcp_listener));
+ sp->next = NULL;
+ if (s->head == NULL) {
+ s->head = sp;
+ } else {
+ s->tail->next = sp;
+ }
+ s->tail = sp;
+ sp->server = s;
+ sp->socket = grpc_winsocket_create(sock, "listener");
+ sp->shutting_down = 0;
+ sp->AcceptEx = AcceptEx;
+ sp->new_socket = INVALID_SOCKET;
+ sp->port = port;
+ sp->port_index = port_index;
+ grpc_closure_init(&sp->on_accept, on_accept, sp);
+ GPR_ASSERT(sp->socket);
+ gpr_mu_unlock(&s->mu);
+ *listener = sp;
+
+ return GRPC_ERROR_NONE;
}
-int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
- size_t addr_len) {
- grpc_tcp_listener *sp;
+grpc_error *grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
+ size_t addr_len, int *port) {
+ grpc_tcp_listener *sp = NULL;
SOCKET sock;
struct sockaddr_in6 addr6_v4mapped;
struct sockaddr_in6 wildcard;
struct sockaddr *allocated_addr = NULL;
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
- int port;
unsigned port_index = 0;
+ grpc_error *error = GRPC_ERROR_NONE;
+
if (s->tail != NULL) {
port_index = s->tail->port_index + 1;
}
@@ -466,11 +471,11 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
sockname_len = sizeof(sockname_temp);
if (0 == getsockname(sp->socket->socket,
(struct sockaddr *)&sockname_temp, &sockname_len)) {
- port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
- if (port > 0) {
+ *port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ if (*port > 0) {
allocated_addr = gpr_malloc(addr_len);
memcpy(allocated_addr, addr, addr_len);
- grpc_sockaddr_set_port(allocated_addr, port);
+ grpc_sockaddr_set_port(allocated_addr, *port);
addr = allocated_addr;
break;
}
@@ -484,8 +489,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
}
/* Treat :: or 0.0.0.0 as a family-agnostic wildcard. */
- if (grpc_sockaddr_is_wildcard(addr, &port)) {
- grpc_sockaddr_make_wildcard6(port, &wildcard);
+ if (grpc_sockaddr_is_wildcard(addr, port)) {
+ grpc_sockaddr_make_wildcard6(*port, &wildcard);
addr = (struct sockaddr *)&wildcard;
addr_len = sizeof(wildcard);
@@ -494,19 +499,26 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) {
- char *utf8_message = gpr_format_message(WSAGetLastError());
- gpr_log(GPR_ERROR, "unable to create socket: %s", utf8_message);
- gpr_free(utf8_message);
+ error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket");
+ goto done;
}
- sp = add_socket_to_server(s, sock, addr, addr_len, port_index);
+ error = add_socket_to_server(s, sock, addr, addr_len, port_index, &sp);
+
+done:
gpr_free(allocated_addr);
- if (sp) {
- return sp->port;
+ if (error != GRPC_ERROR_NONE) {
+ grpc_error *error_out = GRPC_ERROR_CREATE_REFERENCING(
+ "Failed to add port to server", &error, 1);
+ GRPC_ERROR_UNREF(error);
+ error = error_out;
+ *port = -1;
} else {
- return -1;
+ GPR_ASSERT(sp != NULL);
+ *port = sp->port;
}
+ return error;
}
void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
@@ -521,7 +533,7 @@ 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) {
- start_accept(exec_ctx, sp);
+ GPR_ASSERT(GRPC_LOG_IF_ERROR("start_accept", start_accept(exec_ctx, sp)));
s->active_ports++;
}
gpr_mu_unlock(&s->mu);
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index f44bf5fda4..b2af8030aa 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -61,27 +61,34 @@
#define GRPC_FIONBIO FIONBIO
#endif
-static int set_non_block(SOCKET sock) {
+static grpc_error *set_non_block(SOCKET sock) {
int status;
uint32_t param = 1;
DWORD ret;
status = WSAIoctl(sock, GRPC_FIONBIO, &param, sizeof(param), NULL, 0, &ret,
NULL, NULL);
- return status == 0;
+ return status == 0
+ ? GRPC_ERROR_NONE
+ : GRPC_WSA_ERROR(WSAGetLastError(), "WSAIoctl(GRPC_FIONBIO)");
}
-static int set_dualstack(SOCKET sock) {
+static grpc_error *set_dualstack(SOCKET sock) {
int status;
unsigned long param = 0;
status = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&param,
sizeof(param));
- return status == 0;
+ return status == 0
+ ? GRPC_ERROR_NONE
+ : GRPC_WSA_ERROR(WSAGetLastError(), "setsockopt(IPV6_V6ONLY)");
}
-int grpc_tcp_prepare_socket(SOCKET sock) {
- if (!set_non_block(sock)) return 0;
- if (!set_dualstack(sock)) return 0;
- return 1;
+grpc_error *grpc_tcp_prepare_socket(SOCKET sock) {
+ grpc_error *err;
+ err = set_non_block(sock);
+ if (err != GRPC_ERROR_NONE) return err;
+ err = set_dualstack(sock);
+ if (err != GRPC_ERROR_NONE) return err;
+ return GRPC_ERROR_NONE;
}
typedef struct grpc_tcp {
@@ -148,39 +155,35 @@ static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
#endif
/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
+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_winsocket_callback_info *info = &socket->read_info;
- if (success) {
+ GRPC_ERROR_REF(error);
+
+ if (error == GRPC_ERROR_NONE) {
if (info->wsa_error != 0 && !tcp->shutting_down) {
- if (info->wsa_error != WSAECONNRESET) {
- char *utf8_message = gpr_format_message(info->wsa_error);
- gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
- gpr_free(utf8_message);
- }
- success = 0;
+ 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);
} 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);
- success = 1;
} else {
gpr_slice_unref(tcp->read_slice);
- success = 0;
+ error = GRPC_ERROR_CREATE("End of TCP stream");
}
}
}
tcp->read_cb = NULL;
TCP_UNREF(tcp, "read");
- if (cb) {
- cb->cb(exec_ctx, cb->cb_arg, success);
- }
+ grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -194,7 +197,8 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
WSABUF buffer;
if (tcp->shutting_down) {
- grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cb,
+ GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
return;
}
@@ -218,7 +222,7 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
/* Did we get data immediately ? Yay. */
if (info->wsa_error != WSAEWOULDBLOCK) {
info->bytes_transfered = bytes_read;
- grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE, NULL);
return;
}
@@ -231,7 +235,8 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
int wsa_error = WSAGetLastError();
if (wsa_error != WSA_IO_PENDING) {
info->wsa_error = wsa_error;
- grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &tcp->on_read,
+ GRPC_WSA_ERROR(info->wsa_error, "WSARecv"), NULL);
return;
}
}
@@ -240,32 +245,29 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
}
/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
+static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, grpc_error *error) {
grpc_tcp *tcp = (grpc_tcp *)tcpp;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->write_info;
grpc_closure *cb;
+ GRPC_ERROR_REF(error);
+
gpr_mu_lock(&tcp->mu);
cb = tcp->write_cb;
tcp->write_cb = NULL;
gpr_mu_unlock(&tcp->mu);
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
if (info->wsa_error != 0) {
- if (info->wsa_error != WSAECONNRESET) {
- char *utf8_message = gpr_format_message(info->wsa_error);
- gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
- gpr_free(utf8_message);
- }
- success = 0;
+ error = GRPC_WSA_ERROR(info->wsa_error, "WSASend");
} else {
GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
}
}
TCP_UNREF(tcp, "write");
- cb->cb(exec_ctx, cb->cb_arg, success);
+ grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
}
/* Initiates a write. */
@@ -283,7 +285,8 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
size_t len;
if (tcp->shutting_down) {
- grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cb,
+ GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
return;
}
@@ -311,19 +314,10 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
connection that has its send queue filled up. But if we don't, then we can
avoid doing an async write operation at all. */
if (info->wsa_error != WSAEWOULDBLOCK) {
- bool ok = false;
- if (status == 0) {
- ok = true;
- GPR_ASSERT(bytes_sent == tcp->write_slices->length);
- } else {
- if (info->wsa_error != WSAECONNRESET) {
- char *utf8_message = gpr_format_message(info->wsa_error);
- gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
- gpr_free(utf8_message);
- }
- }
- if (allocated) gpr_free(allocated);
- grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
+ grpc_error *error = status == 0
+ ? GRPC_ERROR_NONE
+ : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
+ grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
return;
}
@@ -340,7 +334,8 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
int wsa_error = WSAGetLastError();
if (wsa_error != WSA_IO_PENDING) {
TCP_UNREF(tcp, "write");
- grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"),
+ NULL);
return;
}
}
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
index a2f58eddd5..86d777235e 100644
--- a/src/core/lib/iomgr/tcp_windows.h
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -52,6 +52,6 @@
*/
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string);
-int grpc_tcp_prepare_socket(SOCKET sock);
+grpc_error *grpc_tcp_prepare_socket(SOCKET sock);
#endif /* GRPC_CORE_LIB_IOMGR_TCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/timer.c b/src/core/lib/iomgr/timer.c
index acb5b26c87..9975fa1671 100644
--- a/src/core/lib/iomgr/timer.c
+++ b/src/core/lib/iomgr/timer.c
@@ -73,7 +73,7 @@ static shard_type *g_shard_queue[NUM_SHARDS];
static bool g_initialized = false;
static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
- gpr_timespec *next, int success);
+ gpr_timespec *next, grpc_error *error);
static gpr_timespec compute_min_deadline(shard_type *shard) {
return grpc_timer_heap_is_empty(&shard->heap)
@@ -105,7 +105,8 @@ void grpc_timer_list_init(gpr_timespec now) {
void grpc_timer_list_shutdown(grpc_exec_ctx *exec_ctx) {
int i;
- run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL, 0);
+ run_some_expired_timers(exec_ctx, gpr_inf_future(g_clock_type), NULL,
+ GRPC_ERROR_CREATE("Timer list shutdown"));
for (i = 0; i < NUM_SHARDS; i++) {
shard_type *shard = &g_shards[i];
gpr_mu_destroy(&shard->mu);
@@ -185,13 +186,16 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
if (!g_initialized) {
timer->triggered = 1;
- grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL);
+ grpc_exec_ctx_sched(
+ exec_ctx, &timer->closure,
+ GRPC_ERROR_CREATE("Attempt to create timer before initialization"),
+ NULL);
return;
}
if (gpr_time_cmp(deadline, now) <= 0) {
timer->triggered = 1;
- grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL);
return;
}
@@ -235,10 +239,15 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
}
void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
+ if (!g_initialized) {
+ /* must have already been cancelled, also the shard mutex is invalid */
+ return;
+ }
+
shard_type *shard = &g_shards[shard_idx(timer)];
gpr_mu_lock(&shard->mu);
if (!timer->triggered) {
- grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED, NULL);
timer->triggered = 1;
if (timer->heap_index == INVALID_HEAP_INDEX) {
list_remove(timer);
@@ -278,8 +287,8 @@ static int refill_queue(shard_type *shard, gpr_timespec now) {
return !grpc_timer_heap_is_empty(&shard->heap);
}
-/* This pops the next non-cancelled timer with deadline <= now from the queue,
- or returns NULL if there isn't one.
+/* This pops the next non-cancelled timer with deadline <= now from the
+ queue, or returns NULL if there isn't one.
REQUIRES: shard->mu locked */
static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
grpc_timer *timer;
@@ -299,12 +308,12 @@ static grpc_timer *pop_one(shard_type *shard, gpr_timespec now) {
/* REQUIRES: shard->mu unlocked */
static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
gpr_timespec now, gpr_timespec *new_min_deadline,
- int success) {
+ grpc_error *error) {
size_t n = 0;
grpc_timer *timer;
gpr_mu_lock(&shard->mu);
while ((timer = pop_one(shard, now))) {
- grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error), NULL);
n++;
}
*new_min_deadline = compute_min_deadline(shard);
@@ -313,7 +322,7 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
}
static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
- gpr_timespec *next, int success) {
+ gpr_timespec *next, grpc_error *error) {
size_t n = 0;
/* TODO(ctiller): verify that there are any timers (atomically) here */
@@ -327,8 +336,8 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
/* For efficiency, we pop as many available timers as we can from the
shard. This may violate perfect timer deadline ordering, but that
shouldn't be a big deal because we don't make ordering guarantees. */
- n += pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline,
- success);
+ n +=
+ pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, error);
/* An grpc_timer_init() on the shard could intervene here, adding a new
timer that is earlier than new_min_deadline. However,
@@ -359,6 +368,8 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_timespec now,
*next, gpr_time_add(now, gpr_time_from_millis(1, GPR_TIMESPAN)));
}
+ GRPC_ERROR_UNREF(error);
+
return (int)n;
}
@@ -367,5 +378,7 @@ bool grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
GPR_ASSERT(now.clock_type == g_clock_type);
return run_some_expired_timers(
exec_ctx, now, next,
- gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
+ gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0
+ ? GRPC_ERROR_NONE
+ : GRPC_ERROR_CREATE("Shutting down timer system"));
}
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 98ffccd59b..16150687d3 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -210,6 +210,8 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
size_t addr_len) {
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
+ /* Set send/receive socket buffers to 1 MB */
+ int buffer_size_bytes = 1024 * 1024;
if (fd < 0) {
goto error;
@@ -239,6 +241,18 @@ static int prepare_socket(int fd, const struct sockaddr *addr,
goto error;
}
+ if (!grpc_set_socket_sndbuf(fd, buffer_size_bytes)) {
+ gpr_log(GPR_ERROR, "Failed to set send buffer size to %d bytes",
+ buf_size_bytes);
+ goto error;
+ }
+
+ if (!grpc_set_socket_rcvbuf(fd, buffer_size_bytes)) {
+ gpr_log(GPR_ERROR, "Failed to set receive buffer size to %d bytes",
+ buf_size_bytes);
+ goto error;
+ }
+
return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
error:
diff --git a/src/core/lib/iomgr/unix_sockets_posix.c b/src/core/lib/iomgr/unix_sockets_posix.c
index 5767c852df..0e7670e5a5 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.c
+++ b/src/core/lib/iomgr/unix_sockets_posix.c
@@ -47,17 +47,18 @@ void grpc_create_socketpair_if_unix(int sv[2]) {
GPR_ASSERT(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
}
-grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) {
+grpc_error *grpc_resolve_unix_domain_address(const char *name,
+ grpc_resolved_addresses **addrs) {
struct sockaddr_un *un;
- grpc_resolved_addresses *addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
- addrs->naddrs = 1;
- addrs->addrs = gpr_malloc(sizeof(grpc_resolved_address));
- un = (struct sockaddr_un *)addrs->addrs->addr;
+ *addrs = gpr_malloc(sizeof(grpc_resolved_addresses));
+ (*addrs)->naddrs = 1;
+ (*addrs)->addrs = gpr_malloc(sizeof(grpc_resolved_address));
+ un = (struct sockaddr_un *)(*addrs)->addrs->addr;
un->sun_family = AF_UNIX;
strcpy(un->sun_path, name);
- addrs->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
- return addrs;
+ (*addrs)->addrs->len = strlen(un->sun_path) + sizeof(un->sun_family) + 1;
+ return GRPC_ERROR_NONE;
}
int grpc_is_unix_socket(const struct sockaddr *addr) {
diff --git a/src/core/lib/iomgr/unix_sockets_posix.h b/src/core/lib/iomgr/unix_sockets_posix.h
index 6758c498e5..db0516d945 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.h
+++ b/src/core/lib/iomgr/unix_sockets_posix.h
@@ -43,7 +43,8 @@
void grpc_create_socketpair_if_unix(int sv[2]);
-grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name);
+grpc_error *grpc_resolve_unix_domain_address(
+ const char *name, grpc_resolved_addresses **addresses);
int grpc_is_unix_socket(const struct sockaddr *addr);
diff --git a/src/core/lib/iomgr/unix_sockets_posix_noop.c b/src/core/lib/iomgr/unix_sockets_posix_noop.c
index d30952789f..56b47c3daf 100644
--- a/src/core/lib/iomgr/unix_sockets_posix_noop.c
+++ b/src/core/lib/iomgr/unix_sockets_posix_noop.c
@@ -44,8 +44,10 @@ void grpc_create_socketpair_if_unix(int sv[2]) {
GPR_ASSERT(0);
}
-grpc_resolved_addresses *grpc_resolve_unix_domain_address(const char *name) {
- return NULL;
+grpc_error *grpc_resolve_unix_domain_address(
+ const char *name, grpc_resolved_addresses **addresses) {
+ *addresses = NULL;
+ return GRPC_ERROR_CREATE("Unix domain sockets are not supported on Windows");
}
int grpc_is_unix_socket(const struct sockaddr *addr) { return false; }
diff --git a/src/core/lib/iomgr/wakeup_fd_eventfd.c b/src/core/lib/iomgr/wakeup_fd_eventfd.c
index 8a772add13..667b4a5f90 100644
--- a/src/core/lib/iomgr/wakeup_fd_eventfd.c
+++ b/src/core/lib/iomgr/wakeup_fd_eventfd.c
@@ -44,29 +44,39 @@
#include "src/core/lib/iomgr/wakeup_fd_posix.h"
#include "src/core/lib/profiling/timers.h"
-static void eventfd_create(grpc_wakeup_fd* fd_info) {
+static grpc_error* eventfd_create(grpc_wakeup_fd* fd_info) {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- /* TODO(klempner): Handle failure more gracefully */
- GPR_ASSERT(efd >= 0);
+ if (efd < 0) {
+ return GRPC_OS_ERROR(errno, "eventfd");
+ }
fd_info->read_fd = efd;
fd_info->write_fd = -1;
+ return GRPC_ERROR_NONE;
}
-static void eventfd_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error* eventfd_consume(grpc_wakeup_fd* fd_info) {
eventfd_t value;
int err;
do {
err = eventfd_read(fd_info->read_fd, &value);
} while (err < 0 && errno == EINTR);
+ if (err < 0 && errno != EAGAIN) {
+ return GRPC_OS_ERROR(errno, "eventfd_read");
+ }
+ return GRPC_ERROR_NONE;
}
-static void eventfd_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error* eventfd_wakeup(grpc_wakeup_fd* fd_info) {
int err;
GPR_TIMER_BEGIN("eventfd_wakeup", 0);
do {
err = eventfd_write(fd_info->read_fd, 1);
} while (err < 0 && errno == EINTR);
+ if (err < 0) {
+ return GRPC_OS_ERROR(errno, "eventfd_write");
+ }
GPR_TIMER_END("eventfd_wakeup", 0);
+ return GRPC_ERROR_NONE;
}
static void eventfd_destroy(grpc_wakeup_fd* fd_info) {
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.c b/src/core/lib/iomgr/wakeup_fd_pipe.c
index e9b9a0119f..4e5dbdcb73 100644
--- a/src/core/lib/iomgr/wakeup_fd_pipe.c
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.c
@@ -45,7 +45,7 @@
#include "src/core/lib/iomgr/socket_utils_posix.h"
-static void pipe_init(grpc_wakeup_fd* fd_info) {
+static grpc_error* pipe_init(grpc_wakeup_fd* fd_info) {
int pipefd[2];
/* TODO(klempner): Make this nonfatal */
int r = pipe(pipefd);
@@ -53,36 +53,40 @@ static void pipe_init(grpc_wakeup_fd* fd_info) {
gpr_log(GPR_ERROR, "pipe creation failed (%d): %s", errno, strerror(errno));
abort();
}
- GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[0], 1));
- GPR_ASSERT(grpc_set_socket_nonblocking(pipefd[1], 1));
+ grpc_error* err;
+ err = grpc_set_socket_nonblocking(pipefd[0], 1);
+ if (err != GRPC_ERROR_NONE) return err;
+ err = grpc_set_socket_nonblocking(pipefd[1], 1);
+ if (err != GRPC_ERROR_NONE) return err;
fd_info->read_fd = pipefd[0];
fd_info->write_fd = pipefd[1];
+ return GRPC_ERROR_NONE;
}
-static void pipe_consume(grpc_wakeup_fd* fd_info) {
+static grpc_error* pipe_consume(grpc_wakeup_fd* fd_info) {
char buf[128];
ssize_t r;
for (;;) {
r = read(fd_info->read_fd, buf, sizeof(buf));
if (r > 0) continue;
- if (r == 0) return;
+ if (r == 0) return GRPC_ERROR_NONE;
switch (errno) {
case EAGAIN:
- return;
+ return GRPC_ERROR_NONE;
case EINTR:
continue;
default:
- gpr_log(GPR_ERROR, "error reading pipe: %s", strerror(errno));
- return;
+ return GRPC_OS_ERROR(errno, "read");
}
}
}
-static void pipe_wakeup(grpc_wakeup_fd* fd_info) {
+static grpc_error* pipe_wakeup(grpc_wakeup_fd* fd_info) {
char c = 0;
while (write(fd_info->write_fd, &c, 1) != 1 && errno == EINTR)
;
+ return GRPC_ERROR_NONE;
}
static void pipe_destroy(grpc_wakeup_fd* fd_info) {
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.c b/src/core/lib/iomgr/wakeup_fd_posix.c
index 525369c356..046208abc8 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.c
+++ b/src/core/lib/iomgr/wakeup_fd_posix.c
@@ -53,16 +53,16 @@ void grpc_wakeup_fd_global_init(void) {
void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; }
-void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
- wakeup_fd_vtable->init(fd_info);
+grpc_error *grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
+ return wakeup_fd_vtable->init(fd_info);
}
-void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) {
- wakeup_fd_vtable->consume(fd_info);
+grpc_error *grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd *fd_info) {
+ return wakeup_fd_vtable->consume(fd_info);
}
-void grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) {
- wakeup_fd_vtable->wakeup(fd_info);
+grpc_error *grpc_wakeup_fd_wakeup(grpc_wakeup_fd *fd_info) {
+ return wakeup_fd_vtable->wakeup(fd_info);
}
void grpc_wakeup_fd_destroy(grpc_wakeup_fd *fd_info) {
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h
index 6b069c1837..e269f242d8 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.h
+++ b/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -62,6 +62,8 @@
#ifndef GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
#define GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H
+#include "src/core/lib/iomgr/error.h"
+
void grpc_wakeup_fd_global_init(void);
void grpc_wakeup_fd_global_destroy(void);
@@ -72,9 +74,9 @@ void grpc_wakeup_fd_global_init_force_fallback(void);
typedef struct grpc_wakeup_fd grpc_wakeup_fd;
typedef struct grpc_wakeup_fd_vtable {
- void (*init)(grpc_wakeup_fd* fd_info);
- void (*consume)(grpc_wakeup_fd* fd_info);
- void (*wakeup)(grpc_wakeup_fd* fd_info);
+ grpc_error* (*init)(grpc_wakeup_fd* fd_info);
+ grpc_error* (*consume)(grpc_wakeup_fd* fd_info);
+ grpc_error* (*wakeup)(grpc_wakeup_fd* fd_info);
void (*destroy)(grpc_wakeup_fd* fd_info);
/* Must be called before calling any other functions */
int (*check_availability)(void);
@@ -89,9 +91,10 @@ extern int grpc_allow_specialized_wakeup_fd;
#define GRPC_WAKEUP_FD_GET_READ_FD(fd_info) ((fd_info)->read_fd)
-void grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info);
-void grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info);
-void grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info);
+grpc_error* grpc_wakeup_fd_init(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
+grpc_error* grpc_wakeup_fd_consume_wakeup(grpc_wakeup_fd* fd_info)
+ GRPC_MUST_USE_RESULT;
+grpc_error* grpc_wakeup_fd_wakeup(grpc_wakeup_fd* fd_info) GRPC_MUST_USE_RESULT;
void grpc_wakeup_fd_destroy(grpc_wakeup_fd* fd_info);
/* Defined in some specialized implementation's .c file, or by
diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h
index eeca8c0bf2..5cc40eea50 100644
--- a/src/core/lib/iomgr/workqueue.h
+++ b/src/core/lib/iomgr/workqueue.h
@@ -50,7 +50,8 @@
/* grpc_workqueue is forward declared in exec_ctx.h */
/** Create a work queue */
-grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx);
+grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
+ grpc_workqueue **workqueue);
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
@@ -77,7 +78,7 @@ void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset);
/** Add a work item to a workqueue */
-void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
- int success);
+void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
+ grpc_closure *closure, grpc_error *error);
#endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_H */
diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c
index 80e7a0b206..45e0f6063b 100644
--- a/src/core/lib/iomgr/workqueue_posix.c
+++ b/src/core/lib/iomgr/workqueue_posix.c
@@ -45,22 +45,27 @@
#include "src/core/lib/iomgr/ev_posix.h"
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
-grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) {
+grpc_error *grpc_workqueue_create(grpc_exec_ctx *exec_ctx,
+ grpc_workqueue **workqueue) {
char name[32];
- grpc_workqueue *workqueue = gpr_malloc(sizeof(grpc_workqueue));
- gpr_ref_init(&workqueue->refs, 1);
- gpr_mu_init(&workqueue->mu);
- workqueue->closure_list.head = workqueue->closure_list.tail = NULL;
- grpc_wakeup_fd_init(&workqueue->wakeup_fd);
- sprintf(name, "workqueue:%p", (void *)workqueue);
- workqueue->wakeup_read_fd =
- grpc_fd_create(GRPC_WAKEUP_FD_GET_READ_FD(&workqueue->wakeup_fd), name);
- grpc_closure_init(&workqueue->read_closure, on_readable, workqueue);
- grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
- &workqueue->read_closure);
- return workqueue;
+ *workqueue = gpr_malloc(sizeof(grpc_workqueue));
+ gpr_ref_init(&(*workqueue)->refs, 1);
+ gpr_mu_init(&(*workqueue)->mu);
+ (*workqueue)->closure_list.head = (*workqueue)->closure_list.tail = NULL;
+ grpc_error *err = grpc_wakeup_fd_init(&(*workqueue)->wakeup_fd);
+ if (err != GRPC_ERROR_NONE) {
+ gpr_free(*workqueue);
+ return err;
+ }
+ sprintf(name, "workqueue:%p", (void *)(*workqueue));
+ (*workqueue)->wakeup_read_fd = grpc_fd_create(
+ GRPC_WAKEUP_FD_GET_READ_FD(&(*workqueue)->wakeup_fd), name);
+ grpc_closure_init(&(*workqueue)->read_closure, on_readable, *workqueue);
+ grpc_fd_notify_on_read(exec_ctx, (*workqueue)->wakeup_read_fd,
+ &(*workqueue)->read_closure);
+ return GRPC_ERROR_NONE;
}
static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
@@ -103,17 +108,14 @@ void grpc_workqueue_add_to_pollset(grpc_exec_ctx *exec_ctx,
void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
gpr_mu_lock(&workqueue->mu);
- if (grpc_closure_list_empty(workqueue->closure_list)) {
- grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
- }
grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
gpr_mu_unlock(&workqueue->mu);
}
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_workqueue *workqueue = arg;
- if (!success) {
+ if (error != GRPC_ERROR_NONE) {
gpr_mu_destroy(&workqueue->mu);
/* HACK: let wakeup_fd code know that we stole the fd */
workqueue->wakeup_fd.read_fd = 0;
@@ -123,20 +125,32 @@ static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
} else {
gpr_mu_lock(&workqueue->mu);
grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
- grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
+ error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
gpr_mu_unlock(&workqueue->mu);
- grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
- &workqueue->read_closure);
+ if (error == GRPC_ERROR_NONE) {
+ grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
+ &workqueue->read_closure);
+ } else {
+ /* recurse to get error handling */
+ on_readable(exec_ctx, arg, error);
+ }
}
}
-void grpc_workqueue_push(grpc_workqueue *workqueue, grpc_closure *closure,
- int success) {
+void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
+ grpc_closure *closure, grpc_error *error) {
+ grpc_error *push_error = GRPC_ERROR_NONE;
gpr_mu_lock(&workqueue->mu);
if (grpc_closure_list_empty(workqueue->closure_list)) {
- grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+ push_error = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+ }
+ grpc_closure_list_append(&workqueue->closure_list, closure, error);
+ if (push_error != GRPC_ERROR_NONE) {
+ const char *msg = grpc_error_string(push_error);
+ gpr_log(GPR_ERROR, "Failed to push to workqueue: %s", msg);
+ grpc_error_free_string(msg);
+ grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
}
- grpc_closure_list_add(&workqueue->closure_list, closure, success);
gpr_mu_unlock(&workqueue->mu);
}
diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c
index 50082cd7ee..ee464f310f 100644
--- a/src/core/lib/profiling/basic_timers.c
+++ b/src/core/lib/profiling/basic_timers.c
@@ -141,9 +141,9 @@ static void write_log(gpr_timer_log *log) {
entry->tm = gpr_time_0(entry->tm.clock_type);
}
fprintf(output_file,
- "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
+ "{\"t\": %"PRId64".%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
"\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
- (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd,
+ entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd,
entry->type, entry->tagstr, entry->file, entry->line,
entry->important);
}
diff --git a/src/core/lib/security/credentials/composite/composite_credentials.c b/src/core/lib/security/credentials/composite/composite_credentials.c
index 53dbce1e1e..850e41e646 100644
--- a/src/core/lib/security/credentials/composite/composite_credentials.c
+++ b/src/core/lib/security/credentials/composite/composite_credentials.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#include <string.h>
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/surface/api_trace.h"
#include <grpc/support/alloc.h>
@@ -49,7 +50,7 @@ typedef struct {
grpc_credentials_md_store *md_elems;
grpc_auth_metadata_context auth_md_context;
void *user_data;
- grpc_pollset *pollset;
+ grpc_polling_entity *pollent;
grpc_credentials_metadata_cb cb;
} grpc_composite_call_credentials_metadata_context;
@@ -94,7 +95,7 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_call_credentials *inner_creds =
ctx->composite_creds->inner.creds_array[ctx->creds_index++];
grpc_call_credentials_get_request_metadata(
- exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
+ exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context,
composite_call_metadata_cb, ctx);
return;
}
@@ -107,7 +108,7 @@ static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
static void composite_call_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
grpc_composite_call_credentials_metadata_context *ctx;
@@ -118,10 +119,10 @@ static void composite_call_get_request_metadata(
ctx->user_data = user_data;
ctx->cb = cb;
ctx->composite_creds = c;
- ctx->pollset = pollset;
+ ctx->pollent = pollent;
ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
grpc_call_credentials_get_request_metadata(
- exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
+ exec_ctx, c->inner.creds_array[ctx->creds_index++], ctx->pollent,
auth_md_context, composite_call_metadata_cb, ctx);
}
diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c
index 7034ed57c6..029a357261 100644
--- a/src/core/lib/security/credentials/credentials.c
+++ b/src/core/lib/security/credentials/credentials.c
@@ -58,6 +58,7 @@ grpc_credentials_metadata_request *grpc_credentials_metadata_request_create(
void *user_data) {
grpc_credentials_metadata_request *r =
gpr_malloc(sizeof(grpc_credentials_metadata_request));
+ memset(&r->response, 0, sizeof(r->response));
r->creds = grpc_call_credentials_ref(creds);
r->cb = cb;
r->user_data = user_data;
@@ -67,6 +68,7 @@ grpc_credentials_metadata_request *grpc_credentials_metadata_request_create(
void grpc_credentials_metadata_request_destroy(
grpc_credentials_metadata_request *r) {
grpc_call_credentials_unref(r->creds);
+ grpc_http_response_destroy(&r->response);
gpr_free(r);
}
@@ -111,7 +113,7 @@ void grpc_call_credentials_release(grpc_call_credentials *creds) {
void grpc_call_credentials_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
if (cb != NULL) {
@@ -119,7 +121,7 @@ void grpc_call_credentials_get_request_metadata(
}
return;
}
- creds->vtable->get_request_metadata(exec_ctx, creds, pollset, context, cb,
+ creds->vtable->get_request_metadata(exec_ctx, creds, pollent, context, cb,
user_data);
}
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index b097233bee..8e9d842ead 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -41,6 +41,7 @@
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/transport/security_connector.h"
struct grpc_http_response;
@@ -163,7 +164,8 @@ typedef void (*grpc_credentials_metadata_cb)(
typedef struct {
void (*destruct)(grpc_call_credentials *c);
void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
- grpc_call_credentials *c, grpc_pollset *pollset,
+ grpc_call_credentials *c,
+ grpc_polling_entity *pollent,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data);
@@ -179,7 +181,7 @@ grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
void grpc_call_credentials_unref(grpc_call_credentials *creds);
void grpc_call_credentials_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data);
/* Metadata-only credentials with the specified key and value where
@@ -222,6 +224,7 @@ grpc_server_credentials *grpc_find_server_credentials_in_args(
typedef struct {
grpc_call_credentials *creds;
grpc_credentials_metadata_cb cb;
+ grpc_http_response response;
void *user_data;
} grpc_credentials_metadata_request;
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c
index 8b518938cc..51cafd986f 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.c
+++ b/src/core/lib/security/credentials/fake/fake_credentials.c
@@ -95,7 +95,7 @@ static void md_only_test_destruct(grpc_call_credentials *creds) {
}
static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
- void *user_data, bool success) {
+ void *user_data, grpc_error *error) {
grpc_credentials_metadata_request *r =
(grpc_credentials_metadata_request *)user_data;
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
@@ -106,15 +106,16 @@ static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
static void md_only_test_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) {
grpc_credentials_metadata_request *cb_arg =
grpc_credentials_metadata_request_create(creds, cb, user_data);
- grpc_executor_enqueue(
- grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true);
+ grpc_executor_push(
+ grpc_closure_create(on_simulated_token_fetch_done, cb_arg),
+ GRPC_ERROR_NONE);
} else {
cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK, NULL);
}
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 a521d95abc..312a3d4f90 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
@@ -41,10 +41,12 @@
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/load_file.h"
+#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/support/env.h"
-#include "src/core/lib/support/load_file.h"
+#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
/* -- Constants. -- */
@@ -62,21 +64,23 @@ static gpr_once g_once = GPR_ONCE_INIT;
static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
typedef struct {
- grpc_pollset *pollset;
+ grpc_polling_entity pollent;
int is_done;
int success;
+ grpc_http_response response;
} compute_engine_detector;
-static void on_compute_engine_detection_http_response(
- grpc_exec_ctx *exec_ctx, void *user_data,
- const grpc_http_response *response) {
+static void on_compute_engine_detection_http_response(grpc_exec_ctx *exec_ctx,
+ void *user_data,
+ grpc_error *error) {
compute_engine_detector *detector = (compute_engine_detector *)user_data;
- if (response != NULL && response->status == 200 && response->hdr_count > 0) {
+ if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
+ detector->response.hdr_count > 0) {
/* Internet providers can return a generic response to all requests, so
it is necessary to check that metadata header is present also. */
size_t i;
- for (i = 0; i < response->hdr_count; i++) {
- grpc_http_header *header = &response->hdrs[i];
+ for (i = 0; i < detector->response.hdr_count; i++) {
+ grpc_http_header *header = &detector->response.hdrs[i];
if (strcmp(header->key, "Metadata-Flavor") == 0 &&
strcmp(header->value, "Google") == 0) {
detector->success = 1;
@@ -86,11 +90,13 @@ static void on_compute_engine_detection_http_response(
}
gpr_mu_lock(g_polling_mu);
detector->is_done = 1;
- grpc_pollset_kick(detector->pollset, NULL);
+ GRPC_LOG_IF_ERROR(
+ "Pollset kick",
+ grpc_pollset_kick(grpc_polling_entity_pollset(&detector->pollent), NULL));
gpr_mu_unlock(g_polling_mu);
}
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, grpc_error *e) {
grpc_pollset_destroy(p);
}
@@ -105,11 +111,13 @@ static int is_stack_running_on_compute_engine(void) {
on compute engine. */
gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN);
- detector.pollset = gpr_malloc(grpc_pollset_size());
- grpc_pollset_init(detector.pollset, &g_polling_mu);
+ grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
+ grpc_pollset_init(pollset, &g_polling_mu);
+ detector.pollent = grpc_polling_entity_create_from_pollset(pollset);
detector.is_done = 0;
detector.success = 0;
+ memset(&detector.response, 0, sizeof(detector.response));
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = GRPC_COMPUTE_ENGINE_DETECTION_HOST;
request.http.path = "/";
@@ -117,48 +125,71 @@ static int is_stack_running_on_compute_engine(void) {
grpc_httpcli_context_init(&context);
grpc_httpcli_get(
- &exec_ctx, &context, detector.pollset, &request,
+ &exec_ctx, &context, &detector.pollent, &request,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
- on_compute_engine_detection_http_response, &detector);
+ grpc_closure_create(on_compute_engine_detection_http_response, &detector),
+ &detector.response);
- grpc_exec_ctx_finish(&exec_ctx);
+ grpc_exec_ctx_flush(&exec_ctx);
/* Block until we get the response. This is not ideal but this should only be
called once for the lifetime of the process by the default credentials. */
gpr_mu_lock(g_polling_mu);
while (!detector.is_done) {
grpc_pollset_worker *worker = NULL;
- grpc_pollset_work(&exec_ctx, detector.pollset, &worker,
- gpr_now(GPR_CLOCK_MONOTONIC),
- gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ if (!GRPC_LOG_IF_ERROR(
+ "pollset_work",
+ grpc_pollset_work(&exec_ctx,
+ grpc_polling_entity_pollset(&detector.pollent),
+ &worker, gpr_now(GPR_CLOCK_MONOTONIC),
+ gpr_inf_future(GPR_CLOCK_MONOTONIC)))) {
+ detector.is_done = 1;
+ detector.success = 0;
+ }
}
gpr_mu_unlock(g_polling_mu);
grpc_httpcli_context_destroy(&context);
- grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset);
- grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure);
+ grpc_closure_init(&destroy_closure, destroy_pollset,
+ grpc_polling_entity_pollset(&detector.pollent));
+ grpc_pollset_shutdown(&exec_ctx,
+ grpc_polling_entity_pollset(&detector.pollent),
+ &destroy_closure);
grpc_exec_ctx_finish(&exec_ctx);
g_polling_mu = NULL;
- gpr_free(detector.pollset);
+ gpr_free(grpc_polling_entity_pollset(&detector.pollent));
+ grpc_http_response_destroy(&detector.response);
return detector.success;
}
/* Takes ownership of creds_path if not NULL. */
-static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
+static grpc_error *create_default_creds_from_path(
+ char *creds_path, grpc_call_credentials **creds) {
grpc_json *json = NULL;
grpc_auth_json_key key;
grpc_auth_refresh_token token;
grpc_call_credentials *result = NULL;
gpr_slice creds_data = gpr_empty_slice();
- int file_ok = 0;
- if (creds_path == NULL) goto end;
- creds_data = gpr_load_file(creds_path, 0, &file_ok);
- if (!file_ok) goto end;
+ grpc_error *error = GRPC_ERROR_NONE;
+ if (creds_path == NULL) {
+ error = GRPC_ERROR_CREATE("creds_path unset");
+ goto end;
+ }
+ error = grpc_load_file(creds_path, 0, &creds_data);
+ if (error != GRPC_ERROR_NONE) {
+ goto end;
+ }
json = grpc_json_parse_string_with_len(
(char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data));
- if (json == NULL) goto end;
+ if (json == NULL) {
+ char *dump = gpr_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);
+ goto end;
+ }
/* First, try an auth json key. */
key = grpc_auth_json_key_create_from_json(json);
@@ -166,6 +197,11 @@ static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
result =
grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
key, grpc_max_auth_token_lifetime());
+ if (result == NULL) {
+ error = GRPC_ERROR_CREATE(
+ "grpc_service_account_jwt_access_credentials_create_from_auth_json_"
+ "key failed");
+ }
goto end;
}
@@ -174,19 +210,28 @@ static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
if (grpc_auth_refresh_token_is_valid(&token)) {
result =
grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
+ if (result == NULL) {
+ error = GRPC_ERROR_CREATE(
+ "grpc_refresh_token_credentials_create_from_auth_refresh_token "
+ "failed");
+ }
goto end;
}
end:
+ GPR_ASSERT((result == NULL) + (error == GRPC_ERROR_NONE) == 1);
if (creds_path != NULL) gpr_free(creds_path);
gpr_slice_unref(creds_data);
if (json != NULL) grpc_json_destroy(json);
- return result;
+ *creds = result;
+ return error;
}
grpc_channel_credentials *grpc_google_default_credentials_create(void) {
grpc_channel_credentials *result = NULL;
grpc_call_credentials *call_creds = NULL;
+ grpc_error *error = GRPC_ERROR_CREATE("Failed to create Google credentials");
+ grpc_error *err;
GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
@@ -200,14 +245,16 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
}
/* First, try the environment variable. */
- call_creds = create_default_creds_from_path(
- gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
- if (call_creds != NULL) goto end;
+ err = create_default_creds_from_path(
+ gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
+ if (err == GRPC_ERROR_NONE) goto end;
+ error = grpc_error_add_child(error, err);
/* Then the well-known file. */
- call_creds = create_default_creds_from_path(
- grpc_get_well_known_google_credentials_file_path());
- if (call_creds != NULL) goto end;
+ err = create_default_creds_from_path(
+ grpc_get_well_known_google_credentials_file_path(), &call_creds);
+ if (err == GRPC_ERROR_NONE) goto end;
+ error = grpc_error_add_child(error, err);
/* At last try to see if we're on compute engine (do the detection only once
since it requires a network test). */
@@ -216,6 +263,10 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
compute_engine_detection_done = 1;
if (need_compute_engine_creds) {
call_creds = grpc_google_compute_engine_credentials_create(NULL);
+ if (call_creds == NULL) {
+ error = grpc_error_add_child(
+ error, GRPC_ERROR_CREATE("Failed to get credentials from network"));
+ }
}
}
@@ -239,6 +290,11 @@ end:
}
}
gpr_mu_unlock(&g_state_mu);
+ if (result == NULL) {
+ GRPC_LOG_IF_ERROR("grpc_google_default_credentials_create", error);
+ } else {
+ GRPC_ERROR_UNREF(error);
+ }
return result;
}
diff --git a/src/core/lib/security/credentials/iam/iam_credentials.c b/src/core/lib/security/credentials/iam/iam_credentials.c
index 66e7b0e3db..370a384d0e 100644
--- a/src/core/lib/security/credentials/iam/iam_credentials.c
+++ b/src/core/lib/security/credentials/iam/iam_credentials.c
@@ -49,7 +49,7 @@ static void iam_destruct(grpc_call_credentials *creds) {
static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c
index 7f96e5247b..6323eb9393 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.c
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c
@@ -64,7 +64,7 @@ static void jwt_destruct(grpc_call_credentials *creds) {
static void jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
@@ -150,10 +150,10 @@ grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
"grpc_service_account_jwt_access_credentials_create("
"json_key=%s, "
"token_lifetime="
- "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
5,
- (json_key, (long long)token_lifetime.tv_sec, (int)token_lifetime.tv_nsec,
+ (json_key, token_lifetime.tv_sec, token_lifetime.tv_nsec,
(int)token_lifetime.clock_type, reserved));
GPR_ASSERT(reserved == NULL);
return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index cd6c7ce392..73eb2e3258 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -37,6 +37,7 @@
#include <string.h>
#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/util/b64.h"
#include "src/core/lib/tsi/ssl_types.h"
@@ -44,6 +45,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
#include <openssl/pem.h>
/* --- Utils. --- */
@@ -319,9 +321,15 @@ grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
/* --- verifier_cb_ctx object. --- */
+typedef enum {
+ HTTP_RESPONSE_OPENID = 0,
+ HTTP_RESPONSE_KEYS,
+ HTTP_RESPONSE_COUNT /* must be last */
+} http_response_index;
+
typedef struct {
grpc_jwt_verifier *verifier;
- grpc_pollset *pollset;
+ grpc_polling_entity pollent;
jose_header *header;
grpc_jwt_claims *claims;
char *audience;
@@ -329,6 +337,7 @@ typedef struct {
gpr_slice signed_data;
void *user_data;
grpc_jwt_verification_done_cb user_cb;
+ grpc_http_response responses[HTTP_RESPONSE_COUNT];
} verifier_cb_ctx;
/* Takes ownership of the header, claims and signature. */
@@ -337,10 +346,11 @@ static verifier_cb_ctx *verifier_cb_ctx_create(
grpc_jwt_claims *claims, const char *audience, gpr_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;
verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx));
memset(ctx, 0, sizeof(verifier_cb_ctx));
ctx->verifier = verifier;
- ctx->pollset = pollset;
+ ctx->pollent = grpc_polling_entity_create_from_pollset(pollset);
ctx->header = header;
ctx->audience = gpr_strdup(audience);
ctx->claims = claims;
@@ -348,6 +358,7 @@ static verifier_cb_ctx *verifier_cb_ctx_create(
ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len);
ctx->user_data = user_data;
ctx->user_cb = cb;
+ grpc_exec_ctx_finish(&exec_ctx);
return ctx;
}
@@ -357,6 +368,9 @@ void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) {
gpr_slice_unref(ctx->signature);
gpr_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]);
+ }
/* TODO: see what to do with claims... */
gpr_free(ctx);
}
@@ -571,9 +585,9 @@ end:
}
static void on_keys_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
- const grpc_httpcli_response *response) {
- grpc_json *json = json_from_http(response);
+ grpc_error *error) {
verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
+ grpc_json *json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]);
EVP_PKEY *verification_key = NULL;
grpc_jwt_verifier_status status = GRPC_JWT_VERIFIER_GENERIC_ERROR;
grpc_jwt_claims *claims = NULL;
@@ -612,10 +626,11 @@ end:
}
static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
- const grpc_httpcli_response *response) {
+ grpc_error *error) {
const grpc_json *cur;
- grpc_json *json = json_from_http(response);
verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
+ const grpc_http_response *response = &ctx->responses[HTTP_RESPONSE_OPENID];
+ grpc_json *json = json_from_http(response);
grpc_httpcli_request req;
const char *jwks_uri;
@@ -641,10 +656,12 @@ static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
} else {
*(req.host + (req.http.path - jwks_uri)) = '\0';
}
+
grpc_httpcli_get(
- exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req,
+ exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
- on_keys_retrieved, ctx);
+ grpc_closure_create(on_keys_retrieved, ctx),
+ &ctx->responses[HTTP_RESPONSE_KEYS]);
grpc_json_destroy(json);
gpr_free(req.host);
return;
@@ -686,12 +703,13 @@ static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain,
static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
verifier_cb_ctx *ctx) {
const char *at_sign;
- grpc_httpcli_response_cb http_cb;
+ grpc_closure *http_cb;
char *path_prefix = NULL;
const char *iss;
grpc_httpcli_request req;
memset(&req, 0, sizeof(grpc_httpcli_request));
req.handshaker = &grpc_httpcli_ssl;
+ http_response_index rsp_idx;
GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL);
iss = ctx->claims->iss;
@@ -730,7 +748,8 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
*(path_prefix++) = '\0';
gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss);
}
- http_cb = on_keys_retrieved;
+ http_cb = grpc_closure_create(on_keys_retrieved, ctx);
+ rsp_idx = HTTP_RESPONSE_KEYS;
} else {
req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss);
path_prefix = strchr(req.host, '/');
@@ -741,13 +760,14 @@ static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
gpr_asprintf(&req.http.path, "/%s%s", path_prefix,
GRPC_OPENID_CONFIG_URL_SUFFIX);
}
- http_cb = on_openid_config_retrieved;
+ http_cb = grpc_closure_create(on_openid_config_retrieved, ctx);
+ rsp_idx = HTTP_RESPONSE_OPENID;
}
grpc_httpcli_get(
- exec_ctx, &ctx->verifier->http_ctx, ctx->pollset, &req,
+ exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, &req,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
- http_cb, ctx);
+ http_cb, &ctx->responses[rsp_idx]);
gpr_free(req.host);
gpr_free(req.http.path);
return;
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
index a0e4b6fe8e..c22ea5c468 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
@@ -216,9 +216,9 @@ end:
return status;
}
-static void on_oauth2_token_fetcher_http_response(
- grpc_exec_ctx *exec_ctx, void *user_data,
- const grpc_http_response *response) {
+static void on_oauth2_token_fetcher_http_response(grpc_exec_ctx *exec_ctx,
+ void *user_data,
+ grpc_error *error) {
grpc_credentials_metadata_request *r =
(grpc_credentials_metadata_request *)user_data;
grpc_oauth2_token_fetcher_credentials *c =
@@ -226,9 +226,11 @@ static void on_oauth2_token_fetcher_http_response(
gpr_timespec token_lifetime;
grpc_credentials_status status;
+ GRPC_LOG_IF_ERROR("oauth_fetch", GRPC_ERROR_REF(error));
+
gpr_mu_lock(&c->mu);
status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
- response, &c->access_token_md, &token_lifetime);
+ &r->response, &c->access_token_md, &token_lifetime);
if (status == GRPC_CREDENTIALS_OK) {
c->token_expiration =
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
@@ -245,7 +247,7 @@ static void on_oauth2_token_fetcher_http_response(
static void oauth2_token_fetcher_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
@@ -271,7 +273,7 @@ static void oauth2_token_fetcher_get_request_metadata(
c->fetch_func(
exec_ctx,
grpc_credentials_metadata_request_create(creds, cb, user_data),
- &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
+ &c->httpcli_context, pollent, on_oauth2_token_fetcher_http_response,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
}
}
@@ -296,8 +298,8 @@ static grpc_call_credentials_vtable compute_engine_vtable = {
static void compute_engine_fetch_oauth2(
grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
- grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
- grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+ grpc_httpcli_context *httpcli_context, grpc_polling_entity *pollent,
+ grpc_iomgr_cb_func response_cb, gpr_timespec deadline) {
grpc_http_header header = {"Metadata-Flavor", "Google"};
grpc_httpcli_request request;
memset(&request, 0, sizeof(grpc_httpcli_request));
@@ -305,8 +307,9 @@ static void compute_engine_fetch_oauth2(
request.http.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
request.http.hdr_count = 1;
request.http.hdrs = &header;
- grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline,
- response_cb, metadata_req);
+ grpc_httpcli_get(exec_ctx, httpcli_context, pollent, &request, deadline,
+ grpc_closure_create(response_cb, metadata_req),
+ &metadata_req->response);
}
grpc_call_credentials *grpc_google_compute_engine_credentials_create(
@@ -337,8 +340,8 @@ static grpc_call_credentials_vtable refresh_token_vtable = {
static void refresh_token_fetch_oauth2(
grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
- grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
- grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+ grpc_httpcli_context *httpcli_context, grpc_polling_entity *pollent,
+ grpc_iomgr_cb_func response_cb, gpr_timespec deadline) {
grpc_google_refresh_token_credentials *c =
(grpc_google_refresh_token_credentials *)metadata_req->creds;
grpc_http_header header = {"Content-Type",
@@ -354,8 +357,10 @@ static void refresh_token_fetch_oauth2(
request.http.hdr_count = 1;
request.http.hdrs = &header;
request.handshaker = &grpc_httpcli_ssl;
- grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body,
- strlen(body), deadline, response_cb, metadata_req);
+ grpc_httpcli_post(exec_ctx, httpcli_context, pollent, &request, body,
+ strlen(body), deadline,
+ grpc_closure_create(response_cb, metadata_req),
+ &metadata_req->response);
gpr_free(body);
}
@@ -397,7 +402,7 @@ static void access_token_destruct(grpc_call_credentials *creds) {
static void access_token_get_request_metadata(
grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
- grpc_pollset *pollset, grpc_auth_metadata_context context,
+ grpc_polling_entity *pollent, grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb, void *user_data) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK,
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index 04915b333f..7f6f205c22 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -70,8 +70,8 @@ void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx,
grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
- grpc_pollset *pollset,
- grpc_httpcli_response_cb response_cb,
+ grpc_polling_entity *pollent,
+ grpc_iomgr_cb_func cb,
gpr_timespec deadline);
typedef struct {
grpc_call_credentials base;
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c
index 6397270305..824ff081dc 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.c
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c
@@ -95,7 +95,7 @@ static void plugin_md_request_metadata_ready(void *request,
static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
grpc_call_credentials *creds,
- grpc_pollset *pollset,
+ grpc_polling_entity *pollent,
grpc_auth_metadata_context context,
grpc_credentials_metadata_cb cb,
void *user_data) {
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 0a3f0cd008..399b92c8e1 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -54,11 +54,11 @@ typedef struct {
grpc_call_credentials *creds;
grpc_mdstr *host;
grpc_mdstr *method;
- /* pollset bound to this call; if we need to make external
- network requests, they should be done under this pollset
- so that work can progress when this call wants work to
- progress */
- grpc_pollset *pollset;
+ /* pollset{_set} bound to this call; if we need to make external
+ network requests, they should be done under a pollset added to this
+ pollset_set so that work can progress when this call wants work to progress
+ */
+ grpc_polling_entity *pollent;
grpc_transport_stream_op op;
uint8_t security_context_set;
grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
@@ -188,9 +188,9 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
build_auth_metadata_context(&chand->security_connector->base,
chand->auth_context, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */
- GPR_ASSERT(calld->pollset);
+ GPR_ASSERT(calld->pollent != NULL);
grpc_call_credentials_get_request_metadata(
- exec_ctx, calld->creds, calld->pollset, calld->auth_md_context,
+ exec_ctx, calld->creds, calld->pollent, calld->auth_md_context,
on_credentials_metadata, elem);
}
@@ -274,10 +274,11 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
memset(calld, 0, sizeof(*calld));
}
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_pollset *pollset) {
+static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_call_element *elem,
+ grpc_polling_entity *pollent) {
call_data *calld = elem->call_data;
- calld->pollset = pollset;
+ calld->pollent = pollent;
}
/* Destructor for call_data */
@@ -333,8 +334,14 @@ 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, 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,
+ "client-auth"};
diff --git a/src/core/lib/security/transport/handshake.c b/src/core/lib/security/transport/handshake.c
index 6561f4b47d..b374ca7633 100644
--- a/src/core/lib/security/transport/handshake.c
+++ b/src/core/lib/security/transport/handshake.c
@@ -39,8 +39,10 @@
#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
@@ -60,13 +62,16 @@ typedef struct {
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, bool success);
+ void *setup,
+ grpc_error *error);
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
- bool success);
+ grpc_error *error);
static void security_connector_remove_handshake(grpc_security_handshake *h) {
GPR_ASSERT(!h->is_client_side);
@@ -95,16 +100,34 @@ static void security_connector_remove_handshake(grpc_security_handshake *h) {
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,
- int is_success) {
+ grpc_error *error) {
+ grpc_timer_cancel(exec_ctx, &h->timer);
if (!h->is_client_side) {
security_connector_remove_handshake(h);
}
- if (is_success) {
+ 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);
@@ -113,14 +136,8 @@ static void security_handshake_done(grpc_exec_ctx *exec_ctx,
}
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL);
}
- 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);
+ unref_handshake(h);
+ GRPC_ERROR_UNREF(error);
}
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -130,17 +147,20 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
tsi_frame_protector *protector;
tsi_result result;
if (status != GRPC_SECURITY_OK) {
- gpr_log(GPR_ERROR, "Error checking peer.");
- security_handshake_done(exec_ctx, h, 0);
+ 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) {
- gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(
+ exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Frame protector creation failed"), result));
return;
}
h->secure_endpoint =
@@ -148,7 +168,7 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
h->left_overs.slices, h->left_overs.count);
h->left_overs.count = 0;
h->left_overs.length = 0;
- security_handshake_done(exec_ctx, h, 1);
+ security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE);
return;
}
@@ -157,9 +177,9 @@ static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ 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,
@@ -185,9 +205,9 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
} while (result == TSI_INCOMPLETE_DATA);
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshake failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
@@ -203,7 +223,7 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
void *handshake,
- bool success) {
+ grpc_error *error) {
grpc_security_handshake *h = handshake;
size_t consumed_slice_size = 0;
tsi_result result = TSI_OK;
@@ -211,9 +231,10 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
size_t num_left_overs;
int has_left_overs_in_current_slice = 0;
- if (!success) {
- gpr_log(GPR_ERROR, "Read failed.");
- security_handshake_done(exec_ctx, h, 0);
+ if (error != GRPC_ERROR_NONE) {
+ security_handshake_done(
+ exec_ctx, h,
+ GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1));
return;
}
@@ -238,9 +259,9 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
}
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshake failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
@@ -270,13 +291,15 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
/* If handshake is NULL, the handshake is done. */
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
- void *handshake, bool success) {
+ void *handshake, grpc_error *error) {
grpc_security_handshake *h = handshake;
/* Make sure that write is OK. */
- if (!success) {
- gpr_log(GPR_ERROR, "Write failed.");
- if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
+ if (error != GRPC_ERROR_NONE) {
+ if (handshake != NULL)
+ security_handshake_done(
+ exec_ctx, h,
+ GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1));
return;
}
@@ -291,13 +314,19 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
}
}
-void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
- tsi_handshaker *handshaker,
- grpc_security_connector *connector,
- bool is_client_side,
- grpc_endpoint *nonsecure_endpoint,
- grpc_security_handshake_done_cb cb,
- void *user_data) {
+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_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));
@@ -309,6 +338,7 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
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,
@@ -327,6 +357,8 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&server_connector->mu);
}
send_handshake_bytes_to_peer(exec_ctx, h);
+ grpc_timer_init(exec_ctx, &h->timer, deadline, on_timeout, h,
+ gpr_now(deadline.clock_type));
}
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/handshake.h b/src/core/lib/security/transport/handshake.h
index 6ed850b315..c0906dd6af 100644
--- a/src/core/lib/security/transport/handshake.h
+++ b/src/core/lib/security/transport/handshake.h
@@ -38,13 +38,11 @@
#include "src/core/lib/security/transport/security_connector.h"
/* Calls the callback upon completion. Takes owership of handshaker. */
-void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
- tsi_handshaker *handshaker,
- grpc_security_connector *connector,
- bool is_client_side,
- grpc_endpoint *nonsecure_endpoint,
- grpc_security_handshake_done_cb cb,
- void *user_data);
+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_timespec deadline,
+ grpc_security_handshake_done_cb cb, void *user_data);
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 4438c8e559..7650d68e89 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -38,6 +38,7 @@
#include <grpc/support/slice_buffer.h>
#include <grpc/support/sync.h>
#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/security/transport/tsi_error.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/transport_security_interface.h"
@@ -126,8 +127,8 @@ static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur,
}
static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
- bool success) {
- if (grpc_trace_secure_endpoint) {
+ grpc_error *error) {
+ if (false && 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],
@@ -137,11 +138,12 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
}
}
ep->read_buffer = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, ep->read_cb, error, NULL);
SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read");
}
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data,
+ grpc_error *error) {
unsigned i;
uint8_t keep_looping = 0;
tsi_result result = TSI_OK;
@@ -149,9 +151,10 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
- if (!success) {
+ if (error != GRPC_ERROR_NONE) {
gpr_slice_buffer_reset_and_unref(ep->read_buffer);
- call_read_cb(exec_ctx, ep, 0);
+ call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING(
+ "Secure read failed", &error, 1));
return;
}
@@ -208,11 +211,12 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
if (result != TSI_OK) {
gpr_slice_buffer_reset_and_unref(ep->read_buffer);
- call_read_cb(exec_ctx, ep, 0);
+ call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Unwrap failed"), result));
return;
}
- call_read_cb(exec_ctx, ep, 1);
+ call_read_cb(exec_ctx, ep, GRPC_ERROR_NONE);
}
static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
@@ -226,7 +230,7 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
if (ep->leftover_bytes.count) {
gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
GPR_ASSERT(ep->leftover_bytes.count == 0);
- on_read(exec_ctx, ep, 1);
+ on_read(exec_ctx, ep, GRPC_ERROR_NONE);
return;
}
@@ -252,7 +256,7 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
- if (grpc_trace_secure_endpoint) {
+ if (false && 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);
@@ -315,7 +319,10 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
if (result != TSI_OK) {
/* TODO(yangg) do different things according to the error type? */
gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
- grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
+ grpc_exec_ctx_sched(
+ exec_ctx, cb,
+ grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
+ NULL);
return;
}
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index 72173e7c9d..f0ee6770e5 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -43,12 +43,12 @@
#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/support/env.h"
-#include "src/core/lib/support/load_file.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/tsi/fake_transport_security.h"
#include "src/core/lib/tsi/ssl_transport_security.h"
@@ -127,23 +127,25 @@ void grpc_server_security_connector_shutdown(
void grpc_channel_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
- void *user_data) {
+ grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
+ grpc_security_handshake_done_cb cb, void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
- sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
+ sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, deadline, cb, user_data);
}
}
void grpc_server_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- grpc_security_handshake_done_cb cb, void *user_data) {
+ gpr_timespec deadline, grpc_security_handshake_done_cb cb,
+ void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
- sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data);
+ sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, deadline, cb,
+ user_data);
}
}
@@ -310,20 +312,23 @@ static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
+ 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, cb, user_data);
+ true, nonsecure_endpoint, deadline, cb, user_data);
}
static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint,
+ 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, cb, user_data);
+ false, nonsecure_endpoint, deadline, cb,
+ user_data);
}
static grpc_security_connector_vtable fake_channel_vtable = {
@@ -413,6 +418,7 @@ static grpc_security_status ssl_create_handshaker(
static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
+ gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_ssl_channel_security_connector *c =
@@ -427,7 +433,7 @@ static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, status, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
- nonsecure_endpoint, cb, user_data);
+ nonsecure_endpoint, deadline, cb, user_data);
}
}
@@ -435,6 +441,7 @@ static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint,
+ gpr_timespec deadline,
grpc_security_handshake_done_cb cb,
void *user_data) {
grpc_ssl_server_security_connector *c =
@@ -446,7 +453,7 @@ static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
cb(exec_ctx, user_data, status, NULL, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
- nonsecure_endpoint, cb, user_data);
+ nonsecure_endpoint, deadline, cb, user_data);
}
}
@@ -635,7 +642,8 @@ static gpr_slice compute_default_pem_root_certs_once(void) {
char *default_root_certs_path =
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
if (default_root_certs_path != NULL) {
- result = gpr_load_file(default_root_certs_path, 0, NULL);
+ GRPC_LOG_IF_ERROR("load_file",
+ grpc_load_file(default_root_certs_path, 0, &result));
gpr_free(default_root_certs_path);
}
@@ -653,7 +661,8 @@ static gpr_slice compute_default_pem_root_certs_once(void) {
/* Fall back to installed certs if needed. */
if (GPR_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
- result = gpr_load_file(installed_roots_path, 0, NULL);
+ GRPC_LOG_IF_ERROR("load_file",
+ grpc_load_file(installed_roots_path, 0, &result));
}
return result;
}
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index 84e586deaa..c2ddf5ee1e 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -143,7 +143,7 @@ struct grpc_channel_security_connector {
grpc_security_call_host_check_cb cb, void *user_data);
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
- grpc_endpoint *nonsecure_endpoint,
+ grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
};
@@ -156,8 +156,8 @@ void grpc_channel_security_connector_check_call_host(
/* Handshake. */
void grpc_channel_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
- grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
- void *user_data);
+ grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
+ grpc_security_handshake_done_cb cb, void *user_data);
/* --- server_security_connector object. ---
@@ -174,14 +174,14 @@ struct grpc_server_security_connector {
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
- grpc_endpoint *nonsecure_endpoint,
+ grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
grpc_security_handshake_done_cb cb, void *user_data);
};
void grpc_server_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
- grpc_security_handshake_done_cb cb, void *user_data);
+ 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);
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 714e0adfc9..12e789bde9 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -128,7 +128,7 @@ static void on_md_processing_done(
grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md,
elem);
grpc_metadata_array_destroy(&calld->md);
- calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 1);
+ grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
} else {
gpr_slice message;
grpc_transport_stream_op close_op;
@@ -146,18 +146,21 @@ static void on_md_processing_done(
calld->transport_op.send_trailing_metadata = NULL;
grpc_transport_stream_op_add_close(&close_op, status, &message);
grpc_call_next_op(&exec_ctx, elem, &close_op);
- calld->on_done_recv->cb(&exec_ctx, calld->on_done_recv->cb_arg, 0);
+ grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv,
+ grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
+ GRPC_ERROR_INT_GRPC_STATUS, status),
+ NULL);
}
grpc_exec_ctx_finish(&exec_ctx);
}
static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
- bool success) {
+ grpc_error *error) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
if (chand->creds->processor.process != NULL) {
calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata);
chand->creds->processor.process(
@@ -166,7 +169,8 @@ static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
return;
}
}
- calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, success);
+ grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv, GRPC_ERROR_REF(error),
+ NULL);
}
static void set_recv_ops_md_callbacks(grpc_call_element *elem,
@@ -220,9 +224,6 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_server_security_context_destroy;
}
-static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_pollset *pollset) {}
-
/* Destructor for call_data */
static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
const grpc_call_stats *stats, void *ignored) {}
@@ -258,7 +259,14 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
}
const grpc_channel_filter grpc_server_auth_filter = {
- auth_start_transport_op, grpc_channel_next_op, sizeof(call_data),
- init_call_elem, set_pollset, destroy_call_elem,
- sizeof(channel_data), init_channel_elem, destroy_channel_elem,
- grpc_call_next_get_peer, "server-auth"};
+ auth_start_transport_op,
+ grpc_channel_next_op,
+ sizeof(call_data),
+ init_call_elem,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
+ destroy_call_elem,
+ sizeof(channel_data),
+ init_channel_elem,
+ destroy_channel_elem,
+ grpc_call_next_get_peer,
+ "server-auth"};
diff --git a/src/core/lib/security/transport/tsi_error.c b/src/core/lib/security/transport/tsi_error.c
new file mode 100644
index 0000000000..afc1733567
--- /dev/null
+++ b/src/core/lib/security/transport/tsi_error.c
@@ -0,0 +1,40 @@
+/*
+ *
+ * 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/tsi_error.h"
+
+grpc_error *grpc_set_tsi_error_result(grpc_error *error, tsi_result result) {
+ return grpc_error_set_int(grpc_error_set_str(error, GRPC_ERROR_STR_TSI_ERROR,
+ tsi_result_to_string(result)),
+ GRPC_ERROR_INT_TSI_CODE, result);
+}
diff --git a/src/core/lib/security/transport/tsi_error.h b/src/core/lib/security/transport/tsi_error.h
new file mode 100644
index 0000000000..636fbb89cf
--- /dev/null
+++ b/src/core/lib/security/transport/tsi_error.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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_SECURITY_TRANSPORT_TSI_ERROR_H
+#define GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H
+
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/tsi/transport_security_interface.h"
+
+grpc_error *grpc_set_tsi_error_result(grpc_error *error, tsi_result result);
+
+#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H */
diff --git a/src/core/lib/support/avl.c b/src/core/lib/support/avl.c
index 8d3ce23e6c..acf8fd5a55 100644
--- a/src/core/lib/support/avl.c
+++ b/src/core/lib/support/avl.c
@@ -124,6 +124,15 @@ void *gpr_avl_get(gpr_avl avl, void *key) {
return node ? node->value : NULL;
}
+int gpr_avl_maybe_get(gpr_avl avl, void *key, void **value) {
+ gpr_avl_node *node = get(avl.vtable, avl.root, key);
+ if (node != NULL) {
+ *value = node->value;
+ return 1;
+ }
+ return 0;
+}
+
static gpr_avl_node *rotate_left(const gpr_avl_vtable *vtable, void *key,
void *value, gpr_avl_node *left,
gpr_avl_node *right) {
@@ -286,3 +295,5 @@ gpr_avl gpr_avl_ref(gpr_avl avl) {
}
void gpr_avl_unref(gpr_avl avl) { unref_node(avl.vtable, avl.root); }
+
+int gpr_avl_is_empty(gpr_avl avl) { return avl.root == NULL; }
diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c
index 882abf673c..bae0957df7 100644
--- a/src/core/lib/support/log.c
+++ b/src/core/lib/support/log.c
@@ -96,4 +96,6 @@ void gpr_log_verbosity_init() {
}
}
-void gpr_set_log_function(gpr_log_func f) { g_log_func = f; }
+void gpr_set_log_function(gpr_log_func f) {
+ g_log_func = f ? f : gpr_default_log;
+}
diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c
index ca04c022e3..508fae4eec 100644
--- a/src/core/lib/support/log_linux.c
+++ b/src/core/lib/support/log_linux.c
@@ -95,9 +95,9 @@ void gpr_default_log(gpr_log_func_args *args) {
strcpy(time_buffer, "error:strftime");
}
- gpr_asprintf(&prefix, "%s%s.%09d %7tu %s:%d]",
+ gpr_asprintf(&prefix, "%s%s.%09" PRId32 " %7ld %s:%d]",
gpr_log_severity_string(args->severity), time_buffer,
- (int)(now.tv_nsec), gettid(), display_file, args->line);
+ now.tv_nsec, gettid(), display_file, args->line);
fprintf(stderr, "%-60s %s\n", prefix, args->message);
gpr_free(prefix);
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index a2ab6c5f1f..30c1e67647 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -194,6 +194,16 @@ int int64_ttoa(int64_t value, char *string) {
return i;
}
+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;
+ char *out = gpr_malloc(out_length + 1);
+ memset(out, flag, out_length - str_length);
+ memcpy(out + out_length - str_length, str, str_length);
+ out[out_length] = 0;
+ return out;
+}
+
char *gpr_strjoin(const char **strs, size_t nstrs, size_t *final_length) {
return gpr_strjoin_sep(strs, nstrs, "", final_length);
}
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index ea58610914..2b6bb3eec6 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -83,6 +83,10 @@ int int64_ttoa(int64_t value, char *output);
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
+/* Pad a string with flag characters. The given length specifies the minimum
+ field width. The input string is never truncated. */
+char *gpr_leftpad(const char *str, char flag, size_t length);
+
/* Join a set of strings, returning the resulting string.
Total combined length (excluding null terminator) is returned in total_length
if it is non-null. */
diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c
index 2cf2f00b31..aa9d60ee6a 100644
--- a/src/core/lib/surface/alarm.c
+++ b/src/core/lib/surface/alarm.c
@@ -48,9 +48,9 @@ struct grpc_alarm {
static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
grpc_cq_completion *c) {}
-static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_alarm *alarm = arg;
- grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success,
+ grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, error,
do_nothing_end_completion, NULL, &alarm->completion);
}
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 74a09cf6ed..04291b0ee0 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -40,6 +40,7 @@
#include <grpc/grpc.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>
@@ -52,7 +53,9 @@
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/completion_queue.h"
+#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/transport.h"
/** The maximum number of concurrent batches possible.
Based upon the maximum number of individually queueable ops in the batch
@@ -97,6 +100,7 @@ typedef struct batch_control {
grpc_closure finish_batch;
void *notify_tag;
gpr_refcount steps_to_complete;
+ grpc_error *error;
uint8_t send_initial_metadata;
uint8_t send_message;
@@ -105,11 +109,11 @@ typedef struct batch_control {
uint8_t recv_message;
uint8_t recv_final_op;
uint8_t is_notify_tag_closure;
- uint8_t success;
} batch_control;
struct grpc_call {
grpc_completion_queue *cq;
+ grpc_polling_entity pollent;
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
@@ -153,8 +157,8 @@ struct grpc_call {
/* Call stats: only valid after trailing metadata received */
grpc_call_stats stats;
- /* Compression algorithm for the call */
- grpc_compression_algorithm compression_algorithm;
+ /* Compression algorithm for *incoming* data */
+ grpc_compression_algorithm incoming_compression_algorithm;
/* Supported encodings (compression algorithms), a bitset */
uint32_t encodings_accepted_by_peer;
@@ -213,18 +217,19 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description);
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description);
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
- bool success);
+ grpc_error *error);
static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
- bool success);
-
-grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
- uint32_t propagation_mask,
- grpc_completion_queue *cq,
- const void *server_transport_data,
- grpc_mdelem **add_initial_metadata,
- size_t add_initial_metadata_count,
- gpr_timespec send_deadline) {
+ grpc_error *error);
+
+grpc_call *grpc_call_create(
+ grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+ grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
+ const void *server_transport_data, grpc_mdelem **add_initial_metadata,
+ size_t add_initial_metadata_count, gpr_timespec send_deadline) {
size_t i, j;
grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -261,9 +266,20 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
call->context, server_transport_data,
CALL_STACK_FROM_CALL(call));
if (cq != NULL) {
+ GPR_ASSERT(
+ pollset_set_alternative == NULL &&
+ "Only one of 'cq' and 'pollset_set_alternative' should be non-NULL.");
GRPC_CQ_INTERNAL_REF(cq, "bind");
- grpc_call_stack_set_pollset(&exec_ctx, CALL_STACK_FROM_CALL(call),
- grpc_cq_pollset(cq));
+ call->pollent =
+ grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq));
+ }
+ if (pollset_set_alternative != NULL) {
+ call->pollent =
+ grpc_polling_entity_create_from_pollset_set(pollset_set_alternative);
+ }
+ if (!grpc_polling_entity_is_empty(&call->pollent)) {
+ grpc_call_stack_set_pollset_or_pollset_set(
+ &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
if (parent_call != NULL) {
GRPC_CALL_INTERNAL_REF(parent_call, "child");
@@ -318,10 +334,16 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
grpc_completion_queue *cq) {
GPR_ASSERT(cq);
+
+ if (grpc_polling_entity_pollset_set(&call->pollent) != NULL) {
+ gpr_log(GPR_ERROR, "A pollset_set is already registered for this call.");
+ abort();
+ }
call->cq = cq;
GRPC_CQ_INTERNAL_REF(cq, "bind");
- grpc_call_stack_set_pollset(exec_ctx, CALL_STACK_FROM_CALL(call),
- grpc_cq_pollset(cq));
+ call->pollent = grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq));
+ grpc_call_stack_set_pollset_or_pollset_set(
+ exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
}
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
@@ -338,7 +360,8 @@ void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c REF_ARG) {
GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
}
-static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
+static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
+ grpc_error *error) {
size_t i;
int ii;
grpc_call *c = call;
@@ -383,21 +406,27 @@ static void set_status_code(grpc_call *call, status_source source,
/* TODO(ctiller): what to do about the flush that was previously here */
}
-static void set_compression_algorithm(grpc_call *call,
- grpc_compression_algorithm algo) {
+static void set_incoming_compression_algorithm(
+ grpc_call *call, grpc_compression_algorithm algo) {
GPR_ASSERT(algo < GRPC_COMPRESS_ALGORITHMS_COUNT);
- call->compression_algorithm = algo;
+ call->incoming_compression_algorithm = algo;
}
grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
grpc_call *call) {
grpc_compression_algorithm algorithm;
gpr_mu_lock(&call->mu);
- algorithm = call->compression_algorithm;
+ algorithm = call->incoming_compression_algorithm;
gpr_mu_unlock(&call->mu);
return algorithm;
}
+static grpc_compression_algorithm compression_algorithm_for_level_locked(
+ grpc_call *call, grpc_compression_level level) {
+ return grpc_compression_algorithm_for_level(level,
+ call->encodings_accepted_by_peer);
+}
+
uint32_t grpc_call_test_only_get_message_flags(grpc_call *call) {
uint32_t flags;
gpr_mu_lock(&call->mu);
@@ -523,15 +552,28 @@ static grpc_linked_mdelem *linked_from_md(grpc_metadata *md) {
return (grpc_linked_mdelem *)&md->internal_data;
}
+static grpc_metadata *get_md_elem(grpc_metadata *metadata,
+ grpc_metadata *additional_metadata, int i,
+ int count) {
+ grpc_metadata *res =
+ i < count ? &metadata[i] : &additional_metadata[i - count];
+ GPR_ASSERT(res);
+ return res;
+}
+
static int prepare_application_metadata(grpc_call *call, int count,
grpc_metadata *metadata,
int is_trailing,
- int prepend_extra_metadata) {
+ int prepend_extra_metadata,
+ grpc_metadata *additional_metadata,
+ int additional_metadata_count) {
+ int total_count = count + additional_metadata_count;
int i;
grpc_metadata_batch *batch =
&call->metadata_batch[0 /* is_receiving */][is_trailing];
- for (i = 0; i < count; i++) {
- grpc_metadata *md = &metadata[i];
+ for (i = 0; i < total_count; i++) {
+ const grpc_metadata *md =
+ get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
l->md = grpc_mdelem_from_string_and_buffer(
@@ -550,9 +592,10 @@ static int prepare_application_metadata(grpc_call *call, int count,
break;
}
}
- if (i != count) {
+ if (i != total_count) {
for (int j = 0; j <= i; j++) {
- grpc_metadata *md = &metadata[j];
+ const grpc_metadata *md =
+ get_md_elem(metadata, additional_metadata, j, count);
grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
GRPC_MDELEM_UNREF(l->md);
}
@@ -573,24 +616,36 @@ static int prepare_application_metadata(grpc_call *call, int count,
}
}
}
- for (i = 1; i < count; i++) {
- linked_from_md(&metadata[i])->prev = linked_from_md(&metadata[i - 1]);
+ for (i = 1; i < total_count; i++) {
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
+ grpc_metadata *prev_md =
+ get_md_elem(metadata, additional_metadata, i - 1, count);
+ linked_from_md(md)->prev = linked_from_md(prev_md);
}
- for (i = 0; i < count - 1; i++) {
- linked_from_md(&metadata[i])->next = linked_from_md(&metadata[i + 1]);
+ for (i = 0; i < total_count - 1; i++) {
+ grpc_metadata *md = get_md_elem(metadata, additional_metadata, i, count);
+ grpc_metadata *next_md =
+ get_md_elem(metadata, additional_metadata, i + 1, count);
+ linked_from_md(md)->next = linked_from_md(next_md);
}
- switch (prepend_extra_metadata * 2 + (count != 0)) {
+
+ switch (prepend_extra_metadata * 2 + (total_count != 0)) {
case 0:
/* no prepend, no metadata => nothing to do */
batch->list.head = batch->list.tail = NULL;
break;
- case 1:
+ case 1: {
/* metadata, but no prepend */
- batch->list.head = linked_from_md(&metadata[0]);
- batch->list.tail = linked_from_md(&metadata[count - 1]);
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
+ batch->list.head = linked_from_md(first_md);
+ batch->list.tail = linked_from_md(last_md);
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
+ }
case 2:
/* prepend, but no md */
batch->list.head = &call->send_extra_metadata[0];
@@ -599,17 +654,22 @@ static int prepare_application_metadata(grpc_call *call, int count,
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
- case 3:
+ case 3: {
/* prepend AND md */
+ grpc_metadata *first_md =
+ get_md_elem(metadata, additional_metadata, 0, count);
+ grpc_metadata *last_md =
+ get_md_elem(metadata, additional_metadata, total_count - 1, count);
batch->list.head = &call->send_extra_metadata[0];
call->send_extra_metadata[call->send_extra_metadata_count - 1].next =
- linked_from_md(&metadata[0]);
- linked_from_md(&metadata[0])->prev =
+ linked_from_md(first_md);
+ linked_from_md(first_md)->prev =
&call->send_extra_metadata[call->send_extra_metadata_count - 1];
- batch->list.tail = linked_from_md(&metadata[count - 1]);
+ batch->list.tail = linked_from_md(last_md);
batch->list.head->prev = NULL;
batch->list.tail->next = NULL;
break;
+ }
default:
GPR_UNREACHABLE_CODE(return 0);
}
@@ -678,48 +738,103 @@ grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
return r;
}
-typedef struct cancel_closure {
+typedef struct termination_closure {
grpc_closure closure;
grpc_call *call;
grpc_status_code status;
-} cancel_closure;
+ gpr_slice optional_message;
+ grpc_closure *op_closure;
+ enum { TC_CANCEL, TC_CLOSE } type;
+} termination_closure;
+
+static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
+ grpc_error *error) {
+ termination_closure *tc = tcp;
+ switch (tc->type) {
+ case TC_CANCEL:
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "cancel");
+ break;
+ case TC_CLOSE:
+ GRPC_CALL_INTERNAL_UNREF(exec_ctx, tc->call, "close");
+ break;
+ }
+ gpr_slice_unref(tc->optional_message);
+ grpc_exec_ctx_sched(exec_ctx, tc->op_closure, GRPC_ERROR_NONE, NULL);
+ gpr_free(tc);
+}
-static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
- cancel_closure *cc = ccp;
- GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
- gpr_free(cc);
+static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
+ grpc_transport_stream_op op;
+ termination_closure *tc = tcp;
+ memset(&op, 0, sizeof(op));
+ op.cancel_with_status = tc->status;
+ /* reuse closure to catch completion */
+ grpc_closure_init(&tc->closure, done_termination, tc);
+ op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &op);
}
-static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
+static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
grpc_transport_stream_op op;
- cancel_closure *cc = ccp;
+ termination_closure *tc = tcp;
memset(&op, 0, sizeof(op));
- op.cancel_with_status = cc->status;
+ tc->optional_message = gpr_slice_ref(tc->optional_message);
+ grpc_transport_stream_op_add_close(&op, tc->status, &tc->optional_message);
/* reuse closure to catch completion */
- grpc_closure_init(&cc->closure, done_cancel, cc);
- op.on_complete = &cc->closure;
- execute_op(exec_ctx, cc->call, &op);
+ grpc_closure_init(&tc->closure, done_termination, tc);
+ tc->op_closure = op.on_complete;
+ op.on_complete = &tc->closure;
+ execute_op(exec_ctx, tc->call, &op);
+}
+
+static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
+ termination_closure *tc) {
+ grpc_mdstr *details = NULL;
+ if (GPR_SLICE_LENGTH(tc->optional_message) > 0) {
+ tc->optional_message = gpr_slice_ref(tc->optional_message);
+ details = grpc_mdstr_from_slice(tc->optional_message);
+ }
+
+ set_status_code(tc->call, STATUS_FROM_API_OVERRIDE, (uint32_t)tc->status);
+ set_status_details(tc->call, STATUS_FROM_API_OVERRIDE, details);
+
+ if (tc->type == TC_CANCEL) {
+ grpc_closure_init(&tc->closure, send_cancel, tc);
+ GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
+ } else if (tc->type == TC_CLOSE) {
+ grpc_closure_init(&tc->closure, send_close, tc);
+ GRPC_CALL_INTERNAL_REF(tc->call, "close");
+ }
+ grpc_exec_ctx_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE, NULL);
+ return GRPC_CALL_OK;
}
static grpc_call_error cancel_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
grpc_status_code status,
const char *description) {
- grpc_mdstr *details =
- description ? grpc_mdstr_from_string(description) : NULL;
- cancel_closure *cc = gpr_malloc(sizeof(*cc));
-
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CANCEL;
+ tc->call = c;
+ tc->optional_message = gpr_slice_from_copied_string(description);
GPR_ASSERT(status != GRPC_STATUS_OK);
+ tc->status = status;
- set_status_code(c, STATUS_FROM_API_OVERRIDE, (uint32_t)status);
- set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
+ return terminate_with_status(exec_ctx, tc);
+}
- grpc_closure_init(&cc->closure, send_cancel, cc);
- cc->call = c;
- cc->status = status;
- GRPC_CALL_INTERNAL_REF(c, "cancel");
- grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
+static grpc_call_error close_with_status(grpc_exec_ctx *exec_ctx, grpc_call *c,
+ grpc_status_code status,
+ const char *description) {
+ termination_closure *tc = gpr_malloc(sizeof(*tc));
+ memset(tc, 0, sizeof(termination_closure));
+ tc->type = TC_CLOSE;
+ tc->call = c;
+ tc->optional_message = gpr_slice_from_copied_string(description);
+ GPR_ASSERT(status != GRPC_STATUS_OK);
+ tc->status = status;
- return GRPC_CALL_OK;
+ return terminate_with_status(exec_ctx, tc);
}
static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
@@ -753,11 +868,11 @@ grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
return CALL_FROM_TOP_ELEM(elem);
}
-static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
grpc_call *call = arg;
gpr_mu_lock(&call->mu);
call->have_alarm = 0;
- if (success) {
+ if (error != GRPC_ERROR_CANCELLED) {
cancel_with_status(exec_ctx, call, GRPC_STATUS_DEADLINE_EXCEEDED,
"Deadline Exceeded");
}
@@ -860,9 +975,9 @@ static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
if (elem == NULL) {
return NULL;
} else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
- GPR_TIMER_BEGIN("compression_algorithm", 0);
- set_compression_algorithm(call, decode_compression(elem));
- GPR_TIMER_END("compression_algorithm", 0);
+ GPR_TIMER_BEGIN("incoming_compression_algorithm", 0);
+ set_incoming_compression_algorithm(call, decode_compression(elem));
+ GPR_TIMER_END("incoming_compression_algorithm", 0);
return NULL;
} else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
@@ -943,7 +1058,8 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
batch_control *bctl) {
grpc_call *call = bctl->call;
if (bctl->is_notify_tag_closure) {
- grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL);
+ /* unrefs bctl->error */
+ grpc_exec_ctx_sched(exec_ctx, bctl->notify_tag, bctl->error, NULL);
gpr_mu_lock(&call->mu);
bctl->call->used_batches =
(uint8_t)(bctl->call->used_batches &
@@ -951,7 +1067,8 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&call->mu);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
} else {
- grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->success,
+ /* unrefs bctl->error */
+ grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->error,
finish_batch_completion, bctl, &bctl->cq_completion);
}
}
@@ -983,15 +1100,18 @@ static void continue_receiving_slices(grpc_exec_ctx *exec_ctx,
}
static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
- bool success) {
+ grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
gpr_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) {
+ GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error));
+ }
grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
call->receiving_stream = NULL;
grpc_byte_buffer_destroy(*call->receiving_buffer);
@@ -1025,9 +1145,9 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
} else {
call->test_only_last_message_flags = call->receiving_stream->flags;
if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
- (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
+ (call->incoming_compression_algorithm > GRPC_COMPRESS_NONE)) {
*call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
- NULL, 0, call->compression_algorithm);
+ NULL, 0, call->incoming_compression_algorithm);
} else {
*call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
}
@@ -1040,53 +1160,89 @@ static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
}
static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
- bool success) {
+ grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
gpr_mu_lock(&bctl->call->mu);
- if (bctl->call->has_initial_md_been_received || !success ||
+ if (bctl->call->has_initial_md_been_received || error != GRPC_ERROR_NONE ||
call->receiving_stream == NULL) {
gpr_mu_unlock(&bctl->call->mu);
- process_data_after_md(exec_ctx, bctlp, success);
+ process_data_after_md(exec_ctx, bctlp, error);
} else {
call->saved_receiving_stream_ready_bctlp = bctlp;
gpr_mu_unlock(&bctl->call->mu);
}
}
+static void validate_filtered_metadata(grpc_exec_ctx *exec_ctx,
+ batch_control *bctl) {
+ grpc_call *call = bctl->call;
+ /* validate call->incoming_compression_algorithm */
+ if (call->incoming_compression_algorithm != GRPC_COMPRESS_NONE) {
+ const grpc_compression_algorithm algo =
+ call->incoming_compression_algorithm;
+ char *error_msg = NULL;
+ const grpc_compression_options compression_options =
+ grpc_channel_compression_options(call->channel);
+ /* check if algorithm is known */
+ if (algo >= GRPC_COMPRESS_ALGORITHMS_COUNT) {
+ gpr_asprintf(&error_msg, "Invalid compression algorithm value '%d'.",
+ algo);
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ } else if (grpc_compression_options_is_algorithm_enabled(
+ &compression_options, algo) == 0) {
+ /* check if algorithm is supported by current channel config */
+ char *algo_name;
+ grpc_compression_algorithm_name(algo, &algo_name);
+ gpr_asprintf(&error_msg, "Compression algorithm '%s' is disabled.",
+ algo_name);
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ close_with_status(exec_ctx, call, GRPC_STATUS_UNIMPLEMENTED, error_msg);
+ } else {
+ call->incoming_compression_algorithm = algo;
+ }
+ gpr_free(error_msg);
+ }
+
+ /* make sure the received grpc-encoding is amongst the ones listed in
+ * grpc-accept-encoding */
+ GPR_ASSERT(call->encodings_accepted_by_peer != 0);
+ if (!GPR_BITGET(call->encodings_accepted_by_peer,
+ call->incoming_compression_algorithm)) {
+ extern int grpc_compression_trace;
+ if (grpc_compression_trace) {
+ char *algo_name;
+ grpc_compression_algorithm_name(call->incoming_compression_algorithm,
+ &algo_name);
+ gpr_log(GPR_ERROR,
+ "Compression algorithm (grpc-encoding = '%s') not present in "
+ "the bitset of accepted encodings (grpc-accept-encodings: "
+ "'0x%x')",
+ algo_name, call->encodings_accepted_by_peer);
+ }
+ }
+}
+
static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
- void *bctlp, bool success) {
+ void *bctlp, grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
gpr_mu_lock(&call->mu);
- if (!success) {
- bctl->success = false;
+ if (error != GRPC_ERROR_NONE) {
+ bctl->error = GRPC_ERROR_REF(error);
} else {
grpc_metadata_batch *md =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
grpc_metadata_batch_filter(md, recv_initial_filter, call);
- /* make sure the received grpc-encoding is amongst the ones listed in
- * grpc-accept-encoding */
-
- GPR_ASSERT(call->encodings_accepted_by_peer != 0);
- if (!GPR_BITGET(call->encodings_accepted_by_peer,
- call->compression_algorithm)) {
- extern int grpc_compression_trace;
- if (grpc_compression_trace) {
- char *algo_name;
- grpc_compression_algorithm_name(call->compression_algorithm,
- &algo_name);
- gpr_log(GPR_ERROR,
- "Compression algorithm (grpc-encoding = '%s') not present in "
- "the bitset of accepted encodings (grpc-accept-encodings: "
- "'0x%x')",
- algo_name, call->encodings_accepted_by_peer);
- }
- }
+ GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
+ validate_filtered_metadata(exec_ctx, bctl);
+ GPR_TIMER_END("validate_filtered_metadata", 0);
+
if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
0 &&
!call->is_client) {
@@ -1101,7 +1257,7 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
grpc_closure *saved_rsr_closure = grpc_closure_create(
receiving_stream_ready, call->saved_receiving_stream_ready_bctlp);
call->saved_receiving_stream_ready_bctlp = NULL;
- grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, saved_rsr_closure, error, NULL);
}
gpr_mu_unlock(&call->mu);
@@ -1111,15 +1267,18 @@ static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
}
}
-static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) {
+static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp,
+ grpc_error *error) {
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
grpc_call *child_call;
grpc_call *next_child_call;
+ GRPC_ERROR_REF(error);
+
gpr_mu_lock(&call->mu);
if (bctl->send_initial_metadata) {
- if (!success) {
+ if (error != GRPC_ERROR_NONE) {
set_status_code(call, STATUS_FROM_CORE, GRPC_STATUS_UNAVAILABLE);
}
grpc_metadata_batch_destroy(
@@ -1165,13 +1324,17 @@ static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) {
call->final_op.server.cancelled);
}
- success = 1;
+ GRPC_ERROR_UNREF(error);
+ error = GRPC_ERROR_NONE;
}
- bctl->success = success != 0;
+ GRPC_ERROR_UNREF(bctl->error);
+ bctl->error = GRPC_ERROR_REF(error);
gpr_mu_unlock(&call->mu);
if (gpr_unref(&bctl->steps_to_complete)) {
post_batch_completion(exec_ctx, bctl);
}
+
+ GRPC_ERROR_UNREF(error);
}
static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
@@ -1201,7 +1364,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (nops == 0) {
GRPC_CALL_INTERNAL_REF(call, "completion");
- bctl->success = 1;
+ bctl->error = GRPC_ERROR_NONE;
if (!is_notify_tag_closure) {
grpc_cq_begin_op(call->cq, notify_tag);
}
@@ -1229,7 +1392,40 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
goto done_with_error;
}
- if (op->data.send_initial_metadata.count > INT_MAX) {
+ /* process compression level */
+ grpc_metadata compression_md;
+ memset(&compression_md, 0, sizeof(grpc_metadata));
+ size_t additional_metadata_count = 0;
+ grpc_compression_level effective_compression_level;
+ bool level_set = false;
+ if (op->data.send_initial_metadata.maybe_compression_level.is_set) {
+ effective_compression_level =
+ op->data.send_initial_metadata.maybe_compression_level.level;
+ level_set = true;
+ } else {
+ const grpc_compression_options copts =
+ grpc_channel_compression_options(call->channel);
+ level_set = copts.default_level.is_set;
+ if (level_set) {
+ effective_compression_level = copts.default_level.level;
+ }
+ }
+ if (level_set && !call->is_client) {
+ const grpc_compression_algorithm calgo =
+ compression_algorithm_for_level_locked(
+ call, effective_compression_level);
+ char *calgo_name;
+ grpc_compression_algorithm_name(calgo, &calgo_name);
+ // the following will be picked up by the compress filter and used as
+ // the call's compression algorithm.
+ compression_md.key = GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY;
+ compression_md.value = calgo_name;
+ compression_md.value_length = strlen(calgo_name);
+ additional_metadata_count++;
+ }
+
+ if (op->data.send_initial_metadata.count + additional_metadata_count >
+ INT_MAX) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1237,7 +1433,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
call->sent_initial_metadata = 1;
if (!prepare_application_metadata(
call, (int)op->data.send_initial_metadata.count,
- op->data.send_initial_metadata.metadata, 0, call->is_client)) {
+ op->data.send_initial_metadata.metadata, 0, call->is_client,
+ &compression_md, (int)additional_metadata_count)) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1325,7 +1522,8 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
if (!prepare_application_metadata(
call,
(int)op->data.send_status_from_server.trailing_metadata_count,
- op->data.send_status_from_server.trailing_metadata, 1, 1)) {
+ op->data.send_status_from_server.trailing_metadata, 1, 1, NULL,
+ 0)) {
error = GRPC_CALL_ERROR_INVALID_METADATA;
goto done_with_error;
}
@@ -1514,9 +1712,10 @@ uint8_t grpc_call_is_client(grpc_call *call) { return call->is_client; }
grpc_compression_algorithm grpc_call_compression_for_level(
grpc_call *call, grpc_compression_level level) {
gpr_mu_lock(&call->mu);
- const uint32_t accepted_encodings = call->encodings_accepted_by_peer;
+ grpc_compression_algorithm algo =
+ compression_algorithm_for_level_locked(call, level);
gpr_mu_unlock(&call->mu);
- return grpc_compression_algorithm_for_level(level, accepted_encodings);
+ return algo;
}
const char *grpc_call_error_to_string(grpc_call_error error) {
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 2725e060b8..b640345c21 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -53,6 +53,8 @@ typedef void (*grpc_ioreq_completion_func)(grpc_exec_ctx *exec_ctx,
grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
uint32_t propagation_mask,
grpc_completion_queue *cq,
+ /* if not NULL, it'll be used in lieu of \a cq */
+ grpc_pollset_set *pollset_set_alternative,
const void *server_transport_data,
grpc_mdelem **add_initial_metadata,
size_t add_initial_metadata_count,
diff --git a/src/core/lib/surface/call_log_batch.c b/src/core/lib/surface/call_log_batch.c
index a6d1d5149f..31c074f15d 100644
--- a/src/core/lib/surface/call_log_batch.c
+++ b/src/core/lib/surface/call_log_batch.c
@@ -112,7 +112,7 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
size_t i;
for (i = 0; i < nops; i++) {
tmp = grpc_op_string(&ops[i]);
- gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
+ gpr_log(file, line, severity, "ops[%" PRIuPTR "]: %s", i, tmp);
gpr_free(tmp);
}
}
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index b6b760b5d8..952a769de1 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -36,16 +36,17 @@
#include <stdlib.h>
#include <string.h>
+#include <grpc/compression.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/iomgr/iomgr.h"
#include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
-#include "src/core/lib/surface/init.h"
#include "src/core/lib/transport/static_metadata.h"
/** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
@@ -64,10 +65,12 @@ typedef struct registered_call {
struct grpc_channel {
int is_client;
uint32_t max_message_length;
+ grpc_compression_options compression_options;
grpc_mdelem *default_authority;
gpr_mu registered_call_mu;
registered_call *registered_calls;
+
char *target;
};
@@ -80,7 +83,8 @@ struct grpc_channel {
/* the protobuf library will (by default) start warning at 100megs */
#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
-static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error);
grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_args *input_args,
@@ -111,6 +115,7 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
channel->registered_calls = NULL;
channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
+ grpc_compression_options_init(&channel->compression_options);
if (args) {
for (size_t i = 0; i < args->num_args; i++) {
if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
@@ -151,6 +156,27 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
":authority", args->args[i].value.string);
}
}
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
+ channel->compression_options.default_level.is_set = true;
+ GPR_ASSERT(args->args[i].value.integer >= 0 &&
+ args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
+ channel->compression_options.default_level.level =
+ (grpc_compression_level)args->args[i].value.integer;
+ } else if (0 == strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
+ channel->compression_options.default_algorithm.is_set = true;
+ GPR_ASSERT(args->args[i].value.integer >= 0 &&
+ args->args[i].value.integer <
+ GRPC_COMPRESS_ALGORITHMS_COUNT);
+ channel->compression_options.default_algorithm.algorithm =
+ (grpc_compression_algorithm)args->args[i].value.integer;
+ } else if (0 ==
+ strcmp(args->args[i].key,
+ GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
+ channel->compression_options.enabled_algorithms_bitset =
+ (uint32_t)args->args[i].value.integer |
+ 0x1; /* always support no compression */
}
}
grpc_channel_args_destroy(args);
@@ -166,12 +192,14 @@ char *grpc_channel_get_target(grpc_channel *channel) {
static grpc_call *grpc_channel_create_call_internal(
grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
- grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
- grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
+ grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
+ grpc_mdelem *path_mdelem, grpc_mdelem *authority_mdelem,
+ gpr_timespec deadline) {
grpc_mdelem *send_metadata[2];
size_t num_metadata = 0;
GPR_ASSERT(channel->is_client);
+ GPR_ASSERT(!(cq != NULL && pollset_set_alternative != NULL));
send_metadata[num_metadata++] = path_mdelem;
if (authority_mdelem != NULL) {
@@ -180,8 +208,9 @@ static grpc_call *grpc_channel_create_call_internal(
send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
}
- return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
- send_metadata, num_metadata, deadline);
+ return grpc_call_create(channel, parent_call, propagation_mask, cq,
+ pollset_set_alternative, NULL, send_metadata,
+ num_metadata, deadline);
}
grpc_call *grpc_channel_create_call(grpc_channel *channel,
@@ -194,14 +223,29 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
"grpc_channel_create_call("
"channel=%p, parent_call=%p, propagation_mask=%x, cq=%p, method=%s, "
"host=%s, "
- "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
- (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+ deadline.tv_sec, deadline.tv_nsec,
(int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
- channel, parent_call, propagation_mask, cq,
+ channel, parent_call, propagation_mask, cq, NULL,
+ grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+ grpc_mdstr_from_string(method)),
+ host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
+ grpc_mdstr_from_string(host))
+ : NULL,
+ deadline);
+}
+
+grpc_call *grpc_channel_create_pollset_set_call(
+ grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+ grpc_pollset_set *pollset_set, const char *method, const char *host,
+ gpr_timespec deadline, void *reserved) {
+ GPR_ASSERT(!reserved);
+ return grpc_channel_create_call_internal(
+ channel, parent_call, propagation_mask, NULL, pollset_set,
grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
grpc_mdstr_from_string(method)),
host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
@@ -238,14 +282,14 @@ grpc_call *grpc_channel_create_registered_call(
"grpc_channel_create_registered_call("
"channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
"registered_call_handle=%p, "
- "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
9, (channel, parent_call, (unsigned)propagation_mask, completion_queue,
- registered_call_handle, (long long)deadline.tv_sec,
- (int)deadline.tv_nsec, (int)deadline.clock_type, reserved));
+ registered_call_handle, deadline.tv_sec,
+ deadline.tv_nsec, (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
- channel, parent_call, propagation_mask, completion_queue,
+ channel, parent_call, propagation_mask, completion_queue, NULL,
GRPC_MDELEM_REF(rc->path),
rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
}
@@ -267,7 +311,7 @@ void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
}
static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_success) {
+ grpc_error *error) {
grpc_channel *channel = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) {
@@ -293,7 +337,7 @@ void grpc_channel_destroy(grpc_channel *channel) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
memset(&op, 0, sizeof(op));
- op.disconnect = 1;
+ op.disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed");
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
elem->filter->start_transport_op(&exec_ctx, elem, &op);
@@ -306,6 +350,11 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
return CHANNEL_STACK_FROM_CHANNEL(channel);
}
+grpc_compression_options grpc_channel_compression_options(
+ const grpc_channel *channel) {
+ return channel->compression_options;
+}
+
grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
char tmp[GPR_LTOA_MIN_BUFSIZE];
switch (i) {
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 22dae930e4..7eff7b8883 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -42,6 +42,11 @@ grpc_channel *grpc_channel_create(grpc_exec_ctx *exec_ctx, const char *target,
grpc_channel_stack_type channel_stack_type,
grpc_transport *optional_transport);
+grpc_call *grpc_channel_create_pollset_set_call(
+ grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+ grpc_pollset_set *pollset_set, const char *method, const char *host,
+ gpr_timespec deadline, void *reserved);
+
/** Get a (borrowed) pointer to this channels underlying channel stack */
grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
@@ -71,4 +76,8 @@ void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
grpc_channel_internal_unref(exec_ctx, channel)
#endif
+/** Return the channel's compression options. */
+grpc_compression_options grpc_channel_compression_options(
+ const grpc_channel *channel);
+
#endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_H */
diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c
index 5a50698695..9818f9d2f2 100644
--- a/src/core/lib/surface/channel_ping.c
+++ b/src/core/lib/surface/channel_ping.c
@@ -53,10 +53,10 @@ static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_free(arg);
}
-static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
ping_result *pr = arg;
- grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr,
- &pr->completion_storage);
+ grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, GRPC_ERROR_REF(error), ping_destroy,
+ pr, &pr->completion_storage);
}
void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 5eb7cf1bf4..aa35ae02fe 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -50,6 +50,8 @@
#include "src/core/lib/surface/event_string.h"
#include "src/core/lib/surface/surface_trace.h"
+int grpc_trace_operation_failures;
+
typedef struct {
grpc_pollset_worker **worker;
void *tag;
@@ -92,7 +94,7 @@ static gpr_mu g_freelist_mu;
static grpc_completion_queue *g_freelist;
static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
- bool success);
+ grpc_error *error);
void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); }
@@ -176,7 +178,7 @@ void grpc_cq_internal_ref(grpc_completion_queue *cc) {
}
static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
- bool success) {
+ grpc_error *error) {
grpc_completion_queue *cc = arg;
GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy");
}
@@ -219,7 +221,7 @@ void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
event, then enter shutdown mode */
/* Queue a GRPC_OP_COMPLETED operation */
void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
- void *tag, int success,
+ void *tag, grpc_error *error,
void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
grpc_cq_completion *storage),
void *done_arg, grpc_cq_completion *storage) {
@@ -231,16 +233,24 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
#endif
GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
- GRPC_API_TRACE(
- "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, success=%d, done=%p, "
- "done_arg=%p, storage=%p)",
- 7, (exec_ctx, cc, tag, success, done, done_arg, storage));
+ if (grpc_api_trace ||
+ (grpc_trace_operation_failures && error != GRPC_ERROR_NONE)) {
+ const char *errmsg = grpc_error_string(error);
+ GRPC_API_TRACE(
+ "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, error=%s, done=%p, "
+ "done_arg=%p, storage=%p)",
+ 7, (exec_ctx, cc, tag, errmsg, done, done_arg, storage));
+ if (grpc_trace_operation_failures) {
+ gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+ }
+ grpc_error_free_string(errmsg);
+ }
storage->tag = tag;
storage->done = done;
storage->done_arg = done_arg;
- storage->next =
- ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0));
+ storage->next = ((uintptr_t)&cc->completed_head) |
+ ((uintptr_t)(error == GRPC_ERROR_NONE));
gpr_mu_lock(cc->mu);
#ifndef NDEBUG
@@ -267,8 +277,15 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
break;
}
}
- grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker);
+ grpc_error *kick_error =
+ grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker);
gpr_mu_unlock(cc->mu);
+ if (kick_error != GRPC_ERROR_NONE) {
+ const char *msg = grpc_error_string(kick_error);
+ gpr_log(GPR_ERROR, "Kick failed: %s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(kick_error);
+ }
} else {
cc->completed_tail->next =
((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
@@ -282,6 +299,8 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
}
GPR_TIMER_END("grpc_cq_end_op", 0);
+
+ GRPC_ERROR_UNREF(error);
}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
@@ -297,9 +316,9 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
GRPC_API_TRACE(
"grpc_completion_queue_next("
"cc=%p, "
- "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
- 5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+ 5, (cc, deadline.tv_sec, deadline.tv_nsec,
(int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
@@ -347,8 +366,18 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_mu_lock(cc->mu);
continue;
} else {
- grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
- iteration_deadline);
+ grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc),
+ &worker, now, iteration_deadline);
+ if (err != GRPC_ERROR_NONE) {
+ gpr_mu_unlock(cc->mu);
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(err);
+ memset(&ret, 0, sizeof(ret));
+ ret.type = GRPC_QUEUE_TIMEOUT;
+ break;
+ }
}
}
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
@@ -399,9 +428,9 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
GRPC_API_TRACE(
"grpc_completion_queue_pluck("
"cc=%p, tag=%p, "
- "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %"PRId64", tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
- 6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+ 6, (cc, tag, deadline.tv_sec, deadline.tv_nsec,
(int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
@@ -464,8 +493,19 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(cc->mu);
} else {
- grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
- iteration_deadline);
+ grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc),
+ &worker, now, iteration_deadline);
+ if (err != GRPC_ERROR_NONE) {
+ del_plucker(cc, tag, &worker);
+ gpr_mu_unlock(cc->mu);
+ const char *msg = grpc_error_string(err);
+ gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
+ grpc_error_free_string(msg);
+ GRPC_ERROR_UNREF(err);
+ memset(&ret, 0, sizeof(ret));
+ ret.type = GRPC_QUEUE_TIMEOUT;
+ break;
+ }
}
del_plucker(cc, tag, &worker);
}
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index 3d0dd13c53..b9dd1092b6 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -39,6 +39,8 @@
#include <grpc/grpc.h>
#include "src/core/lib/iomgr/pollset.h"
+extern int grpc_trace_operation_failures;
+
typedef struct grpc_cq_completion {
/** user supplied tag */
void *tag;
@@ -75,7 +77,7 @@ void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
/* Queue a GRPC_OP_COMPLETED operation; tag must correspond to the tag passed to
grpc_cq_begin_op */
void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
- void *tag, int success,
+ void *tag, grpc_error *error,
void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
grpc_cq_completion *storage),
void *done_arg, grpc_cq_completion *storage);
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 1c8b709015..f07039cb94 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -165,6 +165,7 @@ void grpc_init(void) {
&grpc_trace_channel_stack_builder);
grpc_register_tracer("http1", &grpc_http1_trace);
grpc_register_tracer("compression", &grpc_compression_trace);
+ grpc_register_tracer("op_failure", &grpc_trace_operation_failures);
grpc_security_pre_init();
grpc_iomgr_init();
grpc_executor_init();
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index eef862787f..5ea4cba5d1 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -80,7 +80,8 @@ static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
} else if (op->recv_trailing_metadata != NULL) {
fill_metadata(elem, op->recv_trailing_metadata);
}
- grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
+ grpc_transport_stream_op_finish_with_failure(
+ exec_ctx, op, GRPC_ERROR_CREATE("lame client channel"));
}
static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
@@ -93,15 +94,17 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
if (op->on_connectivity_state_change) {
GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_SHUTDOWN);
*op->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
- op->on_connectivity_state_change->cb(
- exec_ctx, op->on_connectivity_state_change->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change,
+ GRPC_ERROR_NONE, NULL);
}
if (op->on_consumed != NULL) {
- op->on_consumed->cb(exec_ctx, op->on_consumed->cb_arg, 1);
+ grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
}
if (op->send_ping != NULL) {
- op->send_ping->cb(exec_ctx, op->send_ping->cb_arg, 0);
+ grpc_exec_ctx_sched(exec_ctx, op->send_ping,
+ GRPC_ERROR_CREATE("lame client channel"), NULL);
}
+ GRPC_ERROR_UNREF(op->disconnect_with_error);
}
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
@@ -128,7 +131,7 @@ const grpc_channel_filter grpc_lame_filter = {
lame_start_transport_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 9532e090a4..def6e5068b 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -230,9 +230,10 @@ struct grpc_server {
#define SERVER_FROM_CALL_ELEM(elem) \
(((channel_data *)(elem)->channel_data)->server)
-static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *calld, bool success);
+static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *calld,
+ grpc_error *error);
static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
- size_t cq_idx, requested_call *rc);
+ size_t cq_idx, requested_call *rc, grpc_error *error);
/* Before calling maybe_finish_shutdown, we must hold mu_global and not
hold mu_call */
static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_server *server);
@@ -263,14 +264,14 @@ struct shutdown_cleanup_args {
};
static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
- bool iomgr_status_ignored) {
+ grpc_error *error) {
struct shutdown_cleanup_args *a = arg;
gpr_slice_unref(a->slice);
gpr_free(a);
}
static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
- int send_goaway, int send_disconnect) {
+ int send_goaway, grpc_error *send_disconnect) {
grpc_transport_op op;
struct shutdown_cleanup_args *sc;
grpc_channel_element *elem;
@@ -281,7 +282,7 @@ static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
sc->slice = gpr_slice_from_copied_string("Server shutdown");
op.goaway_message = &sc->slice;
op.goaway_status = GRPC_STATUS_OK;
- op.disconnect = send_disconnect;
+ op.disconnect_with_error = send_disconnect;
grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
op.on_consumed = &sc->closure;
@@ -292,14 +293,16 @@ static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
channel_broadcaster *cb,
int send_goaway,
- int force_disconnect) {
+ grpc_error *force_disconnect) {
size_t i;
for (i = 0; i < cb->num_channels; i++) {
- send_shutdown(exec_ctx, cb->channels[i], send_goaway, force_disconnect);
+ send_shutdown(exec_ctx, cb->channels[i], send_goaway,
+ GRPC_ERROR_REF(force_disconnect));
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, cb->channels[i], "broadcast");
}
gpr_free(cb->channels);
+ GRPC_ERROR_UNREF(force_disconnect);
}
/*
@@ -325,7 +328,8 @@ static void request_matcher_destroy(request_matcher *rm) {
gpr_free(rm->requests_per_cq);
}
-static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) {
+static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem,
+ grpc_error *error) {
grpc_call_destroy(grpc_call_from_top_element(elem));
}
@@ -340,20 +344,24 @@ static void request_matcher_zombify_all_pending_calls(grpc_exec_ctx *exec_ctx,
grpc_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
- grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE,
+ NULL);
}
}
static void request_matcher_kill_requests(grpc_exec_ctx *exec_ctx,
grpc_server *server,
- request_matcher *rm) {
+ request_matcher *rm,
+ grpc_error *error) {
int request_id;
for (size_t i = 0; i < server->cq_count; i++) {
while ((request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[i])) !=
-1) {
- fail_call(exec_ctx, server, i, &server->requested_calls[request_id]);
+ fail_call(exec_ctx, server, i, &server->requested_calls[request_id],
+ GRPC_ERROR_REF(error));
}
}
+ GRPC_ERROR_UNREF(error);
}
/*
@@ -410,7 +418,7 @@ static void orphan_channel(channel_data *chand) {
}
static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd,
- bool success) {
+ grpc_error *error) {
channel_data *chand = cd;
grpc_server *server = chand->server;
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server");
@@ -499,25 +507,26 @@ static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
channel_data *chand = elem->channel_data;
server_ref(chand->server);
- grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, true, done_request_event, rc,
- &rc->completion);
+ grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, GRPC_ERROR_NONE,
+ done_request_event, rc, &rc->completion);
}
-static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+static void publish_new_rpc(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_error *error) {
grpc_call_element *call_elem = arg;
call_data *calld = call_elem->call_data;
channel_data *chand = call_elem->channel_data;
request_matcher *rm = calld->request_matcher;
grpc_server *server = rm->server;
- if (!success || gpr_atm_acq_load(&server->shutdown_flag)) {
+ if (error != GRPC_ERROR_NONE || gpr_atm_acq_load(&server->shutdown_flag)) {
gpr_mu_lock(&calld->mu_state);
calld->state = ZOMBIED;
gpr_mu_unlock(&calld->mu_state);
grpc_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
- grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, error, NULL);
return;
}
@@ -562,7 +571,8 @@ static void finish_start_new_rpc(
calld->state = ZOMBIED;
gpr_mu_unlock(&calld->mu_state);
grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
- grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE,
+ NULL);
return;
}
@@ -570,7 +580,7 @@ static void finish_start_new_rpc(
switch (payload_handling) {
case GRPC_SRM_PAYLOAD_NONE:
- publish_new_rpc(exec_ctx, elem, true);
+ publish_new_rpc(exec_ctx, elem, GRPC_ERROR_NONE);
break;
case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER: {
grpc_op op;
@@ -658,18 +668,21 @@ static int num_channels(grpc_server *server) {
}
static void kill_pending_work_locked(grpc_exec_ctx *exec_ctx,
- grpc_server *server) {
+ grpc_server *server, grpc_error *error) {
if (server->started) {
request_matcher_kill_requests(exec_ctx, server,
- &server->unregistered_request_matcher);
+ &server->unregistered_request_matcher,
+ GRPC_ERROR_REF(error));
request_matcher_zombify_all_pending_calls(
exec_ctx, &server->unregistered_request_matcher);
for (registered_method *rm = server->registered_methods; rm;
rm = rm->next) {
- request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher);
+ request_matcher_kill_requests(exec_ctx, server, &rm->request_matcher,
+ GRPC_ERROR_REF(error));
request_matcher_zombify_all_pending_calls(exec_ctx, &rm->request_matcher);
}
}
+ GRPC_ERROR_UNREF(error);
}
static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
@@ -679,7 +692,8 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
return;
}
- kill_pending_work_locked(exec_ctx, server);
+ kill_pending_work_locked(exec_ctx, server,
+ GRPC_ERROR_CREATE("Server Shutdown"));
if (server->root_channel_data.next != &server->root_channel_data ||
server->listeners_destroyed < num_listeners(server)) {
@@ -700,7 +714,8 @@ static void maybe_finish_shutdown(grpc_exec_ctx *exec_ctx,
for (i = 0; i < server->num_shutdown_tags; i++) {
server_ref(server);
grpc_cq_end_op(exec_ctx, server->shutdown_tags[i].cq,
- server->shutdown_tags[i].tag, 1, done_shutdown_event, server,
+ server->shutdown_tags[i].tag, GRPC_ERROR_NONE,
+ done_shutdown_event, server,
&server->shutdown_tags[i].completion);
}
}
@@ -723,11 +738,12 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
}
static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
- bool success) {
+ grpc_error *error) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
gpr_timespec op_deadline;
+ GRPC_ERROR_REF(error);
grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem);
op_deadline = calld->recv_initial_metadata->deadline;
if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
@@ -736,11 +752,13 @@ static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
if (calld->host && calld->path) {
/* do nothing */
} else {
- success = 0;
+ GRPC_ERROR_UNREF(error);
+ error =
+ GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1);
}
- calld->on_done_recv_initial_metadata->cb(
- exec_ctx, calld->on_done_recv_initial_metadata->cb_arg, success);
+ grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv_initial_metadata, error,
+ NULL);
}
static void server_mutate_op(grpc_call_element *elem,
@@ -765,10 +783,10 @@ static void server_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
}
static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
- bool success) {
+ grpc_error *error) {
grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
- if (success) {
+ if (error == GRPC_ERROR_NONE) {
start_new_rpc(exec_ctx, elem);
} else {
gpr_mu_lock(&calld->mu_state);
@@ -776,7 +794,8 @@ static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
calld->state = ZOMBIED;
gpr_mu_unlock(&calld->mu_state);
grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
- grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure,
+ GRPC_ERROR_NONE, NULL);
} else if (calld->state == PENDING) {
calld->state = ZOMBIED;
gpr_mu_unlock(&calld->mu_state);
@@ -793,9 +812,9 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd,
const void *transport_server_data) {
channel_data *chand = cd;
/* create a call */
- grpc_call *call =
- grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data,
- NULL, 0, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+ grpc_call *call = grpc_call_create(chand->channel, NULL, 0, NULL, NULL,
+ transport_server_data, NULL, 0,
+ gpr_inf_future(GPR_CLOCK_MONOTONIC));
grpc_call_element *elem =
grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
call_data *calld = elem->call_data;
@@ -809,7 +828,7 @@ static void accept_stream(grpc_exec_ctx *exec_ctx, void *cd,
}
static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd,
- bool iomgr_status_ignored) {
+ grpc_error *error) {
channel_data *chand = cd;
grpc_server *server = chand->server;
if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
@@ -910,7 +929,7 @@ const grpc_channel_filter grpc_server_top_filter = {
grpc_channel_next_op,
sizeof(call_data),
init_call_elem,
- grpc_call_stack_ignore_set_pollset,
+ grpc_call_stack_ignore_set_pollset_or_pollset_set,
destroy_call_elem,
sizeof(channel_data),
init_channel_elem,
@@ -1148,7 +1167,9 @@ void grpc_server_setup_transport(grpc_exec_ctx *exec_ctx, grpc_server *s,
op.set_accept_stream_user_data = chand;
op.on_connectivity_state_change = &chand->channel_connectivity_changed;
op.connectivity_state = &chand->connectivity_state;
- op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0;
+ if (gpr_atm_acq_load(&s->shutdown_flag) != 0) {
+ op.disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
+ }
grpc_transport_perform_op(exec_ctx, transport, &op);
}
@@ -1159,7 +1180,7 @@ void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg,
}
static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s,
- bool success) {
+ grpc_error *error) {
grpc_server *server = s;
gpr_mu_lock(&server->mu_global);
server->listeners_destroyed++;
@@ -1181,8 +1202,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
gpr_mu_lock(&server->mu_global);
grpc_cq_begin_op(cq, tag);
if (server->shutdown_published) {
- grpc_cq_end_op(&exec_ctx, cq, tag, 1, done_published_shutdown, NULL,
- gpr_malloc(sizeof(grpc_cq_completion)));
+ grpc_cq_end_op(&exec_ctx, cq, tag, GRPC_ERROR_NONE, done_published_shutdown,
+ NULL, gpr_malloc(sizeof(grpc_cq_completion)));
gpr_mu_unlock(&server->mu_global);
goto done;
}
@@ -1205,7 +1226,8 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
/* collect all unregistered then registered calls */
gpr_mu_lock(&server->mu_call);
- kill_pending_work_locked(&exec_ctx, server);
+ kill_pending_work_locked(&exec_ctx, server,
+ GRPC_ERROR_CREATE("Server Shutdown"));
gpr_mu_unlock(&server->mu_call);
maybe_finish_shutdown(&exec_ctx, server);
@@ -1233,7 +1255,8 @@ void grpc_server_cancel_all_calls(grpc_server *server) {
channel_broadcaster_init(server, &broadcaster);
gpr_mu_unlock(&server->mu_global);
- channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0, 1);
+ channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0,
+ GRPC_ERROR_CREATE("Cancelling all calls"));
grpc_exec_ctx_finish(&exec_ctx);
}
@@ -1280,13 +1303,15 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
request_matcher *rm = NULL;
int request_id;
if (gpr_atm_acq_load(&server->shutdown_flag)) {
- fail_call(exec_ctx, server, cq_idx, rc);
+ fail_call(exec_ctx, server, cq_idx, rc,
+ GRPC_ERROR_CREATE("Server Shutdown"));
return GRPC_CALL_OK;
}
request_id = gpr_stack_lockfree_pop(server->request_freelist);
if (request_id == -1) {
/* out of request ids: just fail this one */
- fail_call(exec_ctx, server, cq_idx, rc);
+ fail_call(exec_ctx, server, cq_idx, rc,
+ GRPC_ERROR_CREATE("Server Shutdown"));
return GRPC_CALL_OK;
}
switch (rc->type) {
@@ -1314,8 +1339,8 @@ static grpc_call_error queue_call_request(grpc_exec_ctx *exec_ctx,
grpc_closure_init(
&calld->kill_zombie_closure, kill_zombie,
grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
- grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true,
- NULL);
+ grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure,
+ GRPC_ERROR_NONE, NULL);
} else {
GPR_ASSERT(calld->state == PENDING);
calld->state = ACTIVATED;
@@ -1421,13 +1446,14 @@ done:
}
static void fail_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
- size_t cq_idx, requested_call *rc) {
+ size_t cq_idx, requested_call *rc, grpc_error *error) {
*rc->call = NULL;
rc->initial_metadata->count = 0;
+ GPR_ASSERT(error != GRPC_ERROR_NONE);
server_ref(server);
- grpc_cq_end_op(exec_ctx, server->cqs[cq_idx], rc->tag, 0, done_request_event,
- rc, &rc->completion);
+ grpc_cq_end_op(exec_ctx, server->cqs[cq_idx], rc->tag, error,
+ done_request_event, rc, &rc->completion);
}
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index aca76d2bb7..53f3c43854 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,4 +36,4 @@
#include <grpc/grpc.h>
-const char *grpc_version_string(void) { return "0.15.0-dev"; }
+const char *grpc_version_string(void) { return "0.16.0-dev"; }
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
index 74a5ef5c13..054f112127 100644
--- a/src/core/lib/transport/connectivity_state.c
+++ b/src/core/lib/transport/connectivity_state.c
@@ -52,7 +52,7 @@ const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
case GRPC_CHANNEL_TRANSIENT_FAILURE:
return "TRANSIENT_FAILURE";
case GRPC_CHANNEL_SHUTDOWN:
- return "FATAL_FAILURE";
+ return "SHUTDOWN";
}
GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
@@ -61,35 +61,40 @@ void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state init_state,
const char *name) {
tracker->current_state = init_state;
+ tracker->current_error = GRPC_ERROR_NONE;
tracker->watchers = NULL;
tracker->name = gpr_strdup(name);
}
void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state_tracker *tracker) {
- int success;
+ grpc_error *error;
grpc_connectivity_state_watcher *w;
while ((w = tracker->watchers)) {
tracker->watchers = w->next;
if (GRPC_CHANNEL_SHUTDOWN != *w->current) {
*w->current = GRPC_CHANNEL_SHUTDOWN;
- success = 1;
+ error = GRPC_ERROR_NONE;
} else {
- success = 0;
+ error = GRPC_ERROR_CREATE("Shutdown connectivity owner");
}
- grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL);
+ grpc_exec_ctx_sched(exec_ctx, w->notify, error, NULL);
gpr_free(w);
}
+ GRPC_ERROR_UNREF(tracker->current_error);
gpr_free(tracker->name);
}
grpc_connectivity_state grpc_connectivity_state_check(
- grpc_connectivity_state_tracker *tracker) {
+ grpc_connectivity_state_tracker *tracker, grpc_error **error) {
if (grpc_connectivity_state_trace) {
gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
grpc_connectivity_state_name(tracker->current_state));
}
+ if (error != NULL) {
+ *error = GRPC_ERROR_REF(tracker->current_error);
+ }
return tracker->current_state;
}
@@ -109,7 +114,7 @@ int grpc_connectivity_state_notify_on_state_change(
if (current == NULL) {
grpc_connectivity_state_watcher *w = tracker->watchers;
if (w != NULL && w->notify == notify) {
- grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
tracker->watchers = w->next;
gpr_free(w);
return 0;
@@ -117,7 +122,7 @@ int grpc_connectivity_state_notify_on_state_change(
while (w != NULL) {
grpc_connectivity_state_watcher *rm_candidate = w->next;
if (rm_candidate != NULL && rm_candidate->notify == notify) {
- grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
+ grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
w->next = w->next->next;
gpr_free(rm_candidate);
return 0;
@@ -128,7 +133,8 @@ int grpc_connectivity_state_notify_on_state_change(
} else {
if (tracker->current_state != *current) {
*current = tracker->current_state;
- grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, notify,
+ GRPC_ERROR_REF(tracker->current_error), NULL);
} else {
grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
w->current = current;
@@ -143,13 +149,28 @@ int grpc_connectivity_state_notify_on_state_change(
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state state,
- const char *reason) {
+ grpc_error *error, const char *reason) {
grpc_connectivity_state_watcher *w;
if (grpc_connectivity_state_trace) {
- gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name,
- grpc_connectivity_state_name(tracker->current_state),
- grpc_connectivity_state_name(state), reason);
+ const char *error_string = grpc_error_string(error);
+ gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker,
+ tracker->name, grpc_connectivity_state_name(tracker->current_state),
+ grpc_connectivity_state_name(state), reason, error, error_string);
+ grpc_error_free_string(error_string);
+ }
+ switch (state) {
+ case GRPC_CHANNEL_CONNECTING:
+ case GRPC_CHANNEL_IDLE:
+ case GRPC_CHANNEL_READY:
+ GPR_ASSERT(error == GRPC_ERROR_NONE);
+ break;
+ case GRPC_CHANNEL_SHUTDOWN:
+ case GRPC_CHANNEL_TRANSIENT_FAILURE:
+ GPR_ASSERT(error != GRPC_ERROR_NONE);
+ break;
}
+ GRPC_ERROR_UNREF(tracker->current_error);
+ tracker->current_error = error;
if (tracker->current_state == state) {
return;
}
@@ -158,7 +179,8 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
while ((w = tracker->watchers) != NULL) {
*w->current = tracker->current_state;
tracker->watchers = w->next;
- grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, w->notify,
+ GRPC_ERROR_REF(tracker->current_error), NULL);
gpr_free(w);
}
}
diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h
index 2eb7e09124..7a2fa52c10 100644
--- a/src/core/lib/transport/connectivity_state.h
+++ b/src/core/lib/transport/connectivity_state.h
@@ -49,6 +49,8 @@ typedef struct grpc_connectivity_state_watcher {
typedef struct {
/** current connectivity state */
grpc_connectivity_state current_state;
+ /** error associated with state */
+ grpc_error *current_error;
/** all our watchers */
grpc_connectivity_state_watcher *watchers;
/** a name to help debugging */
@@ -70,10 +72,11 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state state,
+ grpc_error *associated_error,
const char *reason);
grpc_connectivity_state grpc_connectivity_state_check(
- grpc_connectivity_state_tracker *tracker);
+ 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
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index 82c8e239f6..0677f29766 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -129,7 +129,10 @@ typedef struct mdtab_shard {
internal_metadata **elems;
size_t count;
size_t capacity;
- size_t free;
+ /** Estimate of the number of unreferenced mdelems in the hash table.
+ This will eventually converge to the exact number, but it's instantaneous
+ accuracy is not guaranteed */
+ gpr_atm free_estimate;
} mdtab_shard;
#define LOG2_STRTAB_SHARD_COUNT 5
@@ -217,7 +220,7 @@ void grpc_mdctx_global_init(void) {
mdtab_shard *shard = &g_mdtab_shard[i];
gpr_mu_init(&shard->mu);
shard->count = 0;
- shard->free = 0;
+ gpr_atm_no_barrier_store(&shard->free_estimate, 0);
shard->capacity = INITIAL_MDTAB_CAPACITY;
shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
@@ -232,7 +235,7 @@ void grpc_mdctx_global_shutdown(void) {
gc_mdtab(shard);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
- gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
+ gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked",
shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
@@ -245,7 +248,7 @@ void grpc_mdctx_global_shutdown(void) {
gpr_mu_destroy(&shard->mu);
/* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
if (shard->count != 0) {
- gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
+ gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
shard->count);
for (size_t j = 0; j < shard->capacity; j++) {
for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) {
@@ -281,10 +284,8 @@ static void ref_md_locked(mdtab_shard *shard,
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
- if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
- shard->free--;
- } else {
- GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
+ if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
+ gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -1);
}
}
@@ -447,6 +448,7 @@ static void gc_mdtab(mdtab_shard *shard) {
size_t i;
internal_metadata **prev_next;
internal_metadata *md, *next;
+ gpr_atm num_freed = 0;
GPR_TIMER_BEGIN("gc_mdtab", 0);
for (i = 0; i < shard->capacity; i++) {
@@ -463,13 +465,14 @@ static void gc_mdtab(mdtab_shard *shard) {
}
gpr_free(md);
*prev_next = next;
- shard->free--;
+ num_freed++;
shard->count--;
} else {
prev_next = &md->bucket_next;
}
}
}
+ gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -num_freed);
GPR_TIMER_END("gc_mdtab", 0);
}
@@ -504,7 +507,8 @@ static void grow_mdtab(mdtab_shard *shard) {
}
static void rehash_mdtab(mdtab_shard *shard) {
- if (shard->free > shard->capacity / 4) {
+ if (gpr_atm_no_barrier_load(&shard->free_estimate) >
+ (gpr_atm)(shard->capacity / 4)) {
gc_mdtab(shard);
} else {
grow_mdtab(shard);
@@ -553,7 +557,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
/* not found: create a new pair */
md = gpr_malloc(sizeof(internal_metadata));
- gpr_atm_rel_store(&md->refcnt, 2);
+ gpr_atm_rel_store(&md->refcnt, 1);
md->key = key;
md->value = value;
md->user_data = 0;
@@ -645,7 +649,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
this function - meaning that no adjustment to mdtab_free is necessary,
simplifying the logic here to be just an atomic increment */
/* use C assert to have this removed in opt builds */
- assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
+ assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
return gmd;
}
@@ -662,18 +666,13 @@ void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
#endif
- if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
- uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+ uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
+ if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
+ /* once the refcount hits zero, some other thread can come along and
+ free md at any time: it's unsafe from this point on to access it */
mdtab_shard *shard =
&g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
- GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
- gpr_mu_lock(&shard->mu);
- if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
- shard->free++;
- gpr_atm_no_barrier_store(&md->refcnt, 0);
- }
- gpr_mu_unlock(&shard->mu);
- GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
+ gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1);
}
}
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index e6d524abe6..1105494a85 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -60,7 +60,7 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_stream_refcount *refcount) {
#endif
if (gpr_unref(&refcount->refs)) {
- grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL);
+ grpc_exec_ctx_sched(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE, NULL);
}
}
@@ -125,10 +125,19 @@ void grpc_transport_perform_op(grpc_exec_ctx *exec_ctx,
transport->vtable->perform_op(exec_ctx, transport, op);
}
-void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_transport *transport, grpc_stream *stream,
- grpc_pollset *pollset) {
- transport->vtable->set_pollset(exec_ctx, transport, stream, pollset);
+void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport,
+ grpc_stream *stream,
+ grpc_polling_entity *pollent) {
+ grpc_pollset *pollset;
+ grpc_pollset_set *pollset_set;
+ if ((pollset = grpc_polling_entity_pollset(pollent)) != NULL) {
+ transport->vtable->set_pollset(exec_ctx, transport, stream, pollset);
+ } else if ((pollset_set = grpc_polling_entity_pollset_set(pollent)) != NULL) {
+ transport->vtable->set_pollset_set(exec_ctx, transport, stream,
+ pollset_set);
+ } else {
+ abort();
+ }
}
void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
@@ -143,11 +152,14 @@ char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
return transport->vtable->get_peer(exec_ctx, transport);
}
-void grpc_transport_stream_op_finish_with_failure(
- grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) {
- grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL);
- grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL);
- grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL);
+void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
+ grpc_transport_stream_op *op,
+ grpc_error *error) {
+ grpc_exec_ctx_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error),
+ NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->recv_initial_metadata_ready,
+ GRPC_ERROR_REF(error), NULL);
+ grpc_exec_ctx_sched(exec_ctx, op->on_complete, error, NULL);
}
void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
@@ -171,11 +183,11 @@ typedef struct {
grpc_closure closure;
} close_message_data;
-static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) {
+static void free_message(grpc_exec_ctx *exec_ctx, void *p, grpc_error *error) {
close_message_data *cmd = p;
gpr_slice_unref(cmd->message);
if (cmd->then_call != NULL) {
- cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, iomgr_success);
+ cmd->then_call->cb(exec_ctx, cmd->then_call->cb_arg, GRPC_ERROR_REF(error));
}
gpr_free(cmd);
}
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 482a9d1791..a46ccb643c 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/polling_entity.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/transport/byte_stream.h"
@@ -154,7 +155,7 @@ typedef struct grpc_transport_op {
grpc_closure *on_connectivity_state_change;
grpc_connectivity_state *connectivity_state;
/** should the transport be disconnected */
- int disconnect;
+ grpc_error *disconnect_with_error;
/** should we send a goaway?
after a goaway is sent, once there are no more active calls on
the transport, the transport should disconnect */
@@ -197,9 +198,8 @@ int grpc_transport_init_stream(grpc_exec_ctx *exec_ctx,
grpc_stream_refcount *refcount,
const void *server_data);
-void grpc_transport_set_pollset(grpc_exec_ctx *exec_ctx,
- grpc_transport *transport, grpc_stream *stream,
- grpc_pollset *pollset);
+void grpc_transport_set_pops(grpc_exec_ctx *exec_ctx, grpc_transport *transport,
+ grpc_stream *stream, grpc_polling_entity *pollent);
/* Destroy transport data for a stream.
@@ -216,7 +216,8 @@ void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
grpc_stream *stream, void *and_free_memory);
void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
- grpc_transport_stream_op *op);
+ grpc_transport_stream_op *op,
+ grpc_error *error);
void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
grpc_status_code status);
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 956155eec8..fc7140671b 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -53,6 +53,10 @@ typedef struct grpc_transport_vtable {
void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
grpc_stream *stream, grpc_pollset *pollset);
+ /* implementation of grpc_transport_set_pollset */
+ void (*set_pollset_set)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
+ grpc_stream *stream, grpc_pollset_set *pollset_set);
+
/* implementation of grpc_transport_perform_stream_op */
void (*perform_stream_op)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
grpc_stream *stream, grpc_transport_stream_op *op);
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index df04c61127..d8fae7805e 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -63,8 +63,8 @@ static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
}
if (gpr_time_cmp(md.deadline, gpr_inf_future(md.deadline.clock_type)) != 0) {
char *tmp;
- gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec,
- (int)md.deadline.tv_nsec);
+ gpr_asprintf(&tmp, " deadline=%"PRId64".%09d", md.deadline.tv_sec,
+ md.deadline.tv_nsec);
gpr_strvec_add(b, tmp);
}
}
diff --git a/src/core/plugin_registry/grpc_cronet_plugin_registry.c b/src/core/plugin_registry/grpc_cronet_plugin_registry.c
new file mode 100644
index 0000000000..d0b5f5c702
--- /dev/null
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 <grpc/grpc.h>
+
+extern void grpc_chttp2_plugin_init(void);
+extern void grpc_chttp2_plugin_shutdown(void);
+extern void grpc_client_config_init(void);
+extern void grpc_client_config_shutdown(void);
+
+void grpc_register_built_in_plugins(void) {
+ grpc_register_plugin(grpc_chttp2_plugin_init,
+ grpc_chttp2_plugin_shutdown);
+ grpc_register_plugin(grpc_client_config_init,
+ grpc_client_config_shutdown);
+}
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 32c7794ade..0ba77a5057 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -33,15 +33,14 @@
#include <grpc++/client_context.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/time.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
-#include "src/core/lib/channel/compress_filter.h"
+#include <grpc++/security/credentials.h>
+#include <grpc++/server_context.h>
+#include <grpc++/support/time.h>
namespace grpc {
@@ -64,6 +63,7 @@ ClientContext::ClientContext()
call_(nullptr),
call_canceled_(false),
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
+ census_context_(nullptr),
propagate_from_call_(nullptr) {
g_client_callbacks->DefaultConstructor(this);
}
@@ -112,7 +112,7 @@ void ClientContext::set_compression_algorithm(
abort();
}
GPR_ASSERT(algorithm_name != nullptr);
- AddMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
+ AddMetadata(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY, algorithm_name);
}
void ClientContext::TryCancel() {
diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc
new file mode 100644
index 0000000000..60cfed3d62
--- /dev/null
+++ b/src/cpp/client/create_channel_posix.cc
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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 <grpc++/channel.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/impl/grpc_library.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_posix.h>
+
+#include "src/cpp/client/create_channel_internal.h"
+
+namespace grpc {
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+std::shared_ptr<Channel> CreateInsecureChannelFromFd(const grpc::string& target,
+ int fd) {
+ internal::GrpcLibrary init_lib;
+ init_lib.init();
+ return CreateChannelInternal(
+ "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr));
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
+
+} // namespace grpc
diff --git a/src/cpp/codegen/codegen_init.cc b/src/cpp/codegen/codegen_init.cc
index c5d22124b7..103a7c1258 100644
--- a/src/cpp/codegen/codegen_init.cc
+++ b/src/cpp/codegen/codegen_init.cc
@@ -34,12 +34,12 @@
#include <grpc++/impl/codegen/core_codegen_interface.h>
#include <grpc++/impl/codegen/grpc_library.h>
-/// Initializes the global gRPC variables for the codegen library. These will
+/// Null-initializes the global gRPC variables for the codegen library. These
/// stay null in the absence of of grpc++ library. In this case, no gRPC
/// features such as the ability to perform calls will be available. Trying to
/// perform them would result in a segmentation fault when trying to deference
/// the following nulled globals. These should be associated with actual
/// as part of the instantiation of a \a grpc::GrpcLibraryInitializer variable.
-grpc::CoreCodegenInterface* grpc::g_core_codegen_interface = nullptr;
-grpc::GrpcLibraryInterface* grpc::g_glip = nullptr;
+grpc::CoreCodegenInterface* grpc::g_core_codegen_interface;
+grpc::GrpcLibraryInterface* grpc::g_glip;
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 8e8d42eb29..cc35aa69ba 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -31,7 +31,7 @@
*
*/
-#include "src/cpp/common/core_codegen.h"
+#include <grpc++/impl/codegen/core_codegen.h>
#include <stdlib.h>
diff --git a/src/cpp/common/core_codegen.h b/src/cpp/common/core_codegen.h
deleted file mode 100644
index 656b11e7e7..0000000000
--- a/src/cpp/common/core_codegen.h
+++ /dev/null
@@ -1,83 +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.
- *
- */
-
-// This file should be compiled as part of grpc++.
-
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc/byte_buffer.h>
-#include <grpc/impl/codegen/grpc_types.h>
-
-namespace grpc {
-
-/// Implementation of the core codegen interface.
-class CoreCodegen : public CoreCodegenInterface {
- private:
- grpc_completion_queue* grpc_completion_queue_create(void* reserved) override;
- void grpc_completion_queue_destroy(grpc_completion_queue* cq) override;
- grpc_event grpc_completion_queue_pluck(grpc_completion_queue* cq, void* tag,
- gpr_timespec deadline,
- void* reserved) override;
-
- void* gpr_malloc(size_t size) override;
- void gpr_free(void* p) override;
-
- void grpc_byte_buffer_destroy(grpc_byte_buffer* bb) override;
-
- void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader* reader,
- grpc_byte_buffer* buffer) override;
- void grpc_byte_buffer_reader_destroy(
- grpc_byte_buffer_reader* reader) override;
- int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader* reader,
- gpr_slice* slice) override;
-
- grpc_byte_buffer* grpc_raw_byte_buffer_create(gpr_slice* slice,
- size_t nslices) override;
-
- gpr_slice gpr_slice_malloc(size_t length) override;
- void gpr_slice_unref(gpr_slice slice) override;
- gpr_slice gpr_slice_split_tail(gpr_slice* s, size_t split) override;
- void gpr_slice_buffer_add(gpr_slice_buffer* sb, gpr_slice slice) override;
- void gpr_slice_buffer_pop(gpr_slice_buffer* sb) override;
-
- void grpc_metadata_array_init(grpc_metadata_array* array) override;
- void grpc_metadata_array_destroy(grpc_metadata_array* array) override;
-
- gpr_timespec gpr_inf_future(gpr_clock_type type) override;
-
- virtual const Status& ok() override;
- virtual const Status& cancelled() override;
-
- void assert_fail(const char* failed_assertion) override;
-};
-
-} // namespace grpc
diff --git a/src/cpp/ext/proto_server_reflection.cc b/src/cpp/ext/proto_server_reflection.cc
new file mode 100644
index 0000000000..3973bfb58e
--- /dev/null
+++ b/src/cpp/ext/proto_server_reflection.cc
@@ -0,0 +1,227 @@
+/*
+ *
+ * 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 <unordered_set>
+#include <vector>
+
+#include <grpc++/grpc++.h>
+
+#include "src/cpp/ext/proto_server_reflection.h"
+
+using grpc::Status;
+using grpc::StatusCode;
+using grpc::reflection::v1alpha::ServerReflectionRequest;
+using grpc::reflection::v1alpha::ExtensionRequest;
+using grpc::reflection::v1alpha::ServerReflectionResponse;
+using grpc::reflection::v1alpha::ListServiceResponse;
+using grpc::reflection::v1alpha::ServiceResponse;
+using grpc::reflection::v1alpha::ExtensionNumberResponse;
+using grpc::reflection::v1alpha::ErrorResponse;
+using grpc::reflection::v1alpha::FileDescriptorResponse;
+
+namespace grpc {
+
+ProtoServerReflection::ProtoServerReflection()
+ : descriptor_pool_(protobuf::DescriptorPool::generated_pool()) {}
+
+void ProtoServerReflection::SetServiceList(
+ const std::vector<grpc::string>* services) {
+ services_ = services;
+}
+
+Status ProtoServerReflection::ServerReflectionInfo(
+ ServerContext* context,
+ ServerReaderWriter<ServerReflectionResponse, ServerReflectionRequest>*
+ stream) {
+ ServerReflectionRequest request;
+ ServerReflectionResponse response;
+ Status status;
+ while (stream->Read(&request)) {
+ switch (request.message_request_case()) {
+ case ServerReflectionRequest::MessageRequestCase::kFileByFilename:
+ status = GetFileByName(context, request.file_by_filename(), &response);
+ break;
+ case ServerReflectionRequest::MessageRequestCase::kFileContainingSymbol:
+ status = GetFileContainingSymbol(
+ context, request.file_containing_symbol(), &response);
+ break;
+ case ServerReflectionRequest::MessageRequestCase::
+ kFileContainingExtension:
+ status = GetFileContainingExtension(
+ context, &request.file_containing_extension(), &response);
+ break;
+ case ServerReflectionRequest::MessageRequestCase::
+ kAllExtensionNumbersOfType:
+ status = GetAllExtensionNumbers(
+ context, request.all_extension_numbers_of_type(),
+ response.mutable_all_extension_numbers_response());
+ break;
+ case ServerReflectionRequest::MessageRequestCase::kListServices:
+ status =
+ ListService(context, response.mutable_list_services_response());
+ break;
+ default:
+ status = Status(StatusCode::UNIMPLEMENTED, "");
+ }
+
+ if (!status.ok()) {
+ FillErrorResponse(status, response.mutable_error_response());
+ }
+ response.set_valid_host(request.host());
+ response.set_allocated_original_request(
+ new ServerReflectionRequest(request));
+ stream->Write(response);
+ }
+
+ return Status::OK;
+}
+
+void ProtoServerReflection::FillErrorResponse(const Status& status,
+ ErrorResponse* error_response) {
+ error_response->set_error_code(status.error_code());
+ error_response->set_error_message(status.error_message());
+}
+
+Status ProtoServerReflection::ListService(ServerContext* context,
+ ListServiceResponse* response) {
+ if (services_ == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "Services not found.");
+ }
+ for (auto it = services_->begin(); it != services_->end(); ++it) {
+ ServiceResponse* service_response = response->add_service();
+ service_response->set_name(*it);
+ }
+ return Status::OK;
+}
+
+Status ProtoServerReflection::GetFileByName(
+ ServerContext* context, const grpc::string& filename,
+ ServerReflectionResponse* response) {
+ if (descriptor_pool_ == nullptr) {
+ return Status::CANCELLED;
+ }
+
+ const protobuf::FileDescriptor* file_desc =
+ descriptor_pool_->FindFileByName(filename);
+ if (file_desc == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "File not found.");
+ }
+ std::unordered_set<grpc::string> seen_files;
+ FillFileDescriptorResponse(file_desc, response, &seen_files);
+ return Status::OK;
+}
+
+Status ProtoServerReflection::GetFileContainingSymbol(
+ ServerContext* context, const grpc::string& symbol,
+ ServerReflectionResponse* response) {
+ if (descriptor_pool_ == nullptr) {
+ return Status::CANCELLED;
+ }
+
+ const protobuf::FileDescriptor* file_desc =
+ descriptor_pool_->FindFileContainingSymbol(symbol);
+ if (file_desc == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "Symbol not found.");
+ }
+ std::unordered_set<grpc::string> seen_files;
+ FillFileDescriptorResponse(file_desc, response, &seen_files);
+ return Status::OK;
+}
+
+Status ProtoServerReflection::GetFileContainingExtension(
+ ServerContext* context, const ExtensionRequest* request,
+ ServerReflectionResponse* response) {
+ if (descriptor_pool_ == nullptr) {
+ return Status::CANCELLED;
+ }
+
+ const protobuf::Descriptor* desc =
+ descriptor_pool_->FindMessageTypeByName(request->containing_type());
+ if (desc == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "Type not found.");
+ }
+
+ const protobuf::FieldDescriptor* field_desc =
+ descriptor_pool_->FindExtensionByNumber(desc,
+ request->extension_number());
+ if (field_desc == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "Extension not found.");
+ }
+ std::unordered_set<grpc::string> seen_files;
+ FillFileDescriptorResponse(field_desc->file(), response, &seen_files);
+ return Status::OK;
+}
+
+Status ProtoServerReflection::GetAllExtensionNumbers(
+ ServerContext* context, const grpc::string& type,
+ ExtensionNumberResponse* response) {
+ if (descriptor_pool_ == nullptr) {
+ return Status::CANCELLED;
+ }
+
+ const protobuf::Descriptor* desc =
+ descriptor_pool_->FindMessageTypeByName(type);
+ if (desc == nullptr) {
+ return Status(StatusCode::NOT_FOUND, "Type not found.");
+ }
+
+ std::vector<const protobuf::FieldDescriptor*> extensions;
+ descriptor_pool_->FindAllExtensions(desc, &extensions);
+ for (auto it = extensions.begin(); it != extensions.end(); it++) {
+ response->add_extension_number((*it)->number());
+ }
+ response->set_base_type_name(type);
+ return Status::OK;
+}
+
+void ProtoServerReflection::FillFileDescriptorResponse(
+ const protobuf::FileDescriptor* file_desc,
+ ServerReflectionResponse* response,
+ std::unordered_set<grpc::string>* seen_files) {
+ if (seen_files->find(file_desc->name()) != seen_files->end()) {
+ return;
+ }
+ seen_files->insert(file_desc->name());
+
+ protobuf::FileDescriptorProto file_desc_proto;
+ grpc::string data;
+ file_desc->CopyTo(&file_desc_proto);
+ file_desc_proto.SerializeToString(&data);
+ response->mutable_file_descriptor_response()->add_file_descriptor_proto(data);
+
+ for (int i = 0; i < file_desc->dependency_count(); ++i) {
+ FillFileDescriptorResponse(file_desc->dependency(i), response, seen_files);
+ }
+}
+
+} // namespace grpc
diff --git a/src/cpp/ext/proto_server_reflection.h b/src/cpp/ext/proto_server_reflection.h
new file mode 100644
index 0000000000..23c130513d
--- /dev/null
+++ b/src/cpp/ext/proto_server_reflection.h
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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_INTERNAL_CPP_EXT_PROTO_SERVER_REFLECTION_H
+#define GRPC_INTERNAL_CPP_EXT_PROTO_SERVER_REFLECTION_H
+
+#include <unordered_set>
+#include <vector>
+
+#include <grpc++/ext/reflection.grpc.pb.h>
+#include <grpc++/grpc++.h>
+
+namespace grpc {
+
+class ProtoServerReflection GRPC_FINAL
+ : public reflection::v1alpha::ServerReflection::Service {
+ public:
+ ProtoServerReflection();
+
+ // Add the full names of registered services
+ void SetServiceList(const std::vector<grpc::string>* services);
+
+ // implementation of ServerReflectionInfo(stream ServerReflectionRequest) rpc
+ // in ServerReflection service
+ Status ServerReflectionInfo(
+ ServerContext* context,
+ ServerReaderWriter<reflection::v1alpha::ServerReflectionResponse,
+ reflection::v1alpha::ServerReflectionRequest>* stream)
+ GRPC_OVERRIDE;
+
+ private:
+ Status ListService(ServerContext* context,
+ reflection::v1alpha::ListServiceResponse* response);
+
+ Status GetFileByName(ServerContext* context, const grpc::string& file_name,
+ reflection::v1alpha::ServerReflectionResponse* response);
+
+ Status GetFileContainingSymbol(
+ ServerContext* context, const grpc::string& symbol,
+ reflection::v1alpha::ServerReflectionResponse* response);
+
+ Status GetFileContainingExtension(
+ ServerContext* context,
+ const reflection::v1alpha::ExtensionRequest* request,
+ reflection::v1alpha::ServerReflectionResponse* response);
+
+ Status GetAllExtensionNumbers(
+ ServerContext* context, const grpc::string& type,
+ reflection::v1alpha::ExtensionNumberResponse* response);
+
+ void FillFileDescriptorResponse(
+ const protobuf::FileDescriptor* file_desc,
+ reflection::v1alpha::ServerReflectionResponse* response,
+ std::unordered_set<grpc::string>* seen_files);
+
+ void FillErrorResponse(const Status& status,
+ reflection::v1alpha::ErrorResponse* error_response);
+
+ const protobuf::DescriptorPool* descriptor_pool_;
+ const std::vector<string>* services_;
+};
+
+} // namespace grpc
+
+#endif // GRPC_INTERNAL_CPP_EXT_PROTO_SERVER_REFLECTION_H
diff --git a/src/cpp/ext/proto_server_reflection_plugin.cc b/src/cpp/ext/proto_server_reflection_plugin.cc
new file mode 100644
index 0000000000..5b806ce1ae
--- /dev/null
+++ b/src/cpp/ext/proto_server_reflection_plugin.cc
@@ -0,0 +1,97 @@
+/*
+ *
+ * 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 <grpc++/ext/proto_server_reflection_plugin.h>
+#include <grpc++/impl/server_builder_plugin.h>
+#include <grpc++/impl/server_initializer.h>
+#include <grpc++/server.h>
+
+#include "src/cpp/ext/proto_server_reflection.h"
+
+namespace grpc {
+namespace reflection {
+
+ProtoServerReflectionPlugin::ProtoServerReflectionPlugin()
+ : reflection_service_(new grpc::ProtoServerReflection()) {}
+
+grpc::string ProtoServerReflectionPlugin::name() {
+ return "proto_server_reflection";
+}
+
+void ProtoServerReflectionPlugin::InitServer(grpc::ServerInitializer* si) {
+ si->RegisterService(reflection_service_);
+}
+
+void ProtoServerReflectionPlugin::Finish(grpc::ServerInitializer* si) {
+ reflection_service_->SetServiceList(si->GetServiceList());
+}
+
+void ProtoServerReflectionPlugin::ChangeArguments(const grpc::string& name,
+ void* value) {}
+
+bool ProtoServerReflectionPlugin::has_sync_methods() const {
+ if (reflection_service_) {
+ return reflection_service_->has_synchronous_methods();
+ }
+ return false;
+}
+
+bool ProtoServerReflectionPlugin::has_async_methods() const {
+ if (reflection_service_) {
+ return reflection_service_->has_async_methods();
+ }
+ return false;
+}
+
+static std::unique_ptr< ::grpc::ServerBuilderPlugin> CreateProtoReflection() {
+ return std::unique_ptr< ::grpc::ServerBuilderPlugin>(
+ new ProtoServerReflectionPlugin());
+}
+
+void InitProtoReflectionServerBuilderPlugin() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ ::grpc::ServerBuilder::InternalAddPluginFactory(&CreateProtoReflection);
+}
+
+// Force InitProtoReflectionServerBuilderPlugin() to be called at static
+// initialization time.
+struct StaticProtoReflectionPluginInitializer {
+ StaticProtoReflectionPluginInitializer() {
+ InitProtoReflectionServerBuilderPlugin();
+ }
+} static_proto_reflection_plugin_initializer;
+
+} // namespace reflection
+} // namespace grpc
diff --git a/src/cpp/ext/reflection.grpc.pb.cc b/src/cpp/ext/reflection.grpc.pb.cc
new file mode 100644
index 0000000000..b046dfc1b8
--- /dev/null
+++ b/src/cpp/ext/reflection.grpc.pb.cc
@@ -0,0 +1,97 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+// Generated by the gRPC protobuf plugin.
+// If you make any local change, they will be lost.
+// source: reflection.proto
+
+#include <grpc++/ext/reflection.pb.h>
+#include <grpc++/ext/reflection.grpc.pb.h>
+
+#include <grpc++/impl/codegen/async_stream.h>
+#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/client_unary_call.h>
+#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+namespace grpc {
+namespace reflection {
+namespace v1alpha {
+
+static const char* ServerReflection_method_names[] = {
+ "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo",
+};
+
+std::unique_ptr< ServerReflection::Stub> ServerReflection::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
+ std::unique_ptr< ServerReflection::Stub> stub(new ServerReflection::Stub(channel));
+ return stub;
+}
+
+ServerReflection::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)
+ : channel_(channel), rpcmethod_ServerReflectionInfo_(ServerReflection_method_names[0], ::grpc::RpcMethod::BIDI_STREAMING, channel)
+ {}
+
+::grpc::ClientReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* ServerReflection::Stub::ServerReflectionInfoRaw(::grpc::ClientContext* context) {
+ return new ::grpc::ClientReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>(channel_.get(), rpcmethod_ServerReflectionInfo_, context);
+}
+
+::grpc::ClientAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>* ServerReflection::Stub::AsyncServerReflectionInfoRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
+ return new ::grpc::ClientAsyncReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>(channel_.get(), cq, rpcmethod_ServerReflectionInfo_, context, tag);
+}
+
+ServerReflection::Service::Service() {
+ (void)ServerReflection_method_names;
+ AddMethod(new ::grpc::RpcServiceMethod(
+ ServerReflection_method_names[0],
+ ::grpc::RpcMethod::BIDI_STREAMING,
+ new ::grpc::BidiStreamingHandler< ServerReflection::Service, ::grpc::reflection::v1alpha::ServerReflectionRequest, ::grpc::reflection::v1alpha::ServerReflectionResponse>(
+ std::mem_fn(&ServerReflection::Service::ServerReflectionInfo), this)));
+}
+
+ServerReflection::Service::~Service() {
+}
+
+::grpc::Status ServerReflection::Service::ServerReflectionInfo(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< ::grpc::reflection::v1alpha::ServerReflectionResponse, ::grpc::reflection::v1alpha::ServerReflectionRequest>* stream) {
+ (void) context;
+ (void) stream;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+
+} // namespace grpc
+} // namespace reflection
+} // namespace v1alpha
+
diff --git a/src/cpp/ext/reflection.pb.cc b/src/cpp/ext/reflection.pb.cc
new file mode 100644
index 0000000000..b73a65d0a0
--- /dev/null
+++ b/src/cpp/ext/reflection.pb.cc
@@ -0,0 +1,3946 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: reflection.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include <grpc++/ext/reflection.pb.h>
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace grpc {
+namespace reflection {
+namespace v1alpha {
+
+namespace {
+
+const ::google::protobuf::Descriptor* ServerReflectionRequest_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ServerReflectionRequest_reflection_ = NULL;
+struct ServerReflectionRequestOneofInstance {
+ ::google::protobuf::internal::ArenaStringPtr file_by_filename_;
+ ::google::protobuf::internal::ArenaStringPtr file_containing_symbol_;
+ const ::grpc::reflection::v1alpha::ExtensionRequest* file_containing_extension_;
+ ::google::protobuf::internal::ArenaStringPtr all_extension_numbers_of_type_;
+ ::google::protobuf::internal::ArenaStringPtr list_services_;
+}* ServerReflectionRequest_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* ExtensionRequest_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ExtensionRequest_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ServerReflectionResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ServerReflectionResponse_reflection_ = NULL;
+struct ServerReflectionResponseOneofInstance {
+ const ::grpc::reflection::v1alpha::FileDescriptorResponse* file_descriptor_response_;
+ const ::grpc::reflection::v1alpha::ExtensionNumberResponse* all_extension_numbers_response_;
+ const ::grpc::reflection::v1alpha::ListServiceResponse* list_services_response_;
+ const ::grpc::reflection::v1alpha::ErrorResponse* error_response_;
+}* ServerReflectionResponse_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* FileDescriptorResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ FileDescriptorResponse_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ExtensionNumberResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ExtensionNumberResponse_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ListServiceResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ListServiceResponse_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ServiceResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ServiceResponse_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ErrorResponse_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+ ErrorResponse_reflection_ = NULL;
+
+} // namespace
+
+
+void protobuf_AssignDesc_reflection_2eproto() {
+ protobuf_AddDesc_reflection_2eproto();
+ const ::google::protobuf::FileDescriptor* file =
+ ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+ "reflection.proto");
+ GOOGLE_CHECK(file != NULL);
+ ServerReflectionRequest_descriptor_ = file->message_type(0);
+ static const int ServerReflectionRequest_offsets_[7] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionRequest, host_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionRequest_default_oneof_instance_, file_by_filename_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionRequest_default_oneof_instance_, file_containing_symbol_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionRequest_default_oneof_instance_, file_containing_extension_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionRequest_default_oneof_instance_, all_extension_numbers_of_type_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionRequest_default_oneof_instance_, list_services_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionRequest, message_request_),
+ };
+ ServerReflectionRequest_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ServerReflectionRequest_descriptor_,
+ ServerReflectionRequest::default_instance_,
+ ServerReflectionRequest_offsets_,
+ -1,
+ -1,
+ -1,
+ ServerReflectionRequest_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionRequest, _oneof_case_[0]),
+ sizeof(ServerReflectionRequest),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionRequest, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionRequest, _is_default_instance_));
+ ExtensionRequest_descriptor_ = file->message_type(1);
+ static const int ExtensionRequest_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionRequest, containing_type_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionRequest, extension_number_),
+ };
+ ExtensionRequest_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ExtensionRequest_descriptor_,
+ ExtensionRequest::default_instance_,
+ ExtensionRequest_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(ExtensionRequest),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionRequest, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionRequest, _is_default_instance_));
+ ServerReflectionResponse_descriptor_ = file->message_type(2);
+ static const int ServerReflectionResponse_offsets_[7] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, valid_host_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, original_request_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionResponse_default_oneof_instance_, file_descriptor_response_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionResponse_default_oneof_instance_, all_extension_numbers_response_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionResponse_default_oneof_instance_, list_services_response_),
+ PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ServerReflectionResponse_default_oneof_instance_, error_response_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, message_response_),
+ };
+ ServerReflectionResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ServerReflectionResponse_descriptor_,
+ ServerReflectionResponse::default_instance_,
+ ServerReflectionResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ ServerReflectionResponse_default_oneof_instance_,
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, _oneof_case_[0]),
+ sizeof(ServerReflectionResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServerReflectionResponse, _is_default_instance_));
+ FileDescriptorResponse_descriptor_ = file->message_type(3);
+ static const int FileDescriptorResponse_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorResponse, file_descriptor_proto_),
+ };
+ FileDescriptorResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ FileDescriptorResponse_descriptor_,
+ FileDescriptorResponse::default_instance_,
+ FileDescriptorResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(FileDescriptorResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorResponse, _is_default_instance_));
+ ExtensionNumberResponse_descriptor_ = file->message_type(4);
+ static const int ExtensionNumberResponse_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionNumberResponse, base_type_name_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionNumberResponse, extension_number_),
+ };
+ ExtensionNumberResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ExtensionNumberResponse_descriptor_,
+ ExtensionNumberResponse::default_instance_,
+ ExtensionNumberResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(ExtensionNumberResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionNumberResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExtensionNumberResponse, _is_default_instance_));
+ ListServiceResponse_descriptor_ = file->message_type(5);
+ static const int ListServiceResponse_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListServiceResponse, service_),
+ };
+ ListServiceResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ListServiceResponse_descriptor_,
+ ListServiceResponse::default_instance_,
+ ListServiceResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(ListServiceResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListServiceResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ListServiceResponse, _is_default_instance_));
+ ServiceResponse_descriptor_ = file->message_type(6);
+ static const int ServiceResponse_offsets_[1] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceResponse, name_),
+ };
+ ServiceResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ServiceResponse_descriptor_,
+ ServiceResponse::default_instance_,
+ ServiceResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(ServiceResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceResponse, _is_default_instance_));
+ ErrorResponse_descriptor_ = file->message_type(7);
+ static const int ErrorResponse_offsets_[2] = {
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ErrorResponse, error_code_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ErrorResponse, error_message_),
+ };
+ ErrorResponse_reflection_ =
+ ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+ ErrorResponse_descriptor_,
+ ErrorResponse::default_instance_,
+ ErrorResponse_offsets_,
+ -1,
+ -1,
+ -1,
+ sizeof(ErrorResponse),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ErrorResponse, _internal_metadata_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ErrorResponse, _is_default_instance_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+inline void protobuf_AssignDescriptorsOnce() {
+ ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+ &protobuf_AssignDesc_reflection_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ServerReflectionRequest_descriptor_, &ServerReflectionRequest::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ExtensionRequest_descriptor_, &ExtensionRequest::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ServerReflectionResponse_descriptor_, &ServerReflectionResponse::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ FileDescriptorResponse_descriptor_, &FileDescriptorResponse::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ExtensionNumberResponse_descriptor_, &ExtensionNumberResponse::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ListServiceResponse_descriptor_, &ListServiceResponse::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ServiceResponse_descriptor_, &ServiceResponse::default_instance());
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+ ErrorResponse_descriptor_, &ErrorResponse::default_instance());
+}
+
+} // namespace
+
+void protobuf_ShutdownFile_reflection_2eproto() {
+ delete ServerReflectionRequest::default_instance_;
+ delete ServerReflectionRequest_default_oneof_instance_;
+ delete ServerReflectionRequest_reflection_;
+ delete ExtensionRequest::default_instance_;
+ delete ExtensionRequest_reflection_;
+ delete ServerReflectionResponse::default_instance_;
+ delete ServerReflectionResponse_default_oneof_instance_;
+ delete ServerReflectionResponse_reflection_;
+ delete FileDescriptorResponse::default_instance_;
+ delete FileDescriptorResponse_reflection_;
+ delete ExtensionNumberResponse::default_instance_;
+ delete ExtensionNumberResponse_reflection_;
+ delete ListServiceResponse::default_instance_;
+ delete ListServiceResponse_reflection_;
+ delete ServiceResponse::default_instance_;
+ delete ServiceResponse_reflection_;
+ delete ErrorResponse::default_instance_;
+ delete ErrorResponse_reflection_;
+}
+
+void protobuf_AddDesc_reflection_2eproto() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+ "\n\020reflection.proto\022\027grpc.reflection.v1al"
+ "pha\"\212\002\n\027ServerReflectionRequest\022\014\n\004host\030"
+ "\001 \001(\t\022\032\n\020file_by_filename\030\003 \001(\tH\000\022 \n\026fil"
+ "e_containing_symbol\030\004 \001(\tH\000\022N\n\031file_cont"
+ "aining_extension\030\005 \001(\0132).grpc.reflection"
+ ".v1alpha.ExtensionRequestH\000\022\'\n\035all_exten"
+ "sion_numbers_of_type\030\006 \001(\tH\000\022\027\n\rlist_ser"
+ "vices\030\007 \001(\tH\000B\021\n\017message_request\"E\n\020Exte"
+ "nsionRequest\022\027\n\017containing_type\030\001 \001(\t\022\030\n"
+ "\020extension_number\030\002 \001(\005\"\321\003\n\030ServerReflec"
+ "tionResponse\022\022\n\nvalid_host\030\001 \001(\t\022J\n\020orig"
+ "inal_request\030\002 \001(\01320.grpc.reflection.v1a"
+ "lpha.ServerReflectionRequest\022S\n\030file_des"
+ "criptor_response\030\004 \001(\0132/.grpc.reflection"
+ ".v1alpha.FileDescriptorResponseH\000\022Z\n\036all"
+ "_extension_numbers_response\030\005 \001(\01320.grpc"
+ ".reflection.v1alpha.ExtensionNumberRespo"
+ "nseH\000\022N\n\026list_services_response\030\006 \001(\0132,."
+ "grpc.reflection.v1alpha.ListServiceRespo"
+ "nseH\000\022@\n\016error_response\030\007 \001(\0132&.grpc.ref"
+ "lection.v1alpha.ErrorResponseH\000B\022\n\020messa"
+ "ge_response\"7\n\026FileDescriptorResponse\022\035\n"
+ "\025file_descriptor_proto\030\001 \003(\014\"K\n\027Extensio"
+ "nNumberResponse\022\026\n\016base_type_name\030\001 \001(\t\022"
+ "\030\n\020extension_number\030\002 \003(\005\"P\n\023ListService"
+ "Response\0229\n\007service\030\001 \003(\0132(.grpc.reflect"
+ "ion.v1alpha.ServiceResponse\"\037\n\017ServiceRe"
+ "sponse\022\014\n\004name\030\001 \001(\t\":\n\rErrorResponse\022\022\n"
+ "\nerror_code\030\001 \001(\005\022\025\n\rerror_message\030\002 \001(\t"
+ "2\223\001\n\020ServerReflection\022\177\n\024ServerReflectio"
+ "nInfo\0220.grpc.reflection.v1alpha.ServerRe"
+ "flectionRequest\0321.grpc.reflection.v1alph"
+ "a.ServerReflectionResponse(\0010\001b\006proto3", 1318);
+ ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+ "reflection.proto", &protobuf_RegisterTypes);
+ ServerReflectionRequest::default_instance_ = new ServerReflectionRequest();
+ ServerReflectionRequest_default_oneof_instance_ = new ServerReflectionRequestOneofInstance();
+ ExtensionRequest::default_instance_ = new ExtensionRequest();
+ ServerReflectionResponse::default_instance_ = new ServerReflectionResponse();
+ ServerReflectionResponse_default_oneof_instance_ = new ServerReflectionResponseOneofInstance();
+ FileDescriptorResponse::default_instance_ = new FileDescriptorResponse();
+ ExtensionNumberResponse::default_instance_ = new ExtensionNumberResponse();
+ ListServiceResponse::default_instance_ = new ListServiceResponse();
+ ServiceResponse::default_instance_ = new ServiceResponse();
+ ErrorResponse::default_instance_ = new ErrorResponse();
+ ServerReflectionRequest::default_instance_->InitAsDefaultInstance();
+ ExtensionRequest::default_instance_->InitAsDefaultInstance();
+ ServerReflectionResponse::default_instance_->InitAsDefaultInstance();
+ FileDescriptorResponse::default_instance_->InitAsDefaultInstance();
+ ExtensionNumberResponse::default_instance_->InitAsDefaultInstance();
+ ListServiceResponse::default_instance_->InitAsDefaultInstance();
+ ServiceResponse::default_instance_->InitAsDefaultInstance();
+ ErrorResponse::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_reflection_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_reflection_2eproto {
+ StaticDescriptorInitializer_reflection_2eproto() {
+ protobuf_AddDesc_reflection_2eproto();
+ }
+} static_descriptor_initializer_reflection_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;
+static void MergeFromFail(int line) {
+ GOOGLE_CHECK(false) << __FILE__ << ":" << line;
+}
+
+} // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ServerReflectionRequest::kHostFieldNumber;
+const int ServerReflectionRequest::kFileByFilenameFieldNumber;
+const int ServerReflectionRequest::kFileContainingSymbolFieldNumber;
+const int ServerReflectionRequest::kFileContainingExtensionFieldNumber;
+const int ServerReflectionRequest::kAllExtensionNumbersOfTypeFieldNumber;
+const int ServerReflectionRequest::kListServicesFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ServerReflectionRequest::ServerReflectionRequest()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ServerReflectionRequest)
+}
+
+void ServerReflectionRequest::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+ ServerReflectionRequest_default_oneof_instance_->file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ ServerReflectionRequest_default_oneof_instance_->file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ ServerReflectionRequest_default_oneof_instance_->file_containing_extension_ = const_cast< ::grpc::reflection::v1alpha::ExtensionRequest*>(&::grpc::reflection::v1alpha::ExtensionRequest::default_instance());
+ ServerReflectionRequest_default_oneof_instance_->all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ ServerReflectionRequest_default_oneof_instance_->list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+ServerReflectionRequest::ServerReflectionRequest(const ServerReflectionRequest& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ServerReflectionRequest)
+}
+
+void ServerReflectionRequest::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ host_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_message_request();
+}
+
+ServerReflectionRequest::~ServerReflectionRequest() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ServerReflectionRequest)
+ SharedDtor();
+}
+
+void ServerReflectionRequest::SharedDtor() {
+ host_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (has_message_request()) {
+ clear_message_request();
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void ServerReflectionRequest::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ServerReflectionRequest::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ServerReflectionRequest_descriptor_;
+}
+
+const ServerReflectionRequest& ServerReflectionRequest::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ServerReflectionRequest* ServerReflectionRequest::default_instance_ = NULL;
+
+ServerReflectionRequest* ServerReflectionRequest::New(::google::protobuf::Arena* arena) const {
+ ServerReflectionRequest* n = new ServerReflectionRequest;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ServerReflectionRequest::clear_message_request() {
+// @@protoc_insertion_point(one_of_clear_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ switch(message_request_case()) {
+ case kFileByFilename: {
+ message_request_.file_by_filename_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ break;
+ }
+ case kFileContainingSymbol: {
+ message_request_.file_containing_symbol_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ break;
+ }
+ case kFileContainingExtension: {
+ delete message_request_.file_containing_extension_;
+ break;
+ }
+ case kAllExtensionNumbersOfType: {
+ message_request_.all_extension_numbers_of_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ break;
+ }
+ case kListServices: {
+ message_request_.list_services_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ break;
+ }
+ case MESSAGE_REQUEST_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = MESSAGE_REQUEST_NOT_SET;
+}
+
+
+void ServerReflectionRequest::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ host_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_message_request();
+}
+
+bool ServerReflectionRequest::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string host = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_host()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->host().data(), this->host().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.host"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(26)) goto parse_file_by_filename;
+ break;
+ }
+
+ // optional string file_by_filename = 3;
+ case 3: {
+ if (tag == 26) {
+ parse_file_by_filename:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_file_by_filename()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_by_filename().data(), this->file_by_filename().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(34)) goto parse_file_containing_symbol;
+ break;
+ }
+
+ // optional string file_containing_symbol = 4;
+ case 4: {
+ if (tag == 34) {
+ parse_file_containing_symbol:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_file_containing_symbol()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_containing_symbol().data(), this->file_containing_symbol().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(42)) goto parse_file_containing_extension;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionRequest file_containing_extension = 5;
+ case 5: {
+ if (tag == 42) {
+ parse_file_containing_extension:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_file_containing_extension()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(50)) goto parse_all_extension_numbers_of_type;
+ break;
+ }
+
+ // optional string all_extension_numbers_of_type = 6;
+ case 6: {
+ if (tag == 50) {
+ parse_all_extension_numbers_of_type:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_all_extension_numbers_of_type()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->all_extension_numbers_of_type().data(), this->all_extension_numbers_of_type().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(58)) goto parse_list_services;
+ break;
+ }
+
+ // optional string list_services = 7;
+ case 7: {
+ if (tag == 58) {
+ parse_list_services:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_list_services()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->list_services().data(), this->list_services().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.list_services"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ServerReflectionRequest)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ServerReflectionRequest)
+ return false;
+#undef DO_
+}
+
+void ServerReflectionRequest::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ // optional string host = 1;
+ if (this->host().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->host().data(), this->host().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.host");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->host(), output);
+ }
+
+ // optional string file_by_filename = 3;
+ if (has_file_by_filename()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_by_filename().data(), this->file_by_filename().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 3, this->file_by_filename(), output);
+ }
+
+ // optional string file_containing_symbol = 4;
+ if (has_file_containing_symbol()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_containing_symbol().data(), this->file_containing_symbol().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 4, this->file_containing_symbol(), output);
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionRequest file_containing_extension = 5;
+ if (has_file_containing_extension()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 5, *message_request_.file_containing_extension_, output);
+ }
+
+ // optional string all_extension_numbers_of_type = 6;
+ if (has_all_extension_numbers_of_type()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->all_extension_numbers_of_type().data(), this->all_extension_numbers_of_type().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 6, this->all_extension_numbers_of_type(), output);
+ }
+
+ // optional string list_services = 7;
+ if (has_list_services()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->list_services().data(), this->list_services().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.list_services");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 7, this->list_services(), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ServerReflectionRequest)
+}
+
+::google::protobuf::uint8* ServerReflectionRequest::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ // optional string host = 1;
+ if (this->host().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->host().data(), this->host().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.host");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->host(), target);
+ }
+
+ // optional string file_by_filename = 3;
+ if (has_file_by_filename()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_by_filename().data(), this->file_by_filename().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 3, this->file_by_filename(), target);
+ }
+
+ // optional string file_containing_symbol = 4;
+ if (has_file_containing_symbol()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->file_containing_symbol().data(), this->file_containing_symbol().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 4, this->file_containing_symbol(), target);
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionRequest file_containing_extension = 5;
+ if (has_file_containing_extension()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 5, *message_request_.file_containing_extension_, target);
+ }
+
+ // optional string all_extension_numbers_of_type = 6;
+ if (has_all_extension_numbers_of_type()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->all_extension_numbers_of_type().data(), this->all_extension_numbers_of_type().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 6, this->all_extension_numbers_of_type(), target);
+ }
+
+ // optional string list_services = 7;
+ if (has_list_services()) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->list_services().data(), this->list_services().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionRequest.list_services");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 7, this->list_services(), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ServerReflectionRequest)
+ return target;
+}
+
+int ServerReflectionRequest::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ int total_size = 0;
+
+ // optional string host = 1;
+ if (this->host().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->host());
+ }
+
+ switch (message_request_case()) {
+ // optional string file_by_filename = 3;
+ case kFileByFilename: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->file_by_filename());
+ break;
+ }
+ // optional string file_containing_symbol = 4;
+ case kFileContainingSymbol: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->file_containing_symbol());
+ break;
+ }
+ // optional .grpc.reflection.v1alpha.ExtensionRequest file_containing_extension = 5;
+ case kFileContainingExtension: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *message_request_.file_containing_extension_);
+ break;
+ }
+ // optional string all_extension_numbers_of_type = 6;
+ case kAllExtensionNumbersOfType: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->all_extension_numbers_of_type());
+ break;
+ }
+ // optional string list_services = 7;
+ case kListServices: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->list_services());
+ break;
+ }
+ case MESSAGE_REQUEST_NOT_SET: {
+ break;
+ }
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ServerReflectionRequest::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ServerReflectionRequest* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ServerReflectionRequest>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ServerReflectionRequest)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ServerReflectionRequest)
+ MergeFrom(*source);
+ }
+}
+
+void ServerReflectionRequest::MergeFrom(const ServerReflectionRequest& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ switch (from.message_request_case()) {
+ case kFileByFilename: {
+ set_file_by_filename(from.file_by_filename());
+ break;
+ }
+ case kFileContainingSymbol: {
+ set_file_containing_symbol(from.file_containing_symbol());
+ break;
+ }
+ case kFileContainingExtension: {
+ mutable_file_containing_extension()->::grpc::reflection::v1alpha::ExtensionRequest::MergeFrom(from.file_containing_extension());
+ break;
+ }
+ case kAllExtensionNumbersOfType: {
+ set_all_extension_numbers_of_type(from.all_extension_numbers_of_type());
+ break;
+ }
+ case kListServices: {
+ set_list_services(from.list_services());
+ break;
+ }
+ case MESSAGE_REQUEST_NOT_SET: {
+ break;
+ }
+ }
+ if (from.host().size() > 0) {
+
+ host_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.host_);
+ }
+}
+
+void ServerReflectionRequest::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ServerReflectionRequest::CopyFrom(const ServerReflectionRequest& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ServerReflectionRequest)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ServerReflectionRequest::IsInitialized() const {
+
+ return true;
+}
+
+void ServerReflectionRequest::Swap(ServerReflectionRequest* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ServerReflectionRequest::InternalSwap(ServerReflectionRequest* other) {
+ host_.Swap(&other->host_);
+ std::swap(message_request_, other->message_request_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ServerReflectionRequest::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ServerReflectionRequest_descriptor_;
+ metadata.reflection = ServerReflectionRequest_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServerReflectionRequest
+
+// optional string host = 1;
+void ServerReflectionRequest::clear_host() {
+ host_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ServerReflectionRequest::host() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+ return host_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServerReflectionRequest::set_host(const ::std::string& value) {
+
+ host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+}
+ void ServerReflectionRequest::set_host(const char* value) {
+
+ host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+}
+ void ServerReflectionRequest::set_host(const char* value, size_t size) {
+
+ host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+}
+ ::std::string* ServerReflectionRequest::mutable_host() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+ return host_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionRequest::release_host() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+
+ return host_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServerReflectionRequest::set_allocated_host(::std::string* host) {
+ if (host != NULL) {
+
+ } else {
+
+ }
+ host_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), host);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.host)
+}
+
+// optional string file_by_filename = 3;
+bool ServerReflectionRequest::has_file_by_filename() const {
+ return message_request_case() == kFileByFilename;
+}
+void ServerReflectionRequest::set_has_file_by_filename() {
+ _oneof_case_[0] = kFileByFilename;
+}
+void ServerReflectionRequest::clear_file_by_filename() {
+ if (has_file_by_filename()) {
+ message_request_.file_by_filename_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_message_request();
+ }
+}
+ const ::std::string& ServerReflectionRequest::file_by_filename() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+ if (has_file_by_filename()) {
+ return message_request_.file_by_filename_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+ void ServerReflectionRequest::set_file_by_filename(const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+ if (!has_file_by_filename()) {
+ clear_message_request();
+ set_has_file_by_filename();
+ message_request_.file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_by_filename_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+}
+ void ServerReflectionRequest::set_file_by_filename(const char* value) {
+ if (!has_file_by_filename()) {
+ clear_message_request();
+ set_has_file_by_filename();
+ message_request_.file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_by_filename_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+}
+ void ServerReflectionRequest::set_file_by_filename(const char* value, size_t size) {
+ if (!has_file_by_filename()) {
+ clear_message_request();
+ set_has_file_by_filename();
+ message_request_.file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_by_filename_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+}
+ ::std::string* ServerReflectionRequest::mutable_file_by_filename() {
+ if (!has_file_by_filename()) {
+ clear_message_request();
+ set_has_file_by_filename();
+ message_request_.file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+ return message_request_.file_by_filename_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionRequest::release_file_by_filename() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+ if (has_file_by_filename()) {
+ clear_has_message_request();
+ return message_request_.file_by_filename_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ } else {
+ return NULL;
+ }
+}
+ void ServerReflectionRequest::set_allocated_file_by_filename(::std::string* file_by_filename) {
+ if (!has_file_by_filename()) {
+ message_request_.file_by_filename_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ clear_message_request();
+ if (file_by_filename != NULL) {
+ set_has_file_by_filename();
+ message_request_.file_by_filename_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ file_by_filename);
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.file_by_filename)
+}
+
+// optional string file_containing_symbol = 4;
+bool ServerReflectionRequest::has_file_containing_symbol() const {
+ return message_request_case() == kFileContainingSymbol;
+}
+void ServerReflectionRequest::set_has_file_containing_symbol() {
+ _oneof_case_[0] = kFileContainingSymbol;
+}
+void ServerReflectionRequest::clear_file_containing_symbol() {
+ if (has_file_containing_symbol()) {
+ message_request_.file_containing_symbol_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_message_request();
+ }
+}
+ const ::std::string& ServerReflectionRequest::file_containing_symbol() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+ if (has_file_containing_symbol()) {
+ return message_request_.file_containing_symbol_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+ void ServerReflectionRequest::set_file_containing_symbol(const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+ if (!has_file_containing_symbol()) {
+ clear_message_request();
+ set_has_file_containing_symbol();
+ message_request_.file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_containing_symbol_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+}
+ void ServerReflectionRequest::set_file_containing_symbol(const char* value) {
+ if (!has_file_containing_symbol()) {
+ clear_message_request();
+ set_has_file_containing_symbol();
+ message_request_.file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_containing_symbol_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+}
+ void ServerReflectionRequest::set_file_containing_symbol(const char* value, size_t size) {
+ if (!has_file_containing_symbol()) {
+ clear_message_request();
+ set_has_file_containing_symbol();
+ message_request_.file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.file_containing_symbol_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+}
+ ::std::string* ServerReflectionRequest::mutable_file_containing_symbol() {
+ if (!has_file_containing_symbol()) {
+ clear_message_request();
+ set_has_file_containing_symbol();
+ message_request_.file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+ return message_request_.file_containing_symbol_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionRequest::release_file_containing_symbol() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+ if (has_file_containing_symbol()) {
+ clear_has_message_request();
+ return message_request_.file_containing_symbol_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ } else {
+ return NULL;
+ }
+}
+ void ServerReflectionRequest::set_allocated_file_containing_symbol(::std::string* file_containing_symbol) {
+ if (!has_file_containing_symbol()) {
+ message_request_.file_containing_symbol_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ clear_message_request();
+ if (file_containing_symbol != NULL) {
+ set_has_file_containing_symbol();
+ message_request_.file_containing_symbol_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ file_containing_symbol);
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_symbol)
+}
+
+// optional .grpc.reflection.v1alpha.ExtensionRequest file_containing_extension = 5;
+bool ServerReflectionRequest::has_file_containing_extension() const {
+ return message_request_case() == kFileContainingExtension;
+}
+void ServerReflectionRequest::set_has_file_containing_extension() {
+ _oneof_case_[0] = kFileContainingExtension;
+}
+void ServerReflectionRequest::clear_file_containing_extension() {
+ if (has_file_containing_extension()) {
+ delete message_request_.file_containing_extension_;
+ clear_has_message_request();
+ }
+}
+ const ::grpc::reflection::v1alpha::ExtensionRequest& ServerReflectionRequest::file_containing_extension() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_extension)
+ return has_file_containing_extension()
+ ? *message_request_.file_containing_extension_
+ : ::grpc::reflection::v1alpha::ExtensionRequest::default_instance();
+}
+::grpc::reflection::v1alpha::ExtensionRequest* ServerReflectionRequest::mutable_file_containing_extension() {
+ if (!has_file_containing_extension()) {
+ clear_message_request();
+ set_has_file_containing_extension();
+ message_request_.file_containing_extension_ = new ::grpc::reflection::v1alpha::ExtensionRequest;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_extension)
+ return message_request_.file_containing_extension_;
+}
+::grpc::reflection::v1alpha::ExtensionRequest* ServerReflectionRequest::release_file_containing_extension() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_extension)
+ if (has_file_containing_extension()) {
+ clear_has_message_request();
+ ::grpc::reflection::v1alpha::ExtensionRequest* temp = message_request_.file_containing_extension_;
+ message_request_.file_containing_extension_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+void ServerReflectionRequest::set_allocated_file_containing_extension(::grpc::reflection::v1alpha::ExtensionRequest* file_containing_extension) {
+ clear_message_request();
+ if (file_containing_extension) {
+ set_has_file_containing_extension();
+ message_request_.file_containing_extension_ = file_containing_extension;
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.file_containing_extension)
+}
+
+// optional string all_extension_numbers_of_type = 6;
+bool ServerReflectionRequest::has_all_extension_numbers_of_type() const {
+ return message_request_case() == kAllExtensionNumbersOfType;
+}
+void ServerReflectionRequest::set_has_all_extension_numbers_of_type() {
+ _oneof_case_[0] = kAllExtensionNumbersOfType;
+}
+void ServerReflectionRequest::clear_all_extension_numbers_of_type() {
+ if (has_all_extension_numbers_of_type()) {
+ message_request_.all_extension_numbers_of_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_message_request();
+ }
+}
+ const ::std::string& ServerReflectionRequest::all_extension_numbers_of_type() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+ if (has_all_extension_numbers_of_type()) {
+ return message_request_.all_extension_numbers_of_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+ void ServerReflectionRequest::set_all_extension_numbers_of_type(const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+ if (!has_all_extension_numbers_of_type()) {
+ clear_message_request();
+ set_has_all_extension_numbers_of_type();
+ message_request_.all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.all_extension_numbers_of_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+}
+ void ServerReflectionRequest::set_all_extension_numbers_of_type(const char* value) {
+ if (!has_all_extension_numbers_of_type()) {
+ clear_message_request();
+ set_has_all_extension_numbers_of_type();
+ message_request_.all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.all_extension_numbers_of_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+}
+ void ServerReflectionRequest::set_all_extension_numbers_of_type(const char* value, size_t size) {
+ if (!has_all_extension_numbers_of_type()) {
+ clear_message_request();
+ set_has_all_extension_numbers_of_type();
+ message_request_.all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.all_extension_numbers_of_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+}
+ ::std::string* ServerReflectionRequest::mutable_all_extension_numbers_of_type() {
+ if (!has_all_extension_numbers_of_type()) {
+ clear_message_request();
+ set_has_all_extension_numbers_of_type();
+ message_request_.all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+ return message_request_.all_extension_numbers_of_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionRequest::release_all_extension_numbers_of_type() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+ if (has_all_extension_numbers_of_type()) {
+ clear_has_message_request();
+ return message_request_.all_extension_numbers_of_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ } else {
+ return NULL;
+ }
+}
+ void ServerReflectionRequest::set_allocated_all_extension_numbers_of_type(::std::string* all_extension_numbers_of_type) {
+ if (!has_all_extension_numbers_of_type()) {
+ message_request_.all_extension_numbers_of_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ clear_message_request();
+ if (all_extension_numbers_of_type != NULL) {
+ set_has_all_extension_numbers_of_type();
+ message_request_.all_extension_numbers_of_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ all_extension_numbers_of_type);
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.all_extension_numbers_of_type)
+}
+
+// optional string list_services = 7;
+bool ServerReflectionRequest::has_list_services() const {
+ return message_request_case() == kListServices;
+}
+void ServerReflectionRequest::set_has_list_services() {
+ _oneof_case_[0] = kListServices;
+}
+void ServerReflectionRequest::clear_list_services() {
+ if (has_list_services()) {
+ message_request_.list_services_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ clear_has_message_request();
+ }
+}
+ const ::std::string& ServerReflectionRequest::list_services() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+ if (has_list_services()) {
+ return message_request_.list_services_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+ void ServerReflectionRequest::set_list_services(const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+ if (!has_list_services()) {
+ clear_message_request();
+ set_has_list_services();
+ message_request_.list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.list_services_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+}
+ void ServerReflectionRequest::set_list_services(const char* value) {
+ if (!has_list_services()) {
+ clear_message_request();
+ set_has_list_services();
+ message_request_.list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.list_services_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+}
+ void ServerReflectionRequest::set_list_services(const char* value, size_t size) {
+ if (!has_list_services()) {
+ clear_message_request();
+ set_has_list_services();
+ message_request_.list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ message_request_.list_services_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+ reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+}
+ ::std::string* ServerReflectionRequest::mutable_list_services() {
+ if (!has_list_services()) {
+ clear_message_request();
+ set_has_list_services();
+ message_request_.list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+ return message_request_.list_services_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionRequest::release_list_services() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+ if (has_list_services()) {
+ clear_has_message_request();
+ return message_request_.list_services_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ } else {
+ return NULL;
+ }
+}
+ void ServerReflectionRequest::set_allocated_list_services(::std::string* list_services) {
+ if (!has_list_services()) {
+ message_request_.list_services_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ }
+ clear_message_request();
+ if (list_services != NULL) {
+ set_has_list_services();
+ message_request_.list_services_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ list_services);
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionRequest.list_services)
+}
+
+bool ServerReflectionRequest::has_message_request() const {
+ return message_request_case() != MESSAGE_REQUEST_NOT_SET;
+}
+void ServerReflectionRequest::clear_has_message_request() {
+ _oneof_case_[0] = MESSAGE_REQUEST_NOT_SET;
+}
+ServerReflectionRequest::MessageRequestCase ServerReflectionRequest::message_request_case() const {
+ return ServerReflectionRequest::MessageRequestCase(_oneof_case_[0]);
+}
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ExtensionRequest::kContainingTypeFieldNumber;
+const int ExtensionRequest::kExtensionNumberFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ExtensionRequest::ExtensionRequest()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ExtensionRequest)
+}
+
+void ExtensionRequest::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+ExtensionRequest::ExtensionRequest(const ExtensionRequest& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ExtensionRequest)
+}
+
+void ExtensionRequest::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ containing_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ extension_number_ = 0;
+}
+
+ExtensionRequest::~ExtensionRequest() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ExtensionRequest)
+ SharedDtor();
+}
+
+void ExtensionRequest::SharedDtor() {
+ containing_type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (this != default_instance_) {
+ }
+}
+
+void ExtensionRequest::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ExtensionRequest::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ExtensionRequest_descriptor_;
+}
+
+const ExtensionRequest& ExtensionRequest::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ExtensionRequest* ExtensionRequest::default_instance_ = NULL;
+
+ExtensionRequest* ExtensionRequest::New(::google::protobuf::Arena* arena) const {
+ ExtensionRequest* n = new ExtensionRequest;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ExtensionRequest::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ExtensionRequest)
+ containing_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ extension_number_ = 0;
+}
+
+bool ExtensionRequest::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ExtensionRequest)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string containing_type = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_containing_type()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->containing_type().data(), this->containing_type().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ExtensionRequest.containing_type"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(16)) goto parse_extension_number;
+ break;
+ }
+
+ // optional int32 extension_number = 2;
+ case 2: {
+ if (tag == 16) {
+ parse_extension_number:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &extension_number_)));
+
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ExtensionRequest)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ExtensionRequest)
+ return false;
+#undef DO_
+}
+
+void ExtensionRequest::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ExtensionRequest)
+ // optional string containing_type = 1;
+ if (this->containing_type().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->containing_type().data(), this->containing_type().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ExtensionRequest.containing_type");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->containing_type(), output);
+ }
+
+ // optional int32 extension_number = 2;
+ if (this->extension_number() != 0) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->extension_number(), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ExtensionRequest)
+}
+
+::google::protobuf::uint8* ExtensionRequest::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ExtensionRequest)
+ // optional string containing_type = 1;
+ if (this->containing_type().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->containing_type().data(), this->containing_type().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ExtensionRequest.containing_type");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->containing_type(), target);
+ }
+
+ // optional int32 extension_number = 2;
+ if (this->extension_number() != 0) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->extension_number(), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ExtensionRequest)
+ return target;
+}
+
+int ExtensionRequest::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ExtensionRequest)
+ int total_size = 0;
+
+ // optional string containing_type = 1;
+ if (this->containing_type().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->containing_type());
+ }
+
+ // optional int32 extension_number = 2;
+ if (this->extension_number() != 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->extension_number());
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ExtensionRequest::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ExtensionRequest)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ExtensionRequest* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ExtensionRequest>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ExtensionRequest)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ExtensionRequest)
+ MergeFrom(*source);
+ }
+}
+
+void ExtensionRequest::MergeFrom(const ExtensionRequest& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ExtensionRequest)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ if (from.containing_type().size() > 0) {
+
+ containing_type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.containing_type_);
+ }
+ if (from.extension_number() != 0) {
+ set_extension_number(from.extension_number());
+ }
+}
+
+void ExtensionRequest::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ExtensionRequest)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ExtensionRequest::CopyFrom(const ExtensionRequest& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ExtensionRequest)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ExtensionRequest::IsInitialized() const {
+
+ return true;
+}
+
+void ExtensionRequest::Swap(ExtensionRequest* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ExtensionRequest::InternalSwap(ExtensionRequest* other) {
+ containing_type_.Swap(&other->containing_type_);
+ std::swap(extension_number_, other->extension_number_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ExtensionRequest::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ExtensionRequest_descriptor_;
+ metadata.reflection = ExtensionRequest_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ExtensionRequest
+
+// optional string containing_type = 1;
+void ExtensionRequest::clear_containing_type() {
+ containing_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ExtensionRequest::containing_type() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+ return containing_type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ExtensionRequest::set_containing_type(const ::std::string& value) {
+
+ containing_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+}
+ void ExtensionRequest::set_containing_type(const char* value) {
+
+ containing_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+}
+ void ExtensionRequest::set_containing_type(const char* value, size_t size) {
+
+ containing_type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+}
+ ::std::string* ExtensionRequest::mutable_containing_type() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+ return containing_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ExtensionRequest::release_containing_type() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+
+ return containing_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ExtensionRequest::set_allocated_containing_type(::std::string* containing_type) {
+ if (containing_type != NULL) {
+
+ } else {
+
+ }
+ containing_type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), containing_type);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ExtensionRequest.containing_type)
+}
+
+// optional int32 extension_number = 2;
+void ExtensionRequest::clear_extension_number() {
+ extension_number_ = 0;
+}
+ ::google::protobuf::int32 ExtensionRequest::extension_number() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ExtensionRequest.extension_number)
+ return extension_number_;
+}
+ void ExtensionRequest::set_extension_number(::google::protobuf::int32 value) {
+
+ extension_number_ = value;
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ExtensionRequest.extension_number)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ServerReflectionResponse::kValidHostFieldNumber;
+const int ServerReflectionResponse::kOriginalRequestFieldNumber;
+const int ServerReflectionResponse::kFileDescriptorResponseFieldNumber;
+const int ServerReflectionResponse::kAllExtensionNumbersResponseFieldNumber;
+const int ServerReflectionResponse::kListServicesResponseFieldNumber;
+const int ServerReflectionResponse::kErrorResponseFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ServerReflectionResponse::ServerReflectionResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ServerReflectionResponse)
+}
+
+void ServerReflectionResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+ original_request_ = const_cast< ::grpc::reflection::v1alpha::ServerReflectionRequest*>(&::grpc::reflection::v1alpha::ServerReflectionRequest::default_instance());
+ ServerReflectionResponse_default_oneof_instance_->file_descriptor_response_ = const_cast< ::grpc::reflection::v1alpha::FileDescriptorResponse*>(&::grpc::reflection::v1alpha::FileDescriptorResponse::default_instance());
+ ServerReflectionResponse_default_oneof_instance_->all_extension_numbers_response_ = const_cast< ::grpc::reflection::v1alpha::ExtensionNumberResponse*>(&::grpc::reflection::v1alpha::ExtensionNumberResponse::default_instance());
+ ServerReflectionResponse_default_oneof_instance_->list_services_response_ = const_cast< ::grpc::reflection::v1alpha::ListServiceResponse*>(&::grpc::reflection::v1alpha::ListServiceResponse::default_instance());
+ ServerReflectionResponse_default_oneof_instance_->error_response_ = const_cast< ::grpc::reflection::v1alpha::ErrorResponse*>(&::grpc::reflection::v1alpha::ErrorResponse::default_instance());
+}
+
+ServerReflectionResponse::ServerReflectionResponse(const ServerReflectionResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ServerReflectionResponse)
+}
+
+void ServerReflectionResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ valid_host_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ original_request_ = NULL;
+ clear_has_message_response();
+}
+
+ServerReflectionResponse::~ServerReflectionResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ServerReflectionResponse)
+ SharedDtor();
+}
+
+void ServerReflectionResponse::SharedDtor() {
+ valid_host_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (has_message_response()) {
+ clear_message_response();
+ }
+ if (this != default_instance_) {
+ delete original_request_;
+ }
+}
+
+void ServerReflectionResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ServerReflectionResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ServerReflectionResponse_descriptor_;
+}
+
+const ServerReflectionResponse& ServerReflectionResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ServerReflectionResponse* ServerReflectionResponse::default_instance_ = NULL;
+
+ServerReflectionResponse* ServerReflectionResponse::New(::google::protobuf::Arena* arena) const {
+ ServerReflectionResponse* n = new ServerReflectionResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ServerReflectionResponse::clear_message_response() {
+// @@protoc_insertion_point(one_of_clear_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ switch(message_response_case()) {
+ case kFileDescriptorResponse: {
+ delete message_response_.file_descriptor_response_;
+ break;
+ }
+ case kAllExtensionNumbersResponse: {
+ delete message_response_.all_extension_numbers_response_;
+ break;
+ }
+ case kListServicesResponse: {
+ delete message_response_.list_services_response_;
+ break;
+ }
+ case kErrorResponse: {
+ delete message_response_.error_response_;
+ break;
+ }
+ case MESSAGE_RESPONSE_NOT_SET: {
+ break;
+ }
+ }
+ _oneof_case_[0] = MESSAGE_RESPONSE_NOT_SET;
+}
+
+
+void ServerReflectionResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ valid_host_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (GetArenaNoVirtual() == NULL && original_request_ != NULL) delete original_request_;
+ original_request_ = NULL;
+ clear_message_response();
+}
+
+bool ServerReflectionResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string valid_host = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_valid_host()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->valid_host().data(), this->valid_host().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServerReflectionResponse.valid_host"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_original_request;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.ServerReflectionRequest original_request = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_original_request:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_original_request()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(34)) goto parse_file_descriptor_response;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.FileDescriptorResponse file_descriptor_response = 4;
+ case 4: {
+ if (tag == 34) {
+ parse_file_descriptor_response:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_file_descriptor_response()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(42)) goto parse_all_extension_numbers_response;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionNumberResponse all_extension_numbers_response = 5;
+ case 5: {
+ if (tag == 42) {
+ parse_all_extension_numbers_response:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_all_extension_numbers_response()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(50)) goto parse_list_services_response;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.ListServiceResponse list_services_response = 6;
+ case 6: {
+ if (tag == 50) {
+ parse_list_services_response:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_list_services_response()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(58)) goto parse_error_response;
+ break;
+ }
+
+ // optional .grpc.reflection.v1alpha.ErrorResponse error_response = 7;
+ case 7: {
+ if (tag == 58) {
+ parse_error_response:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+ input, mutable_error_response()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ServerReflectionResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ServerReflectionResponse)
+ return false;
+#undef DO_
+}
+
+void ServerReflectionResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ // optional string valid_host = 1;
+ if (this->valid_host().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->valid_host().data(), this->valid_host().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionResponse.valid_host");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->valid_host(), output);
+ }
+
+ // optional .grpc.reflection.v1alpha.ServerReflectionRequest original_request = 2;
+ if (this->has_original_request()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 2, *this->original_request_, output);
+ }
+
+ // optional .grpc.reflection.v1alpha.FileDescriptorResponse file_descriptor_response = 4;
+ if (has_file_descriptor_response()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 4, *message_response_.file_descriptor_response_, output);
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionNumberResponse all_extension_numbers_response = 5;
+ if (has_all_extension_numbers_response()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 5, *message_response_.all_extension_numbers_response_, output);
+ }
+
+ // optional .grpc.reflection.v1alpha.ListServiceResponse list_services_response = 6;
+ if (has_list_services_response()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 6, *message_response_.list_services_response_, output);
+ }
+
+ // optional .grpc.reflection.v1alpha.ErrorResponse error_response = 7;
+ if (has_error_response()) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 7, *message_response_.error_response_, output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ServerReflectionResponse)
+}
+
+::google::protobuf::uint8* ServerReflectionResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ // optional string valid_host = 1;
+ if (this->valid_host().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->valid_host().data(), this->valid_host().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServerReflectionResponse.valid_host");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->valid_host(), target);
+ }
+
+ // optional .grpc.reflection.v1alpha.ServerReflectionRequest original_request = 2;
+ if (this->has_original_request()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 2, *this->original_request_, target);
+ }
+
+ // optional .grpc.reflection.v1alpha.FileDescriptorResponse file_descriptor_response = 4;
+ if (has_file_descriptor_response()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 4, *message_response_.file_descriptor_response_, target);
+ }
+
+ // optional .grpc.reflection.v1alpha.ExtensionNumberResponse all_extension_numbers_response = 5;
+ if (has_all_extension_numbers_response()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 5, *message_response_.all_extension_numbers_response_, target);
+ }
+
+ // optional .grpc.reflection.v1alpha.ListServiceResponse list_services_response = 6;
+ if (has_list_services_response()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 6, *message_response_.list_services_response_, target);
+ }
+
+ // optional .grpc.reflection.v1alpha.ErrorResponse error_response = 7;
+ if (has_error_response()) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 7, *message_response_.error_response_, target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ServerReflectionResponse)
+ return target;
+}
+
+int ServerReflectionResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ int total_size = 0;
+
+ // optional string valid_host = 1;
+ if (this->valid_host().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->valid_host());
+ }
+
+ // optional .grpc.reflection.v1alpha.ServerReflectionRequest original_request = 2;
+ if (this->has_original_request()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *this->original_request_);
+ }
+
+ switch (message_response_case()) {
+ // optional .grpc.reflection.v1alpha.FileDescriptorResponse file_descriptor_response = 4;
+ case kFileDescriptorResponse: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *message_response_.file_descriptor_response_);
+ break;
+ }
+ // optional .grpc.reflection.v1alpha.ExtensionNumberResponse all_extension_numbers_response = 5;
+ case kAllExtensionNumbersResponse: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *message_response_.all_extension_numbers_response_);
+ break;
+ }
+ // optional .grpc.reflection.v1alpha.ListServiceResponse list_services_response = 6;
+ case kListServicesResponse: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *message_response_.list_services_response_);
+ break;
+ }
+ // optional .grpc.reflection.v1alpha.ErrorResponse error_response = 7;
+ case kErrorResponse: {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ *message_response_.error_response_);
+ break;
+ }
+ case MESSAGE_RESPONSE_NOT_SET: {
+ break;
+ }
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ServerReflectionResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ServerReflectionResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ServerReflectionResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ServerReflectionResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ServerReflectionResponse)
+ MergeFrom(*source);
+ }
+}
+
+void ServerReflectionResponse::MergeFrom(const ServerReflectionResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ switch (from.message_response_case()) {
+ case kFileDescriptorResponse: {
+ mutable_file_descriptor_response()->::grpc::reflection::v1alpha::FileDescriptorResponse::MergeFrom(from.file_descriptor_response());
+ break;
+ }
+ case kAllExtensionNumbersResponse: {
+ mutable_all_extension_numbers_response()->::grpc::reflection::v1alpha::ExtensionNumberResponse::MergeFrom(from.all_extension_numbers_response());
+ break;
+ }
+ case kListServicesResponse: {
+ mutable_list_services_response()->::grpc::reflection::v1alpha::ListServiceResponse::MergeFrom(from.list_services_response());
+ break;
+ }
+ case kErrorResponse: {
+ mutable_error_response()->::grpc::reflection::v1alpha::ErrorResponse::MergeFrom(from.error_response());
+ break;
+ }
+ case MESSAGE_RESPONSE_NOT_SET: {
+ break;
+ }
+ }
+ if (from.valid_host().size() > 0) {
+
+ valid_host_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.valid_host_);
+ }
+ if (from.has_original_request()) {
+ mutable_original_request()->::grpc::reflection::v1alpha::ServerReflectionRequest::MergeFrom(from.original_request());
+ }
+}
+
+void ServerReflectionResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ServerReflectionResponse::CopyFrom(const ServerReflectionResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ServerReflectionResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ServerReflectionResponse::IsInitialized() const {
+
+ return true;
+}
+
+void ServerReflectionResponse::Swap(ServerReflectionResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ServerReflectionResponse::InternalSwap(ServerReflectionResponse* other) {
+ valid_host_.Swap(&other->valid_host_);
+ std::swap(original_request_, other->original_request_);
+ std::swap(message_response_, other->message_response_);
+ std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ServerReflectionResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ServerReflectionResponse_descriptor_;
+ metadata.reflection = ServerReflectionResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServerReflectionResponse
+
+// optional string valid_host = 1;
+void ServerReflectionResponse::clear_valid_host() {
+ valid_host_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ServerReflectionResponse::valid_host() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+ return valid_host_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServerReflectionResponse::set_valid_host(const ::std::string& value) {
+
+ valid_host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+}
+ void ServerReflectionResponse::set_valid_host(const char* value) {
+
+ valid_host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+}
+ void ServerReflectionResponse::set_valid_host(const char* value, size_t size) {
+
+ valid_host_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+}
+ ::std::string* ServerReflectionResponse::mutable_valid_host() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+ return valid_host_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServerReflectionResponse::release_valid_host() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+
+ return valid_host_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServerReflectionResponse::set_allocated_valid_host(::std::string* valid_host) {
+ if (valid_host != NULL) {
+
+ } else {
+
+ }
+ valid_host_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), valid_host);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.valid_host)
+}
+
+// optional .grpc.reflection.v1alpha.ServerReflectionRequest original_request = 2;
+bool ServerReflectionResponse::has_original_request() const {
+ return !_is_default_instance_ && original_request_ != NULL;
+}
+void ServerReflectionResponse::clear_original_request() {
+ if (GetArenaNoVirtual() == NULL && original_request_ != NULL) delete original_request_;
+ original_request_ = NULL;
+}
+const ::grpc::reflection::v1alpha::ServerReflectionRequest& ServerReflectionResponse::original_request() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.original_request)
+ return original_request_ != NULL ? *original_request_ : *default_instance_->original_request_;
+}
+::grpc::reflection::v1alpha::ServerReflectionRequest* ServerReflectionResponse::mutable_original_request() {
+
+ if (original_request_ == NULL) {
+ original_request_ = new ::grpc::reflection::v1alpha::ServerReflectionRequest;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.original_request)
+ return original_request_;
+}
+::grpc::reflection::v1alpha::ServerReflectionRequest* ServerReflectionResponse::release_original_request() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.original_request)
+
+ ::grpc::reflection::v1alpha::ServerReflectionRequest* temp = original_request_;
+ original_request_ = NULL;
+ return temp;
+}
+void ServerReflectionResponse::set_allocated_original_request(::grpc::reflection::v1alpha::ServerReflectionRequest* original_request) {
+ delete original_request_;
+ original_request_ = original_request;
+ if (original_request) {
+
+ } else {
+
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.original_request)
+}
+
+// optional .grpc.reflection.v1alpha.FileDescriptorResponse file_descriptor_response = 4;
+bool ServerReflectionResponse::has_file_descriptor_response() const {
+ return message_response_case() == kFileDescriptorResponse;
+}
+void ServerReflectionResponse::set_has_file_descriptor_response() {
+ _oneof_case_[0] = kFileDescriptorResponse;
+}
+void ServerReflectionResponse::clear_file_descriptor_response() {
+ if (has_file_descriptor_response()) {
+ delete message_response_.file_descriptor_response_;
+ clear_has_message_response();
+ }
+}
+ const ::grpc::reflection::v1alpha::FileDescriptorResponse& ServerReflectionResponse::file_descriptor_response() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.file_descriptor_response)
+ return has_file_descriptor_response()
+ ? *message_response_.file_descriptor_response_
+ : ::grpc::reflection::v1alpha::FileDescriptorResponse::default_instance();
+}
+::grpc::reflection::v1alpha::FileDescriptorResponse* ServerReflectionResponse::mutable_file_descriptor_response() {
+ if (!has_file_descriptor_response()) {
+ clear_message_response();
+ set_has_file_descriptor_response();
+ message_response_.file_descriptor_response_ = new ::grpc::reflection::v1alpha::FileDescriptorResponse;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.file_descriptor_response)
+ return message_response_.file_descriptor_response_;
+}
+::grpc::reflection::v1alpha::FileDescriptorResponse* ServerReflectionResponse::release_file_descriptor_response() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.file_descriptor_response)
+ if (has_file_descriptor_response()) {
+ clear_has_message_response();
+ ::grpc::reflection::v1alpha::FileDescriptorResponse* temp = message_response_.file_descriptor_response_;
+ message_response_.file_descriptor_response_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+void ServerReflectionResponse::set_allocated_file_descriptor_response(::grpc::reflection::v1alpha::FileDescriptorResponse* file_descriptor_response) {
+ clear_message_response();
+ if (file_descriptor_response) {
+ set_has_file_descriptor_response();
+ message_response_.file_descriptor_response_ = file_descriptor_response;
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.file_descriptor_response)
+}
+
+// optional .grpc.reflection.v1alpha.ExtensionNumberResponse all_extension_numbers_response = 5;
+bool ServerReflectionResponse::has_all_extension_numbers_response() const {
+ return message_response_case() == kAllExtensionNumbersResponse;
+}
+void ServerReflectionResponse::set_has_all_extension_numbers_response() {
+ _oneof_case_[0] = kAllExtensionNumbersResponse;
+}
+void ServerReflectionResponse::clear_all_extension_numbers_response() {
+ if (has_all_extension_numbers_response()) {
+ delete message_response_.all_extension_numbers_response_;
+ clear_has_message_response();
+ }
+}
+ const ::grpc::reflection::v1alpha::ExtensionNumberResponse& ServerReflectionResponse::all_extension_numbers_response() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.all_extension_numbers_response)
+ return has_all_extension_numbers_response()
+ ? *message_response_.all_extension_numbers_response_
+ : ::grpc::reflection::v1alpha::ExtensionNumberResponse::default_instance();
+}
+::grpc::reflection::v1alpha::ExtensionNumberResponse* ServerReflectionResponse::mutable_all_extension_numbers_response() {
+ if (!has_all_extension_numbers_response()) {
+ clear_message_response();
+ set_has_all_extension_numbers_response();
+ message_response_.all_extension_numbers_response_ = new ::grpc::reflection::v1alpha::ExtensionNumberResponse;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.all_extension_numbers_response)
+ return message_response_.all_extension_numbers_response_;
+}
+::grpc::reflection::v1alpha::ExtensionNumberResponse* ServerReflectionResponse::release_all_extension_numbers_response() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.all_extension_numbers_response)
+ if (has_all_extension_numbers_response()) {
+ clear_has_message_response();
+ ::grpc::reflection::v1alpha::ExtensionNumberResponse* temp = message_response_.all_extension_numbers_response_;
+ message_response_.all_extension_numbers_response_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+void ServerReflectionResponse::set_allocated_all_extension_numbers_response(::grpc::reflection::v1alpha::ExtensionNumberResponse* all_extension_numbers_response) {
+ clear_message_response();
+ if (all_extension_numbers_response) {
+ set_has_all_extension_numbers_response();
+ message_response_.all_extension_numbers_response_ = all_extension_numbers_response;
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.all_extension_numbers_response)
+}
+
+// optional .grpc.reflection.v1alpha.ListServiceResponse list_services_response = 6;
+bool ServerReflectionResponse::has_list_services_response() const {
+ return message_response_case() == kListServicesResponse;
+}
+void ServerReflectionResponse::set_has_list_services_response() {
+ _oneof_case_[0] = kListServicesResponse;
+}
+void ServerReflectionResponse::clear_list_services_response() {
+ if (has_list_services_response()) {
+ delete message_response_.list_services_response_;
+ clear_has_message_response();
+ }
+}
+ const ::grpc::reflection::v1alpha::ListServiceResponse& ServerReflectionResponse::list_services_response() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.list_services_response)
+ return has_list_services_response()
+ ? *message_response_.list_services_response_
+ : ::grpc::reflection::v1alpha::ListServiceResponse::default_instance();
+}
+::grpc::reflection::v1alpha::ListServiceResponse* ServerReflectionResponse::mutable_list_services_response() {
+ if (!has_list_services_response()) {
+ clear_message_response();
+ set_has_list_services_response();
+ message_response_.list_services_response_ = new ::grpc::reflection::v1alpha::ListServiceResponse;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.list_services_response)
+ return message_response_.list_services_response_;
+}
+::grpc::reflection::v1alpha::ListServiceResponse* ServerReflectionResponse::release_list_services_response() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.list_services_response)
+ if (has_list_services_response()) {
+ clear_has_message_response();
+ ::grpc::reflection::v1alpha::ListServiceResponse* temp = message_response_.list_services_response_;
+ message_response_.list_services_response_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+void ServerReflectionResponse::set_allocated_list_services_response(::grpc::reflection::v1alpha::ListServiceResponse* list_services_response) {
+ clear_message_response();
+ if (list_services_response) {
+ set_has_list_services_response();
+ message_response_.list_services_response_ = list_services_response;
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.list_services_response)
+}
+
+// optional .grpc.reflection.v1alpha.ErrorResponse error_response = 7;
+bool ServerReflectionResponse::has_error_response() const {
+ return message_response_case() == kErrorResponse;
+}
+void ServerReflectionResponse::set_has_error_response() {
+ _oneof_case_[0] = kErrorResponse;
+}
+void ServerReflectionResponse::clear_error_response() {
+ if (has_error_response()) {
+ delete message_response_.error_response_;
+ clear_has_message_response();
+ }
+}
+ const ::grpc::reflection::v1alpha::ErrorResponse& ServerReflectionResponse::error_response() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServerReflectionResponse.error_response)
+ return has_error_response()
+ ? *message_response_.error_response_
+ : ::grpc::reflection::v1alpha::ErrorResponse::default_instance();
+}
+::grpc::reflection::v1alpha::ErrorResponse* ServerReflectionResponse::mutable_error_response() {
+ if (!has_error_response()) {
+ clear_message_response();
+ set_has_error_response();
+ message_response_.error_response_ = new ::grpc::reflection::v1alpha::ErrorResponse;
+ }
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServerReflectionResponse.error_response)
+ return message_response_.error_response_;
+}
+::grpc::reflection::v1alpha::ErrorResponse* ServerReflectionResponse::release_error_response() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServerReflectionResponse.error_response)
+ if (has_error_response()) {
+ clear_has_message_response();
+ ::grpc::reflection::v1alpha::ErrorResponse* temp = message_response_.error_response_;
+ message_response_.error_response_ = NULL;
+ return temp;
+ } else {
+ return NULL;
+ }
+}
+void ServerReflectionResponse::set_allocated_error_response(::grpc::reflection::v1alpha::ErrorResponse* error_response) {
+ clear_message_response();
+ if (error_response) {
+ set_has_error_response();
+ message_response_.error_response_ = error_response;
+ }
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServerReflectionResponse.error_response)
+}
+
+bool ServerReflectionResponse::has_message_response() const {
+ return message_response_case() != MESSAGE_RESPONSE_NOT_SET;
+}
+void ServerReflectionResponse::clear_has_message_response() {
+ _oneof_case_[0] = MESSAGE_RESPONSE_NOT_SET;
+}
+ServerReflectionResponse::MessageResponseCase ServerReflectionResponse::message_response_case() const {
+ return ServerReflectionResponse::MessageResponseCase(_oneof_case_[0]);
+}
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FileDescriptorResponse::kFileDescriptorProtoFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FileDescriptorResponse::FileDescriptorResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.FileDescriptorResponse)
+}
+
+void FileDescriptorResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+FileDescriptorResponse::FileDescriptorResponse(const FileDescriptorResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.FileDescriptorResponse)
+}
+
+void FileDescriptorResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+}
+
+FileDescriptorResponse::~FileDescriptorResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.FileDescriptorResponse)
+ SharedDtor();
+}
+
+void FileDescriptorResponse::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void FileDescriptorResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FileDescriptorResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return FileDescriptorResponse_descriptor_;
+}
+
+const FileDescriptorResponse& FileDescriptorResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+FileDescriptorResponse* FileDescriptorResponse::default_instance_ = NULL;
+
+FileDescriptorResponse* FileDescriptorResponse::New(::google::protobuf::Arena* arena) const {
+ FileDescriptorResponse* n = new FileDescriptorResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void FileDescriptorResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ file_descriptor_proto_.Clear();
+}
+
+bool FileDescriptorResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // repeated bytes file_descriptor_proto = 1;
+ case 1: {
+ if (tag == 10) {
+ parse_file_descriptor_proto:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+ input, this->add_file_descriptor_proto()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(10)) goto parse_file_descriptor_proto;
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.FileDescriptorResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.FileDescriptorResponse)
+ return false;
+#undef DO_
+}
+
+void FileDescriptorResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ // repeated bytes file_descriptor_proto = 1;
+ for (int i = 0; i < this->file_descriptor_proto_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteBytes(
+ 1, this->file_descriptor_proto(i), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.FileDescriptorResponse)
+}
+
+::google::protobuf::uint8* FileDescriptorResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ // repeated bytes file_descriptor_proto = 1;
+ for (int i = 0; i < this->file_descriptor_proto_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteBytesToArray(1, this->file_descriptor_proto(i), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.FileDescriptorResponse)
+ return target;
+}
+
+int FileDescriptorResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ int total_size = 0;
+
+ // repeated bytes file_descriptor_proto = 1;
+ total_size += 1 * this->file_descriptor_proto_size();
+ for (int i = 0; i < this->file_descriptor_proto_size(); i++) {
+ total_size += ::google::protobuf::internal::WireFormatLite::BytesSize(
+ this->file_descriptor_proto(i));
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void FileDescriptorResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const FileDescriptorResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const FileDescriptorResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.FileDescriptorResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.FileDescriptorResponse)
+ MergeFrom(*source);
+ }
+}
+
+void FileDescriptorResponse::MergeFrom(const FileDescriptorResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ file_descriptor_proto_.MergeFrom(from.file_descriptor_proto_);
+}
+
+void FileDescriptorResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void FileDescriptorResponse::CopyFrom(const FileDescriptorResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.FileDescriptorResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool FileDescriptorResponse::IsInitialized() const {
+
+ return true;
+}
+
+void FileDescriptorResponse::Swap(FileDescriptorResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void FileDescriptorResponse::InternalSwap(FileDescriptorResponse* other) {
+ file_descriptor_proto_.UnsafeArenaSwap(&other->file_descriptor_proto_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FileDescriptorResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = FileDescriptorResponse_descriptor_;
+ metadata.reflection = FileDescriptorResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FileDescriptorResponse
+
+// repeated bytes file_descriptor_proto = 1;
+int FileDescriptorResponse::file_descriptor_proto_size() const {
+ return file_descriptor_proto_.size();
+}
+void FileDescriptorResponse::clear_file_descriptor_proto() {
+ file_descriptor_proto_.Clear();
+}
+ const ::std::string& FileDescriptorResponse::file_descriptor_proto(int index) const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ return file_descriptor_proto_.Get(index);
+}
+ ::std::string* FileDescriptorResponse::mutable_file_descriptor_proto(int index) {
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ return file_descriptor_proto_.Mutable(index);
+}
+ void FileDescriptorResponse::set_file_descriptor_proto(int index, const ::std::string& value) {
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ file_descriptor_proto_.Mutable(index)->assign(value);
+}
+ void FileDescriptorResponse::set_file_descriptor_proto(int index, const char* value) {
+ file_descriptor_proto_.Mutable(index)->assign(value);
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+}
+ void FileDescriptorResponse::set_file_descriptor_proto(int index, const void* value, size_t size) {
+ file_descriptor_proto_.Mutable(index)->assign(
+ reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+}
+ ::std::string* FileDescriptorResponse::add_file_descriptor_proto() {
+ // @@protoc_insertion_point(field_add_mutable:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ return file_descriptor_proto_.Add();
+}
+ void FileDescriptorResponse::add_file_descriptor_proto(const ::std::string& value) {
+ file_descriptor_proto_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+}
+ void FileDescriptorResponse::add_file_descriptor_proto(const char* value) {
+ file_descriptor_proto_.Add()->assign(value);
+ // @@protoc_insertion_point(field_add_char:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+}
+ void FileDescriptorResponse::add_file_descriptor_proto(const void* value, size_t size) {
+ file_descriptor_proto_.Add()->assign(reinterpret_cast<const char*>(value), size);
+ // @@protoc_insertion_point(field_add_pointer:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+}
+ const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FileDescriptorResponse::file_descriptor_proto() const {
+ // @@protoc_insertion_point(field_list:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ return file_descriptor_proto_;
+}
+ ::google::protobuf::RepeatedPtrField< ::std::string>*
+FileDescriptorResponse::mutable_file_descriptor_proto() {
+ // @@protoc_insertion_point(field_mutable_list:grpc.reflection.v1alpha.FileDescriptorResponse.file_descriptor_proto)
+ return &file_descriptor_proto_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ExtensionNumberResponse::kBaseTypeNameFieldNumber;
+const int ExtensionNumberResponse::kExtensionNumberFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ExtensionNumberResponse::ExtensionNumberResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ExtensionNumberResponse)
+}
+
+void ExtensionNumberResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+ExtensionNumberResponse::ExtensionNumberResponse(const ExtensionNumberResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ExtensionNumberResponse)
+}
+
+void ExtensionNumberResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ base_type_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+ExtensionNumberResponse::~ExtensionNumberResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ SharedDtor();
+}
+
+void ExtensionNumberResponse::SharedDtor() {
+ base_type_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (this != default_instance_) {
+ }
+}
+
+void ExtensionNumberResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ExtensionNumberResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ExtensionNumberResponse_descriptor_;
+}
+
+const ExtensionNumberResponse& ExtensionNumberResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ExtensionNumberResponse* ExtensionNumberResponse::default_instance_ = NULL;
+
+ExtensionNumberResponse* ExtensionNumberResponse::New(::google::protobuf::Arena* arena) const {
+ ExtensionNumberResponse* n = new ExtensionNumberResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ExtensionNumberResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ base_type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ extension_number_.Clear();
+}
+
+bool ExtensionNumberResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string base_type_name = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_base_type_name()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->base_type_name().data(), this->base_type_name().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_extension_number;
+ break;
+ }
+
+ // repeated int32 extension_number = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_extension_number:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, this->mutable_extension_number())));
+ } else if (tag == 16) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ 1, 18, input, this->mutable_extension_number())));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ return false;
+#undef DO_
+}
+
+void ExtensionNumberResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ // optional string base_type_name = 1;
+ if (this->base_type_name().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->base_type_name().data(), this->base_type_name().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->base_type_name(), output);
+ }
+
+ // repeated int32 extension_number = 2;
+ if (this->extension_number_size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::WriteTag(2, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+ output->WriteVarint32(_extension_number_cached_byte_size_);
+ }
+ for (int i = 0; i < this->extension_number_size(); i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+ this->extension_number(i), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ExtensionNumberResponse)
+}
+
+::google::protobuf::uint8* ExtensionNumberResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ // optional string base_type_name = 1;
+ if (this->base_type_name().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->base_type_name().data(), this->base_type_name().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->base_type_name(), target);
+ }
+
+ // repeated int32 extension_number = 2;
+ if (this->extension_number_size() > 0) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+ 2,
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+ target);
+ target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+ _extension_number_cached_byte_size_, target);
+ }
+ for (int i = 0; i < this->extension_number_size(); i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteInt32NoTagToArray(this->extension_number(i), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ return target;
+}
+
+int ExtensionNumberResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ int total_size = 0;
+
+ // optional string base_type_name = 1;
+ if (this->base_type_name().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->base_type_name());
+ }
+
+ // repeated int32 extension_number = 2;
+ {
+ int data_size = 0;
+ for (int i = 0; i < this->extension_number_size(); i++) {
+ data_size += ::google::protobuf::internal::WireFormatLite::
+ Int32Size(this->extension_number(i));
+ }
+ if (data_size > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _extension_number_cached_byte_size_ = data_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ total_size += data_size;
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ExtensionNumberResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ExtensionNumberResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ExtensionNumberResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ MergeFrom(*source);
+ }
+}
+
+void ExtensionNumberResponse::MergeFrom(const ExtensionNumberResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ extension_number_.MergeFrom(from.extension_number_);
+ if (from.base_type_name().size() > 0) {
+
+ base_type_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.base_type_name_);
+ }
+}
+
+void ExtensionNumberResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ExtensionNumberResponse::CopyFrom(const ExtensionNumberResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ExtensionNumberResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ExtensionNumberResponse::IsInitialized() const {
+
+ return true;
+}
+
+void ExtensionNumberResponse::Swap(ExtensionNumberResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ExtensionNumberResponse::InternalSwap(ExtensionNumberResponse* other) {
+ base_type_name_.Swap(&other->base_type_name_);
+ extension_number_.UnsafeArenaSwap(&other->extension_number_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ExtensionNumberResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ExtensionNumberResponse_descriptor_;
+ metadata.reflection = ExtensionNumberResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ExtensionNumberResponse
+
+// optional string base_type_name = 1;
+void ExtensionNumberResponse::clear_base_type_name() {
+ base_type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ExtensionNumberResponse::base_type_name() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+ return base_type_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ExtensionNumberResponse::set_base_type_name(const ::std::string& value) {
+
+ base_type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+}
+ void ExtensionNumberResponse::set_base_type_name(const char* value) {
+
+ base_type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+}
+ void ExtensionNumberResponse::set_base_type_name(const char* value, size_t size) {
+
+ base_type_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+}
+ ::std::string* ExtensionNumberResponse::mutable_base_type_name() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+ return base_type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ExtensionNumberResponse::release_base_type_name() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+
+ return base_type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ExtensionNumberResponse::set_allocated_base_type_name(::std::string* base_type_name) {
+ if (base_type_name != NULL) {
+
+ } else {
+
+ }
+ base_type_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), base_type_name);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ExtensionNumberResponse.base_type_name)
+}
+
+// repeated int32 extension_number = 2;
+int ExtensionNumberResponse::extension_number_size() const {
+ return extension_number_.size();
+}
+void ExtensionNumberResponse::clear_extension_number() {
+ extension_number_.Clear();
+}
+ ::google::protobuf::int32 ExtensionNumberResponse::extension_number(int index) const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ExtensionNumberResponse.extension_number)
+ return extension_number_.Get(index);
+}
+ void ExtensionNumberResponse::set_extension_number(int index, ::google::protobuf::int32 value) {
+ extension_number_.Set(index, value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ExtensionNumberResponse.extension_number)
+}
+ void ExtensionNumberResponse::add_extension_number(::google::protobuf::int32 value) {
+ extension_number_.Add(value);
+ // @@protoc_insertion_point(field_add:grpc.reflection.v1alpha.ExtensionNumberResponse.extension_number)
+}
+ const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+ExtensionNumberResponse::extension_number() const {
+ // @@protoc_insertion_point(field_list:grpc.reflection.v1alpha.ExtensionNumberResponse.extension_number)
+ return extension_number_;
+}
+ ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+ExtensionNumberResponse::mutable_extension_number() {
+ // @@protoc_insertion_point(field_mutable_list:grpc.reflection.v1alpha.ExtensionNumberResponse.extension_number)
+ return &extension_number_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ListServiceResponse::kServiceFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ListServiceResponse::ListServiceResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ListServiceResponse)
+}
+
+void ListServiceResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+ListServiceResponse::ListServiceResponse(const ListServiceResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ListServiceResponse)
+}
+
+void ListServiceResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ _cached_size_ = 0;
+}
+
+ListServiceResponse::~ListServiceResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ListServiceResponse)
+ SharedDtor();
+}
+
+void ListServiceResponse::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void ListServiceResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ListServiceResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ListServiceResponse_descriptor_;
+}
+
+const ListServiceResponse& ListServiceResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ListServiceResponse* ListServiceResponse::default_instance_ = NULL;
+
+ListServiceResponse* ListServiceResponse::New(::google::protobuf::Arena* arena) const {
+ ListServiceResponse* n = new ListServiceResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ListServiceResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ListServiceResponse)
+ service_.Clear();
+}
+
+bool ListServiceResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ListServiceResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // repeated .grpc.reflection.v1alpha.ServiceResponse service = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(input->IncrementRecursionDepth());
+ parse_loop_service:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+ input, add_service()));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(10)) goto parse_loop_service;
+ input->UnsafeDecrementRecursionDepth();
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ListServiceResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ListServiceResponse)
+ return false;
+#undef DO_
+}
+
+void ListServiceResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ListServiceResponse)
+ // repeated .grpc.reflection.v1alpha.ServiceResponse service = 1;
+ for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
+ ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+ 1, this->service(i), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ListServiceResponse)
+}
+
+::google::protobuf::uint8* ListServiceResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ListServiceResponse)
+ // repeated .grpc.reflection.v1alpha.ServiceResponse service = 1;
+ for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
+ target = ::google::protobuf::internal::WireFormatLite::
+ WriteMessageNoVirtualToArray(
+ 1, this->service(i), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ListServiceResponse)
+ return target;
+}
+
+int ListServiceResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ListServiceResponse)
+ int total_size = 0;
+
+ // repeated .grpc.reflection.v1alpha.ServiceResponse service = 1;
+ total_size += 1 * this->service_size();
+ for (int i = 0; i < this->service_size(); i++) {
+ total_size +=
+ ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+ this->service(i));
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ListServiceResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ListServiceResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ListServiceResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ListServiceResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ListServiceResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ListServiceResponse)
+ MergeFrom(*source);
+ }
+}
+
+void ListServiceResponse::MergeFrom(const ListServiceResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ListServiceResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ service_.MergeFrom(from.service_);
+}
+
+void ListServiceResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ListServiceResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ListServiceResponse::CopyFrom(const ListServiceResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ListServiceResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ListServiceResponse::IsInitialized() const {
+
+ return true;
+}
+
+void ListServiceResponse::Swap(ListServiceResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ListServiceResponse::InternalSwap(ListServiceResponse* other) {
+ service_.UnsafeArenaSwap(&other->service_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ListServiceResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ListServiceResponse_descriptor_;
+ metadata.reflection = ListServiceResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ListServiceResponse
+
+// repeated .grpc.reflection.v1alpha.ServiceResponse service = 1;
+int ListServiceResponse::service_size() const {
+ return service_.size();
+}
+void ListServiceResponse::clear_service() {
+ service_.Clear();
+}
+const ::grpc::reflection::v1alpha::ServiceResponse& ListServiceResponse::service(int index) const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ListServiceResponse.service)
+ return service_.Get(index);
+}
+::grpc::reflection::v1alpha::ServiceResponse* ListServiceResponse::mutable_service(int index) {
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ListServiceResponse.service)
+ return service_.Mutable(index);
+}
+::grpc::reflection::v1alpha::ServiceResponse* ListServiceResponse::add_service() {
+ // @@protoc_insertion_point(field_add:grpc.reflection.v1alpha.ListServiceResponse.service)
+ return service_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::grpc::reflection::v1alpha::ServiceResponse >*
+ListServiceResponse::mutable_service() {
+ // @@protoc_insertion_point(field_mutable_list:grpc.reflection.v1alpha.ListServiceResponse.service)
+ return &service_;
+}
+const ::google::protobuf::RepeatedPtrField< ::grpc::reflection::v1alpha::ServiceResponse >&
+ListServiceResponse::service() const {
+ // @@protoc_insertion_point(field_list:grpc.reflection.v1alpha.ListServiceResponse.service)
+ return service_;
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ServiceResponse::kNameFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ServiceResponse::ServiceResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ServiceResponse)
+}
+
+void ServiceResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+ServiceResponse::ServiceResponse(const ServiceResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ServiceResponse)
+}
+
+void ServiceResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+ServiceResponse::~ServiceResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ServiceResponse)
+ SharedDtor();
+}
+
+void ServiceResponse::SharedDtor() {
+ name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (this != default_instance_) {
+ }
+}
+
+void ServiceResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ServiceResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ServiceResponse_descriptor_;
+}
+
+const ServiceResponse& ServiceResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ServiceResponse* ServiceResponse::default_instance_ = NULL;
+
+ServiceResponse* ServiceResponse::New(::google::protobuf::Arena* arena) const {
+ ServiceResponse* n = new ServiceResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ServiceResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ServiceResponse)
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool ServiceResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ServiceResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string name = 1;
+ case 1: {
+ if (tag == 10) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_name()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ServiceResponse.name"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ServiceResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ServiceResponse)
+ return false;
+#undef DO_
+}
+
+void ServiceResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ServiceResponse)
+ // optional string name = 1;
+ if (this->name().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServiceResponse.name");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 1, this->name(), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ServiceResponse)
+}
+
+::google::protobuf::uint8* ServiceResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ServiceResponse)
+ // optional string name = 1;
+ if (this->name().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->name().data(), this->name().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ServiceResponse.name");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 1, this->name(), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ServiceResponse)
+ return target;
+}
+
+int ServiceResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ServiceResponse)
+ int total_size = 0;
+
+ // optional string name = 1;
+ if (this->name().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->name());
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ServiceResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ServiceResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ServiceResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ServiceResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ServiceResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ServiceResponse)
+ MergeFrom(*source);
+ }
+}
+
+void ServiceResponse::MergeFrom(const ServiceResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ServiceResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ if (from.name().size() > 0) {
+
+ name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+ }
+}
+
+void ServiceResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ServiceResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ServiceResponse::CopyFrom(const ServiceResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ServiceResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ServiceResponse::IsInitialized() const {
+
+ return true;
+}
+
+void ServiceResponse::Swap(ServiceResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ServiceResponse::InternalSwap(ServiceResponse* other) {
+ name_.Swap(&other->name_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ServiceResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ServiceResponse_descriptor_;
+ metadata.reflection = ServiceResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ServiceResponse
+
+// optional string name = 1;
+void ServiceResponse::clear_name() {
+ name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ServiceResponse::name() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ServiceResponse.name)
+ return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceResponse::set_name(const ::std::string& value) {
+
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ServiceResponse.name)
+}
+ void ServiceResponse::set_name(const char* value) {
+
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ServiceResponse.name)
+}
+ void ServiceResponse::set_name(const char* value, size_t size) {
+
+ name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ServiceResponse.name)
+}
+ ::std::string* ServiceResponse::mutable_name() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ServiceResponse.name)
+ return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ServiceResponse::release_name() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ServiceResponse.name)
+
+ return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ServiceResponse::set_allocated_name(::std::string* name) {
+ if (name != NULL) {
+
+ } else {
+
+ }
+ name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ServiceResponse.name)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ErrorResponse::kErrorCodeFieldNumber;
+const int ErrorResponse::kErrorMessageFieldNumber;
+#endif // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ErrorResponse::ErrorResponse()
+ : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+ SharedCtor();
+ // @@protoc_insertion_point(constructor:grpc.reflection.v1alpha.ErrorResponse)
+}
+
+void ErrorResponse::InitAsDefaultInstance() {
+ _is_default_instance_ = true;
+}
+
+ErrorResponse::ErrorResponse(const ErrorResponse& from)
+ : ::google::protobuf::Message(),
+ _internal_metadata_(NULL) {
+ SharedCtor();
+ MergeFrom(from);
+ // @@protoc_insertion_point(copy_constructor:grpc.reflection.v1alpha.ErrorResponse)
+}
+
+void ErrorResponse::SharedCtor() {
+ _is_default_instance_ = false;
+ ::google::protobuf::internal::GetEmptyString();
+ _cached_size_ = 0;
+ error_code_ = 0;
+ error_message_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+ErrorResponse::~ErrorResponse() {
+ // @@protoc_insertion_point(destructor:grpc.reflection.v1alpha.ErrorResponse)
+ SharedDtor();
+}
+
+void ErrorResponse::SharedDtor() {
+ error_message_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+ if (this != default_instance_) {
+ }
+}
+
+void ErrorResponse::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ErrorResponse::descriptor() {
+ protobuf_AssignDescriptorsOnce();
+ return ErrorResponse_descriptor_;
+}
+
+const ErrorResponse& ErrorResponse::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_reflection_2eproto();
+ return *default_instance_;
+}
+
+ErrorResponse* ErrorResponse::default_instance_ = NULL;
+
+ErrorResponse* ErrorResponse::New(::google::protobuf::Arena* arena) const {
+ ErrorResponse* n = new ErrorResponse;
+ if (arena != NULL) {
+ arena->Own(n);
+ }
+ return n;
+}
+
+void ErrorResponse::Clear() {
+// @@protoc_insertion_point(message_clear_start:grpc.reflection.v1alpha.ErrorResponse)
+ error_code_ = 0;
+ error_message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+bool ErrorResponse::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+ ::google::protobuf::uint32 tag;
+ // @@protoc_insertion_point(parse_start:grpc.reflection.v1alpha.ErrorResponse)
+ for (;;) {
+ ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+ tag = p.first;
+ if (!p.second) goto handle_unusual;
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional int32 error_code = 1;
+ case 1: {
+ if (tag == 8) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &error_code_)));
+
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectTag(18)) goto parse_error_message;
+ break;
+ }
+
+ // optional string error_message = 2;
+ case 2: {
+ if (tag == 18) {
+ parse_error_message:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_error_message()));
+ DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->error_message().data(), this->error_message().length(),
+ ::google::protobuf::internal::WireFormatLite::PARSE,
+ "grpc.reflection.v1alpha.ErrorResponse.error_message"));
+ } else {
+ goto handle_unusual;
+ }
+ if (input->ExpectAtEnd()) goto success;
+ break;
+ }
+
+ default: {
+ handle_unusual:
+ if (tag == 0 ||
+ ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ goto success;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+success:
+ // @@protoc_insertion_point(parse_success:grpc.reflection.v1alpha.ErrorResponse)
+ return true;
+failure:
+ // @@protoc_insertion_point(parse_failure:grpc.reflection.v1alpha.ErrorResponse)
+ return false;
+#undef DO_
+}
+
+void ErrorResponse::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // @@protoc_insertion_point(serialize_start:grpc.reflection.v1alpha.ErrorResponse)
+ // optional int32 error_code = 1;
+ if (this->error_code() != 0) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->error_code(), output);
+ }
+
+ // optional string error_message = 2;
+ if (this->error_message().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->error_message().data(), this->error_message().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ErrorResponse.error_message");
+ ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+ 2, this->error_message(), output);
+ }
+
+ // @@protoc_insertion_point(serialize_end:grpc.reflection.v1alpha.ErrorResponse)
+}
+
+::google::protobuf::uint8* ErrorResponse::SerializeWithCachedSizesToArray(
+ ::google::protobuf::uint8* target) const {
+ // @@protoc_insertion_point(serialize_to_array_start:grpc.reflection.v1alpha.ErrorResponse)
+ // optional int32 error_code = 1;
+ if (this->error_code() != 0) {
+ target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->error_code(), target);
+ }
+
+ // optional string error_message = 2;
+ if (this->error_message().size() > 0) {
+ ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+ this->error_message().data(), this->error_message().length(),
+ ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+ "grpc.reflection.v1alpha.ErrorResponse.error_message");
+ target =
+ ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+ 2, this->error_message(), target);
+ }
+
+ // @@protoc_insertion_point(serialize_to_array_end:grpc.reflection.v1alpha.ErrorResponse)
+ return target;
+}
+
+int ErrorResponse::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:grpc.reflection.v1alpha.ErrorResponse)
+ int total_size = 0;
+
+ // optional int32 error_code = 1;
+ if (this->error_code() != 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->error_code());
+ }
+
+ // optional string error_message = 2;
+ if (this->error_message().size() > 0) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->error_message());
+ }
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void ErrorResponse::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:grpc.reflection.v1alpha.ErrorResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ const ErrorResponse* source =
+ ::google::protobuf::internal::DynamicCastToGenerated<const ErrorResponse>(
+ &from);
+ if (source == NULL) {
+ // @@protoc_insertion_point(generalized_merge_from_cast_fail:grpc.reflection.v1alpha.ErrorResponse)
+ ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+ } else {
+ // @@protoc_insertion_point(generalized_merge_from_cast_success:grpc.reflection.v1alpha.ErrorResponse)
+ MergeFrom(*source);
+ }
+}
+
+void ErrorResponse::MergeFrom(const ErrorResponse& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:grpc.reflection.v1alpha.ErrorResponse)
+ if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+ if (from.error_code() != 0) {
+ set_error_code(from.error_code());
+ }
+ if (from.error_message().size() > 0) {
+
+ error_message_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.error_message_);
+ }
+}
+
+void ErrorResponse::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:grpc.reflection.v1alpha.ErrorResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+void ErrorResponse::CopyFrom(const ErrorResponse& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:grpc.reflection.v1alpha.ErrorResponse)
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool ErrorResponse::IsInitialized() const {
+
+ return true;
+}
+
+void ErrorResponse::Swap(ErrorResponse* other) {
+ if (other == this) return;
+ InternalSwap(other);
+}
+void ErrorResponse::InternalSwap(ErrorResponse* other) {
+ std::swap(error_code_, other->error_code_);
+ error_message_.Swap(&other->error_message_);
+ _internal_metadata_.Swap(&other->_internal_metadata_);
+ std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ErrorResponse::GetMetadata() const {
+ protobuf_AssignDescriptorsOnce();
+ ::google::protobuf::Metadata metadata;
+ metadata.descriptor = ErrorResponse_descriptor_;
+ metadata.reflection = ErrorResponse_reflection_;
+ return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ErrorResponse
+
+// optional int32 error_code = 1;
+void ErrorResponse::clear_error_code() {
+ error_code_ = 0;
+}
+ ::google::protobuf::int32 ErrorResponse::error_code() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ErrorResponse.error_code)
+ return error_code_;
+}
+ void ErrorResponse::set_error_code(::google::protobuf::int32 value) {
+
+ error_code_ = value;
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ErrorResponse.error_code)
+}
+
+// optional string error_message = 2;
+void ErrorResponse::clear_error_message() {
+ error_message_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ const ::std::string& ErrorResponse::error_message() const {
+ // @@protoc_insertion_point(field_get:grpc.reflection.v1alpha.ErrorResponse.error_message)
+ return error_message_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ErrorResponse::set_error_message(const ::std::string& value) {
+
+ error_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+ // @@protoc_insertion_point(field_set:grpc.reflection.v1alpha.ErrorResponse.error_message)
+}
+ void ErrorResponse::set_error_message(const char* value) {
+
+ error_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+ // @@protoc_insertion_point(field_set_char:grpc.reflection.v1alpha.ErrorResponse.error_message)
+}
+ void ErrorResponse::set_error_message(const char* value, size_t size) {
+
+ error_message_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+ ::std::string(reinterpret_cast<const char*>(value), size));
+ // @@protoc_insertion_point(field_set_pointer:grpc.reflection.v1alpha.ErrorResponse.error_message)
+}
+ ::std::string* ErrorResponse::mutable_error_message() {
+
+ // @@protoc_insertion_point(field_mutable:grpc.reflection.v1alpha.ErrorResponse.error_message)
+ return error_message_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ ::std::string* ErrorResponse::release_error_message() {
+ // @@protoc_insertion_point(field_release:grpc.reflection.v1alpha.ErrorResponse.error_message)
+
+ return error_message_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+ void ErrorResponse::set_allocated_error_message(::std::string* error_message) {
+ if (error_message != NULL) {
+
+ } else {
+
+ }
+ error_message_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error_message);
+ // @@protoc_insertion_point(field_set_allocated:grpc.reflection.v1alpha.ErrorResponse.error_message)
+}
+
+#endif // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+} // namespace v1alpha
+} // namespace reflection
+} // namespace grpc
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index f6c3e5747c..fb4c68ebe4 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -67,7 +67,7 @@ static std::shared_ptr<Server::GlobalCallbacks> g_callbacks = nullptr;
static gpr_once g_once_init_callbacks = GPR_ONCE_INIT;
static void InitGlobalCallbacks() {
- if (g_callbacks == nullptr) {
+ if (!g_callbacks) {
g_callbacks.reset(new DefaultGlobalCallbacks());
}
}
@@ -324,11 +324,15 @@ Server::~Server() {
}
void Server::SetGlobalCallbacks(GlobalCallbacks* callbacks) {
- GPR_ASSERT(g_callbacks == nullptr);
- GPR_ASSERT(callbacks != nullptr);
+ GPR_ASSERT(!g_callbacks);
+ GPR_ASSERT(callbacks);
g_callbacks.reset(callbacks);
}
+grpc_server* Server::c_server() { return server_; }
+
+CompletionQueue* Server::completion_queue() { return &cq_; }
+
static grpc_server_register_method_payload_handling PayloadHandlingForMethod(
RpcServiceMethod* method) {
switch (method->method_type()) {
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 54feac3982..45bb858e2e 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -37,6 +37,8 @@
#include <grpc++/server.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
+
+#include "include/grpc/support/useful.h"
#include "src/cpp/server/thread_pool_interface.h"
namespace grpc {
@@ -52,12 +54,19 @@ static void do_plugin_list_init(void) {
ServerBuilder::ServerBuilder()
: max_message_size_(-1), generic_service_(nullptr) {
- grpc_compression_options_init(&compression_options_);
gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
- for (auto factory : (*g_plugin_factory_list)) {
- std::unique_ptr<ServerBuilderPlugin> plugin = factory();
- plugins_[plugin->name()] = std::move(plugin);
+ for (auto it = g_plugin_factory_list->begin();
+ it != g_plugin_factory_list->end(); it++) {
+ auto& factory = *it;
+ plugins_.emplace_back(factory());
}
+ // all compression algorithms enabled by default.
+ enabled_compression_algorithms_bitset_ =
+ (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
+ memset(&maybe_default_compression_level_, 0,
+ sizeof(maybe_default_compression_level_));
+ memset(&maybe_default_compression_algorithm_, 0,
+ sizeof(maybe_default_compression_algorithm_));
}
std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
@@ -67,35 +76,65 @@ std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
return std::unique_ptr<ServerCompletionQueue>(cq);
}
-void ServerBuilder::RegisterService(Service* service) {
+ServerBuilder& ServerBuilder::RegisterService(Service* service) {
services_.emplace_back(new NamedService(service));
+ return *this;
}
-void ServerBuilder::RegisterService(const grpc::string& addr,
- Service* service) {
+ServerBuilder& ServerBuilder::RegisterService(const grpc::string& addr,
+ Service* service) {
services_.emplace_back(new NamedService(addr, service));
+ return *this;
}
-void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
+ServerBuilder& ServerBuilder::RegisterAsyncGenericService(
+ AsyncGenericService* service) {
if (generic_service_) {
gpr_log(GPR_ERROR,
"Adding multiple AsyncGenericService is unsupported for now. "
"Dropping the service %p",
service);
- return;
+ } else {
+ generic_service_ = service;
}
- generic_service_ = service;
+ return *this;
}
-void ServerBuilder::SetOption(std::unique_ptr<ServerBuilderOption> option) {
+ServerBuilder& ServerBuilder::SetOption(
+ std::unique_ptr<ServerBuilderOption> option) {
options_.push_back(std::move(option));
+ return *this;
+}
+
+ServerBuilder& ServerBuilder::SetCompressionAlgorithmSupportStatus(
+ grpc_compression_algorithm algorithm, bool enabled) {
+ if (enabled) {
+ GPR_BITSET(&enabled_compression_algorithms_bitset_, algorithm);
+ } else {
+ GPR_BITCLEAR(&enabled_compression_algorithms_bitset_, algorithm);
+ }
+ return *this;
}
-void ServerBuilder::AddListeningPort(const grpc::string& addr,
- std::shared_ptr<ServerCredentials> creds,
- int* selected_port) {
+ServerBuilder& ServerBuilder::SetDefaultCompressionLevel(
+ grpc_compression_level level) {
+ maybe_default_compression_level_.level = level;
+ return *this;
+}
+
+ServerBuilder& ServerBuilder::SetDefaultCompressionAlgorithm(
+ grpc_compression_algorithm algorithm) {
+ maybe_default_compression_algorithm_.is_set = true;
+ maybe_default_compression_algorithm_.algorithm = algorithm;
+ return *this;
+}
+
+ServerBuilder& ServerBuilder::AddListeningPort(
+ const grpc::string& addr, std::shared_ptr<ServerCredentials> creds,
+ int* selected_port) {
Port port = {addr, creds, selected_port};
ports_.push_back(port);
+ return *this;
}
std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
@@ -103,7 +142,7 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
bool has_sync_methods = false;
for (auto it = services_.begin(); it != services_.end(); ++it) {
if ((*it)->service->has_synchronous_methods()) {
- if (thread_pool == nullptr) {
+ if (!thread_pool) {
thread_pool.reset(CreateDefaultThreadPool());
has_sync_methods = true;
break;
@@ -115,9 +154,9 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
(*option)->UpdateArguments(&args);
(*option)->UpdatePlugins(&plugins_);
}
- if (thread_pool == nullptr) {
+ if (!thread_pool) {
for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
- if ((*plugin).second->has_sync_methods()) {
+ if ((*plugin)->has_sync_methods()) {
thread_pool.reset(CreateDefaultThreadPool());
has_sync_methods = true;
break;
@@ -128,7 +167,15 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH, max_message_size_);
}
args.SetInt(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
- compression_options_.enabled_algorithms_bitset);
+ enabled_compression_algorithms_bitset_);
+ if (maybe_default_compression_level_.is_set) {
+ args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL,
+ maybe_default_compression_level_.level);
+ }
+ if (maybe_default_compression_algorithm_.is_set) {
+ args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
+ maybe_default_compression_algorithm_.algorithm);
+ }
std::unique_ptr<Server> server(
new Server(thread_pool.release(), true, max_message_size_, &args));
ServerInitializer* initializer = server->initializer();
@@ -166,7 +213,7 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
}
}
for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
- (*plugin).second->InitServer(initializer);
+ (*plugin)->InitServer(initializer);
}
if (generic_service_) {
server->RegisterAsyncGenericService(generic_service_);
@@ -192,7 +239,7 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
return nullptr;
}
for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
- (*plugin).second->Finish(initializer);
+ (*plugin)->Finish(initializer);
}
return server;
}
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 204fef1b09..43117fd1e9 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -42,7 +42,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include "src/core/lib/channel/compress_filter.h"
#include "src/core/lib/surface/call.h"
namespace grpc {
@@ -196,6 +195,9 @@ bool ServerContext::IsCancelled() const {
}
void ServerContext::set_compression_level(grpc_compression_level level) {
+ // TODO(dgq): get rid of grpc_call_compression_for_level and propagate the
+ // compression level by adding a new argument to
+ // CallOpSendInitialMetadata::SendInitialMetadata.
const grpc_compression_algorithm algorithm_for_level =
grpc_call_compression_for_level(call_, level);
set_compression_algorithm(algorithm_for_level);
@@ -210,7 +212,7 @@ void ServerContext::set_compression_algorithm(
abort();
}
GPR_ASSERT(algorithm_name != NULL);
- AddInitialMetadata(GRPC_COMPRESS_REQUEST_ALGORITHM_KEY, algorithm_name);
+ AddInitialMetadata(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY, algorithm_name);
}
grpc::string ServerContext::peer() const {
diff --git a/src/cpp/server/server_posix.cc b/src/cpp/server/server_posix.cc
new file mode 100644
index 0000000000..c3aa2adc60
--- /dev/null
+++ b/src/cpp/server/server_posix.cc
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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 <grpc++/server_posix.h>
+
+#include <grpc/grpc_posix.h>
+
+namespace grpc {
+
+#ifdef GPR_SUPPORT_CHANNELS_FROM_FD
+
+void AddInsecureChannelFromFd(Server* server, int fd) {
+ grpc_server_add_insecure_channel_from_fd(
+ server->c_server(), server->completion_queue()->cq(), fd);
+}
+
+#endif // GPR_SUPPORT_CHANNELS_FROM_FD
+
+} // namespace grpc
diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore
index 0f96a48221..fc2875a1dd 100644
--- a/src/csharp/.gitignore
+++ b/src/csharp/.gitignore
@@ -1,5 +1,7 @@
+*.xproj.user
*.userprefs
*.csproj.user
+*.lock.json
StyleCop.Cache
test-results
packages
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 3acea7d2f8..1fa14fc3df 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -81,6 +81,7 @@
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Auth.nuspec" />
+ <None Include="Grpc.Auth.project.json" />
<None Include="packages.config" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.project.json b/src/csharp/Grpc.Auth/Grpc.Auth.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.xproj b/src/csharp/Grpc.Auth/Grpc.Auth.xproj
new file mode 100644
index 0000000000..dd3d94c574
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.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>c82631ed-06d1-4458-87bc-8257d12307a8</ProjectGuid>
+ <RootNamespace>Grpc.Auth</RootNamespace>
+ <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\Grpc.Core\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.Auth/project.json b/src/csharp/Grpc.Auth/project.json
new file mode 100644
index 0000000000..4c5c960204
--- /dev/null
+++ b/src/csharp/Grpc.Auth/project.json
@@ -0,0 +1,32 @@
+{
+ "version": "0.16.0-dev",
+ "title": "gRPC C# Auth",
+ "authors": [ "Google Inc." ],
+ "copyright": "Copyright 2015, Google Inc.",
+ "packOptions": {
+ "summary": "Auth library for C# implementation of gRPC - an RPC library and framework",
+ "description": "Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+ "owners": [ "grpc-packages" ],
+ "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+ "projectUrl": "https://github.com/grpc/grpc",
+ "requireLicenseAcceptance": false,
+ "tags": [ "gRPC RPC Protocol HTTP/2 Auth OAuth2" ],
+ },
+ "dependencies": {
+ "Grpc.Core": "0.16.0-dev",
+ "Google.Apis.Auth": "1.11.1"
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "net45"
+ ],
+ "dependencies": {
+ "Microsoft.NETCore.Portable.Compatibility": "1.0.1-rc2-24027",
+ "NETStandard.Library": "1.5.0-rc2-24027",
+ "System.Threading.Tasks": "4.0.11-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
new file mode 100644
index 0000000000..064bc13cab
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/AppDomainUnloadTest.cs
@@ -0,0 +1,92 @@
+#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.Threading.Tasks;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class AppDomainUnloadTest
+ {
+#if NETSTANDARD1_5
+ [Test]
+ [Ignore("Not supported for CoreCLR")]
+ public void AppDomainUnloadHookCanCleanupAbandonedCall()
+ {
+ }
+#else
+ [Test]
+ public void AppDomainUnloadHookCanCleanupAbandonedCall()
+ {
+ var setup = new AppDomainSetup
+ {
+ ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
+ };
+ var childDomain = AppDomain.CreateDomain("test", null, setup);
+ var remoteObj = childDomain.CreateInstance(typeof(AppDomainTestClass).Assembly.GetName().Name, typeof(AppDomainTestClass).FullName);
+
+ // Try to unload the appdomain once we've created a server and a channel inside the appdomain.
+ AppDomain.Unload(childDomain);
+ }
+
+ public class AppDomainTestClass
+ {
+ const string Host = "127.0.0.1";
+
+ /// <summary>
+ /// Creates a server and a channel and initiates a call. The code is invoked from inside of an AppDomain
+ /// to test if AppDomain.Unload() work if Grpc is being used.
+ /// </summary>
+ public AppDomainTestClass()
+ {
+ var helper = new MockServiceHelper(Host);
+ var server = helper.GetServer();
+ server.Start();
+ var channel = helper.GetChannel();
+
+ var readyToShutdown = new TaskCompletionSource<object>();
+ helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
+ {
+ readyToShutdown.SetResult(null);
+ await requestStream.ToListAsync();
+ });
+
+ var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
+ readyToShutdown.Task.Wait(); // make sure handler is running
+ }
+ }
+#endif
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index 850d70ce92..db0ef3a4cd 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -71,7 +71,7 @@ namespace Grpc.Core.Tests
public void WaitForStateChangedAsync_InvalidArgument()
{
var channel = new Channel("localhost", ChannelCredentials.Insecure);
- Assert.ThrowsAsync(typeof(ArgumentException), async () => await channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
+ Assert.ThrowsAsync(typeof(ArgumentException), async () => await channel.WaitForStateChangedAsync(ChannelState.Shutdown));
channel.ShutdownAsync().Wait();
}
@@ -102,11 +102,11 @@ namespace Grpc.Core.Tests
}
[Test]
- public async Task StateIsFatalFailureAfterShutdown()
+ public async Task StateIsShutdownAfterShutdown()
{
var channel = new Channel("localhost", ChannelCredentials.Insecure);
await channel.ShutdownAsync();
- Assert.AreEqual(ChannelState.FatalFailure, channel.State);
+ Assert.AreEqual(ChannelState.Shutdown, channel.State);
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/CompressionTest.cs b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
index 378c81851c..16be210508 100644
--- a/src/csharp/Grpc.Core.Tests/CompressionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CompressionTest.cs
@@ -34,6 +34,7 @@
using System;
using System.Diagnostics;
using System.Linq;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@@ -118,5 +119,30 @@ namespace Grpc.Core.Tests
await call.ResponseStream.ToListAsync();
}
+
+ [Test]
+ public void CanReadCompressedMessages()
+ {
+ var compressionMetadata = new Metadata
+ {
+ { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, "gzip") }
+ };
+
+ helper.UnaryHandler = new UnaryServerMethod<string, string>(async (req, context) =>
+ {
+ await context.WriteResponseHeadersAsync(compressionMetadata);
+ return req;
+ });
+
+ var stringBuilder = new StringBuilder();
+ for (int i = 0; i < 200000; i++)
+ {
+ stringBuilder.Append('a');
+ }
+ var request = stringBuilder.ToString();
+ var response = Calls.BlockingUnaryCall(helper.CreateUnaryCall(new CallOptions(compressionMetadata)), request);
+
+ Assert.AreEqual(request, response);
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 47131fc454..f6c226567d 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -86,6 +86,10 @@
<Compile Include="NUnitMain.cs" />
<Compile Include="Internal\FakeNativeCall.cs" />
<Compile Include="Internal\AsyncCallServerTest.cs" />
+ <Compile Include="ShutdownHookServerTest.cs" />
+ <Compile Include="ShutdownHookPendingCallTest.cs" />
+ <Compile Include="ShutdownHookClientTest.cs" />
+ <Compile Include="AppDomainUnloadTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -95,6 +99,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.Core.Tests.project.json" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj
new file mode 100644
index 0000000000..0582329154
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.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>759e23b2-fc04-4695-902d-b073cded3599</ProjectGuid>
+ <RootNamespace>Grpc.Core.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.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 6fe382751a..3ec2cf48cd 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -49,7 +49,7 @@ namespace Grpc.Core.Tests
{
Assert.IsNotNull(env.CompletionQueues.ElementAt(i));
}
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
}
[Test]
@@ -58,8 +58,8 @@ namespace Grpc.Core.Tests
var env1 = GrpcEnvironment.AddRef();
var env2 = GrpcEnvironment.AddRef();
Assert.AreSame(env1, env2);
- GrpcEnvironment.Release();
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
+ GrpcEnvironment.ReleaseAsync().Wait();
}
[Test]
@@ -68,10 +68,10 @@ namespace Grpc.Core.Tests
Assert.AreEqual(0, GrpcEnvironment.GetRefCount());
var env1 = GrpcEnvironment.AddRef();
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
var env2 = GrpcEnvironment.AddRef();
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
Assert.AreNotSame(env1, env2);
}
@@ -80,7 +80,7 @@ namespace Grpc.Core.Tests
public void ReleaseWithoutAddRef()
{
Assert.AreEqual(0, GrpcEnvironment.GetRefCount());
- Assert.Throws(typeof(InvalidOperationException), () => GrpcEnvironment.Release());
+ Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await GrpcEnvironment.ReleaseAsync());
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 81897f8c77..98e27a17a1 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -224,7 +224,7 @@ namespace Grpc.Core.Internal.Tests
fakeCall.UnaryResponseClientHandler(true,
new ClientSideStatus(new Status(StatusCode.OutOfRange, ""), new Metadata()),
- null,
+ CreateResponsePayload(),
new Metadata());
AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.OutOfRange);
diff --git a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
index 195119f920..e9ec59eb3d 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
@@ -48,7 +48,7 @@ namespace Grpc.Core.Internal.Tests
GrpcEnvironment.AddRef();
var cq = CompletionQueueSafeHandle.Create();
cq.Dispose();
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
}
[Test]
@@ -59,7 +59,7 @@ namespace Grpc.Core.Internal.Tests
cq.Shutdown();
var ev = cq.Next();
cq.Dispose();
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
Assert.AreEqual(CompletionQueueEvent.CompletionType.Shutdown, ev.type);
Assert.AreNotEqual(IntPtr.Zero, ev.success);
Assert.AreEqual(IntPtr.Zero, ev.tag);
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 3047314345..4d90470056 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -102,7 +102,7 @@ namespace Grpc.Core.Tests
marshaller,
marshaller);
- serviceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName)
+ serviceDefinition = ServerServiceDefinition.CreateBuilder()
.AddMethod(unaryMethod, (request, context) => unaryHandler(request, context))
.AddMethod(clientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context))
.AddMethod(serverStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context))
diff --git a/src/csharp/Grpc.Core.Tests/NUnitMain.cs b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
index 9c1d7bf3c8..24a9f846d1 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@ namespace Grpc.Core.Tests
{
// 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 DOTNET5_4
+#if NETSTANDARD1_5
return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
#else
return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
index 3fa6ad09c0..1a9e441611 100644
--- a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
+++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs
@@ -56,7 +56,7 @@ namespace Grpc.Core.Tests
Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " +
"This test has failed to indicate that.");
Console.Error.Flush();
- Environment.Exit(1);
+ throw new Exception("NUnitVersionTest has failed.");
}
}
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index d2b2fc6a66..d3735c7880 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -65,7 +65,7 @@ namespace Grpc.Core.Tests
cq.Dispose();
});
- GrpcEnvironment.Release();
+ GrpcEnvironment.ReleaseAsync().Wait();
}
/// <summary>
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 3830f0cbac..501992c569 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -45,6 +45,8 @@ namespace Grpc.Core.Tests
{
public class SanityTest
{
+ // TODO: make sanity test work for CoreCLR as well
+#if !NETSTANDARD1_5
/// <summary>
/// Because we depend on a native library, sometimes when things go wrong, the
/// entire NUnit test process crashes. To be able to track down problems better,
@@ -121,5 +123,6 @@ namespace Grpc.Core.Tests
}
return result;
}
+#endif
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index b40508accc..3b51aa6330 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -89,9 +89,24 @@ namespace Grpc.Core.Tests
};
server.Start();
Assert.Throws(typeof(InvalidOperationException), () => server.Ports.Add("localhost", 9999, ServerCredentials.Insecure));
- Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder("serviceName").Build()));
+ Assert.Throws(typeof(InvalidOperationException), () => server.Services.Add(ServerServiceDefinition.CreateBuilder().Build()));
server.ShutdownAsync().Wait();
}
+
+ [Test]
+ public void UnstartedServerCanBeShutdown()
+ {
+ var server = new Server();
+ server.ShutdownAsync().Wait();
+ Assert.Throws(typeof(InvalidOperationException), () => server.Start());
+ }
+
+ [Test]
+ public void UnstartedServerDoesNotPreventShutdown()
+ {
+ // just create a server, don't start it, and make sure it doesn't prevent shutdown.
+ var server = new Server();
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/ShutdownHookClientTest.cs b/src/csharp/Grpc.Core.Tests/ShutdownHookClientTest.cs
new file mode 100644
index 0000000000..12b8452f64
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ShutdownHookClientTest.cs
@@ -0,0 +1,57 @@
+#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.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class ShutdownHookClientTest
+ {
+ const string Host = "127.0.0.1";
+
+ [Test]
+ public void ProcessExitHookCanCleanupAbandonedChannels()
+ {
+ var channel = new Channel(Host, 1000, ChannelCredentials.Insecure);
+ var channel2 = new Channel(Host, 1001, ChannelCredentials.Insecure);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ShutdownHookPendingCallTest.cs b/src/csharp/Grpc.Core.Tests/ShutdownHookPendingCallTest.cs
new file mode 100644
index 0000000000..175233840d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ShutdownHookPendingCallTest.cs
@@ -0,0 +1,69 @@
+#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.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class ShutdownHookPendingCallTest
+ {
+ const string Host = "127.0.0.1";
+
+ [Test]
+ public void ProcessExitHookCanCleanupAbandonedCall()
+ {
+ var helper = new MockServiceHelper(Host);
+ var server = helper.GetServer();
+ server.Start();
+ var channel = helper.GetChannel();
+
+ var readyToShutdown = new TaskCompletionSource<object>();
+ helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
+ {
+ readyToShutdown.SetResult(null);
+ await requestStream.ToListAsync();
+ });
+
+ var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
+ readyToShutdown.Task.Wait(); // make sure handler is running
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ShutdownHookServerTest.cs b/src/csharp/Grpc.Core.Tests/ShutdownHookServerTest.cs
new file mode 100644
index 0000000000..e7ea7a0bf5
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/ShutdownHookServerTest.cs
@@ -0,0 +1,58 @@
+#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.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class ShutdownHookServerTest
+ {
+ const string Host = "127.0.0.1";
+
+ [Test]
+ public void ProcessExitHookCanCleanupAbandonedServers()
+ {
+ var helper = new MockServiceHelper(Host);
+ var server = helper.GetServer();
+ server.Start();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
new file mode 100644
index 0000000000..3ad081df39
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/project.json
@@ -0,0 +1,56 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.Core": {
+ "target": "project"
+ },
+ "Newtonsoft.Json": "8.0.3",
+ "NUnit": "3.2.0",
+ "NUnitLite": "3.2.0-*"
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ },
+}
diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
index 5646fed3d9..02b08d2a10 100644
--- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs
@@ -127,6 +127,10 @@ namespace Grpc.Core
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
/// As a result, all resources being used by the call should be released eventually.
/// </summary>
+ /// <remarks>
+ /// Normally, there is no need for you to dispose the call unless you want to utilize the
+ /// "Cancel" semantics of invoking <c>Dispose</c>.
+ /// </remarks>
public void Dispose()
{
disposeAction.Invoke();
diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
index e75108c7e5..68fd6d0b05 100644
--- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs
@@ -117,6 +117,10 @@ namespace Grpc.Core
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
/// As a result, all resources being used by the call should be released eventually.
/// </summary>
+ /// <remarks>
+ /// Normally, there is no need for you to dispose the call unless you want to utilize the
+ /// "Cancel" semantics of invoking <c>Dispose</c>.
+ /// </remarks>
public void Dispose()
{
disposeAction.Invoke();
diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
index f953091984..5777c72615 100644
--- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
+++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs
@@ -103,6 +103,10 @@ namespace Grpc.Core
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
/// As a result, all resources being used by the call should be released eventually.
/// </summary>
+ /// <remarks>
+ /// Normally, there is no need for you to dispose the call unless you want to utilize the
+ /// "Cancel" semantics of invoking <c>Dispose</c>.
+ /// </remarks>
public void Dispose()
{
disposeAction.Invoke();
diff --git a/src/csharp/Grpc.Core/AsyncUnaryCall.cs b/src/csharp/Grpc.Core/AsyncUnaryCall.cs
index 97df8f5e91..d180c27922 100644
--- a/src/csharp/Grpc.Core/AsyncUnaryCall.cs
+++ b/src/csharp/Grpc.Core/AsyncUnaryCall.cs
@@ -112,6 +112,10 @@ namespace Grpc.Core
/// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call.
/// As a result, all resources being used by the call should be released eventually.
/// </summary>
+ /// <remarks>
+ /// Normally, there is no need for you to dispose the call unless you want to utilize the
+ /// "Cancel" semantics of invoking <c>Dispose</c>.
+ /// </remarks>
public void Dispose()
{
disposeAction.Invoke();
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index 9ca88849ee..35548cfc96 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -88,7 +88,13 @@ namespace Grpc.Core
}
/// <summary>
- /// Token that can be used for cancelling the call.
+ /// Token that can be used for cancelling the call on the client side.
+ /// Cancelling the token will request cancellation
+ /// of the remote call. Best effort will be made to deliver the cancellation
+ /// notification to the server and interaction of the call with the server side
+ /// will be terminated. Unless the call finishes before the cancellation could
+ /// happen (there is an inherent race),
+ /// the call will finish with <c>StatusCode.Cancelled</c> status.
/// </summary>
public CancellationToken CancellationToken
{
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 886adfec33..4f29c35b32 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -67,8 +67,19 @@ namespace Grpc.Core
/// </summary>
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
+ public Channel(string target, ChannelCredentials credentials) :
+ this(target, credentials, null)
+ {
+ }
+
+ /// <summary>
+ /// Creates a channel that connects to a specific host.
+ /// Port will default to 80 for an unsecure channel and to 443 for a secure channel.
+ /// </summary>
+ /// <param name="target">Target of the channel.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
+ public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options)
{
this.target = GrpcPreconditions.CheckNotNull(target, "target");
this.options = CreateOptionsDictionary(options);
@@ -88,6 +99,18 @@ namespace Grpc.Core
this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs);
}
}
+ GrpcEnvironment.RegisterChannel(this);
+ }
+
+ /// <summary>
+ /// Creates a channel that connects to a specific host and port.
+ /// </summary>
+ /// <param name="host">The name or IP address of the host.</param>
+ /// <param name="port">The port.</param>
+ /// <param name="credentials">Credentials to secure the channel.</param>
+ public Channel(string host, int port, ChannelCredentials credentials) :
+ this(host, port, credentials, null)
+ {
}
/// <summary>
@@ -97,14 +120,14 @@ namespace Grpc.Core
/// <param name="port">The port.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null) :
+ public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
/// <summary>
/// Gets current connectivity state of this channel.
- /// After channel is has been shutdown, <c>ChannelState.FatalFailure</c> will be returned.
+ /// After channel is has been shutdown, <c>ChannelState.Shutdown</c> will be returned.
/// </summary>
public ChannelState State
{
@@ -121,8 +144,8 @@ namespace Grpc.Core
/// </summary>
public Task WaitForStateChangedAsync(ChannelState lastObservedState, DateTime? deadline = null)
{
- GrpcPreconditions.CheckArgument(lastObservedState != ChannelState.FatalFailure,
- "FatalFailure is a terminal state. No further state changes can occur.");
+ GrpcPreconditions.CheckArgument(lastObservedState != ChannelState.Shutdown,
+ "Shutdown is a terminal state. No further state changes can occur.");
var tcs = new TaskCompletionSource<object>();
var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
var handler = new BatchCompletionDelegate((success, ctx) =>
@@ -172,7 +195,7 @@ namespace Grpc.Core
/// <summary>
/// Allows explicitly requesting channel to connect without starting an RPC.
/// Returned task completes once state Ready was seen. If the deadline is reached,
- /// or channel enters the FatalFailure state, the task is cancelled.
+ /// or channel enters the Shutdown state, the task is cancelled.
/// There is no need to call this explicitly unless your use case requires that.
/// Starting an RPC on a new channel will request connection implicitly.
/// </summary>
@@ -182,9 +205,9 @@ namespace Grpc.Core
var currentState = GetConnectivityState(true);
while (currentState != ChannelState.Ready)
{
- if (currentState == ChannelState.FatalFailure)
+ if (currentState == ChannelState.Shutdown)
{
- throw new OperationCanceledException("Channel has reached FatalFailure state.");
+ throw new OperationCanceledException("Channel has reached Shutdown state.");
}
await WaitForStateChangedAsync(currentState, deadline).ConfigureAwait(false);
currentState = GetConnectivityState(false);
@@ -192,9 +215,16 @@ namespace Grpc.Core
}
/// <summary>
- /// Waits until there are no more active calls for this channel and then cleans up
- /// resources used by this channel.
+ /// Shuts down the channel cleanly. It is strongly recommended to shutdown
+ /// all previously created channels before exiting from the process.
/// </summary>
+ /// <remarks>
+ /// This method doesn't wait for all calls on this channel to finish (nor does
+ /// it explicitly cancel all outstanding calls). It is user's responsibility to make sure
+ /// all the calls on this channel have finished (successfully or with an error)
+ /// before shutting down the channel to ensure channel shutdown won't impact
+ /// the outcome of those remote calls.
+ /// </remarks>
public async Task ShutdownAsync()
{
lock (myLock)
@@ -202,6 +232,7 @@ namespace Grpc.Core
GrpcPreconditions.CheckState(!shutdownRequested);
shutdownRequested = true;
}
+ GrpcEnvironment.UnregisterChannel(this);
shutdownTokenSource.Cancel();
@@ -213,7 +244,7 @@ namespace Grpc.Core
handle.Dispose();
- await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
+ await GrpcEnvironment.ReleaseAsync().ConfigureAwait(false);
}
internal ChannelSafeHandle Handle
@@ -264,7 +295,7 @@ namespace Grpc.Core
}
catch (ObjectDisposedException)
{
- return ChannelState.FatalFailure;
+ return ChannelState.Shutdown;
}
}
diff --git a/src/csharp/Grpc.Core/ChannelState.cs b/src/csharp/Grpc.Core/ChannelState.cs
index d293b98f75..a6c3b2a488 100644
--- a/src/csharp/Grpc.Core/ChannelState.cs
+++ b/src/csharp/Grpc.Core/ChannelState.cs
@@ -64,6 +64,6 @@ namespace Grpc.Core
/// <summary>
/// Channel has seen a failure that it cannot recover from
/// </summary>
- FatalFailure
+ Shutdown
}
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index a8b7b5f00d..1952ee3712 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -136,9 +136,12 @@
<Compile Include="Internal\ClientSideStatus.cs" />
<Compile Include="Internal\ClockType.cs" />
<Compile Include="Internal\CallError.cs" />
+ <Compile Include="Logging\LogLevel.cs" />
+ <Compile Include="Logging\LogLevelFilterLogger.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />
+ <None Include="Grpc.Core.project.json" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="NativeDeps.targets" />
@@ -146,7 +149,7 @@
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="..\..\..\etc\roots.pem">
- <Link>Resources\roots.pem</Link>
+ <Link>roots.pem</Link>
</EmbeddedResource>
</ItemGroup>
</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
index 0ada0049c2..47593f787b 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -24,11 +24,12 @@
<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" />
- <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
- <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
- <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
- <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
- <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
- <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
+ <!-- without backslashes in the the source path, nuget won't copy the files -->
+ <file src="..\nativelibs\windows_x86\grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
+ <file src="..\nativelibs\windows_x64\grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
+ <file src="..\nativelibs\linux_x86\libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
+ <file src="..\nativelibs\linux_x64\libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
+ <file src="..\nativelibs\macosx_x86\libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
+ <file src="..\nativelibs\macosx_x64\libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
</files>
</package>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.project.json b/src/csharp/Grpc.Core/Grpc.Core.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Core/Grpc.Core.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.xproj b/src/csharp/Grpc.Core/Grpc.Core.xproj
new file mode 100644
index 0000000000..137236ffdb
--- /dev/null
+++ b/src/csharp/Grpc.Core/Grpc.Core.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>dc9908b6-f291-4fc8-a46d-2ea2551790ec</ProjectGuid>
+ <RootNamespace>Grpc.Core</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.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 18af1099f1..eeed699712 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
@@ -46,6 +47,7 @@ namespace Grpc.Core
/// </summary>
public class GrpcEnvironment
{
+ const LogLevel DefaultLogLevel = LogLevel.Info;
const int MinDefaultThreadPoolSize = 4;
static object staticLock = new object();
@@ -53,12 +55,16 @@ namespace Grpc.Core
static int refCount;
static int? customThreadPoolSize;
static int? customCompletionQueueCount;
+ static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>();
+ static readonly HashSet<Server> registeredServers = new HashSet<Server>();
- static ILogger logger = new ConsoleLogger();
+ static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), DefaultLogLevel);
+ readonly object myLock = new object();
readonly GrpcThreadPool threadPool;
readonly DebugStats debugStats = new DebugStats();
readonly AtomicCounter cqPickerCounter = new AtomicCounter();
+
bool isClosed;
/// <summary>
@@ -67,6 +73,8 @@ namespace Grpc.Core
/// </summary>
internal static GrpcEnvironment AddRef()
{
+ ShutdownHooks.Register();
+
lock (staticLock)
{
refCount++;
@@ -79,21 +87,26 @@ namespace Grpc.Core
}
/// <summary>
- /// Decrements the reference count for currently active environment and shuts down the gRPC environment if reference count drops to zero.
- /// (and blocks until the environment has been fully shutdown).
+ /// Decrements the reference count for currently active environment and asynchronously shuts down the gRPC environment if reference count drops to zero.
/// </summary>
- internal static void Release()
+ internal static async Task ReleaseAsync()
{
+ GrpcEnvironment instanceToShutdown = null;
lock (staticLock)
{
GrpcPreconditions.CheckState(refCount > 0);
refCount--;
if (refCount == 0)
{
- instance.Close();
+ instanceToShutdown = instance;
instance = null;
}
}
+
+ if (instanceToShutdown != null)
+ {
+ await instanceToShutdown.ShutdownAsync().ConfigureAwait(false);
+ }
}
internal static int GetRefCount()
@@ -104,6 +117,68 @@ namespace Grpc.Core
}
}
+ internal static void RegisterChannel(Channel channel)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckNotNull(channel);
+ registeredChannels.Add(channel);
+ }
+ }
+
+ internal static void UnregisterChannel(Channel channel)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckNotNull(channel);
+ GrpcPreconditions.CheckArgument(registeredChannels.Remove(channel), "Channel not found in the registered channels set.");
+ }
+ }
+
+ internal static void RegisterServer(Server server)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckNotNull(server);
+ registeredServers.Add(server);
+ }
+ }
+
+ internal static void UnregisterServer(Server server)
+ {
+ lock (staticLock)
+ {
+ GrpcPreconditions.CheckNotNull(server);
+ GrpcPreconditions.CheckArgument(registeredServers.Remove(server), "Server not found in the registered servers set.");
+ }
+ }
+
+ /// <summary>
+ /// Requests shutdown of all channels created by the current process.
+ /// </summary>
+ public static Task ShutdownChannelsAsync()
+ {
+ HashSet<Channel> snapshot = null;
+ lock (staticLock)
+ {
+ snapshot = new HashSet<Channel>(registeredChannels);
+ }
+ return Task.WhenAll(snapshot.Select((channel) => channel.ShutdownAsync()));
+ }
+
+ /// <summary>
+ /// Requests immediate shutdown of all servers created by the current process.
+ /// </summary>
+ public static Task KillServersAsync()
+ {
+ HashSet<Server> snapshot = null;
+ lock (staticLock)
+ {
+ snapshot = new HashSet<Server>(registeredServers);
+ }
+ return Task.WhenAll(snapshot.Select((server) => server.KillAsync()));
+ }
+
/// <summary>
/// Gets application-wide logger used by gRPC.
/// </summary>
@@ -180,6 +255,14 @@ namespace Grpc.Core
}
}
+ internal bool IsAlive
+ {
+ get
+ {
+ return this.threadPool.IsAlive;
+ }
+ }
+
/// <summary>
/// Picks a completion queue in a round-robin fashion.
/// Shouldn't be invoked on a per-call basis (used at per-channel basis).
@@ -223,13 +306,13 @@ namespace Grpc.Core
/// <summary>
/// Shuts down this environment.
/// </summary>
- private void Close()
+ private async Task ShutdownAsync()
{
if (isClosed)
{
throw new InvalidOperationException("Close has already been called");
}
- threadPool.Stop();
+ await threadPool.StopAsync().ConfigureAwait(false);
GrpcNativeShutdown();
isClosed = true;
@@ -257,5 +340,36 @@ namespace Grpc.Core
// by default, create a completion queue for each thread
return GetThreadPoolSizeOrDefault();
}
+
+ private static class ShutdownHooks
+ {
+ static object staticLock = new object();
+ static bool hooksRegistered;
+
+ public static void Register()
+ {
+ lock (staticLock)
+ {
+ if (!hooksRegistered)
+ {
+ // TODO(jtattermusch): register shutdownhooks for CoreCLR as well
+#if !NETSTANDARD1_5
+
+ AppDomain.CurrentDomain.ProcessExit += ShutdownHookHandler;
+ AppDomain.CurrentDomain.DomainUnload += ShutdownHookHandler;
+#endif
+ }
+ hooksRegistered = true;
+ }
+ }
+
+ /// <summary>
+ /// Handler for AppDomain.DomainUnload and AppDomain.ProcessExit hooks.
+ /// </summary>
+ private static void ShutdownHookHandler(object sender, EventArgs e)
+ {
+ Task.WaitAll(GrpcEnvironment.ShutdownChannelsAsync(), GrpcEnvironment.KillServersAsync());
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core/IAsyncStreamReader.cs b/src/csharp/Grpc.Core/IAsyncStreamReader.cs
index 49e1ea7832..aa3b802a50 100644
--- a/src/csharp/Grpc.Core/IAsyncStreamReader.cs
+++ b/src/csharp/Grpc.Core/IAsyncStreamReader.cs
@@ -41,10 +41,24 @@ namespace Grpc.Core
{
/// <summary>
/// A stream of messages to be read.
+ /// Messages can be awaited <c>await reader.MoveNext()</c>, that returns <c>true</c>
+ /// if there is a message available and <c>false</c> if there are no more messages
+ /// (i.e. the stream has been closed).
+ /// <para>
+ /// On the client side, the last invocation of <c>MoveNext()</c> either returns <c>false</c>
+ /// if the call has finished successfully or throws <c>RpcException</c> if call finished
+ /// with an error. Once the call finishes, subsequent invocations of <c>MoveNext()</c> will
+ /// continue yielding the same result (returning <c>false</c> or throwing an exception).
+ /// </para>
+ /// <para>
+ /// On the server side, <c>MoveNext()</c> does not throw exceptions.
+ /// In case of a failure, the request stream will appear to be finished
+ /// (<c>MoveNext</c> will return <c>false</c>) and the <c>CancellationToken</c>
+ /// associated with the call will be cancelled to signal the failure.
+ /// </para>
/// </summary>
/// <typeparam name="T">The message type.</typeparam>
public interface IAsyncStreamReader<T> : IAsyncEnumerator<T>
{
- // TODO(jtattermusch): consider just using IAsyncEnumerator instead of this interface.
}
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 895be690a5..f549c52876 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -267,7 +267,7 @@ namespace Grpc.Core.Internal
halfcloseRequested = true;
return Task.FromResult<object>(null);
}
- call.StartSendCloseFromClient(HandleSendCloseFromClientFinished);
+ call.StartSendCloseFromClient(HandleSendFinished);
halfcloseRequested = true;
streamingWriteTcs = new TaskCompletionSource<object>();
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index cb8366c216..eb9c3ea62d 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -248,7 +248,7 @@ namespace Grpc.Core.Internal
}
/// <summary>
- /// Handles send completion.
+ /// Handles send completion (including SendCloseFromClient).
/// </summary>
protected void HandleSendFinished(bool success)
{
@@ -272,31 +272,6 @@ namespace Grpc.Core.Internal
}
/// <summary>
- /// Handles halfclose (send close from client) completion.
- /// </summary>
- protected void HandleSendCloseFromClientFinished(bool success)
- {
- TaskCompletionSource<object> origTcs = null;
- lock (myLock)
- {
- origTcs = streamingWriteTcs;
- streamingWriteTcs = null;
-
- ReleaseResourcesIfPossible();
- }
-
- if (!success)
- {
- // TODO(jtattermusch): this method is same as HandleSendFinished (only the error message differs).
- origTcs.SetException(new InvalidOperationException("Sending close from client has failed."));
- }
- else
- {
- origTcs.SetResult(null);
- }
- }
-
- /// <summary>
/// Handles send status from server completion.
/// </summary>
protected void HandleSendStatusFromServerFinished(bool success)
diff --git a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
index aa4dafd7f2..2a96e9920c 100644
--- a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
+++ b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
@@ -46,7 +46,7 @@ namespace Grpc.Core.Internal
/// </summary>
internal static class DefaultSslRootsOverride
{
- const string RootsPemResourceName = "Grpc.Core.Resources.roots.pem";
+ const string RootsPemResourceName = "Grpc.Core.roots.pem";
static object staticLock = new object();
/// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 4de543bef7..a446c1f99f 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
@@ -53,6 +54,8 @@ namespace Grpc.Core.Internal
readonly int poolSize;
readonly int completionQueueCount;
+ bool stopRequested;
+
IReadOnlyCollection<CompletionQueueSafeHandle> completionQueues;
/// <summary>
@@ -84,15 +87,21 @@ namespace Grpc.Core.Internal
}
}
- public void Stop()
+ public Task StopAsync()
{
lock (myLock)
{
+ GrpcPreconditions.CheckState(!stopRequested, "Stop already requested.");
+ stopRequested = true;
+
foreach (var cq in completionQueues)
{
cq.Shutdown();
}
+ }
+ return Task.Run(() =>
+ {
foreach (var thread in threads)
{
thread.Join();
@@ -102,6 +111,21 @@ namespace Grpc.Core.Internal
{
cq.Dispose();
}
+ });
+ }
+
+ /// <summary>
+ /// Returns true if there is at least one thread pool thread that hasn't
+ /// already stopped.
+ /// Threads can either stop because all completion queues shut down or
+ /// because all foreground threads have already shutdown and process is
+ /// going to exit.
+ /// </summary>
+ internal bool IsAlive
+ {
+ get
+ {
+ return threads.Any(t => t.ThreadState != ThreadState.Stopped);
}
}
@@ -119,7 +143,7 @@ namespace Grpc.Core.Internal
var cq = completionQueues.ElementAt(cqIndex);
var thread = new Thread(new ThreadStart(() => RunHandlerLoop(cq)));
- thread.IsBackground = false;
+ thread.IsBackground = true;
thread.Name = string.Format("grpc {0} (cq {1})", threadIndex, cqIndex);
thread.Start();
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index b45ba19c24..a6d7925816 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -117,8 +117,8 @@ namespace Grpc.Core.Internal
private static string GetAssemblyPath()
{
var assembly = typeof(NativeExtension).GetTypeInfo().Assembly;
-#if DOTNET5_4
- // Assembly.EscapedCodeBase does not exit under CoreCLR, but assemblies imported from a nuget package
+#if NETSTANDARD1_5
+ // Assembly.EscapedCodeBase does not exist under CoreCLR, but assemblies imported from a nuget package
// don't seem to be shadowed by DNX-based projects at all.
return assembly.Location;
#else
@@ -136,7 +136,7 @@ namespace Grpc.Core.Internal
#endif
}
-#if !DOTNET5_4
+#if !NETSTANDARD1_5
private static bool IsFileUri(string uri)
{
return uri.ToLowerInvariant().StartsWith(Uri.UriSchemeFile);
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index 5d8c44b589..15391ddc64 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -53,7 +53,7 @@ namespace Grpc.Core.Internal
static PlatformApis()
{
-#if DNXCORE50
+#if NETSTANDARD1_5
isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
isMacOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
diff --git a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
index 702aea2883..230faacff6 100644
--- a/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
+++ b/src/csharp/Grpc.Core/Internal/SafeHandleZeroIsInvalid.cs
@@ -39,7 +39,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Safe handle to wrap native objects.
/// </summary>
- internal abstract class SafeHandleZeroIsInvalid : SafeHandle
+ internal abstract class SafeHandleZeroIsInvalid : System.Runtime.InteropServices.SafeHandle
{
public SafeHandleZeroIsInvalid() : base(IntPtr.Zero, true)
{
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 8581302706..014a8db78f 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -54,7 +54,10 @@ namespace Grpc.Core.Internal
public void RegisterCompletionQueue(CompletionQueueSafeHandle cq)
{
- Native.grpcsharp_server_register_completion_queue(this, cq);
+ using (cq.NewScope())
+ {
+ Native.grpcsharp_server_register_completion_queue(this, cq);
+ }
}
public int AddInsecurePort(string addr)
@@ -74,16 +77,22 @@ namespace Grpc.Core.Internal
public void ShutdownAndNotify(BatchCompletionDelegate callback, CompletionQueueSafeHandle completionQueue)
{
- var ctx = BatchContextSafeHandle.Create();
- completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
- Native.grpcsharp_server_shutdown_and_notify_callback(this, completionQueue, ctx);
+ using (completionQueue.NewScope())
+ {
+ var ctx = BatchContextSafeHandle.Create();
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+ Native.grpcsharp_server_shutdown_and_notify_callback(this, completionQueue, ctx);
+ }
}
public void RequestCall(BatchCompletionDelegate callback, CompletionQueueSafeHandle completionQueue)
{
- var ctx = BatchContextSafeHandle.Create();
- completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
- Native.grpcsharp_server_request_call(this, completionQueue, ctx).CheckOk();
+ using (completionQueue.NewScope())
+ {
+ var ctx = BatchContextSafeHandle.Create();
+ completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+ Native.grpcsharp_server_request_call(this, completionQueue, ctx).CheckOk();
+ }
}
protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Logging/LogLevel.cs b/src/csharp/Grpc.Core/Logging/LogLevel.cs
new file mode 100644
index 0000000000..d64e1f5fd0
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/LogLevel.cs
@@ -0,0 +1,59 @@
+#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;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>Standard logging levels.</summary>
+ public enum LogLevel
+ {
+ /// <summary>
+ /// Debug severity.
+ /// </summary>
+ Debug = 0,
+ /// <summary>
+ /// Info severity.
+ /// </summary>
+ Info,
+ /// <summary>
+ /// Warning severity.
+ /// </summary>
+ Warning,
+ /// <summary>
+ /// Error severity.
+ /// </summary>
+ Error
+ }
+}
diff --git a/src/csharp/Grpc.Core/Logging/LogLevelFilterLogger.cs b/src/csharp/Grpc.Core/Logging/LogLevelFilterLogger.cs
new file mode 100644
index 0000000000..4eeb79c783
--- /dev/null
+++ b/src/csharp/Grpc.Core/Logging/LogLevelFilterLogger.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;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Logging
+{
+ /// <summary>Logger that filters out messages below certain log level.</summary>
+ public class LogLevelFilterLogger : ILogger
+ {
+ readonly ILogger innerLogger;
+ readonly LogLevel logLevel;
+
+ /// <summary>
+ /// Creates and instance of <c>LogLevelFilter.</c>
+ /// </summary>
+ public LogLevelFilterLogger(ILogger logger, LogLevel logLevel)
+ {
+ this.innerLogger = GrpcPreconditions.CheckNotNull(logger);
+ this.logLevel = logLevel;
+ }
+
+ /// <summary>
+ /// Returns a logger associated with the specified type.
+ /// </summary>
+ public virtual ILogger ForType<T>()
+ {
+ var newInnerLogger = innerLogger.ForType<T>();
+ if (object.ReferenceEquals(this.innerLogger, newInnerLogger))
+ {
+ return this;
+ }
+ return new LogLevelFilterLogger(newInnerLogger, logLevel);
+ }
+
+ /// <summary>Logs a message with severity Debug.</summary>
+ public void Debug(string message)
+ {
+ if (logLevel <= LogLevel.Debug)
+ {
+ innerLogger.Debug(message);
+ }
+ }
+
+ /// <summary>Logs a formatted message with severity Debug.</summary>
+ public void Debug(string format, params object[] formatArgs)
+ {
+ if (logLevel <= LogLevel.Debug)
+ {
+ innerLogger.Debug(format, formatArgs);
+ }
+ }
+
+ /// <summary>Logs a message with severity Info.</summary>
+ public void Info(string message)
+ {
+ if (logLevel <= LogLevel.Info)
+ {
+ innerLogger.Info(message);
+ }
+ }
+
+ /// <summary>Logs a formatted message with severity Info.</summary>
+ public void Info(string format, params object[] formatArgs)
+ {
+ if (logLevel <= LogLevel.Info)
+ {
+ innerLogger.Info(format, formatArgs);
+ }
+ }
+
+ /// <summary>Logs a message with severity Warning.</summary>
+ public void Warning(string message)
+ {
+ if (logLevel <= LogLevel.Warning)
+ {
+ innerLogger.Warning(message);
+ }
+ }
+
+ /// <summary>Logs a formatted message with severity Warning.</summary>
+ public void Warning(string format, params object[] formatArgs)
+ {
+ if (logLevel <= LogLevel.Warning)
+ {
+ innerLogger.Warning(format, formatArgs);
+ }
+ }
+
+ /// <summary>Logs a message and an associated exception with severity Warning.</summary>
+ public void Warning(Exception exception, string message)
+ {
+ if (logLevel <= LogLevel.Warning)
+ {
+ innerLogger.Warning(exception, message);
+ }
+ }
+
+ /// <summary>Logs a message with severity Error.</summary>
+ public void Error(string message)
+ {
+ if (logLevel <= LogLevel.Error)
+ {
+ innerLogger.Error(message);
+ }
+ }
+
+ /// <summary>Logs a formatted message with severity Error.</summary>
+ public void Error(string format, params object[] formatArgs)
+ {
+ if (logLevel <= LogLevel.Error)
+ {
+ innerLogger.Error(format, formatArgs);
+ }
+ }
+
+ /// <summary>Logs a message and an associated exception with severity Error.</summary>
+ public void Error(Exception exception, string message)
+ {
+ if (logLevel <= LogLevel.Error)
+ {
+ innerLogger.Error(exception, message);
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index e982fa0c48..915bec146c 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -63,6 +63,13 @@ namespace Grpc.Core
/// </summary>
public static readonly Metadata Empty = new Metadata().Freeze();
+ /// <summary>
+ /// To be used in initial metadata to request specific compression algorithm
+ /// for given call. Direct selection of compression algorithms is an internal
+ /// feature and is not part of public API.
+ /// </summary>
+ internal const string CompressionRequestAlgorithmMetadataKey = "grpc-internal-encoding-request";
+
readonly List<Entry> entries;
bool readOnly;
@@ -95,6 +102,7 @@ namespace Grpc.Core
public void Insert(int index, Metadata.Entry item)
{
+ GrpcPreconditions.CheckNotNull(item);
CheckWriteable();
entries.Insert(index, item);
}
@@ -114,6 +122,7 @@ namespace Grpc.Core
set
{
+ GrpcPreconditions.CheckNotNull(value);
CheckWriteable();
entries[index] = value;
}
@@ -121,6 +130,7 @@ namespace Grpc.Core
public void Add(Metadata.Entry item)
{
+ GrpcPreconditions.CheckNotNull(item);
CheckWriteable();
entries.Add(item);
}
@@ -187,7 +197,7 @@ namespace Grpc.Core
/// <summary>
/// Metadata entry
/// </summary>
- public struct Entry
+ public class Entry
{
private static readonly Encoding Encoding = Encoding.ASCII;
private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$");
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 069185e13a..3b554e5e87 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -67,11 +67,19 @@ namespace Grpc.Core
bool startRequested;
volatile bool shutdownRequested;
+
/// <summary>
- /// Create a new server.
+ /// Creates a new server.
+ /// </summary>
+ public Server() : this(null)
+ {
+ }
+
+ /// <summary>
+ /// Creates a new server.
/// </summary>
/// <param name="options">Channel options.</param>
- public Server(IEnumerable<ChannelOption> options = null)
+ public Server(IEnumerable<ChannelOption> options)
{
this.serviceDefinitions = new ServiceDefinitionCollection(this);
this.ports = new ServerPortCollection(this);
@@ -86,6 +94,7 @@ namespace Grpc.Core
{
this.handle.RegisterCompletionQueue(cq);
}
+ GrpcEnvironment.RegisterServer(this);
}
/// <summary>
@@ -131,6 +140,7 @@ namespace Grpc.Core
lock (myLock)
{
GrpcPreconditions.CheckState(!startRequested);
+ GrpcPreconditions.CheckState(!shutdownRequested);
startRequested = true;
handle.Start();
@@ -152,43 +162,24 @@ namespace Grpc.Core
/// cleans up used resources. The returned task finishes when shutdown procedure
/// is complete.
/// </summary>
- public async Task ShutdownAsync()
+ /// <remarks>
+ /// It is strongly recommended to shutdown all previously created servers before exiting from the process.
+ /// </remarks>
+ public Task ShutdownAsync()
{
- lock (myLock)
- {
- GrpcPreconditions.CheckState(startRequested);
- GrpcPreconditions.CheckState(!shutdownRequested);
- shutdownRequested = true;
- }
-
- var cq = environment.CompletionQueues.First(); // any cq will do
- handle.ShutdownAndNotify(HandleServerShutdown, cq);
- await shutdownTcs.Task.ConfigureAwait(false);
- DisposeHandle();
-
- await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
+ return ShutdownInternalAsync(false);
}
/// <summary>
/// Requests server shutdown while cancelling all the in-progress calls.
/// The returned task finishes when shutdown procedure is complete.
/// </summary>
- public async Task KillAsync()
+ /// <remarks>
+ /// It is strongly recommended to shutdown all previously created servers before exiting from the process.
+ /// </remarks>
+ public Task KillAsync()
{
- lock (myLock)
- {
- GrpcPreconditions.CheckState(startRequested);
- GrpcPreconditions.CheckState(!shutdownRequested);
- shutdownRequested = true;
- }
-
- var cq = environment.CompletionQueues.First(); // any cq will do
- handle.ShutdownAndNotify(HandleServerShutdown, cq);
- handle.CancelAllCalls();
- await shutdownTcs.Task.ConfigureAwait(false);
- DisposeHandle();
-
- await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
+ return ShutdownInternalAsync(true);
}
internal void AddCallReference(object call)
@@ -207,6 +198,51 @@ namespace Grpc.Core
}
/// <summary>
+ /// Shuts down the server.
+ /// </summary>
+ private async Task ShutdownInternalAsync(bool kill)
+ {
+ lock (myLock)
+ {
+ GrpcPreconditions.CheckState(!shutdownRequested);
+ shutdownRequested = true;
+ }
+ GrpcEnvironment.UnregisterServer(this);
+
+ var cq = environment.CompletionQueues.First(); // any cq will do
+ handle.ShutdownAndNotify(HandleServerShutdown, cq);
+ if (kill)
+ {
+ handle.CancelAllCalls();
+ }
+ await ShutdownCompleteOrEnvironmentDeadAsync().ConfigureAwait(false);
+
+ DisposeHandle();
+
+ await GrpcEnvironment.ReleaseAsync().ConfigureAwait(false);
+ }
+
+ /// <summary>
+ /// In case the environment's threadpool becomes dead, the shutdown completion will
+ /// never be delivered, but we need to release the environment's handle anyway.
+ /// </summary>
+ private async Task ShutdownCompleteOrEnvironmentDeadAsync()
+ {
+ while (true)
+ {
+ var task = await Task.WhenAny(shutdownTcs.Task, Task.Delay(20)).ConfigureAwait(false);
+ if (shutdownTcs.Task == task)
+ {
+ return;
+ }
+ if (!environment.IsAlive)
+ {
+ return;
+ }
+ }
+ }
+
+ /// <summary>
/// Adds a service definition.
/// </summary>
private void AddServiceDefinitionInternal(ServerServiceDefinition serviceDefinition)
diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
index deb1431ca3..ac08c04bf6 100644
--- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs
+++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs
@@ -63,11 +63,10 @@ namespace Grpc.Core
/// <summary>
/// Creates a new builder object for <c>ServerServiceDefinition</c>.
/// </summary>
- /// <param name="serviceName">The service name.</param>
/// <returns>The builder object.</returns>
- public static Builder CreateBuilder(string serviceName)
+ public static Builder CreateBuilder()
{
- return new Builder(serviceName);
+ return new Builder();
}
/// <summary>
@@ -75,16 +74,13 @@ namespace Grpc.Core
/// </summary>
public class Builder
{
- readonly string serviceName;
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
/// <summary>
/// Creates a new instance of builder.
/// </summary>
- /// <param name="serviceName">The service name.</param>
- public Builder(string serviceName)
+ public Builder()
{
- this.serviceName = serviceName;
}
/// <summary>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index e1609341d9..cb20967680 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "0.15.0.0";
+ public const string CurrentAssemblyFileVersion = "0.16.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "0.15.0-dev";
+ public const string CurrentVersion = "0.16.0-dev";
}
}
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
new file mode 100644
index 0000000000..4729a9346c
--- /dev/null
+++ b/src/csharp/Grpc.Core/project.json
@@ -0,0 +1,42 @@
+{
+ "version": "0.16.0-dev",
+ "title": "gRPC C# Core",
+ "authors": [ "Google Inc." ],
+ "copyright": "Copyright 2015, Google Inc.",
+ "packOptions": {
+ "summary": "Core C# implementation of gRPC - an RPC library and framework",
+ "description": "Core C# implementation of gRPC - an RPC library and framework. See project site for more info.",
+ "owners": [ "grpc-packages" ],
+ "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+ "projectUrl": "https://github.com/grpc/grpc",
+ "requireLicenseAcceptance": false,
+ "tags": [ "gRPC RPC Protocol HTTP/2" ],
+ "files": {
+ "build/net45/": "Grpc.Core.targets",
+ "build/native/bin/windows_x86/": "../nativelibs/windows_x86/grpc_csharp_ext.dll",
+ "build/native/bin/windows_x64/": "../nativelibs/windows_x64/grpc_csharp_ext.dll",
+ "build/native/bin/linux_x86/": "../nativelibs/linux_x86/libgrpc_csharp_ext.so",
+ "build/native/bin/linux_x64/": "../nativelibs/linux_x64/libgrpc_csharp_ext.so",
+ "build/native/bin/macosx_x86/": "../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib",
+ "build/native/bin/macosx_x64/": "../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib"
+ }
+ },
+ "buildOptions": {
+ "embed": [ "../../../etc/roots.pem" ]
+ },
+ "dependencies": {
+ "Ix-Async": "1.2.5"
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027",
+ "System.Threading.Thread": "4.0.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Dotnet.sln b/src/csharp/Grpc.Dotnet.sln
new file mode 100644
index 0000000000..98b3cd54ab
--- /dev/null
+++ b/src/csharp/Grpc.Dotnet.sln
@@ -0,0 +1,100 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core", "Grpc.Core\Grpc.Core.xproj", "{DC9908B6-F291-4FC8-A46D-2EA2551790EC}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.xproj", "{C82631ED-06D1-4458-87BC-8257D12307A8}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.xproj", "{759E23B2-FC04-4695-902D-B073CDED3599}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.xproj", "{C77B792D-FC78-4CE2-9522-B40B0803C636}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.xproj", "{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.xproj", "{58579368-5372-4E67-ACD6-9B59CB9FA698}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.xproj", "{C61714A6-F633-44FB-97F4-C91F425C1D15}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.xproj", "{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.xproj", "{43DAFAC6-5343-4621-960E-A8A977EA3F0B}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.xproj", "{20354386-3E71-4046-A269-3BC2A06F3EC8}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.xproj", "{48EA5BBE-70E2-4198-869D-D7E59C45F30D}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.xproj", "{661B70D7-F56A-46E0-9B81-6227B591B5E7}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.xproj", "{881F7AD1-A84E-47A2-9402-115C63C4031E}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.xproj", "{0EBC910B-8867-4D3E-8686-91F34183D839}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {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
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 35c0646a3f..65bf236def 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -57,4 +57,7 @@
<Name>Grpc.Examples</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="Grpc.Examples.MathClient.project.json" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj
new file mode 100644
index 0000000000..4655bd4377
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.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>fd48deca-1622-4173-b1d9-2101cf5e7c5f</ProjectGuid>
+ <RootNamespace>Grpc.Examples.MathClient</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.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
new file mode 100644
index 0000000000..b254f15af8
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathClient/project.json
@@ -0,0 +1,53 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.Examples": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index 74d79b44d9..26b42b6936 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -57,4 +57,7 @@
<Name>Grpc.Examples</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="Grpc.Examples.MathServer.project.json" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj
new file mode 100644
index 0000000000..38a449e8f2
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.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>58579368-5372-4e67-acd6-9b59cb9fa698</ProjectGuid>
+ <RootNamespace>Grpc.Examples.MathServer</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.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
new file mode 100644
index 0000000000..b254f15af8
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/project.json
@@ -0,0 +1,53 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.Examples": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 3fd28c6528..4c7d89309a 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -69,6 +69,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.Examples.Tests.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj
new file mode 100644
index 0000000000..9cecd18b2e
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.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>c61714a6-f633-44fb-97f4-c91f425c1d15</ProjectGuid>
+ <RootNamespace>Grpc.Examples.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.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index ee11105efe..50dacc2eaa 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -62,7 +62,7 @@ namespace Math.Tests
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
- client = Math.NewClient(channel);
+ client = new Math.MathClient(channel);
}
[TestFixtureTearDown]
@@ -110,7 +110,7 @@ namespace Math.Tests
{
var responses = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
- responses.ConvertAll((n) => n.Num_));
+ responses.Select((n) => n.Num_));
}
}
@@ -162,7 +162,7 @@ namespace Math.Tests
{
using (var call = client.Sum())
{
- var numbers = new List<long> { 10, 20, 30 }.ConvertAll(n => new Num { Num_ = n });
+ var numbers = new List<long> { 10, 20, 30 }.Select(n => new Num { Num_ = n });
await call.RequestStream.WriteAllAsync(numbers);
var result = await call.ResponseAsync;
@@ -185,8 +185,8 @@ namespace Math.Tests
await call.RequestStream.WriteAllAsync(divArgsList);
var result = await call.ResponseStream.ToListAsync();
- CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
- CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder));
+ CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.Select((divReply) => divReply.Quotient));
+ CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.Select((divReply) => divReply.Remainder));
}
}
}
diff --git a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
index ea87802766..1a522cab93 100644
--- a/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.Examples.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@ namespace Grpc.Examples.Tests
{
// 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 DOTNET5_4
+#if NETSTANDARD1_5
return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
#else
return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.Examples.Tests/project.json b/src/csharp/Grpc.Examples.Tests/project.json
new file mode 100644
index 0000000000..d2779e814f
--- /dev/null
+++ b/src/csharp/Grpc.Examples.Tests/project.json
@@ -0,0 +1,55 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.Examples": {
+ "target": "project"
+ },
+ "NUnit": "3.2.0",
+ "NUnitLite": "3.2.0-*"
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 30170ab03c..3dfa84e896 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -69,6 +69,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.Examples.project.json" />
<None Include="packages.config" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.project.json b/src/csharp/Grpc.Examples/Grpc.Examples.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.xproj b/src/csharp/Grpc.Examples/Grpc.Examples.xproj
new file mode 100644
index 0000000000..d1d7e6d981
--- /dev/null
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.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>c77b792d-fc78-4ce2-9522-b40b0803c636</ProjectGuid>
+ <RootNamespace>Grpc.Examples</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.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index d700a18778..25abc51419 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -81,103 +81,12 @@ namespace Math {
get { return global::Math.MathReflection.Descriptor.Services[0]; }
}
- /// <summary>Client for Math</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IMathClient
- {
- /// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
- /// </summary>
- global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
- /// </summary>
- global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
- /// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
- /// </summary>
- AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
- /// </summary>
- AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
- /// <summary>
- /// DivMany accepts an arbitrary number of division args from the client stream
- /// and sends back the results in the reply stream. The stream continues until
- /// the client closes its end; the server does the same after sending all the
- /// replies. The stream ends immediately if either end aborts.
- /// </summary>
- AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// DivMany accepts an arbitrary number of division args from the client stream
- /// and sends back the results in the reply stream. The stream continues until
- /// the client closes its end; the server does the same after sending all the
- /// replies. The stream ends immediately if either end aborts.
- /// </summary>
- AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
- /// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
- /// generates up to limit numbers; otherwise it continues until the call is
- /// canceled. Unlike Fib above, Fib has no final FibReply.
- /// </summary>
- AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
- /// generates up to limit numbers; otherwise it continues until the call is
- /// canceled. Unlike Fib above, Fib has no final FibReply.
- /// </summary>
- AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
- /// <summary>
- /// Sum sums a stream of numbers, returning the final result once the stream
- /// is closed.
- /// </summary>
- AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Sum sums a stream of numbers, returning the final result once the stream
- /// is closed.
- /// </summary>
- AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of Math</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IMath
- {
- /// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
- /// <summary>
- /// DivMany accepts an arbitrary number of division args from the client stream
- /// and sends back the results in the reply stream. The stream continues until
- /// the client closes its end; the server does the same after sending all the
- /// replies. The stream ends immediately if either end aborts.
- /// </summary>
- global::System.Threading.Tasks.Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
- /// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
- /// generates up to limit numbers; otherwise it continues until the call is
- /// canceled. Unlike Fib above, Fib has no final FibReply.
- /// </summary>
- global::System.Threading.Tasks.Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
- /// <summary>
- /// Sum sums a stream of numbers, returning the final result once the stream
- /// is closed.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of Math</summary>
public abstract class MathBase
{
/// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
+ /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ /// and remainder.
/// </summary>
public virtual global::System.Threading.Tasks.Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
{
@@ -196,7 +105,7 @@ namespace Math {
}
/// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// Fib generates numbers in the Fibonacci sequence. If FibArgs.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
@@ -217,52 +126,55 @@ namespace Math {
}
/// <summary>Client for Math</summary>
- #pragma warning disable 0618
- public class MathClient : ClientBase<MathClient>, IMathClient
- #pragma warning restore 0618
+ public class MathClient : ClientBase<MathClient>
{
+ /// <summary>Creates a new client for Math</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public MathClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for Math that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public MathClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected MathClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected MathClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
/// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
+ /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ /// and remainder.
/// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return Div(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
+ /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ /// and remainder.
/// </summary>
public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
{
return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
}
/// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
+ /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ /// and remainder.
/// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
- /// Div divides args.dividend by args.divisor and returns the quotient and
- /// remainder.
+ /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ /// and remainder.
/// </summary>
public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
{
@@ -289,7 +201,7 @@ namespace Math {
return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
}
/// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// Fib generates numbers in the Fibonacci sequence. If FibArgs.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
@@ -298,7 +210,7 @@ namespace Math {
return Fib(request, new CallOptions(headers, deadline, cancellationToken));
}
/// <summary>
- /// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ /// Fib generates numbers in the Fibonacci sequence. If FibArgs.limit > 0, Fib
/// generates up to limit numbers; otherwise it continues until the call is
/// canceled. Unlike Fib above, Fib has no final FibReply.
/// </summary>
@@ -328,30 +240,10 @@ namespace Math {
}
}
- /// <summary>Creates a new client for Math</summary>
- public static MathClient NewClient(Channel channel)
- {
- return new MathClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IMath serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_Div, serviceImpl.Div)
- .AddMethod(__Method_DivMany, serviceImpl.DivMany)
- .AddMethod(__Method_Fib, serviceImpl.Fib)
- .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(MathBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_Div, serviceImpl.Div)
.AddMethod(__Method_DivMany, serviceImpl.DivMany)
.AddMethod(__Method_Fib, serviceImpl.Fib)
diff --git a/src/csharp/Grpc.Examples/project.json b/src/csharp/Grpc.Examples/project.json
new file mode 100644
index 0000000000..7d3f4dcbb1
--- /dev/null
+++ b/src/csharp/Grpc.Examples/project.json
@@ -0,0 +1,27 @@
+{
+ "buildOptions": {
+ },
+
+ "dependencies": {
+ "Grpc.Core": {
+ "target": "project"
+ },
+ "Google.Protobuf": "3.0.0-beta3"
+ },
+ "frameworks": {
+ "net45": {
+ "frameworkAssemblies": {
+ "System.Runtime": "",
+ "System.IO": ""
+ }
+ },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index a5ee4fdb46..aefacfbcc0 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -74,6 +74,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.HealthCheck.Tests.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj
new file mode 100644
index 0000000000..724c5b2a16
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.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>43dafac6-5343-4621-960e-a8a977ea3f0b</ProjectGuid>
+ <RootNamespace>Grpc.HealthCheck.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.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index 070674bae9..25a58fb386 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -65,7 +65,7 @@ namespace Grpc.HealthCheck.Tests
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
- client = Grpc.Health.V1.Health.NewClient(channel);
+ client = new Grpc.Health.V1.Health.HealthClient(channel);
}
[TestFixtureTearDown]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
index 0820523f35..44634671ce 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/NUnitMain.cs
@@ -49,7 +49,7 @@ namespace Grpc.HealthCheck.Tests
{
// 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 DOTNET5_4
+#if NETSTANDARD1_5
return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
#else
return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.HealthCheck.Tests/project.json b/src/csharp/Grpc.HealthCheck.Tests/project.json
new file mode 100644
index 0000000000..74599bd4b9
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/project.json
@@ -0,0 +1,55 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.HealthCheck": {
+ "target": "project"
+ },
+ "NUnit": "3.2.0",
+ "NUnitLite": "3.2.0-*"
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 2697b74f59..7db8b2d38e 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -65,6 +65,7 @@
</ItemGroup>
<ItemGroup>
<None Include="Grpc.HealthCheck.nuspec" />
+ <None Include="Grpc.HealthCheck.project.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj
new file mode 100644
index 0000000000..5806a7af97
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.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>3be4ad0b-2bf0-4d68-b625-f6018ef0dcfa</ProjectGuid>
+ <RootNamespace>Grpc.HealthCheck</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.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 51c6a39b1d..43eea0f22f 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -58,23 +58,6 @@ namespace Grpc.Health.V1 {
get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
}
- /// <summary>Client for Health</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IHealthClient
- {
- global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
- AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of Health</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IHealth
- {
- global::System.Threading.Tasks.Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of Health</summary>
public abstract class HealthBase
{
@@ -86,21 +69,24 @@ namespace Grpc.Health.V1 {
}
/// <summary>Client for Health</summary>
- #pragma warning disable 0618
- public class HealthClient : ClientBase<HealthClient>, IHealthClient
- #pragma warning restore 0618
+ public class HealthClient : ClientBase<HealthClient>
{
+ /// <summary>Creates a new client for Health</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public HealthClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for Health that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public HealthClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected HealthClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected HealthClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -127,27 +113,10 @@ namespace Grpc.Health.V1 {
}
}
- /// <summary>Creates a new client for Health</summary>
- public static HealthClient NewClient(Channel channel)
- {
- return new HealthClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IHealth serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_Check, serviceImpl.Check).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(HealthBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_Check, serviceImpl.Check).Build();
}
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
new file mode 100644
index 0000000000..c4895c2ad3
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -0,0 +1,35 @@
+{
+ "version": "0.16.0-dev",
+ "title": "gRPC C# Healthchecking",
+ "authors": [ "Google Inc." ],
+ "copyright": "Copyright 2015, Google Inc.",
+ "packOptions": {
+ "summary": "Implementation of gRPC health service",
+ "description": "Example implementation of grpc.health.v1 service that can be used for health-checking.",
+ "owners": [ "grpc-packages" ],
+ "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
+ "projectUrl": "https://github.com/grpc/grpc",
+ "requireLicenseAcceptance": false,
+ "tags": [ "gRPC health check" ]
+ },
+ "dependencies": {
+ "Grpc.Core": "0.16.0-dev",
+ "Google.Protobuf": "3.0.0-beta3"
+ },
+ "frameworks": {
+ "net45": {
+ "frameworkAssemblies": {
+ "System.Runtime": "",
+ "System.IO": ""
+ }
+ },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 339a754c02..91fb3ce5bc 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -83,6 +83,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.IntegrationTesting.Client.project.json" />
<None Include="packages.config" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj
new file mode 100644
index 0000000000..7f456cfaef
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.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>48ea5bbe-70e2-4198-869d-d7e59c45f30d</ProjectGuid>
+ <RootNamespace>Grpc.IntegrationTesting.Client</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.IntegrationTesting.Client/project.json b/src/csharp/Grpc.IntegrationTesting.Client/project.json
new file mode 100644
index 0000000000..e5ba04d717
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/project.json
@@ -0,0 +1,56 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.IntegrationTesting": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45",
+ "net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
index 0dc2751b04..dda26a6892 100644
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -59,5 +59,6 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+ <None Include="Grpc.IntegrationTesting.QpsWorker.project.json" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj
new file mode 100644
index 0000000000..15bec443d6
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.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>661b70d7-f56a-46e0-9b81-6227b591b5e7</ProjectGuid>
+ <RootNamespace>Grpc.IntegrationTesting.QpsWorker</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.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
new file mode 100644
index 0000000000..e5ba04d717
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
@@ -0,0 +1,56 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.IntegrationTesting": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45",
+ "net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 27a5650308..f73d99dbd1 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -83,6 +83,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.IntegrationTesting.Server.project.json" />
<None Include="packages.config" />
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj
new file mode 100644
index 0000000000..689eb0b842
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.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>881f7ad1-a84e-47a2-9402-115c63c4031e</ProjectGuid>
+ <RootNamespace>Grpc.IntegrationTesting.Server</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.IntegrationTesting.Server/project.json b/src/csharp/Grpc.IntegrationTesting.Server/project.json
new file mode 100644
index 0000000000..e5ba04d717
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/project.json
@@ -0,0 +1,56 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.IntegrationTesting": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45",
+ "net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
index d6eba74289..8bd3d78913 100644
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -57,4 +57,7 @@
<Name>Grpc.IntegrationTesting</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="Grpc.IntegrationTesting.StressClient.project.json" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
new file mode 100644
index 0000000000..2f4fdcbb47
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
@@ -0,0 +1,19 @@
+<?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)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>0ebc910b-8867-4d3e-8686-91f34183d839</ProjectGuid>
+ <RootNamespace>Grpc.IntegrationTesting.StressClient</RootNamespace>
+ <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+ <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ </PropertyGroup>
+ <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
new file mode 100644
index 0000000000..e5ba04d717
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
@@ -0,0 +1,56 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.IntegrationTesting": {
+ "target": "project"
+ }
+ },
+ "frameworks": {
+ "net45": { },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45",
+ "net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
index 39b9ae08e6..b9c0fe6d0d 100644
--- a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
@@ -211,7 +211,7 @@ namespace Grpc.IntegrationTesting
bool profilerReset = false;
- var client = BenchmarkService.NewClient(channel);
+ var client = new BenchmarkService.BenchmarkServiceClient(channel);
var request = CreateSimpleRequest();
var stopwatch = new Stopwatch();
@@ -237,7 +237,7 @@ namespace Grpc.IntegrationTesting
private async Task RunUnaryAsync(Channel channel, IInterarrivalTimer timer)
{
- var client = BenchmarkService.NewClient(channel);
+ var client = new BenchmarkService.BenchmarkServiceClient(channel);
var request = CreateSimpleRequest();
var stopwatch = new Stopwatch();
@@ -256,7 +256,7 @@ namespace Grpc.IntegrationTesting
private async Task RunStreamingPingPongAsync(Channel channel, IInterarrivalTimer timer)
{
- var client = BenchmarkService.NewClient(channel);
+ var client = new BenchmarkService.BenchmarkServiceClient(channel);
var request = CreateSimpleRequest();
var stopwatch = new Stopwatch();
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
index 37786b6c30..eb7b55a286 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedClientTest.cs
@@ -40,7 +40,6 @@ using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
-using Moq;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -49,14 +48,16 @@ namespace Grpc.IntegrationTesting
{
TestService.TestServiceClient unimplementedClient = new UnimplementedTestServiceClient();
+ // TODO: replace Moq by some mocking library with CoreCLR support.
+#if !NETSTANDARD1_5
[Test]
public void ExpandedParamOverloadCanBeMocked()
{
var expected = new SimpleResponse();
- var mockClient = new Mock<TestService.TestServiceClient>();
+ var mockClient = new Moq.Mock<TestService.TestServiceClient>();
// mocking is relatively clumsy because one needs to specify value for all the optional params.
- mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
+ mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), null, null, CancellationToken.None)).Returns(expected);
Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest()));
}
@@ -66,11 +67,12 @@ namespace Grpc.IntegrationTesting
{
var expected = new SimpleResponse();
- var mockClient = new Mock<TestService.TestServiceClient>();
- mockClient.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<CallOptions>())).Returns(expected);
+ var mockClient = new Moq.Mock<TestService.TestServiceClient>();
+ mockClient.Setup(m => m.UnaryCall(Moq.It.IsAny<SimpleRequest>(), Moq.It.IsAny<CallOptions>())).Returns(expected);
Assert.AreSame(expected, mockClient.Object.UnaryCall(new SimpleRequest(), new CallOptions()));
}
+#endif
[Test]
public void DefaultMethodStubThrows_UnaryCall()
diff --git a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
index 5fd0e14e78..4216dc1d6b 100644
--- a/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GeneratedServiceBaseTest.cs
@@ -40,7 +40,6 @@ using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
-using Moq;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -62,7 +61,7 @@ namespace Grpc.IntegrationTesting
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
- client = TestService.NewClient(channel);
+ client = new TestService.TestServiceClient(channel);
}
[TearDown]
diff --git a/src/csharp/Grpc.IntegrationTesting/GenericService.cs b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
index c6128264ac..53fa1ee5f6 100644
--- a/src/csharp/Grpc.IntegrationTesting/GenericService.cs
+++ b/src/csharp/Grpc.IntegrationTesting/GenericService.cs
@@ -64,7 +64,7 @@ namespace Grpc.IntegrationTesting
public static ServerServiceDefinition BindHandler(DuplexStreamingServerMethod<byte[], byte[]> handler)
{
- return ServerServiceDefinition.CreateBuilder(StreamingCallMethod.ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(StreamingCallMethod, handler).Build();
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 0089049408..3a0764230d 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -129,6 +129,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="Grpc.IntegrationTesting.project.json" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
new file mode 100644
index 0000000000..c2f5bcb163
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
@@ -0,0 +1,8 @@
+{
+ "frameworks": {
+ "net45": { }
+ },
+ "runtimes": {
+ "win": { }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj
new file mode 100644
index 0000000000..357300ecb9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.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>20354386-3e71-4046-a269-3bc2a06f3ec8</ProjectGuid>
+ <RootNamespace>Grpc.IntegrationTesting</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.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index aea40afee2..e27fe5b3d8 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -145,16 +145,26 @@ namespace Grpc.IntegrationTesting
if (options.TestCase == "jwt_token_creds")
{
+#if !NETSTANDARD1_5
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsTrue(googleCredential.IsCreateScopedRequired);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+#else
+ // TODO(jtattermusch): implement this
+ throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
}
if (options.TestCase == "compute_engine_creds")
{
+#if !NETSTANDARD1_5
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(googleCredential.IsCreateScopedRequired);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+#else
+ // TODO(jtattermusch): implement this
+ throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
}
return credentials;
}
@@ -212,6 +222,12 @@ namespace Grpc.IntegrationTesting
case "unimplemented_method":
RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel));
break;
+ case "client_compressed_unary":
+ RunClientCompressedUnary(client);
+ break;
+ case "client_compressed_streaming":
+ await RunClientCompressedStreamingAsync(client);
+ break;
default:
throw new ArgumentException("Unknown test case " + options.TestCase);
}
@@ -230,13 +246,11 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("running large_unary");
var request = new SimpleRequest
{
- ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828)
};
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Console.WriteLine("Passed!");
}
@@ -245,7 +259,7 @@ namespace Grpc.IntegrationTesting
{
Console.WriteLine("running client_streaming");
- var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
+ var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.Select((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
using (var call = client.StreamingInputCall())
{
@@ -265,18 +279,13 @@ namespace Grpc.IntegrationTesting
var request = new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
- ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) }
+ ResponseParameters = { bodySizes.Select((size) => new ResponseParameters { Size = size }) }
};
using (var call = client.StreamingOutputCall(request))
{
var responseList = await call.ResponseStream.ToListAsync();
- foreach (var res in responseList)
- {
- Assert.AreEqual(PayloadType.Compressable, res.Payload.Type);
- }
- CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length));
+ CollectionAssert.AreEqual(bodySizes, responseList.Select((item) => item.Payload.Body.Length));
}
Console.WriteLine("Passed!");
}
@@ -289,46 +298,38 @@ namespace Grpc.IntegrationTesting
{
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 9 } },
Payload = CreateZerosPayload(8)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 2653 } },
Payload = CreateZerosPayload(1828)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 58979 } },
Payload = CreateZerosPayload(45904)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length);
await call.RequestStream.CompleteAsync();
@@ -357,7 +358,6 @@ namespace Grpc.IntegrationTesting
var request = new SimpleRequest
{
- ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828),
FillUsername = true,
@@ -367,7 +367,6 @@ namespace Grpc.IntegrationTesting
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Assert.False(string.IsNullOrEmpty(response.OauthScope));
Assert.True(oauthScope.Contains(response.OauthScope));
@@ -381,7 +380,6 @@ namespace Grpc.IntegrationTesting
var request = new SimpleRequest
{
- ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828),
FillUsername = true,
@@ -390,7 +388,6 @@ namespace Grpc.IntegrationTesting
// not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
- Assert.AreEqual(PayloadType.Compressable, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
@@ -398,6 +395,7 @@ namespace Grpc.IntegrationTesting
public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
{
+#if !NETSTANDARD1_5
Console.WriteLine("running oauth2_auth_token");
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
@@ -415,10 +413,15 @@ namespace Grpc.IntegrationTesting
Assert.True(oauthScope.Contains(response.OauthScope));
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
+#else
+ // TODO(jtattermusch): implement this
+ throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
}
public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
{
+#if !NETSTANDARD1_5
Console.WriteLine("running per_rpc_creds");
ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
@@ -432,6 +435,10 @@ namespace Grpc.IntegrationTesting
Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
+#else
+ // TODO(jtattermusch): implement this
+ throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
}
public static async Task RunCancelAfterBeginAsync(TestService.TestServiceClient client)
@@ -460,13 +467,11 @@ namespace Grpc.IntegrationTesting
{
await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
});
Assert.IsTrue(await call.ResponseStream.MoveNext());
- Assert.AreEqual(PayloadType.Compressable, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
cts.Cancel();
@@ -526,7 +531,6 @@ namespace Grpc.IntegrationTesting
// step 1: test unary call
var request = new SimpleRequest
{
- ResponseType = PayloadType.Compressable,
ResponseSize = 314159,
Payload = CreateZerosPayload(271828)
};
@@ -545,7 +549,6 @@ namespace Grpc.IntegrationTesting
// step 2: test full duplex call
var request = new StreamingOutputCallRequest
{
- ResponseType = PayloadType.Compressable,
ResponseParameters = { new ResponseParameters { Size = 31415 } },
Payload = CreateZerosPayload(27182)
};
@@ -618,21 +621,127 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
+ public static void RunClientCompressedUnary(TestService.TestServiceClient client)
+ {
+ Console.WriteLine("running client_compressed_unary");
+ var probeRequest = new SimpleRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = true // lie about compression
+ },
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828)
+ };
+ var e = Assert.Throws<RpcException>(() => client.UnaryCall(probeRequest, CreateClientCompressionMetadata(false)));
+ Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode);
+
+ var compressedRequest = new SimpleRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = true
+ },
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828)
+ };
+ var response1 = client.UnaryCall(compressedRequest, CreateClientCompressionMetadata(true));
+ Assert.AreEqual(314159, response1.Payload.Body.Length);
+
+ var uncompressedRequest = new SimpleRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = false
+ },
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828)
+ };
+ var response2 = client.UnaryCall(uncompressedRequest, CreateClientCompressionMetadata(false));
+ Assert.AreEqual(314159, response2.Payload.Body.Length);
+
+ Console.WriteLine("Passed!");
+ }
+
+ public static async Task RunClientCompressedStreamingAsync(TestService.TestServiceClient client)
+ {
+ Console.WriteLine("running client_compressed_streaming");
+ try
+ {
+ var probeCall = client.StreamingInputCall(CreateClientCompressionMetadata(false));
+ await probeCall.RequestStream.WriteAsync(new StreamingInputCallRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = true
+ },
+ Payload = CreateZerosPayload(27182)
+ });
+
+ // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+ await probeCall;
+ Assert.Fail();
+ }
+ catch (RpcException e)
+ {
+ Assert.AreEqual(StatusCode.InvalidArgument, e.Status.StatusCode);
+ }
+
+ var call = client.StreamingInputCall(CreateClientCompressionMetadata(true));
+ await call.RequestStream.WriteAsync(new StreamingInputCallRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = true
+ },
+ Payload = CreateZerosPayload(27182)
+ });
+
+ call.RequestStream.WriteOptions = new WriteOptions(WriteFlags.NoCompress);
+ await call.RequestStream.WriteAsync(new StreamingInputCallRequest
+ {
+ ExpectCompressed = new BoolValue
+ {
+ Value = false
+ },
+ Payload = CreateZerosPayload(45904)
+ });
+ await call.RequestStream.CompleteAsync();
+
+ var response = await call.ResponseAsync;
+ Assert.AreEqual(73086, response.AggregatedPayloadSize);
+
+ Console.WriteLine("Passed!");
+ }
+
private static Payload CreateZerosPayload(int size)
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
+ private static Metadata CreateClientCompressionMetadata(bool compressed)
+ {
+ var algorithmName = compressed ? "gzip" : "identity";
+ return new Metadata
+ {
+ { new Metadata.Entry(Metadata.CompressionRequestAlgorithmMetadataKey, algorithmName) }
+ };
+ }
+
// extracts the client_email field from service account file used for auth test cases
private static string GetEmailFromServiceAccountFile()
{
+#if !NETSTANDARD1_5
string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
Assert.IsNotNull(keyFile);
-
var jobject = JObject.Parse(File.ReadAllText(keyFile));
string email = jobject.GetValue("client_email").Value<string>();
Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
return email;
+#else
+ // TODO(jtattermusch): implement this
+ throw new NotImplementedException("Not supported on CoreCLR yet");
+#endif
}
private static Metadata CreateTestMetadata()
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 4ee1ff5ec8..f907f630da 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -69,7 +69,7 @@ namespace Grpc.IntegrationTesting
};
int port = server.Ports.Single().BoundPort;
channel = new Channel(Host, port, TestCredentials.CreateSslCredentials(), options);
- client = TestService.NewClient(channel);
+ client = new TestService.TestServiceClient(channel);
}
[TestFixtureTearDown]
@@ -148,7 +148,7 @@ namespace Grpc.IntegrationTesting
[Test]
public void UnimplementedMethod()
{
- InteropClient.RunUnimplementedMethod(UnimplementedService.NewClient(channel));
+ InteropClient.RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel));
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index d42501aa5b..1240db128b 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -24,46 +24,48 @@ namespace Grpc.Testing {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"CiVzcmMvcHJvdG8vZ3JwYy90ZXN0aW5nL21lc3NhZ2VzLnByb3RvEgxncnBj",
- "LnRlc3RpbmciQAoHUGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0",
- "aW5nLlBheWxvYWRUeXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIM",
- "CgRjb2RlGAEgASgFEg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVl",
- "c3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXls",
- "b2FkVHlwZRIVCg1yZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyAB",
- "KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQg",
- "ASgIEhgKEGZpbGxfb2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29t",
- "cHJlc3Npb24YBiABKA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBl",
- "EjEKD3Jlc3BvbnNlX3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hv",
- "U3RhdHVzIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
- "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
- "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
- "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
- "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
- "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
- "BRITCgtpbnRlcnZhbF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
- "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
- "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
- "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
- "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJl",
- "c3Npb24YBiABKA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEK",
- "D3Jlc3BvbnNlX3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3Rh",
- "dHVzIkUKG1N0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2Fk",
- "GAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiMwoPUmVjb25uZWN0UGFy",
- "YW1zEiAKGG1heF9yZWNvbm5lY3RfYmFja29mZl9tcxgBIAEoBSIzCg1SZWNv",
- "bm5lY3RJbmZvEg4KBnBhc3NlZBgBIAEoCBISCgpiYWNrb2ZmX21zGAIgAygF",
- "Kj8KC1BheWxvYWRUeXBlEhAKDENPTVBSRVNTQUJMRRAAEhIKDlVOQ09NUFJF",
- "U1NBQkxFEAESCgoGUkFORE9NEAIqMgoPQ29tcHJlc3Npb25UeXBlEggKBE5P",
- "TkUQABIICgRHWklQEAESCwoHREVGTEFURRACYgZwcm90bzM="));
+ "LnRlc3RpbmciGgoJQm9vbFZhbHVlEg0KBXZhbHVlGAEgASgIIkAKB1BheWxv",
+ "YWQSJwoEdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIM",
+ "CgRib2R5GAIgASgMIisKCkVjaG9TdGF0dXMSDAoEY29kZRgBIAEoBRIPCgdt",
+ "ZXNzYWdlGAIgASgJIs4CCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5",
+ "cGUYASABKA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9u",
+ "c2Vfc2l6ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5n",
+ "LlBheWxvYWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRo",
+ "X3Njb3BlGAUgASgIEjQKE3Jlc3BvbnNlX2NvbXByZXNzZWQYBiABKAsyFy5n",
+ "cnBjLnRlc3RpbmcuQm9vbFZhbHVlEjEKD3Jlc3BvbnNlX3N0YXR1cxgHIAEo",
+ "CzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzEjIKEWV4cGVjdF9jb21wcmVz",
+ "c2VkGAggASgLMhcuZ3JwYy50ZXN0aW5nLkJvb2xWYWx1ZSJfCg5TaW1wbGVS",
+ "ZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
+ "YWQSEAoIdXNlcm5hbWUYAiABKAkSEwoLb2F1dGhfc2NvcGUYAyABKAkidwoZ",
+ "U3RyZWFtaW5nSW5wdXRDYWxsUmVxdWVzdBImCgdwYXlsb2FkGAEgASgLMhUu",
+ "Z3JwYy50ZXN0aW5nLlBheWxvYWQSMgoRZXhwZWN0X2NvbXByZXNzZWQYAiAB",
+ "KAsyFy5ncnBjLnRlc3RpbmcuQm9vbFZhbHVlIj0KGlN0cmVhbWluZ0lucHV0",
+ "Q2FsbFJlc3BvbnNlEh8KF2FnZ3JlZ2F0ZWRfcGF5bG9hZF9zaXplGAEgASgF",
+ "ImQKElJlc3BvbnNlUGFyYW1ldGVycxIMCgRzaXplGAEgASgFEhMKC2ludGVy",
+ "dmFsX3VzGAIgASgFEisKCmNvbXByZXNzZWQYAyABKAsyFy5ncnBjLnRlc3Rp",
+ "bmcuQm9vbFZhbHVlIugBChpTdHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBIw",
+ "Cg1yZXNwb25zZV90eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU",
+ "eXBlEj0KE3Jlc3BvbnNlX3BhcmFtZXRlcnMYAiADKAsyIC5ncnBjLnRlc3Rp",
+ "bmcuUmVzcG9uc2VQYXJhbWV0ZXJzEiYKB3BheWxvYWQYAyABKAsyFS5ncnBj",
+ "LnRlc3RpbmcuUGF5bG9hZBIxCg9yZXNwb25zZV9zdGF0dXMYByABKAsyGC5n",
+ "cnBjLnRlc3RpbmcuRWNob1N0YXR1cyJFChtTdHJlYW1pbmdPdXRwdXRDYWxs",
+ "UmVzcG9uc2USJgoHcGF5bG9hZBgBIAEoCzIVLmdycGMudGVzdGluZy5QYXls",
+ "b2FkIjMKD1JlY29ubmVjdFBhcmFtcxIgChhtYXhfcmVjb25uZWN0X2JhY2tv",
+ "ZmZfbXMYASABKAUiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQYASABKAgS",
+ "EgoKYmFja29mZl9tcxgCIAMoBSofCgtQYXlsb2FkVHlwZRIQCgxDT01QUkVT",
+ "U0FCTEUQAGIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedClrTypeInfo[] {
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.BoolValue), global::Grpc.Testing.BoolValue.Parser, new[]{ "Value" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.Payload), global::Grpc.Testing.Payload.Parser, new[]{ "Type", "Body" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.EchoStatus), global::Grpc.Testing.EchoStatus.Parser, new[]{ "Code", "Message" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleRequest), global::Grpc.Testing.SimpleRequest.Parser, new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompressed", "ResponseStatus", "ExpectCompressed" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.SimpleResponse), global::Grpc.Testing.SimpleResponse.Parser, new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), global::Grpc.Testing.StreamingInputCallRequest.Parser, new[]{ "Payload", "ExpectCompressed" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), global::Grpc.Testing.StreamingInputCallResponse.Parser, new[]{ "AggregatedPayloadSize" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ResponseParameters), global::Grpc.Testing.ResponseParameters.Parser, new[]{ "Size", "IntervalUs", "Compressed" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), global::Grpc.Testing.StreamingOutputCallRequest.Parser, new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseStatus" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), global::Grpc.Testing.StreamingOutputCallResponse.Parser, new[]{ "Payload" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectParams), global::Grpc.Testing.ReconnectParams.Parser, new[]{ "MaxReconnectBackoffMs" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Grpc.Testing.ReconnectInfo), global::Grpc.Testing.ReconnectInfo.Parser, new[]{ "Passed", "BackoffMs" }, null, null, null)
@@ -74,6 +76,7 @@ namespace Grpc.Testing {
}
#region Enums
/// <summary>
+ /// DEPRECATED, don't use. To be removed shortly.
/// The type of payload that should be returned.
/// </summary>
public enum PayloadType {
@@ -81,31 +84,122 @@ namespace Grpc.Testing {
/// Compressable text format.
/// </summary>
[pbr::OriginalName("COMPRESSABLE")] Compressable = 0,
- /// <summary>
- /// Uncompressable binary format.
- /// </summary>
- [pbr::OriginalName("UNCOMPRESSABLE")] Uncompressable = 1,
- /// <summary>
- /// Randomly chosen from all other formats defined in this enum.
- /// </summary>
- [pbr::OriginalName("RANDOM")] Random = 2,
}
+ #endregion
+
+ #region Messages
/// <summary>
- /// Compression algorithms
+ /// TODO(dgq): Go back to using well-known types once
+ /// https://github.com/grpc/grpc/issues/6980 has been fixed.
+ /// import "google/protobuf/wrappers.proto";
/// </summary>
- public enum CompressionType {
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class BoolValue : pb::IMessage<BoolValue> {
+ private static readonly pb::MessageParser<BoolValue> _parser = new pb::MessageParser<BoolValue>(() => new BoolValue());
+ public static pb::MessageParser<BoolValue> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[0]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public BoolValue() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public BoolValue(BoolValue other) : this() {
+ value_ = other.value_;
+ }
+
+ public BoolValue Clone() {
+ return new BoolValue(this);
+ }
+
+ /// <summary>Field number for the "value" field.</summary>
+ public const int ValueFieldNumber = 1;
+ private bool value_;
/// <summary>
- /// No compression
+ /// The bool value.
/// </summary>
- [pbr::OriginalName("NONE")] None = 0,
- [pbr::OriginalName("GZIP")] Gzip = 1,
- [pbr::OriginalName("DEFLATE")] Deflate = 2,
- }
+ public bool Value {
+ get { return value_; }
+ set {
+ value_ = value;
+ }
+ }
- #endregion
+ public override bool Equals(object other) {
+ return Equals(other as BoolValue);
+ }
+
+ public bool Equals(BoolValue other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Value != other.Value) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Value != false) hash ^= Value.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Value != false) {
+ output.WriteRawTag(8);
+ output.WriteBool(Value);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Value != false) {
+ size += 1 + 1;
+ }
+ return size;
+ }
+
+ public void MergeFrom(BoolValue other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Value != false) {
+ Value = other.Value;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Value = input.ReadBool();
+ break;
+ }
+ }
+ }
+ }
+
+ }
- #region Messages
/// <summary>
/// A block of data, to simply increase gRPC message size.
/// </summary>
@@ -115,7 +209,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<Payload> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[0]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[1]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -141,6 +235,7 @@ namespace Grpc.Testing {
public const int TypeFieldNumber = 1;
private global::Grpc.Testing.PayloadType type_ = 0;
/// <summary>
+ /// DEPRECATED, don't use. To be removed shortly.
/// The type of data in body.
/// </summary>
public global::Grpc.Testing.PayloadType Type {
@@ -255,7 +350,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[1]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -388,7 +483,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[2]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -407,8 +502,9 @@ namespace Grpc.Testing {
Payload = other.payload_ != null ? other.Payload.Clone() : null;
fillUsername_ = other.fillUsername_;
fillOauthScope_ = other.fillOauthScope_;
- responseCompression_ = other.responseCompression_;
+ ResponseCompressed = other.responseCompressed_ != null ? other.ResponseCompressed.Clone() : null;
ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
+ ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null;
}
public SimpleRequest Clone() {
@@ -419,6 +515,7 @@ namespace Grpc.Testing {
public const int ResponseTypeFieldNumber = 1;
private global::Grpc.Testing.PayloadType responseType_ = 0;
/// <summary>
+ /// DEPRECATED, don't use. To be removed shortly.
/// Desired payload type in the response from the server.
/// If response_type is RANDOM, server randomly chooses one from other formats.
/// </summary>
@@ -434,7 +531,6 @@ namespace Grpc.Testing {
private int responseSize_;
/// <summary>
/// Desired payload size in the response from the server.
- /// If response_type is COMPRESSABLE, this denotes the size before compression.
/// </summary>
public int ResponseSize {
get { return responseSize_; }
@@ -482,16 +578,19 @@ namespace Grpc.Testing {
}
}
- /// <summary>Field number for the "response_compression" field.</summary>
- public const int ResponseCompressionFieldNumber = 6;
- private global::Grpc.Testing.CompressionType responseCompression_ = 0;
+ /// <summary>Field number for the "response_compressed" field.</summary>
+ public const int ResponseCompressedFieldNumber = 6;
+ private global::Grpc.Testing.BoolValue responseCompressed_;
/// <summary>
- /// Compression algorithm to be used by the server for the response (stream)
+ /// Whether to request the server to compress the response. This field is
+ /// "nullable" in order to interoperate seamlessly with clients not able to
+ /// implement the full compression tests by introspecting the call to verify
+ /// the response's compression status.
/// </summary>
- public global::Grpc.Testing.CompressionType ResponseCompression {
- get { return responseCompression_; }
+ public global::Grpc.Testing.BoolValue ResponseCompressed {
+ get { return responseCompressed_; }
set {
- responseCompression_ = value;
+ responseCompressed_ = value;
}
}
@@ -508,6 +607,19 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "expect_compressed" field.</summary>
+ public const int ExpectCompressedFieldNumber = 8;
+ private global::Grpc.Testing.BoolValue expectCompressed_;
+ /// <summary>
+ /// Whether the server should expect this request to be compressed.
+ /// </summary>
+ public global::Grpc.Testing.BoolValue ExpectCompressed {
+ get { return expectCompressed_; }
+ set {
+ expectCompressed_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as SimpleRequest);
}
@@ -524,8 +636,9 @@ namespace Grpc.Testing {
if (!object.Equals(Payload, other.Payload)) return false;
if (FillUsername != other.FillUsername) return false;
if (FillOauthScope != other.FillOauthScope) return false;
- if (ResponseCompression != other.ResponseCompression) return false;
+ if (!object.Equals(ResponseCompressed, other.ResponseCompressed)) return false;
if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
+ if (!object.Equals(ExpectCompressed, other.ExpectCompressed)) return false;
return true;
}
@@ -536,8 +649,9 @@ namespace Grpc.Testing {
if (payload_ != null) hash ^= Payload.GetHashCode();
if (FillUsername != false) hash ^= FillUsername.GetHashCode();
if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
- if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
+ if (responseCompressed_ != null) hash ^= ResponseCompressed.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
+ if (expectCompressed_ != null) hash ^= ExpectCompressed.GetHashCode();
return hash;
}
@@ -566,14 +680,18 @@ namespace Grpc.Testing {
output.WriteRawTag(40);
output.WriteBool(FillOauthScope);
}
- if (ResponseCompression != 0) {
- output.WriteRawTag(48);
- output.WriteEnum((int) ResponseCompression);
+ if (responseCompressed_ != null) {
+ output.WriteRawTag(50);
+ output.WriteMessage(ResponseCompressed);
}
if (responseStatus_ != null) {
output.WriteRawTag(58);
output.WriteMessage(ResponseStatus);
}
+ if (expectCompressed_ != null) {
+ output.WriteRawTag(66);
+ output.WriteMessage(ExpectCompressed);
+ }
}
public int CalculateSize() {
@@ -593,12 +711,15 @@ namespace Grpc.Testing {
if (FillOauthScope != false) {
size += 1 + 1;
}
- if (ResponseCompression != 0) {
- size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+ if (responseCompressed_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseCompressed);
}
if (responseStatus_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
}
+ if (expectCompressed_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExpectCompressed);
+ }
return size;
}
@@ -624,8 +745,11 @@ namespace Grpc.Testing {
if (other.FillOauthScope != false) {
FillOauthScope = other.FillOauthScope;
}
- if (other.ResponseCompression != 0) {
- ResponseCompression = other.ResponseCompression;
+ if (other.responseCompressed_ != null) {
+ if (responseCompressed_ == null) {
+ responseCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ ResponseCompressed.MergeFrom(other.ResponseCompressed);
}
if (other.responseStatus_ != null) {
if (responseStatus_ == null) {
@@ -633,6 +757,12 @@ namespace Grpc.Testing {
}
ResponseStatus.MergeFrom(other.ResponseStatus);
}
+ if (other.expectCompressed_ != null) {
+ if (expectCompressed_ == null) {
+ expectCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ ExpectCompressed.MergeFrom(other.ExpectCompressed);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -665,8 +795,11 @@ namespace Grpc.Testing {
FillOauthScope = input.ReadBool();
break;
}
- case 48: {
- responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+ case 50: {
+ if (responseCompressed_ == null) {
+ responseCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ input.ReadMessage(responseCompressed_);
break;
}
case 58: {
@@ -676,6 +809,13 @@ namespace Grpc.Testing {
input.ReadMessage(responseStatus_);
break;
}
+ case 66: {
+ if (expectCompressed_ == null) {
+ expectCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ input.ReadMessage(expectCompressed_);
+ break;
+ }
}
}
}
@@ -691,7 +831,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[3]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[4]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -867,7 +1007,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[4]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[5]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -882,6 +1022,7 @@ namespace Grpc.Testing {
public StreamingInputCallRequest(StreamingInputCallRequest other) : this() {
Payload = other.payload_ != null ? other.Payload.Clone() : null;
+ ExpectCompressed = other.expectCompressed_ != null ? other.ExpectCompressed.Clone() : null;
}
public StreamingInputCallRequest Clone() {
@@ -901,6 +1042,22 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "expect_compressed" field.</summary>
+ public const int ExpectCompressedFieldNumber = 2;
+ private global::Grpc.Testing.BoolValue expectCompressed_;
+ /// <summary>
+ /// Whether the server should expect this request to be compressed. This field
+ /// is "nullable" in order to interoperate seamlessly with servers not able to
+ /// implement the full compression tests by introspecting the call to verify
+ /// the request's compression status.
+ /// </summary>
+ public global::Grpc.Testing.BoolValue ExpectCompressed {
+ get { return expectCompressed_; }
+ set {
+ expectCompressed_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as StreamingInputCallRequest);
}
@@ -913,12 +1070,14 @@ namespace Grpc.Testing {
return true;
}
if (!object.Equals(Payload, other.Payload)) return false;
+ if (!object.Equals(ExpectCompressed, other.ExpectCompressed)) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (payload_ != null) hash ^= Payload.GetHashCode();
+ if (expectCompressed_ != null) hash ^= ExpectCompressed.GetHashCode();
return hash;
}
@@ -931,6 +1090,10 @@ namespace Grpc.Testing {
output.WriteRawTag(10);
output.WriteMessage(Payload);
}
+ if (expectCompressed_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(ExpectCompressed);
+ }
}
public int CalculateSize() {
@@ -938,6 +1101,9 @@ namespace Grpc.Testing {
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ if (expectCompressed_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ExpectCompressed);
+ }
return size;
}
@@ -951,6 +1117,12 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
+ if (other.expectCompressed_ != null) {
+ if (expectCompressed_ == null) {
+ expectCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ ExpectCompressed.MergeFrom(other.ExpectCompressed);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -967,6 +1139,13 @@ namespace Grpc.Testing {
input.ReadMessage(payload_);
break;
}
+ case 18: {
+ if (expectCompressed_ == null) {
+ expectCompressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ input.ReadMessage(expectCompressed_);
+ break;
+ }
}
}
}
@@ -982,7 +1161,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[5]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[6]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1091,7 +1270,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[6]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[7]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1107,6 +1286,7 @@ namespace Grpc.Testing {
public ResponseParameters(ResponseParameters other) : this() {
size_ = other.size_;
intervalUs_ = other.intervalUs_;
+ Compressed = other.compressed_ != null ? other.Compressed.Clone() : null;
}
public ResponseParameters Clone() {
@@ -1118,7 +1298,6 @@ namespace Grpc.Testing {
private int size_;
/// <summary>
/// Desired payload sizes in responses from the server.
- /// If response_type is COMPRESSABLE, this denotes the size before compression.
/// </summary>
public int Size {
get { return size_; }
@@ -1141,6 +1320,22 @@ namespace Grpc.Testing {
}
}
+ /// <summary>Field number for the "compressed" field.</summary>
+ public const int CompressedFieldNumber = 3;
+ private global::Grpc.Testing.BoolValue compressed_;
+ /// <summary>
+ /// Whether to request the server to compress the response. This field is
+ /// "nullable" in order to interoperate seamlessly with clients not able to
+ /// implement the full compression tests by introspecting the call to verify
+ /// the response's compression status.
+ /// </summary>
+ public global::Grpc.Testing.BoolValue Compressed {
+ get { return compressed_; }
+ set {
+ compressed_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as ResponseParameters);
}
@@ -1154,6 +1349,7 @@ namespace Grpc.Testing {
}
if (Size != other.Size) return false;
if (IntervalUs != other.IntervalUs) return false;
+ if (!object.Equals(Compressed, other.Compressed)) return false;
return true;
}
@@ -1161,6 +1357,7 @@ namespace Grpc.Testing {
int hash = 1;
if (Size != 0) hash ^= Size.GetHashCode();
if (IntervalUs != 0) hash ^= IntervalUs.GetHashCode();
+ if (compressed_ != null) hash ^= Compressed.GetHashCode();
return hash;
}
@@ -1177,6 +1374,10 @@ namespace Grpc.Testing {
output.WriteRawTag(16);
output.WriteInt32(IntervalUs);
}
+ if (compressed_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(Compressed);
+ }
}
public int CalculateSize() {
@@ -1187,6 +1388,9 @@ namespace Grpc.Testing {
if (IntervalUs != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(IntervalUs);
}
+ if (compressed_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Compressed);
+ }
return size;
}
@@ -1200,6 +1404,12 @@ namespace Grpc.Testing {
if (other.IntervalUs != 0) {
IntervalUs = other.IntervalUs;
}
+ if (other.compressed_ != null) {
+ if (compressed_ == null) {
+ compressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ Compressed.MergeFrom(other.Compressed);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -1217,6 +1427,13 @@ namespace Grpc.Testing {
IntervalUs = input.ReadInt32();
break;
}
+ case 26: {
+ if (compressed_ == null) {
+ compressed_ = new global::Grpc.Testing.BoolValue();
+ }
+ input.ReadMessage(compressed_);
+ break;
+ }
}
}
}
@@ -1232,7 +1449,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[7]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[8]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1249,7 +1466,6 @@ namespace Grpc.Testing {
responseType_ = other.responseType_;
responseParameters_ = other.responseParameters_.Clone();
Payload = other.payload_ != null ? other.Payload.Clone() : null;
- responseCompression_ = other.responseCompression_;
ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
@@ -1261,6 +1477,7 @@ namespace Grpc.Testing {
public const int ResponseTypeFieldNumber = 1;
private global::Grpc.Testing.PayloadType responseType_ = 0;
/// <summary>
+ /// DEPRECATED, don't use. To be removed shortly.
/// Desired payload type in the response from the server.
/// If response_type is RANDOM, the payload from each response in the stream
/// might be of different types. This is to simulate a mixed type of payload
@@ -1298,19 +1515,6 @@ namespace Grpc.Testing {
}
}
- /// <summary>Field number for the "response_compression" field.</summary>
- public const int ResponseCompressionFieldNumber = 6;
- private global::Grpc.Testing.CompressionType responseCompression_ = 0;
- /// <summary>
- /// Compression algorithm to be used by the server for the response (stream)
- /// </summary>
- public global::Grpc.Testing.CompressionType ResponseCompression {
- get { return responseCompression_; }
- set {
- responseCompression_ = value;
- }
- }
-
/// <summary>Field number for the "response_status" field.</summary>
public const int ResponseStatusFieldNumber = 7;
private global::Grpc.Testing.EchoStatus responseStatus_;
@@ -1338,7 +1542,6 @@ namespace Grpc.Testing {
if (ResponseType != other.ResponseType) return false;
if(!responseParameters_.Equals(other.responseParameters_)) return false;
if (!object.Equals(Payload, other.Payload)) return false;
- if (ResponseCompression != other.ResponseCompression) return false;
if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@@ -1348,7 +1551,6 @@ namespace Grpc.Testing {
if (ResponseType != 0) hash ^= ResponseType.GetHashCode();
hash ^= responseParameters_.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
- if (ResponseCompression != 0) hash ^= ResponseCompression.GetHashCode();
if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -1367,10 +1569,6 @@ namespace Grpc.Testing {
output.WriteRawTag(26);
output.WriteMessage(Payload);
}
- if (ResponseCompression != 0) {
- output.WriteRawTag(48);
- output.WriteEnum((int) ResponseCompression);
- }
if (responseStatus_ != null) {
output.WriteRawTag(58);
output.WriteMessage(ResponseStatus);
@@ -1386,9 +1584,6 @@ namespace Grpc.Testing {
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
- if (ResponseCompression != 0) {
- size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
- }
if (responseStatus_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
}
@@ -1409,9 +1604,6 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
- if (other.ResponseCompression != 0) {
- ResponseCompression = other.ResponseCompression;
- }
if (other.responseStatus_ != null) {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
@@ -1442,10 +1634,6 @@ namespace Grpc.Testing {
input.ReadMessage(payload_);
break;
}
- case 48: {
- responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
- break;
- }
case 58: {
if (responseStatus_ == null) {
responseStatus_ = new global::Grpc.Testing.EchoStatus();
@@ -1468,7 +1656,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[8]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1584,7 +1772,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ReconnectParams> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[9]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1692,7 +1880,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[10]; }
+ get { return global::Grpc.Testing.MessagesReflection.Descriptor.MessageTypes[11]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index f95af5008f..eb3bb8a28b 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -40,7 +40,6 @@ using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
-using Moq;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -52,19 +51,14 @@ namespace Grpc.IntegrationTesting
Channel channel;
TestService.TestServiceClient client;
List<ChannelOption> options;
- Mock<TestService.TestServiceBase> serviceMock;
AsyncAuthInterceptor asyncAuthInterceptor;
[SetUp]
public void Init()
{
- serviceMock = new Mock<TestService.TestServiceBase>();
- serviceMock.Setup(m => m.UnaryCall(It.IsAny<SimpleRequest>(), It.IsAny<ServerCallContext>()))
- .Returns(new Func<SimpleRequest, ServerCallContext, Task<SimpleResponse>>(UnaryCallHandler));
-
server = new Server
{
- Services = { TestService.BindService(serviceMock.Object) },
+ Services = { TestService.BindService(new FakeTestService()) },
Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateSslServerCredentials() } }
};
server.Start();
@@ -94,26 +88,29 @@ namespace Grpc.IntegrationTesting
var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(),
CallCredentials.FromInterceptor(asyncAuthInterceptor));
channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
- client = TestService.NewClient(channel);
+ client = new TestService.TestServiceClient(channel);
- client.UnaryCall(new SimpleRequest {});
+ client.UnaryCall(new SimpleRequest { });
}
[Test]
public void MetadataCredentials_PerCall()
{
channel = new Channel(Host, server.Ports.Single().BoundPort, TestCredentials.CreateSslCredentials(), options);
- client = TestService.NewClient(channel);
+ client = new TestService.TestServiceClient(channel);
var callCredentials = CallCredentials.FromInterceptor(asyncAuthInterceptor);
client.UnaryCall(new SimpleRequest { }, new CallOptions(credentials: callCredentials));
}
- private Task<SimpleResponse> UnaryCallHandler(SimpleRequest request, ServerCallContext context)
+ private class FakeTestService : TestService.TestServiceBase
{
- var authToken = context.RequestHeaders.First((entry) => entry.Key == "authorization").Value;
- Assert.AreEqual("SECRET_TOKEN", authToken);
- return Task.FromResult(new SimpleResponse());
+ public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+ {
+ var authToken = context.RequestHeaders.First((entry) => entry.Key == "authorization").Value;
+ Assert.AreEqual("SECRET_TOKEN", authToken);
+ return Task.FromResult(new SimpleResponse());
+ }
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index 9d31d1c514..040798e3c2 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -72,53 +72,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.MetricsReflection.Descriptor.Services[0]; }
}
- /// <summary>Client for MetricsService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IMetricsServiceClient
- {
- /// <summary>
- /// Returns the values of all the gauges that are currently being maintained by
- /// the service
- /// </summary>
- AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Returns the values of all the gauges that are currently being maintained by
- /// the service
- /// </summary>
- AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options);
- /// <summary>
- /// Returns the value of one gauge
- /// </summary>
- global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Returns the value of one gauge
- /// </summary>
- global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options);
- /// <summary>
- /// Returns the value of one gauge
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Returns the value of one gauge
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of MetricsService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IMetricsService
- {
- /// <summary>
- /// Returns the values of all the gauges that are currently being maintained by
- /// the service
- /// </summary>
- global::System.Threading.Tasks.Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context);
- /// <summary>
- /// Returns the value of one gauge
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of MetricsService</summary>
public abstract class MetricsServiceBase
{
@@ -142,21 +95,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for MetricsService</summary>
- #pragma warning disable 0618
- public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
- #pragma warning restore 0618
+ public class MetricsServiceClient : ClientBase<MetricsServiceClient>
{
+ /// <summary>Creates a new client for MetricsService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public MetricsServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for MetricsService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public MetricsServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected MetricsServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected MetricsServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -211,28 +167,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for MetricsService</summary>
- public static MetricsServiceClient NewClient(Channel channel)
- {
- return new MetricsServiceClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
- .AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_GetAllGauges, serviceImpl.GetAllGauges)
.AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
}
diff --git a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
index d8902de08f..100ff0b5de 100644
--- a/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
+++ b/src/csharp/Grpc.IntegrationTesting/NUnitMain.cs
@@ -49,7 +49,7 @@ namespace Grpc.IntegrationTesting
{
// 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 DOTNET5_4
+#if NETSTANDARD1_5
return new AutoRun(typeof(NUnitMain).GetTypeInfo().Assembly).Execute(args, new ExtendedTextWrapper(Console.Out), Console.In);
#else
return new AutoRun().Execute(args);
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index f7071ebf6b..e205dea93e 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -67,58 +67,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[0]; }
}
- /// <summary>Client for BenchmarkService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IBenchmarkServiceClient
- {
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of BenchmarkService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IBenchmarkService
- {
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
- /// <summary>
- /// One request followed by one response.
- /// The server returns the client payload as-is.
- /// </summary>
- global::System.Threading.Tasks.Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of BenchmarkService</summary>
public abstract class BenchmarkServiceBase
{
@@ -143,21 +91,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for BenchmarkService</summary>
- #pragma warning disable 0618
- public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
- #pragma warning restore 0618
+ public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>
{
+ /// <summary>Creates a new client for BenchmarkService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public BenchmarkServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for BenchmarkService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public BenchmarkServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected BenchmarkServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected BenchmarkServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -216,28 +167,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for BenchmarkService</summary>
- public static BenchmarkServiceClient NewClient(Channel channel)
- {
- return new BenchmarkServiceClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
- .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
.AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
}
@@ -289,112 +222,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[1]; }
}
- /// <summary>Client for WorkerService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IWorkerServiceClient
- {
- /// <summary>
- /// Start server with specified workload.
- /// First request sent specifies the ServerConfig followed by ServerStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test server
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Start server with specified workload.
- /// First request sent specifies the ServerConfig followed by ServerStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test server
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
- /// <summary>
- /// Start client with specified workload.
- /// First request sent specifies the ClientConfig followed by ClientStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test client
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Start client with specified workload.
- /// First request sent specifies the ClientConfig followed by ClientStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test client
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
- /// <summary>
- /// Just return the core count - unary call
- /// </summary>
- global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Just return the core count - unary call
- /// </summary>
- global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options);
- /// <summary>
- /// Just return the core count - unary call
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Just return the core count - unary call
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options);
- /// <summary>
- /// Quit this worker
- /// </summary>
- global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Quit this worker
- /// </summary>
- global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options);
- /// <summary>
- /// Quit this worker
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// Quit this worker
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of WorkerService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IWorkerService
- {
- /// <summary>
- /// Start server with specified workload.
- /// First request sent specifies the ServerConfig followed by ServerStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test server
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- global::System.Threading.Tasks.Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
- /// <summary>
- /// Start client with specified workload.
- /// First request sent specifies the ClientConfig followed by ClientStatus
- /// response. After that, a "Mark" can be sent anytime to request the latest
- /// stats. Closing the stream will initiate shutdown of the test client
- /// and once the shutdown has finished, the OK status is sent to terminate
- /// this RPC.
- /// </summary>
- global::System.Threading.Tasks.Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
- /// <summary>
- /// Just return the core count - unary call
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
- /// <summary>
- /// Quit this worker
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of WorkerService</summary>
public abstract class WorkerServiceBase
{
@@ -443,21 +270,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for WorkerService</summary>
- #pragma warning disable 0618
- public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
- #pragma warning restore 0618
+ public class WorkerServiceClient : ClientBase<WorkerServiceClient>
{
+ /// <summary>Creates a new client for WorkerService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public WorkerServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for WorkerService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public WorkerServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected WorkerServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected WorkerServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -572,30 +402,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for WorkerService</summary>
- public static WorkerServiceClient NewClient(Channel channel)
- {
- return new WorkerServiceClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_RunServer, serviceImpl.RunServer)
- .AddMethod(__Method_RunClient, serviceImpl.RunClient)
- .AddMethod(__Method_CoreCount, serviceImpl.CoreCount)
- .AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_RunServer, serviceImpl.RunServer)
.AddMethod(__Method_RunClient, serviceImpl.RunClient)
.AddMethod(__Method_CoreCount, serviceImpl.CoreCount)
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
index 3df45b5f70..f85e272711 100644
--- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -79,7 +79,7 @@ namespace Grpc.IntegrationTesting
};
channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
- client = TestService.NewClient(channel);
+ client = new TestService.TestServiceClient(channel);
}
[TestFixtureTearDown]
diff --git a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
index 4d6ca7ece5..74ee040ae4 100644
--- a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
@@ -148,7 +148,7 @@ namespace Grpc.IntegrationTesting
channels.Add(channel);
for (int j = 0; j < options.NumStubsPerChannel; j++)
{
- var client = TestService.NewClient(channel);
+ var client = new TestService.TestServiceClient(channel);
var task = Task.Factory.StartNew(() => RunBodyAsync(client).GetAwaiter().GetResult(),
TaskCreationOptions.LongRunning);
tasks.Add(task);
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index 774563d752..60b9cf4e0b 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -90,7 +90,7 @@ namespace Grpc.IntegrationTesting
private static string GetPath(string relativePath)
{
- var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ var assemblyDir = Path.GetDirectoryName(typeof(TestCredentials).GetTypeInfo().Assembly.Location);
return Path.Combine(assemblyDir, relativePath);
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index cf43a77118..3e149da3e0 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -105,127 +105,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[0]; }
}
- /// <summary>Client for TestService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface ITestServiceClient
- {
- /// <summary>
- /// One empty request followed by one empty response.
- /// </summary>
- global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One empty request followed by one empty response.
- /// </summary>
- global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
- /// <summary>
- /// One empty request followed by one empty response.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One empty request followed by one empty response.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
- /// <summary>
- /// One request followed by one response.
- /// </summary>
- global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by one response.
- /// </summary>
- global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
- /// <summary>
- /// One request followed by one response.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by one response.
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
- /// <summary>
- /// One request followed by a sequence of responses (streamed download).
- /// The server returns the payload with client desired type and sizes.
- /// </summary>
- AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// One request followed by a sequence of responses (streamed download).
- /// The server returns the payload with client desired type and sizes.
- /// </summary>
- AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
- /// <summary>
- /// A sequence of requests followed by one response (streamed upload).
- /// The server returns the aggregated size of client payload as the result.
- /// </summary>
- AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// A sequence of requests followed by one response (streamed upload).
- /// The server returns the aggregated size of client payload as the result.
- /// </summary>
- AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
- /// <summary>
- /// A sequence of requests with each request served by the server immediately.
- /// As one request could lead to multiple responses, this interface
- /// demonstrates the idea of full duplexing.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// A sequence of requests with each request served by the server immediately.
- /// As one request could lead to multiple responses, this interface
- /// demonstrates the idea of full duplexing.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
- /// <summary>
- /// A sequence of requests followed by a sequence of responses.
- /// The server buffers all the client requests and then serves them in order. A
- /// stream of responses are returned to the client when the server starts with
- /// first request.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// A sequence of requests followed by a sequence of responses.
- /// The server buffers all the client requests and then serves them in order. A
- /// stream of responses are returned to the client when the server starts with
- /// first request.
- /// </summary>
- AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of TestService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface ITestService
- {
- /// <summary>
- /// One empty request followed by one empty response.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
- /// <summary>
- /// One request followed by one response.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
- /// <summary>
- /// One request followed by a sequence of responses (streamed download).
- /// The server returns the payload with client desired type and sizes.
- /// </summary>
- global::System.Threading.Tasks.Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- /// <summary>
- /// A sequence of requests followed by one response (streamed upload).
- /// The server returns the aggregated size of client payload as the result.
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
- /// <summary>
- /// A sequence of requests with each request served by the server immediately.
- /// As one request could lead to multiple responses, this interface
- /// demonstrates the idea of full duplexing.
- /// </summary>
- global::System.Threading.Tasks.Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- /// <summary>
- /// A sequence of requests followed by a sequence of responses.
- /// The server buffers all the client requests and then serves them in order. A
- /// stream of responses are returned to the client when the server starts with
- /// first request.
- /// </summary>
- global::System.Threading.Tasks.Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of TestService</summary>
public abstract class TestServiceBase
{
@@ -287,21 +166,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for TestService</summary>
- #pragma warning disable 0618
- public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
- #pragma warning restore 0618
+ public class TestServiceClient : ClientBase<TestServiceClient>
{
+ /// <summary>Creates a new client for TestService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public TestServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for TestService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public TestServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected TestServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected TestServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -438,32 +320,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for TestService</summary>
- public static TestServiceClient NewClient(Channel channel)
- {
- return new TestServiceClient(channel);
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(ITestService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
- .AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
- .AddMethod(__Method_StreamingOutputCall, serviceImpl.StreamingOutputCall)
- .AddMethod(__Method_StreamingInputCall, serviceImpl.StreamingInputCall)
- .AddMethod(__Method_FullDuplexCall, serviceImpl.FullDuplexCall)
- .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_EmptyCall, serviceImpl.EmptyCall)
.AddMethod(__Method_UnaryCall, serviceImpl.UnaryCall)
.AddMethod(__Method_StreamingOutputCall, serviceImpl.StreamingOutputCall)
@@ -496,38 +356,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[1]; }
}
- /// <summary>Client for UnimplementedService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IUnimplementedServiceClient
- {
- /// <summary>
- /// A call that no server should implement
- /// </summary>
- global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// A call that no server should implement
- /// </summary>
- global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
- /// <summary>
- /// A call that no server should implement
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- /// <summary>
- /// A call that no server should implement
- /// </summary>
- AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of UnimplementedService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IUnimplementedService
- {
- /// <summary>
- /// A call that no server should implement
- /// </summary>
- global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of UnimplementedService</summary>
public abstract class UnimplementedServiceBase
{
@@ -542,21 +370,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for UnimplementedService</summary>
- #pragma warning disable 0618
- public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
- #pragma warning restore 0618
+ public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>
{
+ /// <summary>Creates a new client for UnimplementedService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public UnimplementedServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for UnimplementedService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public UnimplementedServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected UnimplementedServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected UnimplementedServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -595,27 +426,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for UnimplementedService</summary>
- public static UnimplementedServiceClient NewClient(Channel channel)
- {
- return new UnimplementedServiceClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
}
@@ -651,28 +465,6 @@ namespace Grpc.Testing {
get { return global::Grpc.Testing.TestReflection.Descriptor.Services[2]; }
}
- /// <summary>Client for ReconnectService</summary>
- [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
- public interface IReconnectServiceClient
- {
- global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::Grpc.Testing.Empty Start(global::Grpc.Testing.ReconnectParams request, CallOptions options);
- AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.ReconnectParams request, CallOptions options);
- global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options);
- AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
- }
-
- /// <summary>Interface of server-side implementations of ReconnectService</summary>
- [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
- public interface IReconnectService
- {
- global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context);
- global::System.Threading.Tasks.Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
- }
-
/// <summary>Base class for server-side implementations of ReconnectService</summary>
public abstract class ReconnectServiceBase
{
@@ -689,21 +481,24 @@ namespace Grpc.Testing {
}
/// <summary>Client for ReconnectService</summary>
- #pragma warning disable 0618
- public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
- #pragma warning restore 0618
+ public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>
{
+ /// <summary>Creates a new client for ReconnectService</summary>
+ /// <param name="channel">The channel to use to make remote calls.</param>
public ReconnectServiceClient(Channel channel) : base(channel)
{
}
+ /// <summary>Creates a new client for ReconnectService that uses a custom <c>CallInvoker</c>.</summary>
+ /// <param name="callInvoker">The callInvoker to use to make remote calls.</param>
public ReconnectServiceClient(CallInvoker callInvoker) : base(callInvoker)
{
}
- ///<summary>Protected parameterless constructor to allow creation of test doubles.</summary>
+ /// <summary>Protected parameterless constructor to allow creation of test doubles.</summary>
protected ReconnectServiceClient() : base()
{
}
- ///<summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <summary>Protected constructor to allow creation of configured clients.</summary>
+ /// <param name="configuration">The client configuration.</param>
protected ReconnectServiceClient(ClientBaseConfiguration configuration) : base(configuration)
{
}
@@ -746,28 +541,10 @@ namespace Grpc.Testing {
}
}
- /// <summary>Creates a new client for ReconnectService</summary>
- public static ReconnectServiceClient NewClient(Channel channel)
- {
- return new ReconnectServiceClient(channel);
- }
-
- /// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
- public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
- #pragma warning restore 0618
- {
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
- .AddMethod(__Method_Start, serviceImpl.Start)
- .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
- }
-
/// <summary>Creates service definition that can be registered with a server</summary>
- #pragma warning disable 0618
public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
- #pragma warning restore 0618
{
- return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ return ServerServiceDefinition.CreateBuilder()
.AddMethod(__Method_Start, serviceImpl.Start)
.AddMethod(__Method_Stop, serviceImpl.Stop).Build();
}
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
new file mode 100644
index 0000000000..3493ab0c22
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/project.json
@@ -0,0 +1,72 @@
+{
+ "buildOptions": {
+ "emitEntryPoint": true
+ },
+ "configurations": {
+ "Debug": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Debug/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Debug/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ },
+ "Release": {
+ "buildOptions": {
+ "copyToOutput": {
+ "include": "data/*",
+ "mappings": {
+ "nativelibs/windows_x64/grpc_csharp_ext.dll": "../../../vsprojects/x64/Release/grpc_csharp_ext.dll",
+ "nativelibs/windows_x86/grpc_csharp_ext.dll": "../../../vsprojects/Release/grpc_csharp_ext.dll",
+ "nativelibs/linux_x64/libgrpc_csharp_ext.so": "../../../libs/opt/libgrpc_csharp_ext.so",
+ "nativelibs/macosx_x64/libgrpc_csharp_ext.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
+ }
+ }
+ }
+ }
+ },
+ "runtimes": {
+ "win7-x64": { },
+ "debian.8-x64": { },
+ "osx.10.11-x64": { }
+ },
+
+ "dependencies": {
+ "Grpc.Auth": {
+ "target": "project"
+ },
+ "Grpc.Core": {
+ "target": "project"
+ },
+ "Google.Protobuf": "3.0.0-beta3",
+ "CommandLineParser": "1.9.71",
+ "NUnit": "3.2.0",
+ "NUnitLite": "3.2.0-*"
+ },
+ "frameworks": {
+ "net45": {
+ "dependencies": {
+ "Moq": "4.2.1510.2205"
+ },
+ "frameworkAssemblies": {
+ "System.Runtime": "",
+ "System.IO": ""
+ }
+ },
+ "netstandard1.5": {
+ "imports": [
+ "portable-net45",
+ "net45"
+ ],
+ "dependencies": {
+ "NETStandard.Library": "1.5.0-rc2-24027",
+ "System.Linq.Expressions": "4.0.11-rc2-24027"
+ }
+ }
+ }
+}
diff --git a/src/csharp/README.md b/src/csharp/README.md
index 201c5ab0b5..86394135c8 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -19,33 +19,13 @@ PREREQUISITES
HOW TO USE
--------------
-**Windows**
+**Windows, Linux, Mac OS X**
-- Open Visual Studio and start a new project/solution.
+- Open Visual Studio / MonoDevelop / Xamarin Studio and start a new project/solution.
- Add NuGet package `Grpc` as a dependency (Project options -> Manage NuGet Packages).
- That will also pull all the transitive dependencies (including the gRPC native library that
- gRPC C# is using internally).
-
-**Linux (Debian)**
-
-- Open MonoDevelop and start a new project/solution.
-
-- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
- That will also pull all the transitive dependencies (including the gRPC native library that
- gRPC C# is using internally).
-
-- NOTE: gRPC C# doesn't have a good story yet for shipping precompiled Linux version of Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin. You can install them using [gRPC Linuxbrew instructions][].
-**Mac OS X**
-
-- Open Xamarin Studio and start a new project/solution.
-
-- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
- That will also pull all the transitive dependencies (including the gRPC native library that
- gRPC C# is using internally).
-
-- NOTE: gRPC C# doesn't have a good story yet for shipping precompiled Mac OS X version of Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin. You can install them using [gRPC Homebrew instructions][].
+- To be able to generate code from Protocol Buffer (`.proto`) file definitions, add NuGet package `Grpc.Tools` that contains Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin.
BUILD FROM SOURCE
-----------------
@@ -61,26 +41,15 @@ If you are a user of gRPC C#, go to Usage section above.
- Open `src\csharp\Grpc.sln` (path is relative to gRPC repository root)
using Visual Studio
-**Linux**
+**Linux and Mac OS X**
- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution:
```sh
# from the gRPC repository root
- $ make CONFIG=dbg grpc_csharp_ext
- ```
-
-- Use MonoDevelop to open the solution Grpc.sln
-
-**Mac OS X**
-
-- The grpc_csharp_ext native library needs to be built so you can build the gRPC C# solution.
-
- ```sh
- # from the gRPC repository root
$ tools/run_tests/run_tests.py -c dbg -l csharp --build_only
```
-- Use Xamarin Studio to open the solution Grpc.sln
+- Use MonoDevelop / Xamarin Studio to open the solution Grpc.sln
RUNNING TESTS
-------------
@@ -100,10 +69,17 @@ different languages.
tools/run_tests/run_tests.py -l csharp
```
+ON .NET CORE SUPPORT
+------------------
+
+We are committed to providing full support for [.NET Core](https://dotnet.github.io/) in near future,
+but currently, the support is for .NET Core is experimental/work-in-progress.
+
DOCUMENTATION
-------------
-- the gRPC C# reference documentation is available online at [grpc.io][]
-- [Helloworld example][]
+- [API Reference][]
+- [Helloworld Example][]
+- [RouteGuide Tutorial][]
CONTENTS
--------
@@ -111,15 +87,15 @@ CONTENTS
- ext:
The extension library that wraps C API to be more digestible by C#.
- Grpc.Auth:
- gRPC OAuth2 support.
+ gRPC OAuth2/JWT support.
- Grpc.Core:
The main gRPC C# library.
- Grpc.Examples:
API examples for math.proto
- Grpc.Examples.MathClient:
- An example client that sends some requests to math server.
+ An example client that sends requests to math server.
- Grpc.Examples.MathServer:
- An example client that sends some requests to math server.
+ An example server that implements a simple math service.
- Grpc.IntegrationTesting:
Cross-language gRPC implementation testing (interop testing).
@@ -130,10 +106,6 @@ Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes
Prior to version 0.13, installing `grpc_csharp_ext` was required to make gRPC work on Linux and MacOS. Starting with version 0.13, we have improved the packaging story significantly and precompiled versions of the native library for all supported platforms are now shipped with the NuGet package. Just installing the `Grpc` NuGet package should be the only step needed to use gRPC C#, regardless of your platform (Windows, Linux or Mac) and the bitness (32 or 64bit).
-[gRPC Linuxbrew instructions]:https://github.com/grpc/homebrew-grpc#quick-install-linux
-[gRPC Homebrew instructions]:https://github.com/grpc/homebrew-grpc#quick-install-linux
-[homebrew]:http://brew.sh
-[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
-[grpc.io]: http://www.grpc.io/docs/installation/csharp.html
-[Debian jessie-backports]:http://backports.debian.org/Instructions/
-[Helloworld example]:../../examples/csharp/helloworld
+[API Reference]: http://www.grpc.io/grpc/csharp/
+[Helloworld Example]: ../../examples/csharp/helloworld
+[RouteGuide Tutorial]: http://www.grpc.io/docs/tutorials/basic/csharp.html
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 1cc63da970..272b30f385 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -30,7 +30,7 @@
@rem Builds gRPC NuGet packages
@rem Current package versions
-set VERSION=0.15.0-dev
+set VERSION=0.16.0-dev
set PROTOBUF_VERSION=3.0.0-beta3
@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
@@ -41,12 +41,12 @@ set NUGET=C:\nuget\nuget.exe
@rem Collect the artifacts built by the previous build step if running on Jenkins
@rem TODO(jtattermusch): is there a better way to do this?
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* Grpc.Core\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* Grpc.Core\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* Grpc.Core\macosx_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64\
+xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86\
+xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64\
@rem Collect protoc artifacts built by the previous build step
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 2a243b94cb..9b8d050ea5 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -249,10 +249,12 @@ grpcsharp_batch_context_recv_initial_metadata(
GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length(
const grpcsharp_batch_context *ctx) {
+ grpc_byte_buffer_reader reader;
if (!ctx->recv_message) {
return -1;
}
- return (intptr_t)grpc_byte_buffer_length(ctx->recv_message);
+ grpc_byte_buffer_reader_init(&reader, ctx->recv_message);
+ return (intptr_t)grpc_byte_buffer_length(reader.buffer_out);
}
/*
@@ -503,6 +505,7 @@ grpcsharp_call_start_unary(grpc_call *call, grpcsharp_batch_context *ctx,
grpc_metadata_array *initial_metadata, uint32_t write_flags) {
/* TODO: don't use magic number */
grpc_op ops[6];
+ memset(ops, 0, sizeof(ops));
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
initial_metadata);
@@ -555,6 +558,7 @@ grpcsharp_call_start_client_streaming(grpc_call *call,
grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[4];
+ memset(ops, 0, sizeof(ops));
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
initial_metadata);
@@ -596,6 +600,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
size_t send_buffer_len, grpc_metadata_array *initial_metadata, uint32_t write_flags) {
/* TODO: don't use magic number */
grpc_op ops[4];
+ memset(ops, 0, sizeof(ops));
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
initial_metadata);
@@ -638,6 +643,7 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[2];
+ memset(ops, 0, sizeof(ops));
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
initial_metadata);
@@ -684,6 +690,7 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx,
int32_t send_empty_initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[2];
+ memset(ops, 0, sizeof(ops));
size_t nops = send_empty_initial_metadata ? 2 : 1;
ops[0].op = GRPC_OP_SEND_MESSAGE;
ctx->send_message = string_to_byte_buffer(send_buffer, send_buffer_len);
@@ -691,8 +698,6 @@ grpcsharp_call_send_message(grpc_call *call, grpcsharp_batch_context *ctx,
ops[0].flags = write_flags;
ops[0].reserved = NULL;
ops[1].op = GRPC_OP_SEND_INITIAL_METADATA;
- ops[1].data.send_initial_metadata.count = 0;
- ops[1].data.send_initial_metadata.metadata = NULL;
ops[1].flags = 0;
ops[1].reserved = NULL;
@@ -719,6 +724,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
size_t optional_send_buffer_len, uint32_t write_flags) {
/* TODO: don't use magic number */
grpc_op ops[3];
+ memset(ops, 0, sizeof(ops));
size_t nops = 1;
ops[0].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[0].data.send_status_from_server.status = status_code;
@@ -743,8 +749,6 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
}
if (send_empty_initial_metadata) {
ops[nops].op = GRPC_OP_SEND_INITIAL_METADATA;
- ops[nops].data.send_initial_metadata.count = 0;
- ops[nops].data.send_initial_metadata.metadata = NULL;
ops[nops].flags = 0;
ops[nops].reserved = NULL;
nops++;
@@ -784,6 +788,7 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
grpc_metadata_array *initial_metadata) {
/* TODO: don't use magic number */
grpc_op ops[1];
+ memset(ops, 0, sizeof(ops));
ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
grpcsharp_metadata_array_move(&(ctx->send_initial_metadata),
initial_metadata);
diff --git a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec b/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
deleted file mode 100644
index cc688e2bc7..0000000000
--- a/src/csharp/grpc.native.csharp/grpc.native.csharp.nuspec
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<package>
- <metadata>
- <id>grpc.native.csharp</id>
- <version>$version$</version>
- <authors>Google Inc.</authors>
- <owners>grpc-packages</owners>
- <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
- <projectUrl>http://github.com/grpc/grpc</projectUrl>
- <requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Native extension needed by gRPC C# library. This is not the package you are looking for, it is only meant to be used as a dependency.</description>
- <releaseNotes>Release of gRPC C core $version$ libraries.</releaseNotes>
- <copyright>Copyright 2015</copyright>
- <title>gRPC C# Native Extension</title>
- <summary>Native library required by gRPC C#</summary>
- <tags>gRPC native</tags>
- </metadata>
- <files>
- <file src="grpc.native.csharp.targets" target="\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets" />
- <file src="windows_x86/grpc_csharp_ext.dll" target="/build/native/bin/windows_x86/grpc_csharp_ext.dll" />
- <file src="windows_x64/grpc_csharp_ext.dll" target="/build/native/bin/windows_x64/grpc_csharp_ext.dll" />
- <file src="linux_x86/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x86/libgrpc_csharp_ext.so" />
- <file src="linux_x64/libgrpc_csharp_ext.so" target="/build/native/bin/linux_x64/libgrpc_csharp_ext.so" />
- <file src="macosx_x86/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x86/libgrpc_csharp_ext.dylib" />
- <file src="macosx_x64/libgrpc_csharp_ext.dylib" target="/build/native/bin/macosx_x64/libgrpc_csharp_ext.dylib" />
- </files>
-</package>
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index f6af3408d5..7e7aee1093 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -7,6 +7,7 @@
"Grpc.Core.Internal.Tests.CompletionQueueSafeHandleTest",
"Grpc.Core.Internal.Tests.MetadataArraySafeHandleTest",
"Grpc.Core.Internal.Tests.TimespecTest",
+ "Grpc.Core.Tests.AppDomainUnloadTest",
"Grpc.Core.Tests.CallCredentialsTest",
"Grpc.Core.Tests.CallOptionsTest",
"Grpc.Core.Tests.ChannelCredentialsTest",
@@ -25,6 +26,9 @@
"Grpc.Core.Tests.ResponseHeadersTest",
"Grpc.Core.Tests.SanityTest",
"Grpc.Core.Tests.ServerTest",
+ "Grpc.Core.Tests.ShutdownHookClientTest",
+ "Grpc.Core.Tests.ShutdownHookPendingCallTest",
+ "Grpc.Core.Tests.ShutdownHookServerTest",
"Grpc.Core.Tests.ShutdownTest",
"Grpc.Core.Tests.TimeoutsTest",
"Grpc.Core.Tests.UserAgentStringTest"
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index f18ce01c6f..ce988f9dfa 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -31,12 +31,16 @@
*
*/
+#include <list>
+
#include <node.h>
#include <nan.h>
#include <v8.h>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/alloc.h"
+#include "grpc/support/log.h"
+#include "grpc/support/time.h"
#include "call.h"
#include "call_credentials.h"
@@ -45,14 +49,32 @@
#include "server.h"
#include "completion_queue_async_worker.h"
#include "server_credentials.h"
+#include "timeval.h"
using v8::FunctionTemplate;
using v8::Local;
using v8::Value;
+using v8::Number;
using v8::Object;
using v8::Uint32;
using v8::String;
+typedef struct log_args {
+ gpr_log_func_args core_args;
+ gpr_timespec timestamp;
+} log_args;
+
+typedef struct logger_state {
+ Nan::Callback *callback;
+ std::list<log_args *> *pending_args;
+ uv_mutex_t mutex;
+ uv_async_t async;
+ // Indicates that a logger has been set
+ bool logger_set;
+} logger_state;
+
+logger_state grpc_logger_state;
+
static char *pem_root_certs = NULL;
void InitStatusConstants(Local<Object> exports) {
@@ -235,6 +257,18 @@ void InitWriteFlags(Local<Object> exports) {
Nan::Set(write_flags, Nan::New("NO_COMPRESS").ToLocalChecked(), NO_COMPRESS);
}
+void InitLogConstants(Local<Object> exports) {
+ Nan::HandleScope scope;
+ Local<Object> log_verbosity = Nan::New<Object>();
+ Nan::Set(exports, Nan::New("logVerbosity").ToLocalChecked(), log_verbosity);
+ Local<Value> DEBUG(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_DEBUG));
+ Nan::Set(log_verbosity, Nan::New("DEBUG").ToLocalChecked(), DEBUG);
+ Local<Value> INFO(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_INFO));
+ Nan::Set(log_verbosity, Nan::New("INFO").ToLocalChecked(), INFO);
+ Local<Value> ERROR(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_ERROR));
+ Nan::Set(log_verbosity, Nan::New("ERROR").ToLocalChecked(), ERROR);
+}
+
NAN_METHOD(MetadataKeyIsLegal) {
if (!info[0]->IsString()) {
return Nan::ThrowTypeError(
@@ -298,16 +332,101 @@ NAN_METHOD(SetDefaultRootsPem) {
}
}
+NAUV_WORK_CB(LogMessagesCallback) {
+ Nan::HandleScope scope;
+ std::list<log_args *> args;
+ uv_mutex_lock(&grpc_logger_state.mutex);
+ args.splice(args.begin(), *grpc_logger_state.pending_args);
+ uv_mutex_unlock(&grpc_logger_state.mutex);
+ /* Call the callback with each log message */
+ while (!args.empty()) {
+ log_args *arg = args.front();
+ args.pop_front();
+ Local<Value> file = Nan::New(arg->core_args.file).ToLocalChecked();
+ Local<Value> line = Nan::New<Uint32, uint32_t>(arg->core_args.line);
+ Local<Value> severity = Nan::New(
+ gpr_log_severity_string(arg->core_args.severity)).ToLocalChecked();
+ Local<Value> message = Nan::New(arg->core_args.message).ToLocalChecked();
+ Local<Value> timestamp = Nan::New<v8::Date>(
+ grpc::node::TimespecToMilliseconds(arg->timestamp)).ToLocalChecked();
+ const int argc = 5;
+ Local<Value> argv[argc] = {file, line, severity, message, timestamp};
+ grpc_logger_state.callback->Call(argc, argv);
+ delete[] arg->core_args.message;
+ delete arg;
+ }
+}
+
+void node_log_func(gpr_log_func_args *args) {
+ // TODO(mlumish): Use the core's log formatter when it becomes available
+ log_args *args_copy = new log_args;
+ size_t message_len = strlen(args->message) + 1;
+ char *message = new char[message_len];
+ memcpy(message, args->message, message_len);
+ memcpy(&args_copy->core_args, args, sizeof(gpr_log_func_args));
+ args_copy->core_args.message = message;
+ args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME);
+
+ uv_mutex_lock(&grpc_logger_state.mutex);
+ grpc_logger_state.pending_args->push_back(args_copy);
+ uv_mutex_unlock(&grpc_logger_state.mutex);
+
+ uv_async_send(&grpc_logger_state.async);
+}
+
+void init_logger() {
+ memset(&grpc_logger_state, 0, sizeof(logger_state));
+ grpc_logger_state.pending_args = new std::list<log_args *>();
+ uv_mutex_init(&grpc_logger_state.mutex);
+ uv_async_init(uv_default_loop(),
+ &grpc_logger_state.async,
+ LogMessagesCallback);
+ uv_unref((uv_handle_t*)&grpc_logger_state.async);
+ grpc_logger_state.logger_set = false;
+
+ gpr_log_verbosity_init();
+}
+
+/* This registers a JavaScript logger for messages from the gRPC core. Because
+ that handler has to be run in the context of the JavaScript event loop, it
+ will be run asynchronously. To minimize the problems that could cause for
+ debugging, we leave core to do its default synchronous logging until a
+ JavaScript logger is set */
+NAN_METHOD(SetDefaultLoggerCallback) {
+ if (!info[0]->IsFunction()) {
+ return Nan::ThrowTypeError(
+ "setDefaultLoggerCallback's argument must be a function");
+ }
+ if (!grpc_logger_state.logger_set) {
+ gpr_set_log_function(node_log_func);
+ grpc_logger_state.logger_set = true;
+ }
+ grpc_logger_state.callback = new Nan::Callback(info[0].As<v8::Function>());
+}
+
+NAN_METHOD(SetLogVerbosity) {
+ if (!info[0]->IsUint32()) {
+ return Nan::ThrowTypeError(
+ "setLogVerbosity's argument must be a number");
+ }
+ gpr_log_severity severity = static_cast<gpr_log_severity>(
+ Nan::To<uint32_t>(info[0]).FromJust());
+ gpr_set_log_verbosity(severity);
+}
+
void init(Local<Object> exports) {
Nan::HandleScope scope;
grpc_init();
grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
+ init_logger();
+
InitStatusConstants(exports);
InitCallErrorConstants(exports);
InitOpTypeConstants(exports);
InitPropagateConstants(exports);
InitConnectivityStateConstants(exports);
InitWriteFlags(exports);
+ InitLogConstants(exports);
grpc::node::Call::Init(exports);
grpc::node::CallCredentials::Init(exports);
@@ -333,6 +452,14 @@ void init(Local<Object> exports) {
Nan::GetFunction(
Nan::New<FunctionTemplate>(SetDefaultRootsPem)
).ToLocalChecked());
+ Nan::Set(exports, Nan::New("setDefaultLoggerCallback").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<FunctionTemplate>(SetDefaultLoggerCallback)
+ ).ToLocalChecked());
+ Nan::Set(exports, Nan::New("setLogVerbosity").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<FunctionTemplate>(SetLogVerbosity)
+ ).ToLocalChecked());
}
NODE_MODULE(grpc_node, init)
diff --git a/src/node/index.js b/src/node/index.js
index 66664d94b5..9fb6faa5d7 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -46,6 +46,8 @@ var client = require('./src/client.js');
var server = require('./src/server.js');
+var common = require('./src/common.js');
+
var Metadata = require('./src/metadata.js');
var grpc = require('./src/grpc_extension');
@@ -122,6 +124,42 @@ exports.load = function load(filename, format, options) {
return loadObject(builder.ns, options);
};
+var log_template = _.template(
+ '{severity} {timestamp}\t{file}:{line}]\t{message}',
+ {interpolate: /{([\s\S]+?)}/g});
+
+/**
+ * Sets the logger function for the gRPC module. For debugging purposes, the C
+ * core will log synchronously directly to stdout unless this function is
+ * called. Note: the output format here is intended to be informational, and
+ * is not guaranteed to stay the same in the future.
+ * Logs will be directed to logger.error.
+ * @param {Console} logger A Console-like object.
+ */
+exports.setLogger = function setLogger(logger) {
+ common.logger = logger;
+ grpc.setDefaultLoggerCallback(function(file, line, severity,
+ message, timestamp) {
+ logger.error(log_template({
+ file: path.basename(file),
+ line: line,
+ severity: severity,
+ message: message,
+ timestamp: timestamp.toISOString()
+ }));
+ });
+};
+
+/**
+ * Sets the logger verbosity for gRPC module logging. The options are members
+ * of the grpc.logVerbosity map.
+ * @param {Number} verbosity The minimum severity to log
+ */
+exports.setLogVerbosity = function setLogVerbosity(verbosity) {
+ common.logVerbosity = verbosity;
+ grpc.setLogVerbosity(verbosity);
+};
+
/**
* @see module:src/server.Server
*/
@@ -153,6 +191,11 @@ exports.callError = grpc.callError;
exports.writeFlags = grpc.writeFlags;
/**
+ * Log verbosity setting name to code number mapping
+ */
+exports.logVerbosity = grpc.logVerbosity;
+
+/**
* Credentials factories
*/
exports.credentials = require('./src/credentials.js');
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 7280762305..05f52a1083 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -45,9 +45,6 @@ var testProto = grpc.load({
var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
-var incompressible_data = fs.readFileSync(
- __dirname + '/../../../test/cpp/interop/rnd.dat');
-
/**
* Create a buffer filled with size zeroes
* @param {number} size The length of the buffer
@@ -88,15 +85,7 @@ function getEchoTrailer(call) {
}
function getPayload(payload_type, size) {
- if (payload_type === 'RANDOM') {
- payload_type = ['COMPRESSABLE',
- 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
- }
- var body;
- switch (payload_type) {
- case 'COMPRESSABLE': body = zeroBuffer(size); break;
- case 'UNCOMPRESSABLE': incompressible_data.slice(size); break;
- }
+ var body = zeroBuffer(size);
return {type: payload_type, body: body};
}
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
index 262aa33862..5ef5260a96 100644
--- a/src/node/performance/benchmark_client.js
+++ b/src/node/performance/benchmark_client.js
@@ -42,6 +42,8 @@ var fs = require('fs');
var path = require('path');
var util = require('util');
var EventEmitter = require('events');
+
+var async = require('async');
var _ = require('lodash');
var PoissonProcess = require('poisson-process');
var Histogram = require('./histogram');
@@ -128,6 +130,36 @@ function BenchmarkClient(server_targets, channels, histogram_params,
util.inherits(BenchmarkClient, EventEmitter);
/**
+ * Start every client in the list of clients by waiting for each to be ready,
+ * then starting outstanding_rpcs_per_channel calls on each of them
+ * @param {Array<grpc.Client>} client_list The list of clients
+ * @param {Number} outstanding_rpcs_per_channel The number of calls to start
+ * on each client
+ * @param {function(grpc.Client)} makeCall Function to make a single call on
+ * a single client
+ * @param {EventEmitter} emitter The event emitter to send errors on, if
+ * necessary
+ */
+function startAllClients(client_list, outstanding_rpcs_per_channel, makeCall,
+ emitter) {
+ var ready_wait_funcs = _.map(client_list, function(client) {
+ return _.partial(grpc.waitForClientReady, client, Infinity);
+ });
+ async.parallel(ready_wait_funcs, function(err) {
+ if (err) {
+ emitter.emit('error', err);
+ return;
+ }
+
+ _.each(client_list, function(client) {
+ _.times(outstanding_rpcs_per_channel, function() {
+ makeCall(client);
+ });
+ });
+ });
+}
+
+/**
* Start a closed-loop test. For each channel, start
* outstanding_rpcs_per_channel RPCs. Then, whenever an RPC finishes, start
* another one.
@@ -212,11 +244,7 @@ BenchmarkClient.prototype.startClosedLoop = function(
};
}
- _.each(client_list, function(client) {
- _.times(outstanding_rpcs_per_channel, function() {
- makeCall(client);
- });
- });
+ startAllClients(client_list, outstanding_rpcs_per_channel, makeCall, self);
};
/**
@@ -310,14 +338,12 @@ BenchmarkClient.prototype.startPoisson = function(
var averageIntervalMs = (1 / offered_load) * 1000;
- _.each(client_list, function(client) {
- _.times(outstanding_rpcs_per_channel, function() {
- var p = PoissonProcess.create(averageIntervalMs, function() {
- makeCall(client, p);
- });
- p.start();
+ startAllClients(client_list, outstanding_rpcs_per_channel, function(client){
+ var p = PoissonProcess.create(averageIntervalMs, function() {
+ makeCall(client, p);
});
- });
+ p.start();
+ }, self);
};
/**
diff --git a/src/node/src/common.js b/src/node/src/common.js
index 8cf43b7a84..22159dd39f 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -157,3 +157,24 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
}];
}));
};
+
+/**
+ * The logger object for the gRPC module. Defaults to console.
+ */
+exports.logger = console;
+
+/**
+ * The current logging verbosity. 0 corresponds to logging everything
+ */
+exports.logVerbosity = 0;
+
+/**
+ * Log a message if the severity is at least as high as the current verbosity
+ * @param {Number} severity A value of the grpc.logVerbosity map
+ * @param {String} message The message to log
+ */
+exports.log = function log(severity, message) {
+ if (severity >= exports.logVerbosity) {
+ exports.logger.error(message);
+ }
+};
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index a12eade4e1..b746d0625d 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -69,6 +69,8 @@ var ChannelCredentials = grpc.ChannelCredentials;
var Metadata = require('./metadata.js');
+var common = require('./common.js');
+
/**
* Create an SSL Credentials object. If using a client-side certificate, both
* the second and third arguments must be passed.
@@ -120,7 +122,7 @@ exports.createFromGoogleCredential = function(google_credential) {
var service_url = auth_context.service_url;
google_credential.getRequestMetadata(service_url, function(err, header) {
if (err) {
- console.log('Auth error:', err);
+ common.log(grpc.logVerbosity.INFO, 'Auth error:' + err);
callback(err);
return;
}
diff --git a/src/node/src/server.js b/src/node/src/server.js
index fd5153f124..b3b414969a 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -735,8 +735,8 @@ Server.prototype.addService = function(service, implementation) {
}
var impl;
if (implementation[name] === undefined) {
- console.warn('Method handler for %s expected but not provided',
- attrs.path);
+ common.log(grpc.logVerbosity.ERROR, 'Method handler for ' +
+ attrs.path + ' expected but not provided');
impl = defaultHandler[method_type];
} else {
impl = _.bind(implementation[name], implementation);
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index d4849c2e38..7c256d7ba0 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc-tools",
- "version": "0.15.0-dev",
+ "version": "0.16.0-dev",
"author": "Google Inc.",
"description": "Tools for developing with gRPC on Node.js",
"homepage": "http://www.grpc.io/",
@@ -34,6 +34,7 @@
"index.js",
"bin/protoc.js",
"bin/protoc_plugin.js",
+ "bin/google/protobuf",
"LICENSE"
],
"main": "index.js"
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
index 343dd48a14..ac2a37d75f 100644
--- a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
@@ -41,7 +41,7 @@
*/
+ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert
forHost:(nonnull NSString *)host
- error:(NSError **)errorPtr;
+ error:(NSError * _Nullable * _Nullable)errorPtr;
/**
* Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate
* Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be
@@ -51,6 +51,6 @@
withPrivateKey:(nullable NSString *)pemPrivateKey
withCertChain:(nullable NSString *)pemCertChain
forHost:(nonnull NSString *)host
- error:(NSError **)errorPtr;
+ error:(NSError * _Nullable * _Nullable)errorPtr;
@end
diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.h b/src/objective-c/GRPCClient/GRPCCall+Cronet.h
index 7f7fc6c2a9..2d8f7ac8fb 100644
--- a/src/objective-c/GRPCClient/GRPCCall+Cronet.h
+++ b/src/objective-c/GRPCClient/GRPCCall+Cronet.h
@@ -30,6 +30,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
+#ifdef GRPC_COMPILE_WITH_CRONET
#import <Cronet/Cronet.h>
#import "GRPCCall.h"
@@ -53,3 +54,4 @@
+(BOOL)isUsingCronet;
@end
+#endif
diff --git a/src/objective-c/GRPCClient/GRPCCall+Cronet.m b/src/objective-c/GRPCClient/GRPCCall+Cronet.m
index 69a410e95a..76ca1a2537 100644
--- a/src/objective-c/GRPCClient/GRPCCall+Cronet.m
+++ b/src/objective-c/GRPCClient/GRPCCall+Cronet.m
@@ -33,6 +33,7 @@
#import "GRPCCall+Cronet.h"
+#ifdef GRPC_COMPILE_WITH_CRONET
static BOOL useCronet = NO;
static cronet_engine *globalCronetEngine;
@@ -52,3 +53,4 @@ static cronet_engine *globalCronetEngine;
}
@end
+#endif
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 7a77ae60b6..b9e741dfa8 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -220,6 +220,8 @@ extern id const kGRPCTrailersKey;
* messages to the response side of the call indefinitely (depending on the semantics of the
* specific remote method called).
* To finish a call right away, invoke cancel.
+ * host parameter should not contain the scheme (http:// or https://), only the name or IP addr
+ * and the port number, for example @"localhost:5050".
*/
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 0eb10656dd..e9678f38a9 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -76,7 +76,6 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
NSString *_host;
NSString *_path;
GRPCWrappedCall *_wrappedCall;
- dispatch_once_t _callAlreadyInvoked;
GRPCConnectivityMonitor *_connectivityMonitor;
// The C gRPC library has less guarantees on the ordering of events than we
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 3219835d02..40e78a92d6 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -58,9 +58,10 @@ struct grpc_channel_credentials;
/**
* Creates a secure channel to the specified @c host using Cronet as a transport mechanism.
*/
+#ifdef GRPC_COMPILE_WITH_CRONET
+ (nullable GRPCChannel *)secureCronetChannelWithHost:(NSString *)host
channelArgs:(NSDictionary *)channelArgs;
-
+#endif
/**
* Creates a secure channel to the specified @c host using the specified @c credentials and
* @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index e4e0dbe6d2..d3192c983d 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -34,13 +34,17 @@
#import "GRPCChannel.h"
#include <grpc/grpc_security.h>
+#ifdef GRPC_COMPILE_WITH_CRONET
#include <grpc/grpc_cronet.h>
+#endif
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
+#ifdef GRPC_COMPILE_WITH_CRONET
#import <Cronet/Cronet.h>
#import <GRPCClient/GRPCCall+Cronet.h>
+#endif
#import "GRPCCompletionQueue.h"
void freeChannelArgs(grpc_channel_args *channel_args) {
@@ -102,6 +106,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
grpc_channel_args *_channelArgs;
}
+#ifdef GRPC_COMPILE_WITH_CRONET
- (instancetype)initWithHost:(NSString *)host
cronetEngine:(cronet_engine *)cronetEngine
channelArgs:(NSDictionary *)channelArgs {
@@ -118,6 +123,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
return self;
}
+#endif
- (instancetype)initWithHost:(NSString *)host
secure:(BOOL)secure
@@ -152,6 +158,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
freeChannelArgs(_channelArgs);
}
+#ifdef GRPC_COMPILE_WITH_CRONET
+ (GRPCChannel *)secureCronetChannelWithHost:(NSString *)host
channelArgs:(NSDictionary *)channelArgs {
cronet_engine *engine = [GRPCCall cronetEngine];
@@ -162,6 +169,7 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
}
return [[GRPCChannel alloc] initWithHost:host cronetEngine:engine channelArgs:channelArgs];
}
+#endif
+ (GRPCChannel *)secureChannelWithHost:(NSString *)host {
return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL];
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 7da508810c..fef6385cea 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -36,8 +36,10 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#import <GRPCClient/GRPCCall.h>
+#ifdef GRPC_COMPILE_WITH_CRONET
#import <GRPCClient/GRPCCall+ChannelArg.h>
#import <GRPCClient/GRPCCall+Cronet.h>
+#endif
#import "GRPCChannel.h"
#import "GRPCCompletionQueue.h"
@@ -201,17 +203,22 @@ NS_ASSUME_NONNULL_BEGIN
- (GRPCChannel *)newChannel {
NSDictionary *args = [self channelArgs];
+#ifdef GRPC_COMPILE_WITH_CRONET
BOOL useCronet = [GRPCCall isUsingCronet];
+#endif
if (_secure) {
GRPCChannel *channel;
@synchronized(self) {
if (_channelCreds == nil) {
[self setTLSPEMRootCerts:nil withPrivateKey:nil withCertChain:nil error:nil];
}
+#ifdef GRPC_COMPILE_WITH_CRONET
if (useCronet) {
channel = [GRPCChannel secureCronetChannelWithHost:_address
channelArgs:args];
- } else {
+ } else
+#endif
+ {
channel = [GRPCChannel secureChannelWithHost:_address
credentials:_channelCreds
channelArgs:args];
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index 16e5bff7ff..a3fa5938cd 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -72,6 +72,8 @@
_op.op = GRPC_OP_SEND_INITIAL_METADATA;
_op.data.send_initial_metadata.count = metadata.count;
_op.data.send_initial_metadata.metadata = metadata.grpc_metadataArray;
+ _op.data.send_initial_metadata.maybe_compression_level.is_set = false;
+ _op.data.send_initial_metadata.maybe_compression_level.level = 0;
_handler = handler;
}
return self;
diff --git a/src/objective-c/ProtoRPC/ProtoMethod.h b/src/objective-c/ProtoRPC/ProtoMethod.h
index a0ed2cf98a..ae3a2723fc 100644
--- a/src/objective-c/ProtoRPC/ProtoMethod.h
+++ b/src/objective-c/ProtoRPC/ProtoMethod.h
@@ -37,6 +37,7 @@
* A fully-qualified proto service method name. Full qualification is needed because a gRPC endpoint
* can implement multiple services.
*/
+__attribute__((deprecated("Please use GRPCProtoMethod.")))
@interface ProtoMethod : NSObject
@property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *service;
@@ -48,3 +49,14 @@
service:(NSString *)service
method:(NSString *)method;
@end
+
+/**
+ * This subclass is empty now. Eventually we'll remove ProtoMethod class
+ * to avoid potential naming conflict
+ */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+@interface GRPCProtoMethod : ProtoMethod
+#pragma clang diagnostic pop
+
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoMethod.m b/src/objective-c/ProtoRPC/ProtoMethod.m
index 4b7ed63123..e9978f38af 100644
--- a/src/objective-c/ProtoRPC/ProtoMethod.m
+++ b/src/objective-c/ProtoRPC/ProtoMethod.m
@@ -53,3 +53,7 @@
}
}
@end
+
+@implementation GRPCProtoMethod
+
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index bd926b7328..04fc1e45f1 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -36,13 +36,29 @@
#import "ProtoMethod.h"
+__attribute__((deprecated("Please use GRPCProtoCall.")))
@interface ProtoRPC : GRPCCall
+/**
+ * host parameter should not contain the scheme (http:// or https://), only the name or IP addr
+ * and the port number, for example @"localhost:5050".
+ */
- (instancetype)initWithHost:(NSString *)host
- method:(ProtoMethod *)method
+ method:(GRPCProtoMethod *)method
requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
- (void)start;
@end
+
+/**
+ * This subclass is empty now. Eventually we'll remove ProtoRPC class
+ * to avoid potential naming conflict
+ */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+@interface GRPCProtoCall : ProtoRPC
+#pragma clang diagnostic pop
+
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 9bf66f347a..fb0b566f19 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -70,7 +70,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
// Designated initializer
- (instancetype)initWithHost:(NSString *)host
- method:(ProtoMethod *)method
+ method:(GRPCProtoMethod *)method
requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable {
@@ -117,3 +117,7 @@ static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsing
_responseWriteable = nil;
}
@end
+
+@implementation GRPCProtoCall
+
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
index 2e8cb33696..7faae1b49c 100644
--- a/src/objective-c/ProtoRPC/ProtoService.h
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -33,17 +33,31 @@
#import <Foundation/Foundation.h>
-@class ProtoRPC;
+@class GRPCProtoCall;
@protocol GRXWriteable;
@class GRXWriter;
+
+__attribute__((deprecated("Please use GRPCProtoService.")))
@interface ProtoService : NSObject
- (instancetype)initWithHost:(NSString *)host
packageName:(NSString *)packageName
serviceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER;
-- (ProtoRPC *)RPCToMethod:(NSString *)method
+- (GRPCProtoCall *)RPCToMethod:(NSString *)method
requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable;
@end
+
+
+/**
+ * This subclass is empty now. Eventually we'll remove ProtoService class
+ * to avoid potential naming conflict
+ */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+@interface GRPCProtoService : ProtoService
+#pragma clang diagnostic pop
+
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
index fccc6aadc9..9740190851 100644
--- a/src/objective-c/ProtoRPC/ProtoService.m
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -69,9 +69,9 @@
requestsWriter:(GRXWriter *)requestsWriter
responseClass:(Class)responseClass
responsesWriteable:(id<GRXWriteable>)responsesWriteable {
- ProtoMethod *methodName = [[ProtoMethod alloc] initWithPackage:_packageName
- service:_serviceName
- method:method];
+ GRPCProtoMethod *methodName = [[GRPCProtoMethod alloc] initWithPackage:_packageName
+ service:_serviceName
+ method:method];
return [[ProtoRPC alloc] initWithHost:_host
method:methodName
requestsWriter:requestsWriter
@@ -79,3 +79,7 @@
responsesWriteable:responsesWriteable];
}
@end
+
+@implementation GRPCProtoService
+
+@end
diff --git a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
index 5addf26fc4..107e6de4e2 100644
--- a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
@@ -2,6 +2,10 @@ Pod::Spec.new do |s|
s.name = "RemoteTest"
s.version = "0.0.1"
s.license = "New BSD"
+ s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+ s.homepage = "http://www.grpc.io/"
+ s.summary = "RemoteTest example"
+ s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = '7.1'
s.osx.deployment_target = '10.9'
diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
index 611eb6032d..5c2a6d14f9 100644
--- a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
+++ b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
@@ -7,16 +7,16 @@
objects = {
/* Begin PBXBuildFile section */
+ 426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C20055928615A6F8434E26B4 /* libPods-Sample.a */; };
6369A2701A9322E20015FC5C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A26F1A9322E20015FC5C /* main.m */; };
6369A2731A9322E20015FC5C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2721A9322E20015FC5C /* AppDelegate.m */; };
6369A2761A9322E20015FC5C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2751A9322E20015FC5C /* ViewController.m */; };
6369A2791A9322E20015FC5C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6369A2771A9322E20015FC5C /* Main.storyboard */; };
6369A27B1A9322E20015FC5C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6369A27A1A9322E20015FC5C /* Images.xcassets */; };
- FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC7B7C4C0410F43B9621631 /* libPods.a */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
- 2DC7B7C4C0410F43B9621631 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
6369A26A1A9322E20015FC5C /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
6369A26E1A9322E20015FC5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6369A26F1A9322E20015FC5C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -26,8 +26,8 @@
6369A2751A9322E20015FC5C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
6369A2781A9322E20015FC5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
6369A27A1A9322E20015FC5C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
- AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
- C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+ C20055928615A6F8434E26B4 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -35,7 +35,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */,
+ 426A5020E0E158A101BCA1D9 /* libPods-Sample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -86,8 +86,8 @@
AB3331C9AE6488E61B2B094E /* Pods */ = {
isa = PBXGroup;
children = (
- AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */,
- C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */,
+ E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */,
+ 5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@@ -95,7 +95,7 @@
C4C2C5219053E079C9EFB930 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 2DC7B7C4C0410F43B9621631 /* libPods.a */,
+ C20055928615A6F8434E26B4 /* libPods-Sample.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -107,11 +107,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 6369A28D1A9322E20015FC5C /* Build configuration list for PBXNativeTarget "Sample" */;
buildPhases = (
- 41F7486D8F66994B0BFB84AF /* Check Pods Manifest.lock */,
+ 41F7486D8F66994B0BFB84AF /* [CP] Check Pods Manifest.lock */,
6369A2661A9322E20015FC5C /* Sources */,
6369A2671A9322E20015FC5C /* Frameworks */,
6369A2681A9322E20015FC5C /* Resources */,
- 04554623324BE4A838846086 /* Copy Pods Resources */,
+ 04554623324BE4A838846086 /* [CP] Copy Pods Resources */,
+ C7FAD018D05AB5F0B0FE81E2 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -167,29 +168,29 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 04554623324BE4A838846086 /* Copy Pods Resources */ = {
+ 04554623324BE4A838846086 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 41F7486D8F66994B0BFB84AF /* Check Pods Manifest.lock */ = {
+ 41F7486D8F66994B0BFB84AF /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -197,6 +198,21 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
+ C7FAD018D05AB5F0B0FE81E2 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -304,7 +320,7 @@
};
6369A28E1A9322E20015FC5C /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */;
+ baseConfigurationReference = E3C01DF315C4E7433BCEC6E6 /* Pods-Sample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist;
@@ -315,7 +331,7 @@
};
6369A28F1A9322E20015FC5C /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */;
+ baseConfigurationReference = 5A8C9F4B28733B249DE4AB6D /* Pods-Sample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Sample/Info.plist;
diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
index 2f5716082b..2a1b30f2cf 100644
--- a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
+++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
@@ -7,15 +7,14 @@
objects = {
/* Begin PBXBuildFile section */
- 253D3A297105CA46DA960A11 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC58ACA18DCCB1553531B885 /* libPods.a */; };
633BFFC81B950B210007E424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC71B950B210007E424 /* AppDelegate.swift */; };
633BFFCA1B950B210007E424 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC91B950B210007E424 /* ViewController.swift */; };
633BFFCD1B950B210007E424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCB1B950B210007E424 /* Main.storyboard */; };
633BFFCF1B950B210007E424 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCE1B950B210007E424 /* Images.xcassets */; };
+ 92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
- 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
633BFFC21B950B210007E424 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
633BFFC61B950B210007E424 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
633BFFC71B950B210007E424 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -23,8 +22,9 @@
633BFFCC1B950B210007E424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
633BFFCE1B950B210007E424 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
6367AD231B951655007FD3A4 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
- C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
- DC58ACA18DCCB1553531B885 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftSample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.debug.xcconfig"; sourceTree = "<group>"; };
+ C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 253D3A297105CA46DA960A11 /* libPods.a in Frameworks */,
+ 92EDB1408A1E1E7DDAB25D9C /* libPods-SwiftSample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -42,8 +42,8 @@
31F283C976AE97586C17CCD9 /* Pods */ = {
isa = PBXGroup;
children = (
- 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */,
- C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */,
+ A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */,
+ C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@@ -90,7 +90,7 @@
9D63A7F6423989BA306810CA /* Frameworks */ = {
isa = PBXGroup;
children = (
- DC58ACA18DCCB1553531B885 /* libPods.a */,
+ 69BB5C6CA3C1F97E007AC527 /* libPods-SwiftSample.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -102,12 +102,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */;
buildPhases = (
- 6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */,
+ 6BEEB33CA2705D7D2F2210E6 /* [CP] Check Pods Manifest.lock */,
633BFFBE1B950B210007E424 /* Sources */,
633BFFBF1B950B210007E424 /* Frameworks */,
633BFFC01B950B210007E424 /* Resources */,
- AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */,
- A1738A987353B0BF2C64F0F7 /* Embed Pods Frameworks */,
+ AC2F6F9AB1C090BB0BEE6E4D /* [CP] Copy Pods Resources */,
+ A1738A987353B0BF2C64F0F7 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -164,14 +164,14 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */ = {
+ 6BEEB33CA2705D7D2F2210E6 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -179,34 +179,34 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- A1738A987353B0BF2C64F0F7 /* Embed Pods Frameworks */ = {
+ A1738A987353B0BF2C64F0F7 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */ = {
+ AC2F6F9AB1C090BB0BEE6E4D /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftSample/Pods-SwiftSample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -320,7 +320,7 @@
};
633BFFE21B950B210007E424 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = A7E614A494D89D01BB395761 /* Pods-SwiftSample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Info.plist;
@@ -333,7 +333,7 @@
};
633BFFE31B950B210007E424 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */;
+ baseConfigurationReference = C314E3E246AF23AC29B38FCF /* Pods-SwiftSample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Info.plist;
diff --git a/src/objective-c/examples/SwiftSample/ViewController.swift b/src/objective-c/examples/SwiftSample/ViewController.swift
index a21ce07978..2a95d2de51 100644
--- a/src/objective-c/examples/SwiftSample/ViewController.swift
+++ b/src/objective-c/examples/SwiftSample/ViewController.swift
@@ -71,7 +71,8 @@ class ViewController: UIViewController {
NSLog("2. Response trailers: \(RPC.responseTrailers)")
}
- RPC.requestHeaders["My-Header"] = "My value"
+ // TODO(jcanizales): Revert to using subscript syntax once XCode 8 is released.
+ RPC.requestHeaders.setObject("My value", forKey: "My-Header")
RPC.start()
@@ -84,7 +85,7 @@ class ViewController: UIViewController {
let call = GRPCCall(host: RemoteHost, path: method.HTTPPath, requestsWriter: requestsWriter)
- call.requestHeaders["My-Header"] = "My value"
+ call.requestHeaders.setObject("My value", forKey: "My-Header")
call.startWithWriteable(GRXWriteable { response, error in
if let response = response as? NSData {
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 9a8d425324..1167a715bb 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -48,9 +48,9 @@ static NSString * const kPackage = @"grpc.testing";
static NSString * const kService = @"TestService";
static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
-static ProtoMethod *kInexistentMethod;
-static ProtoMethod *kEmptyCallMethod;
-static ProtoMethod *kUnaryCallMethod;
+static GRPCProtoMethod *kInexistentMethod;
+static GRPCProtoMethod *kEmptyCallMethod;
+static GRPCProtoMethod *kUnaryCallMethod;
/** Observer class for testing that responseMetadata is KVO-compliant */
@interface PassthroughObserver : NSObject
@@ -109,15 +109,15 @@ static ProtoMethod *kUnaryCallMethod;
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
// This method isn't implemented by the remote server.
- kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
- service:kService
- method:@"Inexistent"];
- kEmptyCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
- service:kService
- method:@"EmptyCall"];
- kUnaryCallMethod = [[ProtoMethod alloc] initWithPackage:kPackage
- service:kService
- method:@"UnaryCall"];
+ kInexistentMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+ service:kService
+ method:@"Inexistent"];
+ kEmptyCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+ service:kService
+ method:@"EmptyCall"];
+ kUnaryCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage
+ service:kService
+ method:@"UnaryCall"];
}
- (void)testConnectionToRemoteServer {
@@ -303,9 +303,9 @@ static ProtoMethod *kUnaryCallMethod;
// Try to set parameters to nil for GRPCCall. This should cause an exception
@try {
- GRPCCall *call = [[GRPCCall alloc] initWithHost:nil
- path:nil
- requestsWriter:nil];
+ (void)[[GRPCCall alloc] initWithHost:nil
+ path:nil
+ requestsWriter:nil];
XCTFail(@"Did not receive an exception when parameters are nil");
} @catch(NSException *theException) {
NSLog(@"Received exception as expected: %@", theException.name);
@@ -316,9 +316,9 @@ static ProtoMethod *kUnaryCallMethod;
GRXWriter *requestsWriter = [GRXWriter emptyWriter];
[requestsWriter finishWithError:nil];
@try {
- GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
- path:kUnaryCallMethod.HTTPPath
- requestsWriter:requestsWriter];
+ (void)[[GRPCCall alloc] initWithHost:kHostAddress
+ path:kUnaryCallMethod.HTTPPath
+ requestsWriter:requestsWriter];
XCTFail(@"Did not receive an exception when GRXWriter has incorrect state.");
} @catch(NSException *theException) {
NSLog(@"Received exception as expected: %@", theException.name);
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index 781c500f73..15ce120c55 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -58,7 +58,7 @@
requestedResponseSize:(NSNumber *)responseSize {
RMTStreamingOutputCallRequest *request = [self message];
RMTResponseParameters *parameters = [RMTResponseParameters message];
- parameters.size = responseSize.integerValue;
+ parameters.size = (int)responseSize.integerValue;
[request.responseParametersArray addObject:parameters];
request.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue];
return request;
@@ -80,7 +80,9 @@
#pragma mark Tests
+#ifdef GRPC_COMPILE_WITH_CRONET
static cronet_engine *cronetEngine = NULL;
+#endif
@implementation InteropTests {
RMTTestService *_service;
@@ -186,7 +188,7 @@ static cronet_engine *cronetEngine = NULL;
RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message];
for (NSNumber *size in expectedSizes) {
RMTResponseParameters *parameters = [RMTResponseParameters message];
- parameters.size = [size integerValue];
+ parameters.size = (int)[size integerValue];
[request.responseParametersArray addObject:parameters];
}
@@ -282,9 +284,9 @@ static cronet_engine *cronetEngine = NULL;
// A buffered pipe to which we never write any value acts as a writer that just hangs.
GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init];
- ProtoRPC *call = [_service RPCToStreamingInputCallWithRequestsWriter:requestsBuffer
- handler:^(RMTStreamingInputCallResponse *response,
- NSError *error) {
+ GRPCProtoCall *call = [_service RPCToStreamingInputCallWithRequestsWriter:requestsBuffer
+ handler:^(RMTStreamingInputCallResponse *response,
+ NSError *error) {
XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED);
[expectation fulfill];
}];
@@ -313,7 +315,7 @@ static cronet_engine *cronetEngine = NULL;
[requestsBuffer writeValue:request];
- __block ProtoRPC *call =
+ __block GRPCProtoCall *call =
[_service RPCToFullDuplexCallWithRequestsWriter:requestsBuffer
eventHandler:^(BOOL done,
RMTStreamingOutputCallResponse *response,
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 508641d681..6d5f94cbda 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -1,32 +1,52 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
-pod 'Protobuf', :path => "../../../third_party/protobuf"
-pod 'BoringSSL', :podspec => ".."
-pod 'CronetFramework', :podspec => ".."
-pod 'gRPC', :path => "../../.."
-pod 'RemoteTest', :path => "RemoteTestClient"
-
-link_with 'AllTests',
- 'RxLibraryUnitTests',
- 'InteropTests',
- 'InteropTestsLocalSSL',
- 'InteropTestsLocalCleartext'
+install! 'cocoapods', :deterministic_uuids => false
+
+def shared_pods
+ pod 'Protobuf', :path => "../../../third_party/protobuf", :inhibit_warnings => true
+ pod 'BoringSSL', :podspec => "..", :inhibit_warnings => true
+ pod 'CronetFramework', :podspec => ".."
+ pod 'gRPC', :path => "../../.."
+ pod 'RemoteTest', :path => "RemoteTestClient"
+end
target 'Tests' do
+ shared_pods
end
target 'AllTests' do
+ shared_pods
end
target 'RxLibraryUnitTests' do
+ shared_pods
end
target 'InteropTestsRemote' do
+ shared_pods
end
target 'InteropTestsLocalSSL' do
+ shared_pods
end
target 'InteropTestsLocalCleartext' do
+ shared_pods
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ target.build_configurations.each do |config|
+ config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES'
+ end
+ if target.name == 'gRPC'
+ 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
+ # function" warning
+ config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO'
+ end
+ end
+ end
end
diff --git a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
index 6ecef0593b..e1fd991038 100644
--- a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
@@ -2,6 +2,10 @@ Pod::Spec.new do |s|
s.name = "RemoteTest"
s.version = "0.0.1"
s.license = "New BSD"
+ s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
+ s.homepage = "http://www.grpc.io/"
+ s.summary = "RemoteTest example"
+ s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = '7.1'
s.osx.deployment_target = '10.9'
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index b0429617c0..e895fe6c79 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -7,33 +7,34 @@
objects = {
/* Begin PBXBuildFile section */
- 036D953EE34B1FD523647ACD /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
- 08A8BB02D19A53D902B214B8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
- 50267643BA114A2A724D4FDF /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
+ 0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */; };
+ 16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; };
+ 20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
+ 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
+ 3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */; };
6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; };
635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
63715F561B780C020029CB0B /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
- 6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; };
- 6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; };
- 6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; settings = {ASSET_TAGS = (); }; };
- 6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; settings = {ASSET_TAGS = (); }; };
- 6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; settings = {ASSET_TAGS = (); }; };
- 63DC84181BE15179000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; };
- 63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; settings = {ASSET_TAGS = (); }; };
- 63DC84281BE15267000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; };
- 63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; settings = {ASSET_TAGS = (); }; };
- 63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; settings = {ASSET_TAGS = (); }; };
- 63DC84391BE15294000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; };
- 63DC84481BE152B5000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; settings = {ASSET_TAGS = (); }; };
- 63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; settings = {ASSET_TAGS = (); }; };
- 63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; settings = {ASSET_TAGS = (); }; };
- 63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; settings = {ASSET_TAGS = (); }; };
+ 6379CC4D1BE1662A001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
+ 6379CC4E1BE1662B001BC0A1 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
+ 6379CC501BE16703001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
+ 6379CC511BE1683B001BC0A1 /* InteropTestsRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 6379CC4F1BE16703001BC0A1 /* InteropTestsRemote.m */; };
+ 6379CC531BE17709001BC0A1 /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
+ 63DC84181BE15179000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+ 63DC841E1BE15180000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
+ 63DC84281BE15267000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+ 63DC842E1BE15278000708E8 /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
+ 63DC842F1BE1527D000708E8 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
+ 63DC84391BE15294000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+ 63DC84481BE152B5000708E8 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+ 63DC844E1BE15350000708E8 /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
+ 63DC844F1BE15353000708E8 /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
+ 63DC84501BE153AA000708E8 /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
- 7D8A186224D39101F90230F6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
- DCFAE001609CCBFE69DFA6A1 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
+ F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -87,8 +88,15 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = "<group>"; };
+ 07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+ 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.release.xcconfig"; sourceTree = "<group>"; };
+ 51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.release.xcconfig"; sourceTree = "<group>"; };
+ 553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.debug.xcconfig"; sourceTree = "<group>"; };
+ 5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = "<group>"; };
63423F441B150A5F006CF63C /* AllTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AllTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
63423F501B151B77006CF63C /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
@@ -105,6 +113,17 @@
63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = "<group>"; };
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = "<group>"; };
+ 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = "<group>"; };
+ A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RxLibraryUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.debug.xcconfig"; sourceTree = "<group>"; };
+ CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AllTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemote.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalSSL.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.debug.xcconfig"; sourceTree = "<group>"; };
+ E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.debug.xcconfig"; sourceTree = "<group>"; };
+ E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = "<group>"; };
+ E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = "<group>"; };
+ FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartext.a"; sourceTree = BUILT_PRODUCTS_DIR; };
FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -114,7 +133,7 @@
buildActionMask = 2147483647;
files = (
63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */,
- 7D8A186224D39101F90230F6 /* libPods.a in Frameworks */,
+ F15EF7852DC70770EFDB1D2C /* libPods-AllTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -122,6 +141,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -130,7 +150,7 @@
buildActionMask = 2147483647;
files = (
63DC84181BE15179000708E8 /* libTests.a in Frameworks */,
- 036D953EE34B1FD523647ACD /* libPods.a in Frameworks */,
+ 20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -139,7 +159,7 @@
buildActionMask = 2147483647;
files = (
63DC84281BE15267000708E8 /* libTests.a in Frameworks */,
- DCFAE001609CCBFE69DFA6A1 /* libPods.a in Frameworks */,
+ 0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -148,7 +168,7 @@
buildActionMask = 2147483647;
files = (
63DC84391BE15294000708E8 /* libTests.a in Frameworks */,
- 08A8BB02D19A53D902B214B8 /* libPods.a in Frameworks */,
+ 16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -157,7 +177,7 @@
buildActionMask = 2147483647;
files = (
63DC84481BE152B5000708E8 /* libTests.a in Frameworks */,
- 50267643BA114A2A724D4FDF /* libPods.a in Frameworks */,
+ 333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -168,6 +188,12 @@
isa = PBXGroup;
children = (
35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */,
+ CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */,
+ FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */,
+ DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */,
+ DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */,
+ A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */,
+ 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -177,6 +203,18 @@
children = (
FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */,
0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */,
+ B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */,
+ 5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */,
+ E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */,
+ 51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */,
+ 553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */,
+ 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */,
+ DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */,
+ E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */,
+ 07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */,
+ 3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */,
+ 060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */,
+ E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
@@ -236,12 +274,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */;
buildPhases = (
- 914ADDD7106BA9BB8A7E569F /* Check Pods Manifest.lock */,
+ 914ADDD7106BA9BB8A7E569F /* 📦 Check Pods Manifest.lock */,
63423F401B150A5F006CF63C /* Sources */,
63423F411B150A5F006CF63C /* Frameworks */,
63423F421B150A5F006CF63C /* Resources */,
- A441F71824DCB9D0CA297748 /* Copy Pods Resources */,
- 5F14F59509E10C2852014F9E /* Embed Pods Frameworks */,
+ A441F71824DCB9D0CA297748 /* 📦 Copy Pods Resources */,
+ 5F14F59509E10C2852014F9E /* 📦 Embed Pods Frameworks */,
);
buildRules = (
);
@@ -257,9 +295,11 @@
isa = PBXNativeTarget;
buildConfigurationList = 635697DB1B14FC11007A7283 /* Build configuration list for PBXNativeTarget "Tests" */;
buildPhases = (
+ 796680C7599CB4ED736DD62A /* 📦 Check Pods Manifest.lock */,
635697C31B14FC11007A7283 /* Sources */,
635697C41B14FC11007A7283 /* Frameworks */,
635697C51B14FC11007A7283 /* CopyFiles */,
+ AEEBFC914CBAEE347382E8C4 /* 📦 Copy Pods Resources */,
);
buildRules = (
);
@@ -274,12 +314,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 63DC841B1BE15179000708E8 /* Build configuration list for PBXNativeTarget "RxLibraryUnitTests" */;
buildPhases = (
- B2986CEEE8CDD4901C97598B /* Check Pods Manifest.lock */,
+ B2986CEEE8CDD4901C97598B /* 📦 Check Pods Manifest.lock */,
63DC840F1BE15179000708E8 /* Sources */,
63DC84101BE15179000708E8 /* Frameworks */,
63DC84111BE15179000708E8 /* Resources */,
- 4F5690DC0E6AD6663FE78B8B /* Embed Pods Frameworks */,
- C977426A8727267BBAC7D48E /* Copy Pods Resources */,
+ 4F5690DC0E6AD6663FE78B8B /* 📦 Embed Pods Frameworks */,
+ C977426A8727267BBAC7D48E /* 📦 Copy Pods Resources */,
);
buildRules = (
);
@@ -295,12 +335,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 63DC842B1BE15267000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsRemote" */;
buildPhases = (
- 4C406327D3907A5E5FBA8AC9 /* Check Pods Manifest.lock */,
+ 4C406327D3907A5E5FBA8AC9 /* 📦 Check Pods Manifest.lock */,
63DC841F1BE15267000708E8 /* Sources */,
63DC84201BE15267000708E8 /* Frameworks */,
63DC84211BE15267000708E8 /* Resources */,
- 900B6EDD4D16BE7D765C3885 /* Embed Pods Frameworks */,
- C2E09DC4BD239F71160F0CC1 /* Copy Pods Resources */,
+ 900B6EDD4D16BE7D765C3885 /* 📦 Embed Pods Frameworks */,
+ C2E09DC4BD239F71160F0CC1 /* 📦 Copy Pods Resources */,
);
buildRules = (
);
@@ -316,12 +356,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 63DC843C1BE15294000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalSSL" */;
buildPhases = (
- 5C20DCCB71C3991E6FE78C22 /* Check Pods Manifest.lock */,
+ 5C20DCCB71C3991E6FE78C22 /* 📦 Check Pods Manifest.lock */,
63DC84301BE15294000708E8 /* Sources */,
63DC84311BE15294000708E8 /* Frameworks */,
63DC84321BE15294000708E8 /* Resources */,
- C591129ACE9F6CC5EE03FCDE /* Embed Pods Frameworks */,
- 693DD0B453431D64EA24FD66 /* Copy Pods Resources */,
+ C591129ACE9F6CC5EE03FCDE /* 📦 Embed Pods Frameworks */,
+ 693DD0B453431D64EA24FD66 /* 📦 Copy Pods Resources */,
);
buildRules = (
);
@@ -337,12 +377,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 63DC844B1BE152B5000708E8 /* Build configuration list for PBXNativeTarget "InteropTestsLocalCleartext" */;
buildPhases = (
- 7418AC7B3844B29E48D24FC7 /* Check Pods Manifest.lock */,
+ 7418AC7B3844B29E48D24FC7 /* 📦 Check Pods Manifest.lock */,
63DC843F1BE152B5000708E8 /* Sources */,
63DC84401BE152B5000708E8 /* Frameworks */,
63DC84411BE152B5000708E8 /* Resources */,
- A8E3AC66DF770B774114A30E /* Embed Pods Frameworks */,
- 8AD3130D3C58A0FB32FF2A36 /* Copy Pods Resources */,
+ A8E3AC66DF770B774114A30E /* 📦 Embed Pods Frameworks */,
+ 8AD3130D3C58A0FB32FF2A36 /* 📦 Copy Pods Resources */,
);
buildRules = (
);
@@ -446,14 +486,14 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 4C406327D3907A5E5FBA8AC9 /* Check Pods Manifest.lock */ = {
+ 4C406327D3907A5E5FBA8AC9 /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -461,29 +501,29 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- 4F5690DC0E6AD6663FE78B8B /* Embed Pods Frameworks */ = {
+ 4F5690DC0E6AD6663FE78B8B /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 5C20DCCB71C3991E6FE78C22 /* Check Pods Manifest.lock */ = {
+ 5C20DCCB71C3991E6FE78C22 /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -491,44 +531,44 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- 5F14F59509E10C2852014F9E /* Embed Pods Frameworks */ = {
+ 5F14F59509E10C2852014F9E /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 693DD0B453431D64EA24FD66 /* Copy Pods Resources */ = {
+ 693DD0B453431D64EA24FD66 /* 📦 Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "📦 Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 7418AC7B3844B29E48D24FC7 /* Check Pods Manifest.lock */ = {
+ 7418AC7B3844B29E48D24FC7 /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -536,44 +576,59 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- 8AD3130D3C58A0FB32FF2A36 /* Copy Pods Resources */ = {
+ 796680C7599CB4ED736DD62A /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+ 8AD3130D3C58A0FB32FF2A36 /* 📦 Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "📦 Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- 900B6EDD4D16BE7D765C3885 /* Embed Pods Frameworks */ = {
+ 900B6EDD4D16BE7D765C3885 /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 914ADDD7106BA9BB8A7E569F /* Check Pods Manifest.lock */ = {
+ 914ADDD7106BA9BB8A7E569F /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -581,44 +636,59 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- A441F71824DCB9D0CA297748 /* Copy Pods Resources */ = {
+ A441F71824DCB9D0CA297748 /* 📦 Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "📦 Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ A8E3AC66DF770B774114A30E /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- A8E3AC66DF770B774114A30E /* Embed Pods Frameworks */ = {
+ AEEBFC914CBAEE347382E8C4 /* 📦 Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "📦 Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- B2986CEEE8CDD4901C97598B /* Check Pods Manifest.lock */ = {
+ B2986CEEE8CDD4901C97598B /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Check Pods Manifest.lock";
+ name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
@@ -626,49 +696,49 @@
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
- C2E09DC4BD239F71160F0CC1 /* Copy Pods Resources */ = {
+ C2E09DC4BD239F71160F0CC1 /* 📦 Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "📦 Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh\"\n";
showEnvVarsInLog = 0;
};
- C591129ACE9F6CC5EE03FCDE /* Embed Pods Frameworks */ = {
+ C591129ACE9F6CC5EE03FCDE /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Embed Pods Frameworks";
+ name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- C977426A8727267BBAC7D48E /* Copy Pods Resources */ = {
+ C977426A8727267BBAC7D48E /* 📦 Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
- name = "Copy Pods Resources";
+ name = "📦 Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -764,7 +834,7 @@
/* Begin XCBuildConfiguration section */
63423F4E1B150A5F006CF63C /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
@@ -782,7 +852,7 @@
};
63423F4F1B150A5F006CF63C /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */;
+ baseConfigurationReference = 5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */;
buildSettings = {
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
@@ -823,6 +893,7 @@
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -859,6 +930,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -874,7 +946,9 @@
};
635697DC1B14FC11007A7283 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */;
buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -882,7 +956,9 @@
};
635697DD1B14FC11007A7283 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */;
buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
@@ -890,7 +966,7 @@
};
63DC841C1BE15179000708E8 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = 07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
@@ -904,7 +980,7 @@
};
63DC841D1BE15179000708E8 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */;
+ baseConfigurationReference = 3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
@@ -916,7 +992,7 @@
};
63DC842C1BE15267000708E8 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = DC3CA1D948F068E76957A861 /* Pods-InteropTestsRemote.debug.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
@@ -930,7 +1006,7 @@
};
63DC842D1BE15267000708E8 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */;
+ baseConfigurationReference = E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
@@ -942,7 +1018,7 @@
};
63DC843D1BE15294000708E8 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = 553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
@@ -956,7 +1032,7 @@
};
63DC843E1BE15294000708E8 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */;
+ baseConfigurationReference = 7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
@@ -968,7 +1044,7 @@
};
63DC844C1BE152B5000708E8 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */;
+ baseConfigurationReference = E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */;
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
@@ -982,7 +1058,7 @@
};
63DC844D1BE152B5000708E8 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */;
+ baseConfigurationReference = 51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */;
buildSettings = {
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
diff --git a/src/objective-c/tests/build_tests.sh b/src/objective-c/tests/build_tests.sh
index e7ad31e403..8547bfd3a8 100755
--- a/src/objective-c/tests/build_tests.sh
+++ b/src/objective-c/tests/build_tests.sh
@@ -33,6 +33,9 @@
set -e
+# CocoaPods requires the terminal to be using UTF-8 encoding.
+export LANG=en_US.UTF-8
+
cd $(dirname $0)
hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; }
diff --git a/src/python/grpcio/grpc/_adapter/_implementations.py b/src/php/bin/stress_client.sh
index b85f228bf6..8c49b7aa4b 100644..100755
--- a/src/python/grpcio/grpc/_adapter/_implementations.py
+++ b/src/php/bin/stress_client.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
# Copyright 2015, Google Inc.
# All rights reserved.
#
@@ -27,22 +28,8 @@
# (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 collections
-
-from grpc.beta import interfaces
-
-class AuthMetadataContext(collections.namedtuple(
- 'AuthMetadataContext', [
- 'service_url',
- 'method_name'
- ]), interfaces.GRPCAuthMetadataContext):
- pass
-
-
-class AuthMetadataPluginCallback(interfaces.GRPCAuthMetadataContext):
-
- def __init__(self, callback):
- self._callback = callback
-
- def __call__(self, metadata, error):
- self._callback(metadata, error)
+set -e
+cd $(dirname $0)
+source ./determine_extension_dir.sh
+php $extension_dir -d max_execution_time=300 \
+ ../tests/interop/stress_client.php $@ 1>&2
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 884130e7d4..0ec502262d 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -292,6 +292,7 @@ PHP_METHOD(Call, startBatch) {
grpc_metadata_array_init(&recv_trailing_metadata);
MAKE_STD_ZVAL(result);
object_init(result);
+ memset(ops, 0, sizeof(ops));
/* "a" == 1 array */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) ==
FAILURE) {
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index 5c537378a6..b76fb105f3 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -47,11 +47,23 @@
#include <zend_exceptions.h>
#include <zend_hash.h>
+#include <grpc/support/alloc.h>
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_channel_credentials;
+static char *default_pem_root_certs = NULL;
+
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+ char **pem_root_certs) {
+ *pem_root_certs = default_pem_root_certs;
+ if (default_pem_root_certs == NULL) {
+ return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+ }
+ return GRPC_SSL_ROOTS_OVERRIDE_OK;
+}
+
/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
wrapped_grpc_channel_credentials *creds =
@@ -94,6 +106,24 @@ zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped TSRMLS
}
/**
+ * Set default roots pem.
+ * @param string pem_roots PEM encoding of the server root certificates
+ * @return void
+ */
+PHP_METHOD(ChannelCredentials, setDefaultRootsPem) {
+ char *pem_roots;
+ int pem_roots_length;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pem_roots,
+ &pem_roots_length) == FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "setDefaultRootsPem expects 1 string", 1 TSRMLS_CC);
+ return;
+ }
+ default_pem_root_certs = gpr_malloc((pem_roots_length + 1) * sizeof(char));
+ memcpy(default_pem_root_certs, pem_roots, pem_roots_length + 1);
+}
+
+/**
* Create a default channel credentials object.
* @return ChannelCredentials The new default channel credentials object
*/
@@ -178,6 +208,8 @@ PHP_METHOD(ChannelCredentials, createInsecure) {
}
static zend_function_entry channel_credentials_methods[] = {
+ PHP_ME(ChannelCredentials, setDefaultRootsPem, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(ChannelCredentials, createDefault, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(ChannelCredentials, createSsl, NULL,
@@ -192,6 +224,7 @@ void grpc_init_channel_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\ChannelCredentials",
channel_credentials_methods);
+ grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
ce.create_object = create_wrapped_grpc_channel_credentials;
grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
}
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index 712af91eb2..c86d298805 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -39,6 +39,7 @@ abstract class AbstractCall
protected $call;
protected $deserialize;
protected $metadata;
+ protected $trailing_metadata;
/**
* Create a new Call wrapper object.
@@ -66,6 +67,7 @@ abstract class AbstractCall
$this->call = new Call($channel, $method, $deadline);
$this->deserialize = $deserialize;
$this->metadata = null;
+ $this->trailing_metadata = null;
if (isset($options['call_credentials_callback']) &&
is_callable($call_credentials_callback =
$options['call_credentials_callback'])) {
@@ -84,6 +86,14 @@ abstract class AbstractCall
}
/**
+ * @return The trailing metadata sent by the server.
+ */
+ public function getTrailingMetadata()
+ {
+ return $this->trailing_metadata;
+ }
+
+ /**
* @return string The URI of the endpoint.
*/
public function getPeer()
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 2de1b337e5..df3fe85d44 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -52,9 +52,14 @@ class BaseStub
* - 'update_metadata': (optional) a callback function which takes in a
* metadata array, and returns an updated metadata array
* - 'grpc.primary_user_agent': (optional) a user-agent string
+ * @param $channel Channel An already created Channel object
*/
- public function __construct($hostname, $opts)
+ public function __construct($hostname, $opts, $channel = null)
{
+ $ssl_roots = file_get_contents(
+ dirname(__FILE__).'/../../../../etc/roots.pem');
+ ChannelCredentials::setDefaultRootsPem($ssl_roots);
+
$this->hostname = $hostname;
$this->update_metadata = null;
if (isset($opts['update_metadata'])) {
@@ -77,7 +82,15 @@ class BaseStub
'required. Please see one of the '.
'ChannelCredentials::create methods');
}
- $this->channel = new Channel($hostname, $opts);
+ if ($channel) {
+ if (!is_a($channel, 'Channel')) {
+ throw new \Exception("The channel argument is not a".
+ "Channel object");
+ }
+ $this->channel = $channel;
+ } else {
+ $this->channel = new Channel($hostname, $opts);
+ }
}
/**
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index bf813c12e7..95e51c5088 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -112,6 +112,7 @@ class BidiStreamingCall extends AbstractCall
OP_RECV_STATUS_ON_CLIENT => true,
]);
+ $this->trailing_metadata = $status_event->status->metadata;
return $status_event->status;
}
}
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 500cfe0d7a..315a406735 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -86,6 +86,8 @@ class ClientStreamingCall extends AbstractCall
]);
$this->metadata = $event->metadata;
- return [$this->deserializeResponse($event->message), $event->status];
+ $status = $event->status;
+ $this->trailing_metadata = $status->metadata;
+ return [$this->deserializeResponse($event->message), $status];
}
}
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index da48523717..53599fe4ae 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -91,6 +91,7 @@ class ServerStreamingCall extends AbstractCall
OP_RECV_STATUS_ON_CLIENT => true,
]);
+ $this->trailing_metadata = $status_event->status->metadata;
return $status_event->status;
}
}
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index b57903d6d0..b114b771b8 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -75,6 +75,8 @@ class UnaryCall extends AbstractCall
OP_RECV_STATUS_ON_CLIENT => true,
]);
- return [$this->deserializeResponse($event->message), $event->status];
+ $status = $event->status;
+ $this->trailing_metadata = $status->metadata;
+ return [$this->deserializeResponse($event->message), $status];
}
}
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 565bfce74f..43b3199d92 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -388,6 +388,103 @@ function timeoutOnSleepingServer($stub)
'Call status was not DEADLINE_EXCEEDED');
}
+function customMetadata($stub)
+{
+ $ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
+ $ECHO_INITIAL_VALUE = 'test_initial_metadata_value';
+ $ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
+ $ECHO_TRAILING_VALUE = 'ababab';
+ $request_len = 271828;
+ $response_len = 314159;
+
+ $request = new grpc\testing\SimpleRequest();
+ $request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE);
+ $request->setResponseSize($response_len);
+ $payload = new grpc\testing\Payload();
+ $payload->setType(grpc\testing\PayloadType::COMPRESSABLE);
+ $payload->setBody(str_repeat("\0", $request_len));
+ $request->setPayload($payload);
+
+ $metadata = [
+ $ECHO_INITIAL_KEY => [$ECHO_INITIAL_VALUE],
+ $ECHO_TRAILING_KEY => [$ECHO_TRAILING_VALUE],
+ ];
+ $call = $stub->UnaryCall($request, $metadata);
+
+ $initial_metadata = $call->getMetadata();
+ hardAssert(array_key_exists($ECHO_INITIAL_KEY, $initial_metadata),
+ 'Initial metadata does not contain expected key');
+ hardAssert($initial_metadata[$ECHO_INITIAL_KEY][0] ==
+ $ECHO_INITIAL_VALUE,
+ 'Incorrect initial metadata value');
+
+ list($result, $status) = $call->wait();
+ hardAssert($status->code === Grpc\STATUS_OK,
+ 'Call did not complete successfully');
+
+ $trailing_metadata = $call->getTrailingMetadata();
+ hardAssert(array_key_exists($ECHO_TRAILING_KEY, $trailing_metadata),
+ 'Trailing metadata does not contain expected key');
+ hardAssert($trailing_metadata[$ECHO_TRAILING_KEY][0] ==
+ $ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
+
+ $streaming_call = $stub->FullDuplexCall($metadata);
+
+ $streaming_request = new grpc\testing\StreamingOutputCallRequest();
+ $streaming_request->setPayload($payload);
+ $streaming_call->write($streaming_request);
+ $streaming_call->writesDone();
+
+ hardAssert($streaming_call->getStatus()->code === Grpc\STATUS_OK,
+ 'Call did not complete successfully');
+
+ $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
+ hardAssert(array_key_exists($ECHO_TRAILING_KEY,
+ $streaming_trailing_metadata),
+ 'Trailing metadata does not contain expected key');
+ hardAssert($streaming_trailing_metadata[$ECHO_TRAILING_KEY][0] ==
+ $ECHO_TRAILING_VALUE, 'Incorrect trailing metadata value');
+}
+
+function statusCodeAndMessage($stub)
+{
+ $echo_status = new grpc\testing\EchoStatus();
+ $echo_status->setCode(2);
+ $echo_status->setMessage("test status message");
+
+ $request = new grpc\testing\SimpleRequest();
+ $request->setResponseStatus($echo_status);
+
+ $call = $stub->UnaryCall($request);
+ list($result, $status) = $call->wait();
+
+ hardAssert($status->code === 2,
+ 'Received unexpected status code');
+ hardAssert($status->details === "test status message",
+ 'Received unexpected status details');
+
+ $streaming_call = $stub->FullDuplexCall();
+
+ $streaming_request = new grpc\testing\StreamingOutputCallRequest();
+ $streaming_request->setResponseStatus($echo_status);
+ $streaming_call->write($streaming_request);
+ $streaming_call->writesDone();
+
+ $status = $streaming_call->getStatus();
+ hardAssert($status->code === 2,
+ 'Received unexpected status code');
+ hardAssert($status->details === "test status message",
+ 'Received unexpected status details');
+}
+
+function unimplementedMethod($stub)
+{
+ $call = $stub->UnimplementedCall(new grpc\testing\EmptyMessage());
+ list($result, $status) = $call->wait();
+ hardAssert($status->code === Grpc\STATUS_UNIMPLEMENTED,
+ 'Received unexpected status code');
+}
+
function _makeStub($args)
{
if (!array_key_exists('server_host', $args)) {
@@ -472,12 +569,17 @@ function _makeStub($args)
$opts['update_metadata'] = $update_metadata;
}
- $stub = new grpc\testing\TestServiceClient($server_address, $opts);
+ if ($test_case == 'unimplemented_method') {
+ $stub = new grpc\testing\UnimplementedServiceClient($server_address, $opts);
+ } else {
+ $stub = new grpc\testing\TestServiceClient($server_address, $opts);
+ }
return $stub;
}
-function interop_main($args, $stub = false) {
+function interop_main($args, $stub = false)
+{
if (!$stub) {
$stub = _makeStub($args);
}
@@ -513,6 +615,15 @@ function interop_main($args, $stub = false) {
case 'timeout_on_sleeping_server':
timeoutOnSleepingServer($stub);
break;
+ case 'custom_metadata':
+ customMetadata($stub);
+ break;
+ case 'status_code_and_message':
+ statusCodeAndMessage($stub);
+ break;
+ case 'unimplemented_method':
+ unimplementedMethod($stub);
+ break;
case 'service_account_creds':
serviceAccountCreds($stub, $args);
break;
diff --git a/src/php/tests/interop/messages.proto b/src/php/tests/interop/messages.proto
index de0b1a2320..44e3c3b8f9 100644
--- a/src/php/tests/interop/messages.proto
+++ b/src/php/tests/interop/messages.proto
@@ -1,5 +1,5 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -41,9 +41,6 @@ enum PayloadType {
// Uncompressable binary format.
UNCOMPRESSABLE = 1;
-
- // Randomly chosen from all other formats defined in this enum.
- RANDOM = 2;
}
// A block of data, to simply increase gRPC message size.
@@ -54,6 +51,13 @@ message Payload {
optional bytes body = 2;
}
+// A protobuf representation for grpc status. This is used by test
+// clients to specify a status that the server should attempt to return.
+message EchoStatus {
+ optional int32 code = 1;
+ optional string message = 2;
+}
+
// Unary request.
message SimpleRequest {
// Desired payload type in the response from the server.
@@ -72,6 +76,12 @@ message SimpleRequest {
// Whether SimpleResponse should include OAuth scope.
optional bool fill_oauth_scope = 5;
+
+ // Whether to request the server to compress the response.
+ optional bool request_compressed_response = 6;
+
+ // Whether server should return a given status
+ optional EchoStatus response_status = 7;
}
// Unary response, as configured by the request.
@@ -123,6 +133,12 @@ message StreamingOutputCallRequest {
// Optional input payload sent along with the request.
optional Payload payload = 3;
+
+ // Whether to request the server to compress the response.
+ optional bool request_compressed_response = 6;
+
+ // Whether server should return a given status
+ optional EchoStatus response_status = 7;
}
// Server-streaming response, as configured by the request and parameters.
@@ -130,3 +146,17 @@ message StreamingOutputCallResponse {
// Payload to increase response size.
optional Payload payload = 1;
}
+
+// For reconnect interop test only.
+// Client tells server what reconnection parameters it used.
+message ReconnectParams {
+ optional int32 max_reconnect_backoff_ms = 1;
+}
+
+// For reconnect interop test only.
+// Server tells client whether its reconnects are following the spec and the
+// reconnect backoffs it saw.
+message ReconnectInfo {
+ optional bool passed = 1;
+ repeated int32 backoff_ms = 2;
+}
diff --git a/src/php/tests/interop/metrics_client.php b/src/php/tests/interop/metrics_client.php
index 46f4212f77..19510dc5d8 100644
--- a/src/php/tests/interop/metrics_client.php
+++ b/src/php/tests/interop/metrics_client.php
@@ -39,11 +39,11 @@ $server_port = (count($parts) == 2) ? $parts[1] : '';
$socket = socket_create(AF_INET, SOCK_STREAM, 0);
if (@!socket_connect($socket, $server_host, $server_port)) {
- echo "Cannot connect to merics server...\n";
- exit(1);
+ echo "Cannot connect to merics server...\n";
+ exit(1);
}
socket_write($socket, 'qps');
while ($out = socket_read($socket, 1024)) {
- echo "$out\n";
+ echo "$out\n";
}
socket_close($socket);
diff --git a/src/php/tests/interop/stress_client.php b/src/php/tests/interop/stress_client.php
index 2339f0d105..f9cfe8aba5 100644
--- a/src/php/tests/interop/stress_client.php
+++ b/src/php/tests/interop/stress_client.php
@@ -32,50 +32,52 @@
*
*/
-include_once('interop_client.php');
+include_once 'interop_client.php';
-function stress_main($args) {
- mt_srand();
- set_time_limit(0);
+function stress_main($args)
+{
+ mt_srand();
+ set_time_limit(0);
- // open socket to listen as metrics server
- $socket = socket_create(AF_INET, SOCK_STREAM, 0);
- socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
- if (@!socket_bind($socket, 'localhost', $args['metrics_port'])) {
- echo "Cannot create socket for metrics server...\n";
- exit(1);
- }
- socket_listen($socket);
- socket_set_nonblock($socket);
+ // open socket to listen as metrics server
+ $socket = socket_create(AF_INET, SOCK_STREAM, 0);
+ socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
+ if (@!socket_bind($socket, 'localhost', $args['metrics_port'])) {
+ echo "Cannot create socket for metrics server...\n";
+ exit(1);
+ }
+ socket_listen($socket);
+ socket_set_nonblock($socket);
- $start_time = microtime(true);
- $count = 0;
- $deadline = $args['test_duration_secs'] ?
- ($start_time + $args['test_duration_secs']) : false;
- $num_test_cases = count($args['test_cases']);
- $stub = false;
+ $start_time = microtime(true);
+ $count = 0;
+ $deadline = $args['test_duration_secs'] ?
+ ($start_time + $args['test_duration_secs']) : false;
+ $num_test_cases = count($args['test_cases']);
+ $stub = false;
- while (true) {
- $current_time = microtime(true);
- if ($deadline && $current_time > $deadline) {
- break;
- }
- if ($client_connection = socket_accept($socket)) {
- // there is an incoming request, respond with qps metrics
- $input = socket_read($client_connection, 1024);
- $qps = round($count / ($current_time - $start_time));
- socket_write($client_connection, "qps: $qps");
- socket_close($client_connection);
- } else {
- // do actual work, run one interop test case
- $args['test_case'] =
- $args['test_cases'][mt_rand(0, $num_test_cases - 1)];
- $stub = @interop_main($args, $stub);
- $count++;
+ while (true) {
+ $current_time = microtime(true);
+ if ($deadline && $current_time > $deadline) {
+ break;
+ }
+ if ($client_connection = socket_accept($socket)) {
+ // there is an incoming request, respond with qps metrics
+ $input = socket_read($client_connection, 1024);
+ $qps = round($count / ($current_time - $start_time));
+ socket_write($client_connection, "qps: $qps");
+ socket_close($client_connection);
+ } else {
+ // do actual work, run one interop test case
+ $args['test_case'] =
+ $args['test_cases'][mt_rand(0, $num_test_cases - 1)];
+ $stub = @interop_main($args, $stub);
+ ++$count;
+ }
}
- }
- socket_close($socket);
- echo "Number of interop tests run in $args[test_duration_secs] seconds: $count.\n";
+ socket_close($socket);
+ echo "Number of interop tests run in $args[test_duration_secs] ".
+ "seconds: $count.\n";
}
// process command line arguments
@@ -85,31 +87,32 @@ $raw_args = getopt('',
'metrics_port::',
'test_duration_secs::',
'num_channels_per_server::',
- 'num_stubs_per_channel::']);
+ 'num_stubs_per_channel::',
+ ]);
$args = [];
if (empty($raw_args['server_addresses'])) {
- $args['server_host'] = 'localhost';
- $args['server_port'] = '8080';
+ $args['server_host'] = 'localhost';
+ $args['server_port'] = '8080';
} else {
- $parts = explode(':', $raw_args['server_addresses']);
- $args['server_host'] = $parts[0];
- $args['server_port'] = (count($parts) == 2) ? $parts[1] : '';
+ $parts = explode(':', $raw_args['server_addresses']);
+ $args['server_host'] = $parts[0];
+ $args['server_port'] = (count($parts) == 2) ? $parts[1] : '';
}
$args['metrics_port'] = empty($raw_args['metrics_port']) ?
- '8081' : $args['metrics_port'];
+ '8081' : $raw_args['metrics_port'];
$args['test_duration_secs'] = empty($raw_args['test_duration_secs']) ||
- $raw_args['test_duration_secs'] == -1 ?
- false : $raw_args['test_duration_secs'];
+ $raw_args['test_duration_secs'] == -1 ?
+ false : $raw_args['test_duration_secs'];
$test_cases = [];
$test_case_strs = explode(',', $raw_args['test_cases']);
foreach ($test_case_strs as $test_case_str) {
- $parts = explode(':', $test_case_str);
- $test_cases = array_merge($test_cases, array_fill(0, $parts[1], $parts[0]));
+ $parts = explode(':', $test_case_str);
+ $test_cases = array_merge($test_cases, array_fill(0, $parts[1], $parts[0]));
}
$args['test_cases'] = $test_cases;
diff --git a/src/php/tests/interop/test.proto b/src/php/tests/interop/test.proto
index 0d169e7f64..57ef30ee1c 100644
--- a/src/php/tests/interop/test.proto
+++ b/src/php/tests/interop/test.proto
@@ -1,5 +1,5 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -69,3 +69,10 @@ service TestService {
rpc HalfDuplexCall(stream StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
}
+
+// A simple service NOT implemented at servers so clients can test for
+// that case.
+service UnimplementedService {
+ // A call that no server should implement
+ rpc UnimplementedCall(grpc.testing.EmptyMessage) returns (grpc.testing.EmptyMessage);
+}
diff --git a/src/proto/grpc/binary_log/v1alpha/log.proto b/src/proto/grpc/binary_log/v1alpha/log.proto
index 83166cd410..46656109bc 100644
--- a/src/proto/grpc/binary_log/v1alpha/log.proto
+++ b/src/proto/grpc/binary_log/v1alpha/log.proto
@@ -29,20 +29,20 @@
syntax = "proto3";
-import "google/protobuf/timestamp.proto"
+import "google/protobuf/timestamp.proto";
package grpc.binary_log.v1alpha;
enum Direction {
- SERVER_SEND;
- SERVER_RECV;
- CLIENT_SEND;
- CLIENT_RECV;
+ SERVER_SEND = 0;
+ SERVER_RECV = 1;
+ CLIENT_SEND = 2;
+ CLIENT_RECV = 3;
}
message KeyValuePair {
- string key;
- string value;
+ string key = 1;
+ string value = 2;
}
// Any sort of metadata that may be sent in either direction during a call
diff --git a/src/proto/grpc/testing/messages.proto b/src/proto/grpc/testing/messages.proto
index a063b470c7..64998c2f23 100644
--- a/src/proto/grpc/testing/messages.proto
+++ b/src/proto/grpc/testing/messages.proto
@@ -34,28 +34,24 @@ syntax = "proto3";
package grpc.testing;
+// TODO(dgq): Go back to using well-known types once
+// https://github.com/grpc/grpc/issues/6980 has been fixed.
+// import "google/protobuf/wrappers.proto";
+message BoolValue {
+ // The bool value.
+ bool value = 1;
+}
+
+// DEPRECATED, don't use. To be removed shortly.
// The type of payload that should be returned.
enum PayloadType {
// Compressable text format.
COMPRESSABLE = 0;
-
- // Uncompressable binary format.
- UNCOMPRESSABLE = 1;
-
- // Randomly chosen from all other formats defined in this enum.
- RANDOM = 2;
-}
-
-// Compression algorithms
-enum CompressionType {
- // No compression
- NONE = 0;
- GZIP = 1;
- DEFLATE = 2;
}
// A block of data, to simply increase gRPC message size.
message Payload {
+ // DEPRECATED, don't use. To be removed shortly.
// The type of data in body.
PayloadType type = 1;
// Primary contents of payload.
@@ -71,12 +67,12 @@ message EchoStatus {
// Unary request.
message SimpleRequest {
+ // DEPRECATED, don't use. To be removed shortly.
// Desired payload type in the response from the server.
// If response_type is RANDOM, server randomly chooses one from other formats.
PayloadType response_type = 1;
// Desired payload size in the response from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
int32 response_size = 2;
// Optional input payload sent along with the request.
@@ -88,11 +84,17 @@ message SimpleRequest {
// Whether SimpleResponse should include OAuth scope.
bool fill_oauth_scope = 5;
- // Compression algorithm to be used by the server for the response (stream)
- CompressionType response_compression = 6;
+ // Whether to request the server to compress the response. This field is
+ // "nullable" in order to interoperate seamlessly with clients not able to
+ // implement the full compression tests by introspecting the call to verify
+ // the response's compression status.
+ BoolValue response_compressed = 6;
// Whether server should return a given status
EchoStatus response_status = 7;
+
+ // Whether the server should expect this request to be compressed.
+ BoolValue expect_compressed = 8;
}
// Unary response, as configured by the request.
@@ -111,6 +113,12 @@ message StreamingInputCallRequest {
// Optional input payload sent along with the request.
Payload payload = 1;
+ // Whether the server should expect this request to be compressed. This field
+ // is "nullable" in order to interoperate seamlessly with servers not able to
+ // implement the full compression tests by introspecting the call to verify
+ // the request's compression status.
+ BoolValue expect_compressed = 2;
+
// Not expecting any payload from the response.
}
@@ -123,16 +131,22 @@ message StreamingInputCallResponse {
// Configuration for a particular response.
message ResponseParameters {
// Desired payload sizes in responses from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
int32 size = 1;
// Desired interval between consecutive responses in the response stream in
// microseconds.
int32 interval_us = 2;
+
+ // Whether to request the server to compress the response. This field is
+ // "nullable" in order to interoperate seamlessly with clients not able to
+ // implement the full compression tests by introspecting the call to verify
+ // the response's compression status.
+ BoolValue compressed = 3;
}
// Server-streaming request.
message StreamingOutputCallRequest {
+ // DEPRECATED, don't use. To be removed shortly.
// Desired payload type in the response from the server.
// If response_type is RANDOM, the payload from each response in the stream
// might be of different types. This is to simulate a mixed type of payload
@@ -145,9 +159,6 @@ message StreamingOutputCallRequest {
// Optional input payload sent along with the request.
Payload payload = 3;
- // Compression algorithm to be used by the server for the response (stream)
- CompressionType response_compression = 6;
-
// Whether server should return a given status
EchoStatus response_status = 7;
}
diff --git a/src/proto/math/math.proto b/src/proto/math/math.proto
index 311e148c02..269c60bde8 100644
--- a/src/proto/math/math.proto
+++ b/src/proto/math/math.proto
@@ -55,8 +55,8 @@ message FibReply {
}
service Math {
- // Div divides args.dividend by args.divisor and returns the quotient and
- // remainder.
+ // Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+ // and remainder.
rpc Div (DivArgs) returns (DivReply) {
}
@@ -67,7 +67,7 @@ service Math {
rpc DivMany (stream DivArgs) returns (stream DivReply) {
}
- // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ // Fib generates numbers in the Fibonacci sequence. If FibArgs.limit > 0, Fib
// generates up to limit numbers; otherwise it continues until the call is
// canceled. Unlike Fib above, Fib has no final FibReply.
rpc Fib (FibArgs) returns (stream Num) {
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 295dab2d27..f498ed4190 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -182,6 +182,8 @@ class BuildProtoModules(setuptools.Command):
'--plugin=protoc-gen-python-grpc={}'.format(
self.grpc_python_plugin_command),
'-I {}'.format(GRPC_STEM),
+ '-I .',
+ '-I {}/third_party/protobuf/src'.format(GRPC_STEM),
'--python_out={}'.format(PROTO_GEN_STEM),
'--python-grpc_out={}'.format(PROTO_GEN_STEM),
] + [path]
@@ -191,7 +193,7 @@ class BuildProtoModules(setuptools.Command):
except subprocess.CalledProcessError as e:
sys.stderr.write(
'warning: Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format(
- command, e.message, e.output))
+ command, str(e), e.output))
# Generated proto directories dont include __init__.py, but
# these are needed for python package resolution
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index bbf04ad03e..b3eeaad1f7 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -29,8 +29,6 @@
"""gRPC's Python API."""
-__import__('pkg_resources').declare_namespace(__name__)
-
import abc
import enum
@@ -212,14 +210,14 @@ class ChannelConnectivity(enum.Enum):
READY: The channel is ready to conduct RPCs.
TRANSIENT_FAILURE: The channel has seen a failure from which it expects to
recover.
- FATAL_FAILURE: The channel has seen a failure from which it cannot recover.
+ SHUTDOWN: The channel has seen a failure from which it cannot recover.
"""
IDLE = (_cygrpc.ConnectivityState.idle, 'idle')
CONNECTING = (_cygrpc.ConnectivityState.connecting, 'connecting')
READY = (_cygrpc.ConnectivityState.ready, 'ready')
TRANSIENT_FAILURE = (
_cygrpc.ConnectivityState.transient_failure, 'transient failure')
- FATAL_FAILURE = (_cygrpc.ConnectivityState.fatal_failure, 'fatal failure')
+ SHUTDOWN = (_cygrpc.ConnectivityState.shutdown, 'shutdown')
@enum.unique
@@ -438,9 +436,7 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
"""Affords invoking a unary-unary RPC."""
@abc.abstractmethod
- def __call__(
- self, request, timeout=None, metadata=None, credentials=None,
- with_call=False):
+ def __call__(self, request, timeout=None, metadata=None, credentials=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -449,12 +445,30 @@ class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: An optional sequence of pairs of bytes to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
- with_call: Whether or not to include return a Call for the RPC in addition
- to the response.
Returns:
- The response value for the RPC, and a Call for the RPC if with_call was
- set to True at invocation.
+ The response value for the RPC.
+
+ Raises:
+ RpcError: Indicating that the RPC terminated with non-OK status. The
+ raised RpcError will also be a Call for the RPC affording the RPC's
+ metadata, status code, and details.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ """Synchronously invokes the underlying RPC.
+
+ Args:
+ request: The request value for the RPC.
+ timeout: An optional durating of time in seconds to allow for the RPC.
+ metadata: An optional sequence of pairs of bytes to be transmitted to the
+ service-side of the RPC.
+ credentials: An optional CallCredentials for the RPC.
+
+ Returns:
+ The response value for the RPC and a Call value for the RPC.
Raises:
RpcError: Indicating that the RPC terminated with non-OK status. The
@@ -510,8 +524,7 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def __call__(
- self, request_iterator, timeout=None, metadata=None, credentials=None,
- with_call=False):
+ self, request_iterator, timeout=None, metadata=None, credentials=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -520,8 +533,6 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
metadata: An optional sequence of pairs of bytes to be transmitted to the
service-side of the RPC.
credentials: An optional CallCredentials for the RPC.
- with_call: Whether or not to include return a Call for the RPC in addition
- to the response.
Returns:
The response value for the RPC, and a Call for the RPC if with_call was
@@ -535,6 +546,28 @@ class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
raise NotImplementedError()
@abc.abstractmethod
+ def with_call(
+ self, request_iterator, timeout=None, metadata=None, credentials=None):
+ """Synchronously invokes the underlying RPC.
+
+ Args:
+ request_iterator: An iterator that yields request values for the RPC.
+ timeout: An optional duration of time in seconds to allow for the RPC.
+ metadata: An optional sequence of pairs of bytes to be transmitted to the
+ service-side of the RPC.
+ credentials: An optional CallCredentials for the RPC.
+
+ Returns:
+ The response value for the RPC and a Call for the RPC.
+
+ Raises:
+ RpcError: Indicating that the RPC terminated with non-OK status. The
+ raised RpcError will also be a Call for the RPC affording the RPC's
+ metadata, status code, and details.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
def future(
self, request_iterator, timeout=None, metadata=None, credentials=None):
"""Asynchronously invokes the underlying RPC.
@@ -900,6 +933,102 @@ class Server(six.with_metaclass(abc.ABCMeta)):
################################# Functions ################################
+def unary_unary_rpc_method_handler(
+ behavior, request_deserializer=None, response_serializer=None):
+ """Creates an RpcMethodHandler for a unary-unary RPC method.
+
+ Args:
+ behavior: The implementation of an RPC method as a callable behavior taking
+ a single request value and returning a single response value.
+ request_deserializer: An optional request deserialization behavior.
+ response_serializer: An optional response serialization behavior.
+
+ Returns:
+ An RpcMethodHandler for a unary-unary RPC method constructed from the given
+ parameters.
+ """
+ from grpc import _utilities
+ return _utilities.RpcMethodHandler(
+ False, False, request_deserializer, response_serializer, behavior, None,
+ None, None)
+
+
+def unary_stream_rpc_method_handler(
+ behavior, request_deserializer=None, response_serializer=None):
+ """Creates an RpcMethodHandler for a unary-stream RPC method.
+
+ Args:
+ behavior: The implementation of an RPC method as a callable behavior taking
+ a single request value and returning an iterator of response values.
+ request_deserializer: An optional request deserialization behavior.
+ response_serializer: An optional response serialization behavior.
+
+ Returns:
+ An RpcMethodHandler for a unary-stream RPC method constructed from the
+ given parameters.
+ """
+ from grpc import _utilities
+ return _utilities.RpcMethodHandler(
+ False, True, request_deserializer, response_serializer, None, behavior,
+ None, None)
+
+
+def stream_unary_rpc_method_handler(
+ behavior, request_deserializer=None, response_serializer=None):
+ """Creates an RpcMethodHandler for a stream-unary RPC method.
+
+ Args:
+ behavior: The implementation of an RPC method as a callable behavior taking
+ an iterator of request values and returning a single response value.
+ request_deserializer: An optional request deserialization behavior.
+ response_serializer: An optional response serialization behavior.
+
+ Returns:
+ An RpcMethodHandler for a stream-unary RPC method constructed from the
+ given parameters.
+ """
+ from grpc import _utilities
+ return _utilities.RpcMethodHandler(
+ True, False, request_deserializer, response_serializer, None, None,
+ behavior, None)
+
+
+def stream_stream_rpc_method_handler(
+ behavior, request_deserializer=None, response_serializer=None):
+ """Creates an RpcMethodHandler for a stream-stream RPC method.
+
+ Args:
+ behavior: The implementation of an RPC method as a callable behavior taking
+ an iterator of request values and returning an iterator of response
+ values.
+ request_deserializer: An optional request deserialization behavior.
+ response_serializer: An optional response serialization behavior.
+
+ Returns:
+ An RpcMethodHandler for a stream-stream RPC method constructed from the
+ given parameters.
+ """
+ from grpc import _utilities
+ return _utilities.RpcMethodHandler(
+ True, True, request_deserializer, response_serializer, None, None, None,
+ behavior)
+
+
+def method_handlers_generic_handler(service, method_handlers):
+ """Creates a grpc.GenericRpcHandler from RpcMethodHandlers.
+
+ Args:
+ service: A service name to be used for the given method handlers.
+ method_handlers: A dictionary from method name to RpcMethodHandler
+ implementing the named method.
+
+ Returns:
+ A GenericRpcHandler constructed from the given parameters.
+ """
+ from grpc import _utilities
+ return _utilities.DictionaryGenericHandler(service, method_handlers)
+
+
def ssl_channel_credentials(
root_certificates=None, private_key=None, certificate_chain=None):
"""Creates a ChannelCredentials for use with an SSL-enabled Channel.
@@ -947,6 +1076,21 @@ def metadata_call_credentials(metadata_plugin, name=None):
metadata_plugin, effective_name))
+def access_token_call_credentials(access_token):
+ """Construct CallCredentials from an access token.
+
+ Args:
+ access_token: A string to place directly in the http request
+ authorization header, ie "Authorization: Bearer <access_token>".
+
+ Returns:
+ A CallCredentials.
+ """
+ from grpc import _auth
+ return metadata_call_credentials(
+ _auth.AccessTokenCallCredentials(access_token))
+
+
def composite_call_credentials(call_credentials, additional_call_credentials):
"""Compose two CallCredentials to make a new one.
@@ -1044,7 +1188,7 @@ def insecure_channel(target, options=None):
A Channel to the target through which RPCs may be conducted.
"""
from grpc import _channel
- return _channel.Channel(target, None, options)
+ return _channel.Channel(target, options, None)
def secure_channel(target, credentials, options=None):
@@ -1060,7 +1204,7 @@ def secure_channel(target, credentials, options=None):
A Channel to the target through which RPCs may be conducted.
"""
from grpc import _channel
- return _channel.Channel(target, credentials, options)
+ return _channel.Channel(target, options, credentials._credentials)
def server(generic_rpc_handlers, thread_pool, options=None):
@@ -1082,3 +1226,49 @@ def server(generic_rpc_handlers, thread_pool, options=None):
"""
from grpc import _server
return _server.Server(generic_rpc_handlers, thread_pool)
+
+
+################################### __all__ #################################
+
+
+__all__ = (
+ 'FutureTimeoutError',
+ 'FutureCancelledError',
+ 'Future',
+ 'ChannelConnectivity',
+ 'StatusCode',
+ 'RpcError',
+ 'RpcContext',
+ 'Call',
+ 'ChannelCredentials',
+ 'CallCredentials',
+ 'AuthMetadataContext',
+ 'AuthMetadataPluginCallback',
+ 'AuthMetadataPlugin',
+ 'ServerCredentials',
+ 'UnaryUnaryMultiCallable',
+ 'UnaryStreamMultiCallable',
+ 'StreamUnaryMultiCallable',
+ 'StreamStreamMultiCallable',
+ 'Channel',
+ 'ServicerContext',
+ 'RpcMethodHandler',
+ 'HandlerCallDetails',
+ 'GenericRpcHandler',
+ 'Server',
+ 'unary_unary_rpc_method_handler',
+ 'unary_stream_rpc_method_handler',
+ 'stream_unary_rpc_method_handler',
+ 'stream_stream_rpc_method_handler',
+ 'method_handlers_generic_handler',
+ 'ssl_channel_credentials',
+ 'metadata_call_credentials',
+ 'access_token_call_credentials',
+ 'composite_call_credentials',
+ 'composite_channel_credentials',
+ 'ssl_server_credentials',
+ 'channel_ready_future',
+ 'insecure_channel',
+ 'secure_channel',
+ 'server',
+)
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index 00788bd4cf..48410167a0 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -30,8 +30,8 @@
import threading
from grpc import _grpcio_metadata
+from grpc import _plugin_wrapping
from grpc._cython import cygrpc
-from grpc._adapter import _implementations
from grpc._adapter import _types
_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
@@ -57,78 +57,8 @@ def channel_credentials_ssl(
return cygrpc.channel_credentials_ssl(root_certificates, pair)
-class _WrappedCygrpcCallback(object):
-
- def __init__(self, cygrpc_callback):
- self.is_called = False
- self.error = None
- self.is_called_lock = threading.Lock()
- self.cygrpc_callback = cygrpc_callback
-
- def _invoke_failure(self, error):
- # TODO(atash) translate different Exception superclasses into different
- # status codes.
- self.cygrpc_callback(
- cygrpc.Metadata([]), cygrpc.StatusCode.internal, error.message)
-
- def _invoke_success(self, metadata):
- try:
- cygrpc_metadata = cygrpc.Metadata(
- cygrpc.Metadatum(key, value)
- for key, value in metadata)
- except Exception as error:
- self._invoke_failure(error)
- return
- self.cygrpc_callback(cygrpc_metadata, cygrpc.StatusCode.ok, '')
-
- def __call__(self, metadata, error):
- with self.is_called_lock:
- if self.is_called:
- raise RuntimeError('callback should only ever be invoked once')
- if self.error:
- self._invoke_failure(self.error)
- return
- self.is_called = True
- if error is None:
- self._invoke_success(metadata)
- else:
- self._invoke_failure(error)
-
- def notify_failure(self, error):
- with self.is_called_lock:
- if not self.is_called:
- self.error = error
-
-
-class _WrappedPlugin(object):
-
- def __init__(self, plugin):
- self.plugin = plugin
-
- def __call__(self, context, cygrpc_callback):
- wrapped_cygrpc_callback = _WrappedCygrpcCallback(cygrpc_callback)
- wrapped_context = _implementations.AuthMetadataContext(context.service_url,
- context.method_name)
- try:
- self.plugin(
- wrapped_context,
- _implementations.AuthMetadataPluginCallback(wrapped_cygrpc_callback))
- except Exception as error:
- wrapped_cygrpc_callback.notify_failure(error)
- raise
-
-
-def call_credentials_metadata_plugin(plugin, name):
- """
- Args:
- plugin: A callable accepting a _types.AuthMetadataContext
- object and a callback (itself accepting a list of metadata key/value
- 2-tuples and a None-able exception value). The callback must be eventually
- called, but need not be called in plugin's invocation.
- plugin's invocation must be non-blocking.
- """
- return cygrpc.call_credentials_metadata_plugin(
- cygrpc.CredentialsMetadataPlugin(_WrappedPlugin(plugin), name))
+call_credentials_metadata_plugin = (
+ _plugin_wrapping.call_credentials_metadata_plugin)
class CompletionQueue(_types.CompletionQueue):
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index f8405949d4..b7cc6fbbb5 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -114,7 +114,7 @@ class ConnectivityState(enum.IntEnum):
CONNECTING = cygrpc.ConnectivityState.connecting
READY = cygrpc.ConnectivityState.ready
TRANSIENT_FAILURE = cygrpc.ConnectivityState.transient_failure
- FATAL_FAILURE = cygrpc.ConnectivityState.fatal_failure
+ FATAL_FAILURE = cygrpc.ConnectivityState.shutdown
class Status(collections.namedtuple(
diff --git a/src/python/grpcio/grpc/beta/_auth.py b/src/python/grpcio/grpc/_auth.py
index 553d4b9991..dea3221c9d 100644
--- a/src/python/grpcio/grpc/beta/_auth.py
+++ b/src/python/grpcio/grpc/_auth.py
@@ -29,9 +29,10 @@
"""GRPCAuthMetadataPlugins for standard authentication."""
+import inspect
from concurrent import futures
-from grpc.beta import interfaces
+import grpc
def _sign_request(callback, token, error):
@@ -39,16 +40,28 @@ def _sign_request(callback, token, error):
callback(metadata, error)
-class GoogleCallCredentials(interfaces.GRPCAuthMetadataPlugin):
+class GoogleCallCredentials(grpc.AuthMetadataPlugin):
"""Metadata wrapper for GoogleCredentials from the oauth2client library."""
def __init__(self, credentials):
self._credentials = credentials
self._pool = futures.ThreadPoolExecutor(max_workers=1)
+ # Hack to determine if these are JWT creds and we need to pass
+ # additional_claims when getting a token
+ if 'additional_claims' in inspect.getargspec(
+ credentials.get_access_token).args:
+ self._is_jwt = True
+ else:
+ self._is_jwt = False
+
def __call__(self, context, callback):
# MetadataPlugins cannot block (see grpc.beta.interfaces.py)
- future = self._pool.submit(self._credentials.get_access_token)
+ if self._is_jwt:
+ future = self._pool.submit(self._credentials.get_access_token,
+ additional_claims={'aud': context.service_url})
+ else:
+ future = self._pool.submit(self._credentials.get_access_token)
future.add_done_callback(lambda x: self._get_token_callback(callback, x))
def _get_token_callback(self, callback, future):
@@ -63,7 +76,7 @@ class GoogleCallCredentials(interfaces.GRPCAuthMetadataPlugin):
self._pool.shutdown(wait=False)
-class AccessTokenCallCredentials(interfaces.GRPCAuthMetadataPlugin):
+class AccessTokenCallCredentials(grpc.AuthMetadataPlugin):
"""Metadata wrapper for raw access token credentials."""
def __init__(self, access_token):
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index d9eb5a4b77..1f34beeb2c 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -85,7 +85,7 @@ def _deadline(timeout):
def _unknown_code_details(unknown_cygrpc_code, details):
- return b'Server sent unknown code {} and details "{}"'.format(
+ return 'Server sent unknown code {} and details "{}"'.format(
unknown_cygrpc_code, details)
@@ -134,19 +134,19 @@ def _handle_event(event, state, response_deserializer):
for batch_operation in event.batch_operations:
operation_type = batch_operation.type
state.due.remove(operation_type)
- if operation_type is cygrpc.OperationType.receive_initial_metadata:
+ if operation_type == cygrpc.OperationType.receive_initial_metadata:
state.initial_metadata = batch_operation.received_metadata
- elif operation_type is cygrpc.OperationType.receive_message:
+ elif operation_type == cygrpc.OperationType.receive_message:
serialized_response = batch_operation.received_message.bytes()
if serialized_response is not None:
response = _common.deserialize(
serialized_response, response_deserializer)
if response is None:
- details = b'Exception deserializing response!'
+ details = 'Exception deserializing response!'
_abort(state, grpc.StatusCode.INTERNAL, details)
else:
state.response = response
- elif operation_type is cygrpc.OperationType.receive_status_on_client:
+ elif operation_type == cygrpc.OperationType.receive_status_on_client:
state.trailing_metadata = batch_operation.received_metadata
if state.code is None:
code = _common.CYGRPC_STATUS_CODE_TO_STATUS_CODE.get(
@@ -186,7 +186,7 @@ def _consume_request_iterator(
if state.code is None and not state.cancelled:
if serialized_request is None:
call.cancel()
- details = b'Exception serializing request!'
+ details = 'Exception serializing request!'
_abort(state, grpc.StatusCode.INTERNAL, details)
return
else:
@@ -230,7 +230,7 @@ class _Rendezvous(grpc.RpcError, grpc.Future, grpc.Call):
if self._state.code is None:
self._call.cancel()
self._state.cancelled = True
- _abort(self._state, grpc.StatusCode.CANCELLED, b'Cancelled!')
+ _abort(self._state, grpc.StatusCode.CANCELLED, 'Cancelled!')
self._state.condition.notify_all()
return False
@@ -402,7 +402,7 @@ def _start_unary_request(request, timeout, request_serializer):
if serialized_request is None:
state = _RPCState(
(), _EMPTY_METADATA, _EMPTY_METADATA, grpc.StatusCode.INTERNAL,
- b'Exception serializing request!')
+ 'Exception serializing request!')
rendezvous = _Rendezvous(state, None, None, deadline)
return deadline, deadline_timespec, None, rendezvous
else:
@@ -449,9 +449,7 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
)
return state, operations, deadline, deadline_timespec, None
- def __call__(
- self, request, timeout=None, metadata=None, credentials=None,
- with_call=False):
+ def _blocking(self, request, timeout, metadata, credentials):
state, operations, deadline, deadline_timespec, rendezvous = self._prepare(
request, timeout, metadata)
if rendezvous:
@@ -464,7 +462,15 @@ class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
call.set_credentials(credentials._credentials)
call.start_batch(cygrpc.Operations(operations), None)
_handle_event(completion_queue.poll(), state, self._response_deserializer)
- return _end_unary_response_blocking(state, with_call, deadline)
+ return state, deadline
+
+ def __call__(self, request, timeout=None, metadata=None, credentials=None):
+ state, deadline, = self._blocking(request, timeout, metadata, credentials)
+ return _end_unary_response_blocking(state, False, deadline)
+
+ def with_call(self, request, timeout=None, metadata=None, credentials=None):
+ state, deadline, = self._blocking(request, timeout, metadata, credentials)
+ return _end_unary_response_blocking(state, True, deadline)
def future(self, request, timeout=None, metadata=None, credentials=None):
state, operations, deadline, deadline_timespec, rendezvous = self._prepare(
@@ -532,9 +538,7 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
self._request_serializer = request_serializer
self._response_deserializer = response_deserializer
- def __call__(
- self, request_iterator, timeout=None, metadata=None, credentials=None,
- with_call=False):
+ def _blocking(self, request_iterator, timeout, metadata, credentials):
deadline, deadline_timespec = _deadline(timeout)
state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
completion_queue = cygrpc.CompletionQueue()
@@ -563,7 +567,19 @@ class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
state.condition.notify_all()
if not state.due:
break
- return _end_unary_response_blocking(state, with_call, deadline)
+ return state, deadline
+
+ def __call__(
+ self, request_iterator, timeout=None, metadata=None, credentials=None):
+ state, deadline, = self._blocking(
+ request_iterator, timeout, metadata, credentials)
+ return _end_unary_response_blocking(state, False, deadline)
+
+ def with_call(
+ self, request_iterator, timeout=None, metadata=None, credentials=None):
+ state, deadline, = self._blocking(
+ request_iterator, timeout, metadata, credentials)
+ return _end_unary_response_blocking(state, True, deadline)
def future(
self, request_iterator, timeout=None, metadata=None, credentials=None):
@@ -814,6 +830,13 @@ def _options(options):
class Channel(grpc.Channel):
def __init__(self, target, options, credentials):
+ """Constructor.
+
+ Args:
+ target: The target to which to connect.
+ options: Configuration options for the channel.
+ credentials: A cygrpc.ChannelCredentials or None.
+ """
self._channel = cygrpc.Channel(target, _options(options), credentials)
self._call_state = _ChannelCallState(self._channel)
self._connectivity_state = _ChannelConnectivityState(self._channel)
diff --git a/src/python/grpcio/grpc/_common.py b/src/python/grpcio/grpc/_common.py
index a3fb66cd07..f351bea9e3 100644
--- a/src/python/grpcio/grpc/_common.py
+++ b/src/python/grpcio/grpc/_common.py
@@ -30,6 +30,8 @@
"""Shared implementation."""
import logging
+import threading
+import time
import six
@@ -44,8 +46,8 @@ CYGRPC_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
cygrpc.ConnectivityState.ready: grpc.ChannelConnectivity.READY,
cygrpc.ConnectivityState.transient_failure:
grpc.ChannelConnectivity.TRANSIENT_FAILURE,
- cygrpc.ConnectivityState.fatal_failure:
- grpc.ChannelConnectivity.FATAL_FAILURE,
+ cygrpc.ConnectivityState.shutdown:
+ grpc.ChannelConnectivity.SHUTDOWN,
}
CYGRPC_STATUS_CODE_TO_STATUS_CODE = {
@@ -97,3 +99,56 @@ def serialize(message, serializer):
def deserialize(serialized_message, deserializer):
return _transform(serialized_message, deserializer,
'Exception deserializing message!')
+
+
+def _encode(s):
+ if isinstance(s, bytes):
+ return s
+ else:
+ return s.encode('ascii')
+
+
+def fully_qualified_method(group, method):
+ group = _encode(group)
+ method = _encode(method)
+ return b'/' + group + b'/' + method
+
+
+class CleanupThread(threading.Thread):
+ """A threading.Thread subclass supporting custom behavior on join().
+
+ On Python Interpreter exit, Python will attempt to join outstanding threads
+ prior to garbage collection. We may need to do additional cleanup, and
+ we accomplish this by overriding the join() method.
+ """
+
+ def __init__(self, behavior, group=None, target=None, name=None,
+ args=(), kwargs={}):
+ """Constructor.
+
+ Args:
+ behavior (function): Function called on join() with a single
+ argument, timeout, indicating the maximum duration of
+ `behavior`, or None indicating `behavior` has no deadline.
+ `behavior` must be idempotent.
+ group (None): should be None. Reseved for future extensions
+ when ThreadGroup is implemented.
+ target (function): The function to invoke when this thread is
+ run. Defaults to None.
+ name (str): The name of this thread. Defaults to None.
+ args (tuple[object]): A tuple of arguments to pass to `target`.
+ kwargs (dict[str,object]): A dictionary of keyword arguments to
+ pass to `target`.
+ """
+ super(CleanupThread, self).__init__(group=group, target=target,
+ name=name, args=args, kwargs=kwargs)
+ self._behavior = behavior
+
+ def join(self, timeout=None):
+ start_time = time.time()
+ self._behavior(timeout)
+ end_time = time.time()
+ if timeout is not None:
+ timeout -= end_time - start_time
+ timeout = max(timeout, 0)
+ super(CleanupThread, self).join(timeout)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index 1bfe6344e0..a09bbc75fe 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -55,6 +55,7 @@ cdef class Call:
def cancel(
self, grpc_status_code error_code=GRPC_STATUS__DO_NOT_USE,
details=None):
+ details = str_to_bytes(details)
if not self.is_valid:
raise ValueError("invalid call object cannot be used from Python")
if (details is None) != (error_code == GRPC_STATUS__DO_NOT_USE):
@@ -63,12 +64,6 @@ cdef class Call:
cdef grpc_call_error result
cdef char *c_details = NULL
if error_code != GRPC_STATUS__DO_NOT_USE:
- if isinstance(details, bytes):
- pass
- elif isinstance(details, basestring):
- details = details.encode()
- else:
- raise TypeError("expected details to be str or bytes")
self.references.append(details)
c_details = details
with nogil:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index c26bc083cf..866cff0d01 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -34,18 +34,13 @@ cdef class Channel:
def __cinit__(self, target, ChannelArgs arguments=None,
ChannelCredentials channel_credentials=None):
+ target = str_to_bytes(target)
cdef grpc_channel_args *c_arguments = NULL
cdef char *c_target = NULL
self.c_channel = NULL
self.references = []
if arguments is not None:
c_arguments = &arguments.c_args
- if isinstance(target, bytes):
- pass
- elif isinstance(target, basestring):
- target = target.encode()
- else:
- raise TypeError("expected target to be str or bytes")
c_target = target
if channel_credentials is None:
with nogil:
@@ -62,25 +57,14 @@ cdef class Channel:
def create_call(self, Call parent, int flags,
CompletionQueue queue not None,
method, host, Timespec deadline not None):
+ method = str_to_bytes(method)
+ host = str_to_bytes(host)
if queue.is_shutting_down:
raise ValueError("queue must not be shutting down or shutdown")
- if isinstance(method, bytes):
- pass
- elif isinstance(method, basestring):
- method = method.encode()
- else:
- raise TypeError("expected method to be str or bytes")
cdef char *method_c_string = method
cdef char *host_c_string = NULL
- if host is None:
- pass
- elif isinstance(host, bytes):
+ if host is not None:
host_c_string = host
- elif isinstance(host, basestring):
- host = host.encode()
- host_c_string = host
- else:
- raise TypeError("expected host to be str, bytes, or None")
cdef Call operation_call = Call()
operation_call.references = [self, method, host, queue]
cdef grpc_call *parent_call = NULL
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
index a67c963684..01089c3dc0 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
@@ -31,9 +31,6 @@
cdef class CompletionQueue:
cdef grpc_completion_queue *c_completion_queue
- cdef object pluck_condition
- cdef int num_plucking
- cdef int num_polling
cdef bint is_shutting_down
cdef bint is_shutdown
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index cdae39d519..90266516fe 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -32,6 +32,8 @@ cimport cpython
import threading
import time
+cdef int _INTERRUPT_CHECK_PERIOD_MS = 200
+
cdef class CompletionQueue:
@@ -40,9 +42,6 @@ cdef class CompletionQueue:
self.c_completion_queue = grpc_completion_queue_create(NULL)
self.is_shutting_down = False
self.is_shutdown = False
- self.pluck_condition = threading.Condition()
- self.num_plucking = 0
- self.num_polling = 0
cdef _interpret_event(self, grpc_event event):
cdef OperationTag tag = None
@@ -83,45 +82,27 @@ cdef class CompletionQueue:
def poll(self, Timespec deadline=None):
# We name this 'poll' to avoid problems with CPython's expectations for
# 'special' methods (like next and __next__).
+ cdef gpr_timespec c_increment
+ cdef gpr_timespec c_timeout
cdef gpr_timespec c_deadline
with nogil:
+ c_increment = gpr_time_from_millis(_INTERRUPT_CHECK_PERIOD_MS, GPR_TIMESPAN)
c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
- if deadline is not None:
- c_deadline = deadline.c_time
- cdef grpc_event event
-
- # Poll within a critical section to detect contention
- with self.pluck_condition:
- assert self.num_plucking == 0, 'cannot simultaneously pluck and poll'
- self.num_polling += 1
- with nogil:
- event = grpc_completion_queue_next(
- self.c_completion_queue, c_deadline, NULL)
- with self.pluck_condition:
- self.num_polling -= 1
- return self._interpret_event(event)
-
- def pluck(self, OperationTag tag, Timespec deadline=None):
- # Plucking a 'None' tag is equivalent to passing control to GRPC core until
- # the deadline.
- cdef gpr_timespec c_deadline = gpr_inf_future(
- GPR_CLOCK_REALTIME)
- if deadline is not None:
- c_deadline = deadline.c_time
- cdef grpc_event event
-
- # Pluck within a critical section to detect contention
- with self.pluck_condition:
- assert self.num_polling == 0, 'cannot simultaneously pluck and poll'
- assert self.num_plucking < GRPC_MAX_COMPLETION_QUEUE_PLUCKERS, (
- 'cannot pluck more than {} times simultaneously'.format(
- GRPC_MAX_COMPLETION_QUEUE_PLUCKERS))
- self.num_plucking += 1
- with nogil:
- event = grpc_completion_queue_pluck(
- self.c_completion_queue, <cpython.PyObject *>tag, c_deadline, NULL)
- with self.pluck_condition:
- self.num_plucking -= 1
+ if deadline is not None:
+ c_deadline = deadline.c_time
+
+ while True:
+ c_timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c_increment)
+ if gpr_time_cmp(c_timeout, c_deadline) > 0:
+ c_timeout = c_deadline
+ event = grpc_completion_queue_next(
+ self.c_completion_queue, c_timeout, NULL)
+ if event.type != GRPC_QUEUE_TIMEOUT or gpr_time_cmp(c_timeout, c_deadline) == 0:
+ break;
+
+ # Handle any signals
+ with gil:
+ cpython.PyErr_CheckSignals()
return self._interpret_event(event)
def shutdown(self):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
index 19a59e08f3..d377a67520 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
@@ -54,7 +54,7 @@ cdef class ServerCredentials:
cdef class CredentialsMetadataPlugin:
cdef object plugin_callback
- cdef str plugin_name
+ cdef bytes plugin_name
cdef grpc_metadata_credentials_plugin make_c_plugin(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 1ba86457af..470382d609 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -82,7 +82,7 @@ cdef class ServerCredentials:
cdef class CredentialsMetadataPlugin:
- def __cinit__(self, object plugin_callback, str name):
+ def __cinit__(self, object plugin_callback, name):
"""
Args:
plugin_callback (callable): Callback accepting a service URL (str/bytes)
@@ -93,6 +93,7 @@ cdef class CredentialsMetadataPlugin:
successful).
name (str): Plugin name.
"""
+ name = str_to_bytes(name)
if not callable(plugin_callback):
raise ValueError('expected callable plugin_callback')
self.plugin_callback = plugin_callback
@@ -129,7 +130,8 @@ cdef void plugin_get_metadata(
grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
def python_callback(
Metadata metadata, grpc_status_code status,
- const char *error_details):
+ error_details):
+ error_details = str_to_bytes(error_details)
cb(user_data, metadata.c_metadata_array.metadata,
metadata.c_metadata_array.count, status, error_details)
cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
@@ -148,14 +150,7 @@ def channel_credentials_google_default():
def channel_credentials_ssl(pem_root_certificates,
SslPemKeyCertPair ssl_pem_key_cert_pair):
- if pem_root_certificates is None:
- pass
- elif isinstance(pem_root_certificates, bytes):
- pass
- elif isinstance(pem_root_certificates, basestring):
- pem_root_certificates = pem_root_certificates.encode()
- else:
- raise TypeError("expected str or bytes for pem_root_certificates")
+ pem_root_certificates = str_to_bytes(pem_root_certificates)
cdef ChannelCredentials credentials = ChannelCredentials()
cdef const char *c_pem_root_certificates = NULL
if pem_root_certificates is not None:
@@ -207,12 +202,7 @@ def call_credentials_google_compute_engine():
def call_credentials_service_account_jwt_access(
json_key, Timespec token_lifetime not None):
- if isinstance(json_key, bytes):
- pass
- elif isinstance(json_key, basestring):
- json_key = json_key.encode()
- else:
- raise TypeError("expected json_key to be str or bytes")
+ json_key = str_to_bytes(json_key)
cdef CallCredentials credentials = CallCredentials()
cdef char *json_key_c_string = json_key
with nogil:
@@ -223,12 +213,7 @@ def call_credentials_service_account_jwt_access(
return credentials
def call_credentials_google_refresh_token(json_refresh_token):
- if isinstance(json_refresh_token, bytes):
- pass
- elif isinstance(json_refresh_token, basestring):
- json_refresh_token = json_refresh_token.encode()
- else:
- raise TypeError("expected json_refresh_token to be str or bytes")
+ json_refresh_token = str_to_bytes(json_refresh_token)
cdef CallCredentials credentials = CallCredentials()
cdef char *json_refresh_token_c_string = json_refresh_token
with nogil:
@@ -238,18 +223,8 @@ def call_credentials_google_refresh_token(json_refresh_token):
return credentials
def call_credentials_google_iam(authorization_token, authority_selector):
- if isinstance(authorization_token, bytes):
- pass
- elif isinstance(authorization_token, basestring):
- authorization_token = authorization_token.encode()
- else:
- raise TypeError("expected authorization_token to be str or bytes")
- if isinstance(authority_selector, bytes):
- pass
- elif isinstance(authority_selector, basestring):
- authority_selector = authority_selector.encode()
- else:
- raise TypeError("expected authority_selector to be str or bytes")
+ authorization_token = str_to_bytes(authorization_token)
+ authority_selector = str_to_bytes(authority_selector)
cdef CallCredentials credentials = CallCredentials()
cdef char *authorization_token_c_string = authorization_token
cdef char *authority_selector_c_string = authority_selector
@@ -272,16 +247,10 @@ def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
bint force_client_auth):
+ pem_root_certs = str_to_bytes(pem_root_certs)
cdef char *c_pem_root_certs = NULL
- if pem_root_certs is None:
- pass
- elif isinstance(pem_root_certs, bytes):
- c_pem_root_certs = pem_root_certs
- elif isinstance(pem_root_certs, basestring):
- pem_root_certs = pem_root_certs.encode()
+ if pem_root_certs is not None:
c_pem_root_certs = pem_root_certs
- else:
- raise TypeError("expected pem_root_certs to be str or bytes")
pem_key_cert_pairs = list(pem_key_cert_pairs)
for pair in pem_key_cert_pairs:
if not isinstance(pair, SslPemKeyCertPair):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 05b8886df7..168b9751aa 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -80,6 +80,12 @@ cdef extern from "grpc/_cython/loader.h":
gpr_timespec gpr_convert_clock_type(gpr_timespec t,
gpr_clock_type target_clock) nogil
+ gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) nogil
+
+ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) nogil
+
+ int gpr_time_cmp(gpr_timespec a, gpr_timespec b) nogil
+
ctypedef enum grpc_status_code:
GRPC_STATUS_OK
GRPC_STATUS_CANCELLED
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
new file mode 100644
index 0000000000..274f038e0a
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc_string.pyx.pxi
@@ -0,0 +1,39 @@
+# 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.
+
+
+# This function will ascii encode unicode string inputs if neccesary.
+# In Python3, unicode strings are the default str type.
+cdef bytes str_to_bytes(object s):
+ if s is None or isinstance(s, bytes):
+ return s
+ elif isinstance(s, unicode):
+ return s.encode('ascii')
+ else:
+ raise TypeError('Expected bytes, str, or unicode, not {}'.format(type(s)))
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index e0219b0086..0055d0d3a2 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -33,7 +33,7 @@ class ConnectivityState:
connecting = GRPC_CHANNEL_CONNECTING
ready = GRPC_CHANNEL_READY
transient_failure = GRPC_CHANNEL_TRANSIENT_FAILURE
- fatal_failure = GRPC_CHANNEL_SHUTDOWN
+ shutdown = GRPC_CHANNEL_SHUTDOWN
class ChannelArgKey:
@@ -235,18 +235,13 @@ cdef class ByteBuffer:
if data is None:
self.c_byte_buffer = NULL
return
- if isinstance(data, bytes):
- pass
- elif isinstance(data, basestring):
- data = data.encode()
- elif isinstance(data, ByteBuffer):
+ if isinstance(data, ByteBuffer):
data = (<ByteBuffer>data).bytes()
if data is None:
self.c_byte_buffer = NULL
return
else:
- raise TypeError("expected value to be of type str, bytes, or "
- "ByteBuffer, not {}".format(type(data)))
+ data = str_to_bytes(data)
cdef char *c_data = data
cdef gpr_slice data_slice
@@ -302,19 +297,8 @@ cdef class ByteBuffer:
cdef class SslPemKeyCertPair:
def __cinit__(self, private_key, certificate_chain):
- if isinstance(private_key, bytes):
- self.private_key = private_key
- elif isinstance(private_key, basestring):
- self.private_key = private_key.encode()
- else:
- raise TypeError("expected private_key to be of type str or bytes")
- if isinstance(certificate_chain, bytes):
- self.certificate_chain = certificate_chain
- elif isinstance(certificate_chain, basestring):
- self.certificate_chain = certificate_chain.encode()
- else:
- raise TypeError("expected certificate_chain to be of type str or bytes "
- "or int")
+ self.private_key = str_to_bytes(private_key)
+ self.certificate_chain = str_to_bytes(certificate_chain)
self.c_pair.private_key = self.private_key
self.c_pair.certificate_chain = self.certificate_chain
@@ -322,27 +306,16 @@ cdef class SslPemKeyCertPair:
cdef class ChannelArg:
def __cinit__(self, key, value):
- if isinstance(key, bytes):
- self.key = key
- elif isinstance(key, basestring):
- self.key = key.encode()
- else:
- raise TypeError("expected key to be of type str or bytes")
- if isinstance(value, bytes):
- self.value = value
- self.c_arg.type = GRPC_ARG_STRING
- self.c_arg.value.string = self.value
- elif isinstance(value, basestring):
- self.value = value.encode()
- self.c_arg.type = GRPC_ARG_STRING
- self.c_arg.value.string = self.value
- elif isinstance(value, int):
+ self.key = str_to_bytes(key)
+ self.c_arg.key = self.key
+ if isinstance(value, int):
self.value = int(value)
self.c_arg.type = GRPC_ARG_INTEGER
self.c_arg.value.integer = self.value
else:
- raise TypeError("expected value to be of type str or bytes or int")
- self.c_arg.key = self.key
+ self.value = str_to_bytes(value)
+ self.c_arg.type = GRPC_ARG_STRING
+ self.c_arg.value.string = self.value
cdef class ChannelArgs:
@@ -375,18 +348,8 @@ cdef class ChannelArgs:
cdef class Metadatum:
def __cinit__(self, key, value):
- if isinstance(key, bytes):
- self._key = key
- elif isinstance(key, basestring):
- self._key = key.encode()
- else:
- raise TypeError("expected key to be of type str or bytes")
- if isinstance(value, bytes):
- self._value = value
- elif isinstance(value, basestring):
- self._value = value.encode()
- else:
- raise TypeError("expected value to be of type str or bytes")
+ self._key = str_to_bytes(key)
+ self._value = str_to_bytes(value)
self.c_metadata.key = self._key
self.c_metadata.value = self._value
self.c_metadata.value_length = len(self._value)
@@ -601,12 +564,7 @@ def operation_send_close_from_client(int flags):
def operation_send_status_from_server(
Metadata metadata, grpc_status_code code, details, int flags):
- if isinstance(details, bytes):
- pass
- elif isinstance(details, basestring):
- details = details.encode()
- else:
- raise TypeError("expected a str or bytes object for details")
+ details = str_to_bytes(details)
cdef Operation op = Operation()
op.c_op.type = GRPC_OP_SEND_STATUS_FROM_SERVER
op.c_op.flags = flags
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index 55948755b2..42afeb8498 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -99,16 +99,11 @@ cdef class Server:
with nogil:
grpc_server_start(self.c_server)
# Ensure the core has gotten a chance to do the start-up work
- self.backup_shutdown_queue.pluck(None, Timespec(None))
+ self.backup_shutdown_queue.poll(Timespec(None))
def add_http2_port(self, address,
ServerCredentials server_credentials=None):
- if isinstance(address, bytes):
- pass
- elif isinstance(address, basestring):
- address = address.encode()
- else:
- raise TypeError("expected address to be a str or bytes")
+ address = str_to_bytes(address)
self.references.append(address)
cdef int result
cdef char *address_c_string = address
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 8823ea5ef5..cf146f5a04 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -35,6 +35,7 @@ import sys
# TODO(atash): figure out why the coverage tool gets confused about the Cython
# coverage plugin when the following files don't have a '.pxi' suffix.
+include "grpc/_cython/_cygrpc/grpc_string.pyx.pxi"
include "grpc/_cython/_cygrpc/call.pyx.pxi"
include "grpc/_cython/_cygrpc/channel.pyx.pxi"
include "grpc/_cython/_cygrpc/credentials.pyx.pxi"
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
index 5d09329680..8437e74ba0 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.c
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -126,7 +126,8 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
-grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
+grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
+grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -259,6 +260,8 @@ gpr_avl_unref_type gpr_avl_unref_import;
gpr_avl_add_type gpr_avl_add_import;
gpr_avl_remove_type gpr_avl_remove_import;
gpr_avl_get_type gpr_avl_get_import;
+gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
+gpr_avl_is_empty_type gpr_avl_is_empty_import;
gpr_cmdline_create_type gpr_cmdline_create_import;
gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
@@ -398,7 +401,8 @@ void pygrpc_load_imports(HMODULE library) {
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
- grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create");
+ grpc_insecure_channel_create_from_fd_import = (grpc_insecure_channel_create_from_fd_type) GetProcAddress(library, "grpc_insecure_channel_create_from_fd");
+ grpc_server_add_insecure_channel_from_fd_import = (grpc_server_add_insecure_channel_from_fd_type) GetProcAddress(library, "grpc_server_add_insecure_channel_from_fd");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
@@ -531,6 +535,8 @@ void pygrpc_load_imports(HMODULE library) {
gpr_avl_add_import = (gpr_avl_add_type) GetProcAddress(library, "gpr_avl_add");
gpr_avl_remove_import = (gpr_avl_remove_type) GetProcAddress(library, "gpr_avl_remove");
gpr_avl_get_import = (gpr_avl_get_type) GetProcAddress(library, "gpr_avl_get");
+ gpr_avl_maybe_get_import = (gpr_avl_maybe_get_type) GetProcAddress(library, "gpr_avl_maybe_get");
+ gpr_avl_is_empty_import = (gpr_avl_is_empty_type) GetProcAddress(library, "gpr_avl_is_empty");
gpr_cmdline_create_import = (gpr_cmdline_create_type) GetProcAddress(library, "gpr_cmdline_create");
gpr_cmdline_add_int_import = (gpr_cmdline_add_int_type) GetProcAddress(library, "gpr_cmdline_add_int");
gpr_cmdline_add_flag_import = (gpr_cmdline_add_flag_type) GetProcAddress(library, "gpr_cmdline_add_flag");
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index cfadad0527..d52e8591b3 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -43,7 +43,7 @@
#include <grpc/census.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
-#include <grpc/grpc_cronet.h>
+#include <grpc/grpc_posix.h>
#include <grpc/grpc_security.h>
#include <grpc/impl/codegen/alloc.h>
#include <grpc/impl/codegen/byte_buffer.h>
@@ -329,9 +329,12 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import;
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
-typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved);
-extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
-#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import
+typedef grpc_channel *(*grpc_insecure_channel_create_from_fd_type)(const char *target, int fd, const grpc_channel_args *args);
+extern grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
+#define grpc_insecure_channel_create_from_fd grpc_insecure_channel_create_from_fd_import
+typedef void(*grpc_server_add_insecure_channel_from_fd_type)(grpc_server *server, grpc_completion_queue *cq, int fd);
+extern grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
+#define grpc_server_add_insecure_channel_from_fd grpc_server_add_insecure_channel_from_fd_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
@@ -479,7 +482,7 @@ extern grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_impo
typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_from_reader_type)(grpc_byte_buffer_reader *reader);
extern grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
#define grpc_raw_byte_buffer_from_reader grpc_raw_byte_buffer_from_reader_import
-typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...);
+typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...) GPRC_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);
@@ -728,6 +731,12 @@ extern gpr_avl_remove_type gpr_avl_remove_import;
typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key);
extern gpr_avl_get_type gpr_avl_get_import;
#define gpr_avl_get gpr_avl_get_import
+typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value);
+extern gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
+#define gpr_avl_maybe_get gpr_avl_maybe_get_import
+typedef int(*gpr_avl_is_empty_type)(gpr_avl avl);
+extern gpr_avl_is_empty_type gpr_avl_is_empty_import;
+#define gpr_avl_is_empty gpr_avl_is_empty_import
typedef gpr_cmdline *(*gpr_cmdline_create_type)(const char *description);
extern gpr_cmdline_create_type gpr_cmdline_create_import;
#define gpr_cmdline_create gpr_cmdline_create_import
@@ -818,7 +827,7 @@ extern gpr_format_message_type gpr_format_message_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, ...);
+typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...) GPRC_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/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index 11310e2240..5fc4994ca0 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -33,6 +33,7 @@ import abc
import enum
import logging
import threading
+import six
import time
from grpc._adapter import _intermediary_low
@@ -177,7 +178,10 @@ class _Kernel(object):
call = service_acceptance.call
call.accept(self._completion_queue, call)
try:
- group, method = service_acceptance.method.split(b'/')[1:3]
+ service_method = service_acceptance.method
+ if six.PY3:
+ service_method = service_method.decode('latin1')
+ group, method = service_method.split('/')[1:3]
except ValueError:
logging.info('Illegal path "%s"!', service_acceptance.method)
return
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index c65070f1b3..bf20f15f72 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -60,21 +60,34 @@ _CANCELLED = 'cancelled'
_EMPTY_FLAGS = 0
_EMPTY_METADATA = cygrpc.Metadata(())
+_UNEXPECTED_EXIT_SERVER_GRACE = 1.0
+
def _serialized_request(request_event):
return request_event.batch_operations[0].received_message.bytes()
-def _code(state):
+def _application_code(code):
+ cygrpc_code = _common.STATUS_CODE_TO_CYGRPC_STATUS_CODE.get(code)
+ return cygrpc.StatusCode.unknown if cygrpc_code is None else cygrpc_code
+
+
+def _completion_code(state):
if state.code is None:
return cygrpc.StatusCode.ok
else:
- code = _common.STATUS_CODE_TO_CYGRPC_STATUS_CODE.get(state.code)
- return cygrpc.StatusCode.unknown if code is None else code
+ return _application_code(state.code)
+
+
+def _abortion_code(state, code):
+ if state.code is None:
+ return code
+ else:
+ return _application_code(state.code)
def _details(state):
- return b'' if state.details is None else state.details
+ return '' if state.details is None else state.details
class _HandlerCallDetails(
@@ -126,20 +139,22 @@ def _send_status_from_server(state, token):
def _abort(state, call, code, details):
if state.client is not _CANCELLED:
+ effective_code = _abortion_code(state, code)
+ effective_details = details if state.details is None else state.details
if state.initial_metadata_allowed:
operations = (
cygrpc.operation_send_initial_metadata(
_EMPTY_METADATA, _EMPTY_FLAGS),
cygrpc.operation_send_status_from_server(
- _common.metadata(state.trailing_metadata), code, details,
- _EMPTY_FLAGS),
+ _common.metadata(state.trailing_metadata), effective_code,
+ effective_details, _EMPTY_FLAGS),
)
token = _SEND_INITIAL_METADATA_AND_SEND_STATUS_FROM_SERVER_TOKEN
else:
operations = (
cygrpc.operation_send_status_from_server(
- _common.metadata(state.trailing_metadata), code, details,
- _EMPTY_FLAGS),
+ _common.metadata(state.trailing_metadata), effective_code,
+ effective_details, _EMPTY_FLAGS),
)
token = _SEND_STATUS_FROM_SERVER_TOKEN
call.start_batch(
@@ -176,7 +191,7 @@ def _receive_message(state, call, request_deserializer):
if request is None:
_abort(
state, call, cygrpc.StatusCode.internal,
- b'Exception deserializing request!')
+ 'Exception deserializing request!')
else:
state.request = request
state.condition.notify_all()
@@ -241,7 +256,7 @@ class _Context(grpc.ServicerContext):
else:
if self._state.initial_metadata_allowed:
operation = cygrpc.operation_send_initial_metadata(
- cygrpc.Metadata(initial_metadata), _EMPTY_FLAGS)
+ _common.metadata(initial_metadata), _EMPTY_FLAGS)
self._rpc_event.operation_call.start_batch(
cygrpc.Operations((operation,)),
_send_initial_metadata(self._state))
@@ -327,12 +342,11 @@ def _unary_request(rpc_event, state, request_deserializer):
state.condition.wait()
if state.request is None:
if state.client is _CLOSED:
- details = b'"{}" requires exactly one request message.'.format(
+ details = '"{}" requires exactly one request message.'.format(
rpc_event.request_call_details.method)
- # TODO(5992#issuecomment-220761992): really, what status code?
_abort(
state, rpc_event.operation_call,
- cygrpc.StatusCode.unavailable, details)
+ cygrpc.StatusCode.unimplemented, details)
return None
elif state.client is _CANCELLED:
return None
@@ -346,15 +360,15 @@ def _unary_request(rpc_event, state, request_deserializer):
def _call_behavior(rpc_event, state, behavior, argument, request_deserializer):
context = _Context(rpc_event, state, request_deserializer)
try:
- return behavior(argument, context)
+ return behavior(argument, context), True
except Exception as e: # pylint: disable=broad-except
with state.condition:
if e not in state.rpc_errors:
- details = b'Exception calling application: {}'.format(e)
+ details = 'Exception calling application: {}'.format(e)
logging.exception(details)
_abort(
state, rpc_event.operation_call, cygrpc.StatusCode.unknown, details)
- return None
+ return None, False
def _take_response_from_response_iterator(rpc_event, state, response_iterator):
@@ -365,7 +379,7 @@ def _take_response_from_response_iterator(rpc_event, state, response_iterator):
except Exception as e: # pylint: disable=broad-except
with state.condition:
if e not in state.rpc_errors:
- details = b'Exception iterating responses: {}'.format(e)
+ details = 'Exception iterating responses: {}'.format(e)
logging.exception(details)
_abort(
state, rpc_event.operation_call, cygrpc.StatusCode.unknown, details)
@@ -378,7 +392,7 @@ def _serialize_response(rpc_event, state, response, response_serializer):
with state.condition:
_abort(
state, rpc_event.operation_call, cygrpc.StatusCode.internal,
- b'Failed to serialize response!')
+ 'Failed to serialize response!')
return None
else:
return serialized_response
@@ -415,7 +429,7 @@ def _status(rpc_event, state, serialized_response):
with state.condition:
if state.client is not _CANCELLED:
trailing_metadata = _common.metadata(state.trailing_metadata)
- code = _code(state)
+ code = _completion_code(state)
details = _details(state)
operations = [
cygrpc.operation_send_status_from_server(
@@ -440,9 +454,9 @@ def _unary_response_in_pool(
response_serializer):
argument = argument_thunk()
if argument is not None:
- response = _call_behavior(
+ response, proceed = _call_behavior(
rpc_event, state, behavior, argument, request_deserializer)
- if response is not None:
+ if proceed:
serialized_response = _serialize_response(
rpc_event, state, response, response_serializer)
if serialized_response is not None:
@@ -455,9 +469,9 @@ def _stream_response_in_pool(
response_serializer):
argument = argument_thunk()
if argument is not None:
- response_iterator = _call_behavior(
+ response_iterator, proceed = _call_behavior(
rpc_event, state, behavior, argument, request_deserializer)
- if response_iterator is not None:
+ if proceed:
while True:
response, proceed = _take_response_from_response_iterator(
rpc_event, state, response_iterator)
@@ -531,7 +545,7 @@ def _handle_unrecognized_method(rpc_event):
cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
cygrpc.operation_send_status_from_server(
_EMPTY_METADATA, cygrpc.StatusCode.unimplemented,
- b'Method not found!', _EMPTY_FLAGS),
+ 'Method not found!', _EMPTY_FLAGS),
)
rpc_state = _RPCState()
rpc_event.operation_call.start_batch(
@@ -657,17 +671,6 @@ def _serve(state):
return
-def _start(state):
- with state.lock:
- if state.stage is not _ServerStage.STOPPED:
- raise ValueError('Cannot start already-started server!')
- state.server.start()
- state.stage = _ServerStage.STARTED
- _request_call(state)
- thread = threading.Thread(target=_serve, args=(state,))
- thread.start()
-
-
def _stop(state, grace):
with state.lock:
if state.stage is _ServerStage.STOPPED:
@@ -706,6 +709,24 @@ def _stop(state, grace):
return shutdown_event
+def _start(state):
+ with state.lock:
+ if state.stage is not _ServerStage.STOPPED:
+ raise ValueError('Cannot start already-started server!')
+ state.server.start()
+ state.stage = _ServerStage.STARTED
+ _request_call(state)
+ def cleanup_server(timeout):
+ if timeout is None:
+ _stop(state, _UNEXPECTED_EXIT_SERVER_GRACE).wait()
+ else:
+ _stop(state, timeout).wait()
+
+ thread = _common.CleanupThread(
+ cleanup_server, target=_serve, args=(state,))
+ thread.start()
+
+
class Server(grpc.Server):
def __init__(self, generic_handlers, thread_pool):
diff --git a/src/python/grpcio/grpc/_utilities.py b/src/python/grpcio/grpc/_utilities.py
index a4ca9b7282..4850967fbc 100644
--- a/src/python/grpcio/grpc/_utilities.py
+++ b/src/python/grpcio/grpc/_utilities.py
@@ -29,16 +29,41 @@
"""Internal utilities for gRPC Python."""
+import collections
import threading
import time
+import six
+
import grpc
+from grpc import _common
from grpc.framework.foundation import callable_util
_DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
'Exception calling connectivity future "done" callback!')
+class RpcMethodHandler(
+ collections.namedtuple(
+ '_RpcMethodHandler',
+ ('request_streaming', 'response_streaming', 'request_deserializer',
+ 'response_serializer', 'unary_unary', 'unary_stream', 'stream_unary',
+ 'stream_stream',)),
+ grpc.RpcMethodHandler):
+ pass
+
+
+class DictionaryGenericHandler(grpc.GenericRpcHandler):
+
+ def __init__(self, service, method_handlers):
+ self._method_handlers = {
+ _common.fully_qualified_method(service, method): method_handler
+ for method, method_handler in six.iteritems(method_handlers)}
+
+ def service(self, handler_call_details):
+ return self._method_handlers.get(handler_call_details.method)
+
+
class _ChannelReadyFuture(grpc.Future):
def __init__(self, channel):
@@ -144,4 +169,3 @@ def channel_ready_future(channel):
ready_future = _ChannelReadyFuture(channel)
ready_future.start()
return ready_future
-
diff --git a/src/python/grpcio/grpc/beta/_client_adaptations.py b/src/python/grpcio/grpc/beta/_client_adaptations.py
new file mode 100644
index 0000000000..56456cc117
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_client_adaptations.py
@@ -0,0 +1,563 @@
+# 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.
+
+"""Translates gRPC's client-side API into gRPC's client-side Beta API."""
+
+import grpc
+from grpc import _common
+from grpc._cython import cygrpc
+from grpc.beta import interfaces
+from grpc.framework.common import cardinality
+from grpc.framework.foundation import future
+from grpc.framework.interfaces.face import face
+
+_STATUS_CODE_TO_ABORTION_KIND_AND_ABORTION_ERROR_CLASS = {
+ grpc.StatusCode.CANCELLED: (
+ face.Abortion.Kind.CANCELLED, face.CancellationError),
+ grpc.StatusCode.UNKNOWN: (
+ face.Abortion.Kind.REMOTE_FAILURE, face.RemoteError),
+ grpc.StatusCode.DEADLINE_EXCEEDED: (
+ face.Abortion.Kind.EXPIRED, face.ExpirationError),
+ grpc.StatusCode.UNIMPLEMENTED: (
+ face.Abortion.Kind.LOCAL_FAILURE, face.LocalError),
+}
+
+
+def _effective_metadata(metadata, metadata_transformer):
+ non_none_metadata = () if metadata is None else metadata
+ if metadata_transformer is None:
+ return non_none_metadata
+ else:
+ return metadata_transformer(non_none_metadata)
+
+
+def _credentials(grpc_call_options):
+ return None if grpc_call_options is None else grpc_call_options.credentials
+
+
+def _abortion(rpc_error_call):
+ code = rpc_error_call.code()
+ pair = _STATUS_CODE_TO_ABORTION_KIND_AND_ABORTION_ERROR_CLASS.get(code)
+ error_kind = face.Abortion.Kind.LOCAL_FAILURE if pair is None else pair[0]
+ return face.Abortion(
+ error_kind, rpc_error_call.initial_metadata(),
+ rpc_error_call.trailing_metadata(), code, rpc_error_code.details())
+
+
+def _abortion_error(rpc_error_call):
+ code = rpc_error_call.code()
+ pair = _STATUS_CODE_TO_ABORTION_KIND_AND_ABORTION_ERROR_CLASS.get(code)
+ exception_class = face.AbortionError if pair is None else pair[1]
+ return exception_class(
+ rpc_error_call.initial_metadata(), rpc_error_call.trailing_metadata(),
+ code, rpc_error_call.details())
+
+
+class _InvocationProtocolContext(interfaces.GRPCInvocationContext):
+
+ def disable_next_request_compression(self):
+ pass # TODO(https://github.com/grpc/grpc/issues/4078): design, implement.
+
+
+class _Rendezvous(future.Future, face.Call):
+
+ def __init__(self, response_future, response_iterator, call):
+ self._future = response_future
+ self._iterator = response_iterator
+ self._call = call
+
+ def cancel(self):
+ return self._call.cancel()
+
+ def cancelled(self):
+ return self._future.cancelled()
+
+ def running(self):
+ return self._future.running()
+
+ def done(self):
+ return self._future.done()
+
+ def result(self, timeout=None):
+ try:
+ return self._future.result(timeout=timeout)
+ except grpc.RpcError as rpc_error_call:
+ raise _abortion_error(rpc_error_call)
+ except grpc.FutureTimeoutError:
+ raise future.TimeoutError()
+ except grpc.FutureCancelledError:
+ raise future.CancelledError()
+
+ def exception(self, timeout=None):
+ try:
+ rpc_error_call = self._future.exception(timeout=timeout)
+ return _abortion_error(rpc_error_call)
+ except grpc.FutureTimeoutError:
+ raise future.TimeoutError()
+ except grpc.FutureCancelledError:
+ raise future.CancelledError()
+
+ def traceback(self, timeout=None):
+ try:
+ return self._future.traceback(timeout=timeout)
+ except grpc.FutureTimeoutError:
+ raise future.TimeoutError()
+ except grpc.FutureCancelledError:
+ raise future.CancelledError()
+
+ def add_done_callback(self, fn):
+ self._future.add_done_callback(lambda ignored_callback: fn(self))
+
+ def __iter__(self):
+ return self
+
+ def _next(self):
+ try:
+ return next(self._iterator)
+ except grpc.RpcError as rpc_error_call:
+ raise _abortion_error(rpc_error_call)
+
+ def __next__(self):
+ return self._next()
+
+ def next(self):
+ return self._next()
+
+ def is_active(self):
+ return self._call.is_active()
+
+ def time_remaining(self):
+ return self._call.time_remaining()
+
+ def add_abortion_callback(self, abortion_callback):
+ registered = self._call.add_callback(
+ lambda: abortion_callback(_abortion(self._call)))
+ return None if registered else _abortion(self._call)
+
+ def protocol_context(self):
+ return _InvocationProtocolContext()
+
+ def initial_metadata(self):
+ return self._call.initial_metadata()
+
+ def terminal_metadata(self):
+ return self._call.terminal_metadata()
+
+ def code(self):
+ return self._call.code()
+
+ def details(self):
+ return self._call.details()
+
+
+def _blocking_unary_unary(
+ channel, group, method, timeout, with_call, protocol_options, metadata,
+ metadata_transformer, request, request_serializer, response_deserializer):
+ try:
+ multi_callable = channel.unary_unary(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ if with_call:
+ response, call = multi_callable.with_call(
+ request, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return response, _Rendezvous(None, None, call)
+ else:
+ return multi_callable(
+ request, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ except grpc.RpcError as rpc_error_call:
+ raise _abortion_error(rpc_error_call)
+
+
+def _future_unary_unary(
+ channel, group, method, timeout, protocol_options, metadata,
+ metadata_transformer, request, request_serializer, response_deserializer):
+ multi_callable = channel.unary_unary(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ response_future = multi_callable.future(
+ request, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return _Rendezvous(response_future, None, response_future)
+
+
+def _unary_stream(
+ channel, group, method, timeout, protocol_options, metadata,
+ metadata_transformer, request, request_serializer, response_deserializer):
+ multi_callable = channel.unary_stream(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ response_iterator = multi_callable(
+ request, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return _Rendezvous(None, response_iterator, response_iterator)
+
+
+def _blocking_stream_unary(
+ channel, group, method, timeout, with_call, protocol_options, metadata,
+ metadata_transformer, request_iterator, request_serializer,
+ response_deserializer):
+ try:
+ multi_callable = channel.stream_unary(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ if with_call:
+ response, call = multi_callable.with_call(
+ request_iterator, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return response, _Rendezvous(None, None, call)
+ else:
+ return multi_callable(
+ request_iterator, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ except grpc.RpcError as rpc_error_call:
+ raise _abortion_error(rpc_error_call)
+
+
+def _future_stream_unary(
+ channel, group, method, timeout, protocol_options, metadata,
+ metadata_transformer, request_iterator, request_serializer,
+ response_deserializer):
+ multi_callable = channel.stream_unary(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ response_future = multi_callable.future(
+ request_iterator, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return _Rendezvous(response_future, None, response_future)
+
+
+def _stream_stream(
+ channel, group, method, timeout, protocol_options, metadata,
+ metadata_transformer, request_iterator, request_serializer,
+ response_deserializer):
+ multi_callable = channel.stream_stream(
+ _common.fully_qualified_method(group, method),
+ request_serializer=request_serializer,
+ response_deserializer=response_deserializer)
+ effective_metadata = _effective_metadata(metadata, metadata_transformer)
+ response_iterator = multi_callable(
+ request_iterator, timeout=timeout, metadata=effective_metadata,
+ credentials=_credentials(protocol_options))
+ return _Rendezvous(None, response_iterator, response_iterator)
+
+
+class _UnaryUnaryMultiCallable(face.UnaryUnaryMultiCallable):
+
+ def __init__(
+ self, channel, group, method, metadata_transformer, request_serializer,
+ response_deserializer):
+ self._channel = channel
+ self._group = group
+ self._method = method
+ self._metadata_transformer = metadata_transformer
+ self._request_serializer = request_serializer
+ self._response_deserializer = response_deserializer
+
+ def __call__(
+ self, request, timeout, metadata=None, with_call=False,
+ protocol_options=None):
+ return _blocking_unary_unary(
+ self._channel, self._group, self._method, timeout, with_call,
+ protocol_options, metadata, self._metadata_transformer, request,
+ self._request_serializer, self._response_deserializer)
+
+ def future(self, request, timeout, metadata=None, protocol_options=None):
+ return _future_unary_unary(
+ self._channel, self._group, self._method, timeout, protocol_options,
+ metadata, self._metadata_transformer, request, self._request_serializer,
+ self._response_deserializer)
+
+ def event(
+ self, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+
+class _UnaryStreamMultiCallable(face.UnaryStreamMultiCallable):
+
+ def __init__(
+ self, channel, group, method, metadata_transformer, request_serializer,
+ response_deserializer):
+ self._channel = channel
+ self._group = group
+ self._method = method
+ self._metadata_transformer = metadata_transformer
+ self._request_serializer = request_serializer
+ self._response_deserializer = response_deserializer
+
+ def __call__(self, request, timeout, metadata=None, protocol_options=None):
+ return _unary_stream(
+ self._channel, self._group, self._method, timeout, protocol_options,
+ metadata, self._metadata_transformer, request, self._request_serializer,
+ self._response_deserializer)
+
+ def event(
+ self, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+
+class _StreamUnaryMultiCallable(face.StreamUnaryMultiCallable):
+
+ def __init__(
+ self, channel, group, method, metadata_transformer, request_serializer,
+ response_deserializer):
+ self._channel = channel
+ self._group = group
+ self._method = method
+ self._metadata_transformer = metadata_transformer
+ self._request_serializer = request_serializer
+ self._response_deserializer = response_deserializer
+
+ def __call__(
+ self, request_iterator, timeout, metadata=None, with_call=False,
+ protocol_options=None):
+ return _blocking_stream_unary(
+ self._channel, self._group, self._method, timeout, with_call,
+ protocol_options, metadata, self._metadata_transformer,
+ request_iterator, self._request_serializer, self._response_deserializer)
+
+ def future(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
+ return _future_stream_unary(
+ self._channel, self._group, self._method, timeout, protocol_options,
+ metadata, self._metadata_transformer, request_iterator,
+ self._request_serializer, self._response_deserializer)
+
+ def event(
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
+ raise NotImplementedError()
+
+
+class _StreamStreamMultiCallable(face.StreamStreamMultiCallable):
+
+ def __init__(
+ self, channel, group, method, metadata_transformer, request_serializer,
+ response_deserializer):
+ self._channel = channel
+ self._group = group
+ self._method = method
+ self._metadata_transformer = metadata_transformer
+ self._request_serializer = request_serializer
+ self._response_deserializer = response_deserializer
+
+ def __call__(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
+ return _stream_stream(
+ self._channel, self._group, self._method, timeout, protocol_options,
+ metadata, self._metadata_transformer, request_iterator,
+ self._request_serializer, self._response_deserializer)
+
+ def event(
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
+ raise NotImplementedError()
+
+
+class _GenericStub(face.GenericStub):
+
+ def __init__(
+ self, channel, metadata_transformer, request_serializers,
+ response_deserializers):
+ self._channel = channel
+ self._metadata_transformer = metadata_transformer
+ self._request_serializers = request_serializers or {}
+ self._response_deserializers = response_deserializers or {}
+
+ def blocking_unary_unary(
+ self, group, method, request, timeout, metadata=None,
+ with_call=None, protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _blocking_unary_unary(
+ self._channel, group, method, timeout, with_call, protocol_options,
+ metadata, self._metadata_transformer, request, request_serializer,
+ response_deserializer)
+
+ def future_unary_unary(
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _future_unary_unary(
+ self._channel, group, method, timeout, protocol_options, metadata,
+ self._metadata_transformer, request, request_serializer,
+ response_deserializer)
+
+ def inline_unary_stream(
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _unary_stream(
+ self._channel, group, method, timeout, protocol_options, metadata,
+ self._metadata_transformer, request, request_serializer,
+ response_deserializer)
+
+ def blocking_stream_unary(
+ self, group, method, request_iterator, timeout, metadata=None,
+ with_call=None, protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _blocking_stream_unary(
+ self._channel, group, method, timeout, with_call, protocol_options,
+ metadata, self._metadata_transformer, request_iterator,
+ request_serializer, response_deserializer)
+
+ def future_stream_unary(
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _future_stream_unary(
+ self._channel, group, method, timeout, protocol_options, metadata,
+ self._metadata_transformer, request_iterator, request_serializer,
+ response_deserializer)
+
+ def inline_stream_stream(
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _stream_stream(
+ self._channel, group, method, timeout, protocol_options, metadata,
+ self._metadata_transformer, request_iterator, request_serializer,
+ response_deserializer)
+
+ def event_unary_unary(
+ self, group, method, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+ def event_unary_stream(
+ self, group, method, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+ def event_stream_unary(
+ self, group, method, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+ def event_stream_stream(
+ self, group, method, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ raise NotImplementedError()
+
+ def unary_unary(self, group, method):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _UnaryUnaryMultiCallable(
+ self._channel, group, method, self._metadata_transformer,
+ request_serializer, response_deserializer)
+
+ def unary_stream(self, group, method):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _UnaryStreamMultiCallable(
+ self._channel, group, method, self._metadata_transformer,
+ request_serializer, response_deserializer)
+
+ def stream_unary(self, group, method):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _StreamUnaryMultiCallable(
+ self._channel, group, method, self._metadata_transformer,
+ request_serializer, response_deserializer)
+
+ def stream_stream(self, group, method):
+ request_serializer = self._request_serializers.get((group, method,))
+ response_deserializer = self._response_deserializers.get((group, method,))
+ return _StreamStreamMultiCallable(
+ self._channel, group, method, self._metadata_transformer,
+ request_serializer, response_deserializer)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ return False
+
+
+class _DynamicStub(face.DynamicStub):
+
+ def __init__(self, generic_stub, group, cardinalities):
+ self._generic_stub = generic_stub
+ self._group = group
+ self._cardinalities = cardinalities
+
+ def __getattr__(self, attr):
+ method_cardinality = self._cardinalities.get(attr)
+ if method_cardinality is cardinality.Cardinality.UNARY_UNARY:
+ return self._generic_stub.unary_unary(self._group, attr)
+ elif method_cardinality is cardinality.Cardinality.UNARY_STREAM:
+ return self._generic_stub.unary_stream(self._group, attr)
+ elif method_cardinality is cardinality.Cardinality.STREAM_UNARY:
+ return self._generic_stub.stream_unary(self._group, attr)
+ elif method_cardinality is cardinality.Cardinality.STREAM_STREAM:
+ return self._generic_stub.stream_stream(self._group, attr)
+ else:
+ raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ return False
+
+
+def generic_stub(
+ channel, host, metadata_transformer, request_serializers,
+ response_deserializers):
+ return _GenericStub(
+ channel, metadata_transformer, request_serializers,
+ response_deserializers)
+
+
+def dynamic_stub(
+ channel, service, cardinalities, host, metadata_transformer,
+ request_serializers, response_deserializers):
+ return _DynamicStub(
+ _GenericStub(
+ channel, metadata_transformer, request_serializers,
+ response_deserializers),
+ service, cardinalities)
diff --git a/src/python/grpcio/grpc/beta/_server_adaptations.py b/src/python/grpcio/grpc/beta/_server_adaptations.py
new file mode 100644
index 0000000000..79e6ca87eb
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_server_adaptations.py
@@ -0,0 +1,367 @@
+# 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.
+
+"""Translates gRPC's server-side API into gRPC's server-side Beta API."""
+
+import collections
+import threading
+
+import grpc
+from grpc import _common
+from grpc.beta import interfaces
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import logging_pool
+from grpc.framework.foundation import stream
+from grpc.framework.interfaces.face import face
+
+_DEFAULT_POOL_SIZE = 8
+
+
+class _ServerProtocolContext(interfaces.GRPCServicerContext):
+
+ def __init__(self, servicer_context):
+ self._servicer_context = servicer_context
+
+ def peer(self):
+ return self._servicer_context.peer()
+
+ def disable_next_response_compression(self):
+ pass # TODO(https://github.com/grpc/grpc/issues/4078): design, implement.
+
+
+class _FaceServicerContext(face.ServicerContext):
+
+ def __init__(self, servicer_context):
+ self._servicer_context = servicer_context
+
+ def is_active(self):
+ return self._servicer_context.is_active()
+
+ def time_remaining(self):
+ return self._servicer_context.time_remaining()
+
+ def add_abortion_callback(self, abortion_callback):
+ raise NotImplementedError(
+ 'add_abortion_callback no longer supported server-side!')
+
+ def cancel(self):
+ self._servicer_context.cancel()
+
+ def protocol_context(self):
+ return _ServerProtocolContext(self._servicer_context)
+
+ def invocation_metadata(self):
+ return self._servicer_context.invocation_metadata()
+
+ def initial_metadata(self, initial_metadata):
+ self._servicer_context.send_initial_metadata(initial_metadata)
+
+ def terminal_metadata(self, terminal_metadata):
+ self._servicer_context.set_terminal_metadata(terminal_metadata)
+
+ def code(self, code):
+ self._servicer_context.set_code(code)
+
+ def details(self, details):
+ self._servicer_context.set_details(details)
+
+
+def _adapt_unary_request_inline(unary_request_inline):
+ def adaptation(request, servicer_context):
+ return unary_request_inline(request, _FaceServicerContext(servicer_context))
+ return adaptation
+
+
+def _adapt_stream_request_inline(stream_request_inline):
+ def adaptation(request_iterator, servicer_context):
+ return stream_request_inline(
+ request_iterator, _FaceServicerContext(servicer_context))
+ return adaptation
+
+
+class _Callback(stream.Consumer):
+
+ def __init__(self):
+ self._condition = threading.Condition()
+ self._values = []
+ self._terminated = False
+ self._cancelled = False
+
+ def consume(self, value):
+ with self._condition:
+ self._values.append(value)
+ self._condition.notify_all()
+
+ def terminate(self):
+ with self._condition:
+ self._terminated = True
+ self._condition.notify_all()
+
+ def consume_and_terminate(self, value):
+ with self._condition:
+ self._values.append(value)
+ self._terminated = True
+ self._condition.notify_all()
+
+ def cancel(self):
+ with self._condition:
+ self._cancelled = True
+ self._condition.notify_all()
+
+ def draw_one_value(self):
+ with self._condition:
+ while True:
+ if self._cancelled:
+ raise abandonment.Abandoned()
+ elif self._values:
+ return self._values.pop(0)
+ elif self._terminated:
+ return None
+ else:
+ self._condition.wait()
+
+ def draw_all_values(self):
+ with self._condition:
+ while True:
+ if self._cancelled:
+ raise abandonment.Abandoned()
+ elif self._terminated:
+ all_values = tuple(self._values)
+ self._values = None
+ return all_values
+ else:
+ self._condition.wait()
+
+
+def _pipe_requests(request_iterator, request_consumer, servicer_context):
+ for request in request_iterator:
+ if not servicer_context.is_active():
+ return
+ request_consumer.consume(request)
+ if not servicer_context.is_active():
+ return
+ request_consumer.terminate()
+
+
+def _adapt_unary_unary_event(unary_unary_event):
+ def adaptation(request, servicer_context):
+ callback = _Callback()
+ if not servicer_context.add_callback(callback.cancel):
+ raise abandonment.Abandoned()
+ unary_unary_event(
+ request, callback.consume_and_terminate,
+ _FaceServicerContext(servicer_context))
+ return callback.draw_all_values()[0]
+ return adaptation
+
+
+def _adapt_unary_stream_event(unary_stream_event):
+ def adaptation(request, servicer_context):
+ callback = _Callback()
+ if not servicer_context.add_callback(callback.cancel):
+ raise abandonment.Abandoned()
+ unary_stream_event(
+ request, callback, _FaceServicerContext(servicer_context))
+ while True:
+ response = callback.draw_one_value()
+ if response is None:
+ return
+ else:
+ yield response
+ return adaptation
+
+
+def _adapt_stream_unary_event(stream_unary_event):
+ def adaptation(request_iterator, servicer_context):
+ callback = _Callback()
+ if not servicer_context.add_callback(callback.cancel):
+ raise abandonment.Abandoned()
+ request_consumer = stream_unary_event(
+ callback.consume_and_terminate, _FaceServicerContext(servicer_context))
+ request_pipe_thread = threading.Thread(
+ target=_pipe_requests,
+ args=(request_iterator, request_consumer, servicer_context,))
+ request_pipe_thread.start()
+ return callback.draw_all_values()[0]
+ return adaptation
+
+
+def _adapt_stream_stream_event(stream_stream_event):
+ def adaptation(request_iterator, servicer_context):
+ callback = _Callback()
+ if not servicer_context.add_callback(callback.cancel):
+ raise abandonment.Abandoned()
+ request_consumer = stream_stream_event(
+ callback, _FaceServicerContext(servicer_context))
+ request_pipe_thread = threading.Thread(
+ target=_pipe_requests,
+ args=(request_iterator, request_consumer, servicer_context,))
+ request_pipe_thread.start()
+ while True:
+ response = callback.draw_one_value()
+ if response is None:
+ return
+ else:
+ yield response
+ return adaptation
+
+
+class _SimpleMethodHandler(
+ collections.namedtuple(
+ '_MethodHandler',
+ ('request_streaming', 'response_streaming', 'request_deserializer',
+ 'response_serializer', 'unary_unary', 'unary_stream', 'stream_unary',
+ 'stream_stream',)),
+ grpc.RpcMethodHandler):
+ pass
+
+
+def _simple_method_handler(
+ implementation, request_deserializer, response_serializer):
+ if implementation.style is style.Service.INLINE:
+ if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ return _SimpleMethodHandler(
+ False, False, request_deserializer, response_serializer,
+ _adapt_unary_request_inline(implementation.unary_unary_inline), None,
+ None, None)
+ elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ return _SimpleMethodHandler(
+ False, True, request_deserializer, response_serializer, None,
+ _adapt_unary_request_inline(implementation.unary_stream_inline), None,
+ None)
+ elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ return _SimpleMethodHandler(
+ True, False, request_deserializer, response_serializer, None, None,
+ _adapt_stream_request_inline(implementation.stream_unary_inline),
+ None)
+ elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ return _SimpleMethodHandler(
+ True, True, request_deserializer, response_serializer, None, None,
+ None,
+ _adapt_stream_request_inline(implementation.stream_stream_inline))
+ elif implementation.style is style.Service.EVENT:
+ if implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ return _SimpleMethodHandler(
+ False, False, request_deserializer, response_serializer,
+ _adapt_unary_unary_event(implementation.unary_unary_event), None,
+ None, None)
+ elif implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ return _SimpleMethodHandler(
+ False, True, request_deserializer, response_serializer, None,
+ _adapt_unary_stream_event(implementation.unary_stream_event), None,
+ None)
+ elif implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ return _SimpleMethodHandler(
+ True, False, request_deserializer, response_serializer, None, None,
+ _adapt_stream_unary_event(implementation.stream_unary_event), None)
+ elif implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ return _SimpleMethodHandler(
+ True, True, request_deserializer, response_serializer, None, None,
+ None, _adapt_stream_stream_event(implementation.stream_stream_event))
+
+
+def _flatten_method_pair_map(method_pair_map):
+ method_pair_map = method_pair_map or {}
+ flat_map = {}
+ for method_pair in method_pair_map:
+ method = _common.fully_qualified_method(method_pair[0], method_pair[1])
+ flat_map[method] = method_pair_map[method_pair]
+ return flat_map
+
+
+class _GenericRpcHandler(grpc.GenericRpcHandler):
+
+ def __init__(
+ self, method_implementations, multi_method_implementation,
+ request_deserializers, response_serializers):
+ self._method_implementations = _flatten_method_pair_map(
+ method_implementations)
+ self._request_deserializers = _flatten_method_pair_map(
+ request_deserializers)
+ self._response_serializers = _flatten_method_pair_map(
+ response_serializers)
+ self._multi_method_implementation = multi_method_implementation
+
+ def service(self, handler_call_details):
+ method_implementation = self._method_implementations.get(
+ handler_call_details.method)
+ if method_implementation is not None:
+ return _simple_method_handler(
+ method_implementation,
+ self._request_deserializers.get(handler_call_details.method),
+ self._response_serializers.get(handler_call_details.method))
+ elif self._multi_method_implementation is None:
+ return None
+ else:
+ try:
+ return None #TODO(nathaniel): call the multimethod.
+ except face.NoSuchMethodError:
+ return None
+
+
+class _Server(interfaces.Server):
+
+ def __init__(self, server):
+ self._server = server
+
+ def add_insecure_port(self, address):
+ return self._server.add_insecure_port(address)
+
+ def add_secure_port(self, address, server_credentials):
+ return self._server.add_secure_port(address, server_credentials)
+
+ def start(self):
+ self._server.start()
+
+ def stop(self, grace):
+ return self._server.stop(grace)
+
+ def __enter__(self):
+ self._server.start()
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self._server.stop(None)
+ return False
+
+
+def server(
+ service_implementations, multi_method_implementation, request_deserializers,
+ response_serializers, thread_pool, thread_pool_size):
+ generic_rpc_handler = _GenericRpcHandler(
+ service_implementations, multi_method_implementation,
+ request_deserializers, response_serializers)
+ if thread_pool is None:
+ effective_thread_pool = logging_pool.pool(
+ _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
+ else:
+ effective_thread_pool = thread_pool
+ return _Server(grpc.server((generic_rpc_handler,), effective_thread_pool))
diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py
index d8c32dd2f5..4ae6e7d675 100644
--- a/src/python/grpcio/grpc/beta/implementations.py
+++ b/src/python/grpcio/grpc/beta/implementations.py
@@ -35,83 +35,20 @@ import enum
import threading # pylint: disable=unused-import
# cardinality and face are referenced from specification in this module.
-from grpc._adapter import _intermediary_low
-from grpc._adapter import _low
+import grpc
+from grpc import _auth
from grpc._adapter import _types
-from grpc.beta import _auth
-from grpc.beta import _connectivity_channel
-from grpc.beta import _server
-from grpc.beta import _stub
+from grpc.beta import _client_adaptations
+from grpc.beta import _server_adaptations
from grpc.beta import interfaces
from grpc.framework.common import cardinality # pylint: disable=unused-import
from grpc.framework.interfaces.face import face # pylint: disable=unused-import
-_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
- 'Exception calling channel subscription callback!')
-
-class ChannelCredentials(object):
- """A value encapsulating the data required to create a secure Channel.
-
- This class and its instances have no supported interface - it exists to define
- the type of its instances and its instances exist to be passed to other
- functions.
- """
-
- def __init__(self, low_credentials):
- self._low_credentials = low_credentials
-
-
-def ssl_channel_credentials(root_certificates=None, private_key=None,
- certificate_chain=None):
- """Creates a ChannelCredentials for use with an SSL-enabled Channel.
-
- Args:
- root_certificates: The PEM-encoded root certificates or unset to ask for
- them to be retrieved from a default location.
- private_key: The PEM-encoded private key to use or unset if no private key
- should be used.
- certificate_chain: The PEM-encoded certificate chain to use or unset if no
- certificate chain should be used.
-
- Returns:
- A ChannelCredentials for use with an SSL-enabled Channel.
- """
- return ChannelCredentials(_low.channel_credentials_ssl(
- root_certificates, private_key, certificate_chain))
-
-
-class CallCredentials(object):
- """A value encapsulating data asserting an identity over an *established*
- channel. May be composed with ChannelCredentials to always assert identity for
- every call over that channel.
-
- This class and its instances have no supported interface - it exists to define
- the type of its instances and its instances exist to be passed to other
- functions.
- """
-
- def __init__(self, low_credentials):
- self._low_credentials = low_credentials
-
-
-def metadata_call_credentials(metadata_plugin, name=None):
- """Construct CallCredentials from an interfaces.GRPCAuthMetadataPlugin.
-
- Args:
- metadata_plugin: An interfaces.GRPCAuthMetadataPlugin to use in constructing
- the CallCredentials object.
-
- Returns:
- A CallCredentials object for use in a GRPCCallOptions object.
- """
- if name is None:
- try:
- name = metadata_plugin.__name__
- except AttributeError:
- name = metadata_plugin.__class__.__name__
- return CallCredentials(
- _low.call_credentials_metadata_plugin(metadata_plugin, name))
+ChannelCredentials = grpc.ChannelCredentials
+ssl_channel_credentials = grpc.ssl_channel_credentials
+CallCredentials = grpc.CallCredentials
+metadata_call_credentials = grpc.metadata_call_credentials
def google_call_credentials(credentials):
@@ -125,53 +62,9 @@ def google_call_credentials(credentials):
"""
return metadata_call_credentials(_auth.GoogleCallCredentials(credentials))
-
-def access_token_call_credentials(access_token):
- """Construct CallCredentials from an access token.
-
- Args:
- access_token: A string to place directly in the http request
- authorization header, ie "Authorization: Bearer <access_token>".
-
- Returns:
- A CallCredentials object for use in a GRPCCallOptions object.
- """
- return metadata_call_credentials(
- _auth.AccessTokenCallCredentials(access_token))
-
-
-def composite_call_credentials(call_credentials, additional_call_credentials):
- """Compose two CallCredentials to make a new one.
-
- Args:
- call_credentials: A CallCredentials object.
- additional_call_credentials: Another CallCredentials object to compose on
- top of call_credentials.
-
- Returns:
- A CallCredentials object for use in a GRPCCallOptions object.
- """
- return CallCredentials(
- _low.call_credentials_composite(
- call_credentials._low_credentials,
- additional_call_credentials._low_credentials))
-
-def composite_channel_credentials(channel_credentials,
- additional_call_credentials):
- """Compose ChannelCredentials on top of client credentials to make a new one.
-
- Args:
- channel_credentials: A ChannelCredentials object.
- additional_call_credentials: A CallCredentials object to compose on
- top of channel_credentials.
-
- Returns:
- A ChannelCredentials object for use in a GRPCCallOptions object.
- """
- return ChannelCredentials(
- _low.channel_credentials_composite(
- channel_credentials._low_credentials,
- additional_call_credentials._low_credentials))
+access_token_call_credentials = grpc.access_token_call_credentials
+composite_call_credentials = grpc.composite_call_credentials
+composite_channel_credentials = grpc.composite_channel_credentials
class Channel(object):
@@ -182,11 +75,8 @@ class Channel(object):
unsupported.
"""
- def __init__(self, low_channel, intermediary_low_channel):
- self._low_channel = low_channel
- self._intermediary_low_channel = intermediary_low_channel
- self._connectivity_channel = _connectivity_channel.ConnectivityChannel(
- low_channel)
+ def __init__(self, channel):
+ self._channel = channel
def subscribe(self, callback, try_to_connect=None):
"""Subscribes to this Channel's connectivity.
@@ -201,7 +91,7 @@ class Channel(object):
attempt to connect if it is not already connected and ready to conduct
RPCs.
"""
- self._connectivity_channel.subscribe(callback, try_to_connect)
+ self._channel.subscribe(callback, try_to_connect=try_to_connect)
def unsubscribe(self, callback):
"""Unsubscribes a callback from this Channel's connectivity.
@@ -210,7 +100,7 @@ class Channel(object):
callback: A callable previously registered with this Channel from having
been passed to its "subscribe" method.
"""
- self._connectivity_channel.unsubscribe(callback)
+ self._channel.unsubscribe(callback)
def insecure_channel(host, port):
@@ -224,9 +114,9 @@ def insecure_channel(host, port):
Returns:
A Channel to the remote host through which RPCs may be conducted.
"""
- intermediary_low_channel = _intermediary_low.Channel(
- '%s:%d' % (host, port) if port else host, None)
- return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
+ channel = grpc.insecure_channel(
+ host if port is None else '%s:%d' % (host, port))
+ return Channel(channel)
def secure_channel(host, port, channel_credentials):
@@ -241,10 +131,9 @@ def secure_channel(host, port, channel_credentials):
Returns:
A secure Channel to the remote host through which RPCs may be conducted.
"""
- intermediary_low_channel = _intermediary_low.Channel(
- '%s:%d' % (host, port) if port else host,
- channel_credentials._low_credentials)
- return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
+ channel = grpc.secure_channel(
+ host if port is None else '%s:%d' % (host, port), channel_credentials)
+ return Channel(channel)
class StubOptions(object):
@@ -308,12 +197,11 @@ def generic_stub(channel, options=None):
A face.GenericStub on which RPCs can be made.
"""
effective_options = _EMPTY_STUB_OPTIONS if options is None else options
- return _stub.generic_stub(
- channel._intermediary_low_channel, effective_options.host, # pylint: disable=protected-access
- effective_options.metadata_transformer,
+ return _client_adaptations.generic_stub(
+ channel._channel, # pylint: disable=protected-access
+ effective_options.host, effective_options.metadata_transformer,
effective_options.request_serializers,
- effective_options.response_deserializers, effective_options.thread_pool,
- effective_options.thread_pool_size)
+ effective_options.response_deserializers)
def dynamic_stub(channel, service, cardinalities, options=None):
@@ -331,55 +219,16 @@ def dynamic_stub(channel, service, cardinalities, options=None):
A face.DynamicStub with which RPCs can be invoked.
"""
effective_options = StubOptions() if options is None else options
- return _stub.dynamic_stub(
- channel._intermediary_low_channel, effective_options.host, service, # pylint: disable=protected-access
- cardinalities, effective_options.metadata_transformer,
+ return _client_adaptations.dynamic_stub(
+ channel._channel, # pylint: disable=protected-access
+ service, cardinalities, effective_options.host,
+ effective_options.metadata_transformer,
effective_options.request_serializers,
- effective_options.response_deserializers, effective_options.thread_pool,
- effective_options.thread_pool_size)
-
-
-class ServerCredentials(object):
- """A value encapsulating the data required to open a secure port on a Server.
+ effective_options.response_deserializers)
- This class and its instances have no supported interface - it exists to define
- the type of its instances and its instances exist to be passed to other
- functions.
- """
- def __init__(self, low_credentials):
- self._low_credentials = low_credentials
-
-
-def ssl_server_credentials(
- private_key_certificate_chain_pairs, root_certificates=None,
- require_client_auth=False):
- """Creates a ServerCredentials for use with an SSL-enabled Server.
-
- Args:
- private_key_certificate_chain_pairs: A nonempty sequence each element of
- which is a pair the first element of which is a PEM-encoded private key
- and the second element of which is the corresponding PEM-encoded
- certificate chain.
- root_certificates: PEM-encoded client root certificates to be used for
- verifying authenticated clients. If omitted, require_client_auth must also
- be omitted or be False.
- require_client_auth: A boolean indicating whether or not to require clients
- to be authenticated. May only be True if root_certificates is not None.
-
- Returns:
- A ServerCredentials for use with an SSL-enabled Server.
- """
- if len(private_key_certificate_chain_pairs) == 0:
- raise ValueError(
- 'At least one private key-certificate chain pairis required!')
- elif require_client_auth and root_certificates is None:
- raise ValueError(
- 'Illegal to require client auth without providing root certificates!')
- else:
- return ServerCredentials(_low.server_credentials_ssl(
- root_certificates, private_key_certificate_chain_pairs,
- require_client_auth))
+ServerCredentials = grpc.ServerCredentials
+ssl_server_credentials = grpc.ssl_server_credentials
class ServerOptions(object):
@@ -452,9 +301,8 @@ def server(service_implementations, options=None):
An interfaces.Server with which RPCs can be serviced.
"""
effective_options = _EMPTY_SERVER_OPTIONS if options is None else options
- return _server.server(
+ return _server_adaptations.server(
service_implementations, effective_options.multi_method_implementation,
effective_options.request_deserializers,
effective_options.response_serializers, effective_options.thread_pool,
- effective_options.thread_pool_size, effective_options.default_timeout,
- effective_options.maximum_timeout)
+ effective_options.thread_pool_size)
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
index 24de9ad1a8..90f6bbbfcc 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -30,53 +30,16 @@
"""Constants and interfaces of the Beta API of gRPC Python."""
import abc
-import enum
import six
-from grpc._adapter import _types
+import grpc
+ChannelConnectivity = grpc.ChannelConnectivity
+# FATAL_FAILURE was a Beta-API name for SHUTDOWN
+ChannelConnectivity.FATAL_FAILURE = ChannelConnectivity.SHUTDOWN
-@enum.unique
-class ChannelConnectivity(enum.Enum):
- """Mirrors grpc_connectivity_state in the gRPC Core.
-
- Attributes:
- IDLE: The channel is idle.
- CONNECTING: The channel is connecting.
- READY: The channel is ready to conduct RPCs.
- TRANSIENT_FAILURE: The channel has seen a failure from which it expects to
- recover.
- FATAL_FAILURE: The channel has seen a failure from which it cannot recover.
- """
- IDLE = (_types.ConnectivityState.IDLE, 'idle',)
- CONNECTING = (_types.ConnectivityState.CONNECTING, 'connecting',)
- READY = (_types.ConnectivityState.READY, 'ready',)
- TRANSIENT_FAILURE = (
- _types.ConnectivityState.TRANSIENT_FAILURE, 'transient failure',)
- FATAL_FAILURE = (_types.ConnectivityState.FATAL_FAILURE, 'fatal failure',)
-
-
-@enum.unique
-class StatusCode(enum.Enum):
- """Mirrors grpc_status_code in the C core."""
- OK = 0
- CANCELLED = 1
- UNKNOWN = 2
- INVALID_ARGUMENT = 3
- DEADLINE_EXCEEDED = 4
- NOT_FOUND = 5
- ALREADY_EXISTS = 6
- PERMISSION_DENIED = 7
- RESOURCE_EXHAUSTED = 8
- FAILED_PRECONDITION = 9
- ABORTED = 10
- OUT_OF_RANGE = 11
- UNIMPLEMENTED = 12
- INTERNAL = 13
- UNAVAILABLE = 14
- DATA_LOSS = 15
- UNAUTHENTICATED = 16
+StatusCode = grpc.StatusCode
class GRPCCallOptions(object):
@@ -106,46 +69,9 @@ def grpc_call_options(disable_compression=False, credentials=None):
"""
return GRPCCallOptions(disable_compression, None, credentials)
-
-class GRPCAuthMetadataContext(six.with_metaclass(abc.ABCMeta)):
- """Provides information to call credentials metadata plugins.
-
- Attributes:
- service_url: A string URL of the service being called into.
- method_name: A string of the fully qualified method name being called.
- """
-
-
-class GRPCAuthMetadataPluginCallback(six.with_metaclass(abc.ABCMeta)):
- """Callback object received by a metadata plugin."""
-
- def __call__(self, metadata, error):
- """Inform the gRPC runtime of the metadata to construct a CallCredentials.
-
- Args:
- metadata: An iterable of 2-sequences (e.g. tuples) of metadata key/value
- pairs.
- error: An Exception to indicate error or None to indicate success.
- """
- raise NotImplementedError()
-
-
-class GRPCAuthMetadataPlugin(six.with_metaclass(abc.ABCMeta)):
- """
- """
-
- def __call__(self, context, callback):
- """Invoke the plugin.
-
- Must not block. Need only be called by the gRPC runtime.
-
- Args:
- context: A GRPCAuthMetadataContext providing information on what the
- plugin is being used for.
- callback: A GRPCAuthMetadataPluginCallback to be invoked either
- synchronously or asynchronously.
- """
- raise NotImplementedError()
+GRPCAuthMetadataContext = grpc.AuthMetadataContext
+GRPCAuthMetadataPluginCallback = grpc.AuthMetadataPluginCallback
+GRPCAuthMetadataPlugin = grpc.AuthMetadataPlugin
class GRPCServicerContext(six.with_metaclass(abc.ABCMeta)):
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 84c83af8a8..839c555f05 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -45,7 +45,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/support/env_windows.c',
'src/core/lib/support/histogram.c',
'src/core/lib/support/host_port.c',
- 'src/core/lib/support/load_file.c',
'src/core/lib/support/log.c',
'src/core/lib/support/log_android.c',
'src/core/lib/support/log_linux.c',
@@ -84,7 +83,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/connected_channel.c',
'src/core/lib/channel/http_client_filter.c',
'src/core/lib/channel/http_server_filter.c',
- 'src/core/lib/compression/compression_algorithm.c',
+ 'src/core/lib/compression/compression.c',
'src/core/lib/compression/message_compress.c',
'src/core/lib/debug/trace.c',
'src/core/lib/http/format_request.c',
@@ -94,6 +93,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/endpoint.c',
'src/core/lib/iomgr/endpoint_pair_posix.c',
'src/core/lib/iomgr/endpoint_pair_windows.c',
+ 'src/core/lib/iomgr/error.c',
'src/core/lib/iomgr/ev_poll_and_epoll_posix.c',
'src/core/lib/iomgr/ev_poll_posix.c',
'src/core/lib/iomgr/ev_posix.c',
@@ -103,6 +103,8 @@ CORE_SOURCE_FILES = [
'src/core/lib/iomgr/iomgr.c',
'src/core/lib/iomgr/iomgr_posix.c',
'src/core/lib/iomgr/iomgr_windows.c',
+ 'src/core/lib/iomgr/load_file.c',
+ 'src/core/lib/iomgr/polling_entity.c',
'src/core/lib/iomgr/pollset_set_windows.c',
'src/core/lib/iomgr/pollset_windows.c',
'src/core/lib/iomgr/resolve_address_posix.c',
@@ -160,6 +162,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/transport.c',
'src/core/lib/transport/transport_op_string.c',
'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
+ 'src/core/ext/transport/chttp2/transport/bin_decoder.c',
'src/core/ext/transport/chttp2/transport/bin_encoder.c',
'src/core/ext/transport/chttp2/transport/chttp2_plugin.c',
'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
@@ -203,6 +206,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/transport/secure_endpoint.c',
'src/core/lib/security/transport/security_connector.c',
'src/core/lib/security/transport/server_auth_filter.c',
+ 'src/core/lib/security/transport/tsi_error.c',
'src/core/lib/security/util/b64.c',
'src/core/lib/security/util/json_util.c',
'src/core/lib/surface/init_secure.c',
@@ -230,10 +234,9 @@ CORE_SOURCE_FILES = [
'src/core/ext/client_config/subchannel_index.c',
'src/core/ext/client_config/uri_parser.c',
'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
+ 'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
- 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
- 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c',
- 'src/core/ext/transport/cronet/transport/cronet_transport.c',
+ 'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
'src/core/ext/lb_policy/grpclb/load_balancer_api.c',
'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
'third_party/nanopb/pb_common.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 0c13104d9d..0f4db9d972 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
-VERSION='0.15.0.dev0'
+VERSION='0.16.0.dev0'
diff --git a/src/python/grpcio/tests/interop/client.py b/src/python/grpcio/tests/interop/client.py
index e3d5545a02..8aa1ce30c1 100644
--- a/src/python/grpcio/tests/interop/client.py
+++ b/src/python/grpcio/tests/interop/client.py
@@ -76,6 +76,9 @@ def _stub(args):
creds = oauth2client_client.GoogleCredentials.get_application_default()
scoped_creds = creds.create_scoped([args.oauth_scope])
call_creds = implementations.google_call_credentials(scoped_creds)
+ elif args.test_case == 'jwt_token_creds':
+ creds = oauth2client_client.GoogleCredentials.get_application_default()
+ call_creds = implementations.google_call_credentials(creds)
else:
call_creds = None
if args.use_tls:
diff --git a/src/python/grpcio/tests/interop/methods.py b/src/python/grpcio/tests/interop/methods.py
index d5ef0c68bb..7eac511525 100644
--- a/src/python/grpcio/tests/interop/methods.py
+++ b/src/python/grpcio/tests/interop/methods.py
@@ -310,6 +310,16 @@ def _oauth2_auth_token(stub, args):
(response.oauth_scope, args.oauth_scope))
+def _jwt_token_creds(stub, args):
+ json_key_filename = os.environ[
+ oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
+ wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
+ response = _large_unary_common_behavior(stub, True, False)
+ if wanted_email != response.username:
+ raise ValueError(
+ 'expected username %s, got %s' % (wanted_email, response.username))
+
+
def _per_rpc_creds(stub, args):
json_key_filename = os.environ[
oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
@@ -338,6 +348,7 @@ class TestCase(enum.Enum):
EMPTY_STREAM = 'empty_stream'
COMPUTE_ENGINE_CREDS = 'compute_engine_creds'
OAUTH2_AUTH_TOKEN = 'oauth2_auth_token'
+ JWT_TOKEN_CREDS = 'jwt_token_creds'
PER_RPC_CREDS = 'per_rpc_creds'
TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server'
@@ -364,6 +375,8 @@ class TestCase(enum.Enum):
_compute_engine_creds(stub, args)
elif self is TestCase.OAUTH2_AUTH_TOKEN:
_oauth2_auth_token(stub, args)
+ elif self is TestCase.JWT_TOKEN_CREDS:
+ _jwt_token_creds(stub, args)
elif self is TestCase.PER_RPC_CREDS:
_per_rpc_creds(stub, args)
else:
diff --git a/src/python/grpcio/tests/protoc_plugin/_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/_python_plugin_test.py
new file mode 100644
index 0000000000..1c9cbb0d0c
--- /dev/null
+++ b/src/python/grpcio/tests/protoc_plugin/_python_plugin_test.py
@@ -0,0 +1,583 @@
+# 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 collections
+from concurrent import futures
+import contextlib
+import distutils.spawn
+import errno
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import unittest
+
+from six import moves
+
+import grpc
+from tests.unit.framework.common import test_constants
+
+# Identifiers of entities we expect to find in the generated module.
+STUB_IDENTIFIER = 'TestServiceStub'
+SERVICER_IDENTIFIER = 'TestServiceServicer'
+ADD_SERVICER_TO_SERVER_IDENTIFIER = 'add_TestServiceServicer_to_server'
+
+
+class _ServicerMethods(object):
+
+ def __init__(self, response_pb2, payload_pb2):
+ self._condition = threading.Condition()
+ self._paused = False
+ self._fail = False
+ self._response_pb2 = response_pb2
+ self._payload_pb2 = payload_pb2
+
+ @contextlib.contextmanager
+ def pause(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._paused = True
+ yield
+ with self._condition:
+ self._paused = False
+ self._condition.notify_all()
+
+ @contextlib.contextmanager
+ def fail(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._fail = True
+ yield
+ with self._condition:
+ self._fail = False
+
+ def _control(self): # pylint: disable=invalid-name
+ with self._condition:
+ if self._fail:
+ raise ValueError()
+ while self._paused:
+ self._condition.wait()
+
+ def UnaryCall(self, request, unused_rpc_context):
+ response = self._response_pb2.SimpleResponse()
+ response.payload.payload_type = self._payload_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * request.response_size
+ self._control()
+ return response
+
+ def StreamingOutputCall(self, request, unused_rpc_context):
+ for parameter in request.response_parameters:
+ response = self._response_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._payload_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def StreamingInputCall(self, request_iter, unused_rpc_context):
+ response = self._response_pb2.StreamingInputCallResponse()
+ aggregated_payload_size = 0
+ for request in request_iter:
+ aggregated_payload_size += len(request.payload.payload_compressable)
+ response.aggregated_payload_size = aggregated_payload_size
+ self._control()
+ return response
+
+ def FullDuplexCall(self, request_iter, unused_rpc_context):
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._response_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._payload_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def HalfDuplexCall(self, request_iter, unused_rpc_context):
+ responses = []
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._response_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._payload_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ responses.append(response)
+ for response in responses:
+ yield response
+
+
+class _Service(
+ collections.namedtuple(
+ '_Service', ('servicer_methods', 'server', 'stub',))):
+ """A live and running service.
+
+ Attributes:
+ servicer_methods: The _ServicerMethods servicing RPCs.
+ server: The grpc.Server servicing RPCs.
+ stub: A stub on which to invoke RPCs.
+ """
+
+
+def _CreateService(service_pb2, response_pb2, payload_pb2):
+ """Provides a servicer backend and a stub.
+
+ Args:
+ service_pb2: The service_pb2 module generated by this test.
+ response_pb2: The response_pb2 module generated by this test.
+ payload_pb2: The payload_pb2 module generated by this test.
+
+ Returns:
+ A _Service with which to test RPCs.
+ """
+ servicer_methods = _ServicerMethods(response_pb2, payload_pb2)
+
+ class Servicer(getattr(service_pb2, SERVICER_IDENTIFIER)):
+
+ def UnaryCall(self, request, context):
+ return servicer_methods.UnaryCall(request, context)
+
+ def StreamingOutputCall(self, request, context):
+ return servicer_methods.StreamingOutputCall(request, context)
+
+ def StreamingInputCall(self, request_iter, context):
+ return servicer_methods.StreamingInputCall(request_iter, context)
+
+ def FullDuplexCall(self, request_iter, context):
+ return servicer_methods.FullDuplexCall(request_iter, context)
+
+ def HalfDuplexCall(self, request_iter, context):
+ return servicer_methods.HalfDuplexCall(request_iter, context)
+
+ server = grpc.server(
+ (), futures.ThreadPoolExecutor(max_workers=test_constants.POOL_SIZE))
+ getattr(service_pb2, ADD_SERVICER_TO_SERVER_IDENTIFIER)(Servicer(), server)
+ port = server.add_insecure_port('[::]:0')
+ server.start()
+ channel = grpc.insecure_channel('localhost:{}'.format(port))
+ stub = getattr(service_pb2, STUB_IDENTIFIER)(channel)
+ return _Service(servicer_methods, server, stub)
+
+
+def _CreateIncompleteService(service_pb2):
+ """Provides a servicer backend that fails to implement methods and its stub.
+
+ Args:
+ service_pb2: The service_pb2 module generated by this test.
+
+ Returns:
+ A _Service with which to test RPCs. The returned _Service's
+ servicer_methods implements none of the methods required of it.
+ """
+
+ class Servicer(getattr(service_pb2, SERVICER_IDENTIFIER)):
+ pass
+
+ server = grpc.server(
+ (), futures.ThreadPoolExecutor(max_workers=test_constants.POOL_SIZE))
+ getattr(service_pb2, ADD_SERVICER_TO_SERVER_IDENTIFIER)(Servicer(), server)
+ port = server.add_insecure_port('[::]:0')
+ server.start()
+ channel = grpc.insecure_channel('localhost:{}'.format(port))
+ stub = getattr(service_pb2, STUB_IDENTIFIER)(channel)
+ return _Service(None, server, stub)
+
+
+def _streaming_input_request_iterator(request_pb2, payload_pb2):
+ for _ in range(3):
+ request = request_pb2.StreamingInputCallRequest()
+ request.payload.payload_type = payload_pb2.COMPRESSABLE
+ request.payload.payload_compressable = 'a'
+ yield request
+
+
+def _streaming_output_request(request_pb2):
+ request = request_pb2.StreamingOutputCallRequest()
+ sizes = [1, 2, 3]
+ request.response_parameters.add(size=sizes[0], interval_us=0)
+ request.response_parameters.add(size=sizes[1], interval_us=0)
+ request.response_parameters.add(size=sizes[2], interval_us=0)
+ return request
+
+
+def _full_duplex_request_iterator(request_pb2):
+ request = request_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = request_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+
+
+class PythonPluginTest(unittest.TestCase):
+ """Test case for the gRPC Python protoc-plugin.
+
+ While reading these tests, remember that the futures API
+ (`stub.method.future()`) only gives futures for the *response-unary*
+ methods and does not exist for response-streaming methods.
+ """
+
+ def setUp(self):
+ # Assume that the appropriate protoc and grpc_python_plugins are on the
+ # path.
+ protoc_command = 'protoc'
+ protoc_plugin_filename = distutils.spawn.find_executable(
+ 'grpc_python_plugin')
+ if not os.path.isfile(protoc_command):
+ # Assume that if we haven't built protoc that it's on the system.
+ protoc_command = 'protoc'
+
+ # Ensure that the output directory exists.
+ self.outdir = tempfile.mkdtemp()
+
+ # Find all proto files
+ paths = []
+ root_dir = os.path.dirname(os.path.realpath(__file__))
+ proto_dir = os.path.join(root_dir, 'protos')
+ for walk_root, _, filenames in os.walk(proto_dir):
+ for filename in filenames:
+ if filename.endswith('.proto'):
+ path = os.path.join(walk_root, filename)
+ paths.append(path)
+
+ # Invoke protoc with the plugin.
+ cmd = [
+ protoc_command,
+ '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename,
+ '-I %s' % root_dir,
+ '--python_out=%s' % self.outdir,
+ '--python-grpc_out=%s' % self.outdir
+ ] + paths
+ subprocess.check_call(' '.join(cmd), shell=True, env=os.environ,
+ cwd=os.path.dirname(os.path.realpath(__file__)))
+
+ # Generated proto directories dont include __init__.py, but
+ # these are needed for python package resolution
+ for walk_root, _, _ in os.walk(os.path.join(self.outdir, 'protos')):
+ path = os.path.join(walk_root, '__init__.py')
+ open(path, 'a').close()
+
+ sys.path.insert(0, self.outdir)
+
+ import protos.payload.test_payload_pb2 as payload_pb2
+ import protos.requests.r.test_requests_pb2 as request_pb2
+ import protos.responses.test_responses_pb2 as response_pb2
+ import protos.service.test_service_pb2 as service_pb2
+ self._payload_pb2 = payload_pb2
+ self._request_pb2 = request_pb2
+ self._response_pb2 = response_pb2
+ self._service_pb2 = service_pb2
+
+ def tearDown(self):
+ try:
+ shutil.rmtree(self.outdir)
+ except OSError as exc:
+ if exc.errno != errno.ENOENT:
+ raise
+ sys.path.remove(self.outdir)
+
+ def testImportAttributes(self):
+ # check that we can access the generated module and its members.
+ self.assertIsNotNone(
+ getattr(self._service_pb2, STUB_IDENTIFIER, None))
+ self.assertIsNotNone(
+ getattr(self._service_pb2, SERVICER_IDENTIFIER, None))
+ self.assertIsNotNone(
+ getattr(self._service_pb2, ADD_SERVICER_TO_SERVER_IDENTIFIER, None))
+
+ def testUpDown(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ self.assertIsNotNone(service.servicer_methods)
+ self.assertIsNotNone(service.server)
+ self.assertIsNotNone(service.stub)
+
+ def testIncompleteServicer(self):
+ service = _CreateIncompleteService(self._service_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ service.stub.UnaryCall(request)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.UNIMPLEMENTED)
+
+ def testUnaryCall(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ response = service.stub.UnaryCall(request)
+ expected_response = service.servicer_methods.UnaryCall(
+ request, 'not a real context!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallFuture(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ # Check that the call does not block waiting for the server to respond.
+ with service.servicer_methods.pause():
+ response_future = service.stub.UnaryCall.future(request)
+ response = response_future.result()
+ expected_response = service.servicer_methods.UnaryCall(
+ request, 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallFutureExpired(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ with service.servicer_methods.pause():
+ response_future = service.stub.UnaryCall.future(
+ request, timeout=test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ response_future.result()
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+ self.assertIs(response_future.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+
+ def testUnaryCallFutureCancelled(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ with service.servicer_methods.pause():
+ response_future = service.stub.UnaryCall.future(request)
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+ self.assertIs(response_future.code(), grpc.StatusCode.CANCELLED)
+
+ def testUnaryCallFutureFailed(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = self._request_pb2.SimpleRequest(response_size=13)
+ with service.servicer_methods.fail():
+ response_future = service.stub.UnaryCall.future(request)
+ self.assertIsNotNone(response_future.exception())
+ self.assertIs(response_future.code(), grpc.StatusCode.UNKNOWN)
+
+ def testStreamingOutputCall(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = _streaming_output_request(self._request_pb2)
+ responses = service.stub.StreamingOutputCall(request)
+ expected_responses = service.servicer_methods.StreamingOutputCall(
+ request, 'not a real RpcContext!')
+ for expected_response, response in moves.zip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ def testStreamingOutputCallExpired(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = _streaming_output_request(self._request_pb2)
+ with service.servicer_methods.pause():
+ responses = service.stub.StreamingOutputCall(
+ request, timeout=test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ list(responses)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+
+ def testStreamingOutputCallCancelled(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = _streaming_output_request(self._request_pb2)
+ responses = service.stub.StreamingOutputCall(request)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ next(responses)
+ self.assertIs(responses.code(), grpc.StatusCode.CANCELLED)
+
+ def testStreamingOutputCallFailed(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request = _streaming_output_request(self._request_pb2)
+ with service.servicer_methods.fail():
+ responses = service.stub.StreamingOutputCall(request)
+ self.assertIsNotNone(responses)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ next(responses)
+ self.assertIs(exception_context.exception.code(), grpc.StatusCode.UNKNOWN)
+
+ def testStreamingInputCall(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ response = service.stub.StreamingInputCall(
+ _streaming_input_request_iterator(
+ self._request_pb2, self._payload_pb2))
+ expected_response = service.servicer_methods.StreamingInputCall(
+ _streaming_input_request_iterator(self._request_pb2, self._payload_pb2),
+ 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallFuture(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.pause():
+ response_future = service.stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(
+ self._request_pb2, self._payload_pb2))
+ response = response_future.result()
+ expected_response = service.servicer_methods.StreamingInputCall(
+ _streaming_input_request_iterator(self._request_pb2, self._payload_pb2),
+ 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallFutureExpired(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.pause():
+ response_future = service.stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(
+ self._request_pb2, self._payload_pb2),
+ timeout=test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ response_future.result()
+ self.assertIsInstance(response_future.exception(), grpc.RpcError)
+ self.assertIs(
+ response_future.exception().code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+
+ def testStreamingInputCallFutureCancelled(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.pause():
+ response_future = service.stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(
+ self._request_pb2, self._payload_pb2))
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+ with self.assertRaises(grpc.FutureCancelledError):
+ response_future.result()
+
+ def testStreamingInputCallFutureFailed(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.fail():
+ response_future = service.stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(
+ self._request_pb2, self._payload_pb2))
+ self.assertIsNotNone(response_future.exception())
+ self.assertIs(response_future.code(), grpc.StatusCode.UNKNOWN)
+
+ def testFullDuplexCall(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ responses = service.stub.FullDuplexCall(
+ _full_duplex_request_iterator(self._request_pb2))
+ expected_responses = service.servicer_methods.FullDuplexCall(
+ _full_duplex_request_iterator(self._request_pb2),
+ 'not a real RpcContext!')
+ for expected_response, response in moves.zip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ def testFullDuplexCallExpired(self):
+ request_iterator = _full_duplex_request_iterator(self._request_pb2)
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.pause():
+ responses = service.stub.FullDuplexCall(
+ request_iterator, timeout=test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ list(responses)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+
+ def testFullDuplexCallCancelled(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ request_iterator = _full_duplex_request_iterator(self._request_pb2)
+ responses = service.stub.FullDuplexCall(request_iterator)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ next(responses)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.CANCELLED)
+
+ def testFullDuplexCallFailed(self):
+ request_iterator = _full_duplex_request_iterator(self._request_pb2)
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with service.servicer_methods.fail():
+ responses = service.stub.FullDuplexCall(request_iterator)
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ next(responses)
+ self.assertIs(exception_context.exception.code(), grpc.StatusCode.UNKNOWN)
+
+ def testHalfDuplexCall(self):
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ def half_duplex_request_iterator():
+ request = self._request_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = self._request_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+ responses = service.stub.HalfDuplexCall(half_duplex_request_iterator())
+ expected_responses = service.servicer_methods.HalfDuplexCall(
+ half_duplex_request_iterator(), 'not a real RpcContext!')
+ for expected_response, response in moves.zip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ def testHalfDuplexCallWedged(self):
+ condition = threading.Condition()
+ wait_cell = [False]
+ @contextlib.contextmanager
+ def wait(): # pylint: disable=invalid-name
+ # Where's Python 3's 'nonlocal' statement when you need it?
+ with condition:
+ wait_cell[0] = True
+ yield
+ with condition:
+ wait_cell[0] = False
+ condition.notify_all()
+ def half_duplex_request_iterator():
+ request = self._request_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ with condition:
+ while wait_cell[0]:
+ condition.wait()
+ service = _CreateService(
+ self._service_pb2, self._response_pb2, self._payload_pb2)
+ with wait():
+ responses = service.stub.HalfDuplexCall(
+ half_duplex_request_iterator(), timeout=test_constants.SHORT_TIMEOUT)
+ # half-duplex waits for the client to send all info
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ next(responses)
+ self.assertIs(
+ exception_context.exception.code(), grpc.StatusCode.DEADLINE_EXCEEDED)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/qps/benchmark_client.py b/src/python/grpcio/tests/qps/benchmark_client.py
index b372ea01ad..080281415d 100644
--- a/src/python/grpcio/tests/qps/benchmark_client.py
+++ b/src/python/grpcio/tests/qps/benchmark_client.py
@@ -30,14 +30,13 @@
"""Defines test client behaviors (UNARY/STREAMING) (SYNC/ASYNC)."""
import abc
+import threading
import time
-try:
- import Queue as queue # Python 2.x
-except ImportError:
- import queue # Python 3
from concurrent import futures
+from six.moves import queue
+import grpc
from grpc.beta import implementations
from grpc.framework.interfaces.face import face
from src.proto.grpc.testing import messages_pb2
@@ -65,6 +64,13 @@ class BenchmarkClient:
else:
channel = implementations.insecure_channel(host, port)
+ connected_event = threading.Event()
+ def wait_for_ready(connectivity):
+ if connectivity == grpc.ChannelConnectivity.READY:
+ connected_event.set()
+ channel.subscribe(wait_for_ready, try_to_connect=True)
+ connected_event.wait()
+
if config.payload_config.WhichOneof('payload') == 'simple_params':
self._generic = False
self._stub = services_pb2.beta_create_BenchmarkService_stub(channel)
@@ -82,6 +88,7 @@ class BenchmarkClient:
self._response_callbacks = []
def add_response_callback(self, callback):
+ """callback will be invoked as callback(client, query_time)"""
self._response_callbacks.append(callback)
@abc.abstractmethod
@@ -95,10 +102,10 @@ class BenchmarkClient:
def stop(self):
pass
- def _handle_response(self, query_time):
+ def _handle_response(self, client, query_time):
self._hist.add(query_time * 1e9) # Report times in nanoseconds
for callback in self._response_callbacks:
- callback(query_time)
+ callback(client, query_time)
class UnarySyncBenchmarkClient(BenchmarkClient):
@@ -121,7 +128,7 @@ class UnarySyncBenchmarkClient(BenchmarkClient):
start_time = time.time()
self._stub.UnaryCall(self._request, _TIMEOUT)
end_time = time.time()
- self._handle_response(end_time - start_time)
+ self._handle_response(self, end_time - start_time)
class UnaryAsyncBenchmarkClient(BenchmarkClient):
@@ -136,19 +143,20 @@ class UnaryAsyncBenchmarkClient(BenchmarkClient):
def _response_received(self, start_time, resp):
resp.result()
end_time = time.time()
- self._handle_response(end_time - start_time)
+ self._handle_response(self, end_time - start_time)
def stop(self):
self._stub = None
-class StreamingSyncBenchmarkClient(BenchmarkClient):
+class _SyncStream(object):
- def __init__(self, server, config, hist):
- super(StreamingSyncBenchmarkClient, self).__init__(server, config, hist)
+ def __init__(self, stub, generic, request, handle_response):
+ self._stub = stub
+ self._generic = generic
+ self._request = request
+ self._handle_response = handle_response
self._is_streaming = False
- self._pool = futures.ThreadPoolExecutor(max_workers=1)
- # Use a thread-safe queue to put requests on the stream
self._request_queue = queue.Queue()
self._send_time_queue = queue.Queue()
@@ -158,15 +166,6 @@ class StreamingSyncBenchmarkClient(BenchmarkClient):
def start(self):
self._is_streaming = True
- self._pool.submit(self._request_stream)
-
- def stop(self):
- self._is_streaming = False
- self._pool.shutdown(wait=True)
- self._stub = None
-
- def _request_stream(self):
- self._is_streaming = True
if self._generic:
stream_callable = self._stub.stream_stream(
'grpc.testing.BenchmarkService', 'StreamingCall')
@@ -175,8 +174,11 @@ class StreamingSyncBenchmarkClient(BenchmarkClient):
response_stream = stream_callable(self._request_generator(), _TIMEOUT)
for _ in response_stream:
- end_time = time.time()
- self._handle_response(end_time - self._send_time_queue.get_nowait())
+ self._handle_response(
+ self, time.time() - self._send_time_queue.get_nowait())
+
+ def stop(self):
+ self._is_streaming = False
def _request_generator(self):
while self._is_streaming:
@@ -187,46 +189,28 @@ class StreamingSyncBenchmarkClient(BenchmarkClient):
pass
-class AsyncReceiver(face.ResponseReceiver):
- """Receiver for async stream responses."""
-
- def __init__(self, send_time_queue, response_handler):
- self._send_time_queue = send_time_queue
- self._response_handler = response_handler
-
- def initial_metadata(self, initial_mdetadata):
- pass
-
- def response(self, response):
- end_time = time.time()
- self._response_handler(end_time - self._send_time_queue.get_nowait())
-
- def complete(self, terminal_metadata, code, details):
- pass
-
-
-class StreamingAsyncBenchmarkClient(BenchmarkClient):
+class StreamingSyncBenchmarkClient(BenchmarkClient):
def __init__(self, server, config, hist):
- super(StreamingAsyncBenchmarkClient, self).__init__(server, config, hist)
- self._send_time_queue = queue.Queue()
- self._receiver = AsyncReceiver(self._send_time_queue, self._handle_response)
- self._rendezvous = None
+ super(StreamingSyncBenchmarkClient, self).__init__(server, config, hist)
+ self._pool = futures.ThreadPoolExecutor(
+ max_workers=config.outstanding_rpcs_per_channel)
+ self._streams = [_SyncStream(self._stub, self._generic,
+ self._request, self._handle_response)
+ for _ in xrange(config.outstanding_rpcs_per_channel)]
+ self._curr_stream = 0
def send_request(self):
- if self._rendezvous is not None:
- self._send_time_queue.put(time.time())
- self._rendezvous.consume(self._request)
+ # Use a round_robin scheduler to determine what stream to send on
+ self._streams[self._curr_stream].send_request()
+ self._curr_stream = (self._curr_stream + 1) % len(self._streams)
def start(self):
- if self._generic:
- stream_callable = self._stub.stream_stream(
- 'grpc.testing.BenchmarkService', 'StreamingCall')
- else:
- stream_callable = self._stub.StreamingCall
- self._rendezvous = stream_callable.event(
- self._receiver, lambda *args: None, _TIMEOUT)
+ for stream in self._streams:
+ self._pool.submit(stream.start)
def stop(self):
- self._rendezvous.terminate()
- self._rendezvous = None
+ for stream in self._streams:
+ stream.stop()
+ self._pool.shutdown(wait=True)
+ self._stub = None
diff --git a/src/python/grpcio/tests/qps/client_runner.py b/src/python/grpcio/tests/qps/client_runner.py
index 1ede7d2af1..1fd58687ad 100644
--- a/src/python/grpcio/tests/qps/client_runner.py
+++ b/src/python/grpcio/tests/qps/client_runner.py
@@ -34,7 +34,7 @@ ClientRunner invokes either periodically or in response to some event.
"""
import abc
-import thread
+import threading
import time
@@ -61,15 +61,18 @@ class OpenLoopClientRunner(ClientRunner):
super(OpenLoopClientRunner, self).__init__(client)
self._is_running = False
self._interval_generator = interval_generator
+ self._dispatch_thread = threading.Thread(
+ target=self._dispatch_requests, args=())
def start(self):
self._is_running = True
self._client.start()
- thread.start_new_thread(self._dispatch_requests, ())
-
+ self._dispatch_thread.start()
+
def stop(self):
self._is_running = False
self._client.stop()
+ self._dispatch_thread.join()
self._client = None
def _dispatch_requests(self):
@@ -98,7 +101,6 @@ class ClosedLoopClientRunner(ClientRunner):
self._client.stop()
self._client = None
- def _send_request(self, response_time):
+ def _send_request(self, client, response_time):
if self._is_running:
- self._client.send_request()
-
+ client.send_request()
diff --git a/src/python/grpcio/tests/qps/qps_worker.py b/src/python/grpcio/tests/qps/qps_worker.py
index 3dda718638..16926379a5 100644
--- a/src/python/grpcio/tests/qps/qps_worker.py
+++ b/src/python/grpcio/tests/qps/qps_worker.py
@@ -43,9 +43,7 @@ def run_worker_server(port):
server.add_insecure_port('[::]:{}'.format(port))
server.start()
servicer.wait_for_quit()
- # Drain outstanding requests for clean exit
- time.sleep(2)
- server.stop(0)
+ server.stop(2)
if __name__ == '__main__':
diff --git a/src/python/grpcio/tests/qps/worker_server.py b/src/python/grpcio/tests/qps/worker_server.py
index 1f9af5482c..d41f8377c2 100644
--- a/src/python/grpcio/tests/qps/worker_server.py
+++ b/src/python/grpcio/tests/qps/worker_server.py
@@ -153,9 +153,8 @@ class WorkerServer(services_pb2.BetaWorkerServiceServicer):
if config.rpc_type == control_pb2.UNARY:
client = benchmark_client.UnaryAsyncBenchmarkClient(
server, config, qps_data)
- elif config.rpc_type == control_pb2.STREAMING:
- client = benchmark_client.StreamingAsyncBenchmarkClient(
- server, config, qps_data)
+ else:
+ raise Exception('Async streaming client not supported')
else:
raise Exception('Unsupported client type {}'.format(config.client_type))
diff --git a/src/python/grpcio/tests/stress/client.py b/src/python/grpcio/tests/stress/client.py
index e2e016760c..0de2532cd8 100644
--- a/src/python/grpcio/tests/stress/client.py
+++ b/src/python/grpcio/tests/stress/client.py
@@ -30,10 +30,10 @@
"""Entry point for running stress tests."""
import argparse
-import Queue
import threading
from grpc.beta import implementations
+from six.moves import queue
from src.proto.grpc.testing import metrics_pb2
from src.proto.grpc.testing import test_pb2
@@ -94,7 +94,7 @@ def run_test(args):
test_cases = _parse_weighted_test_cases(args.test_cases)
test_servers = args.server_addresses.split(',')
# Propagate any client exceptions with a queue
- exception_queue = Queue.Queue()
+ exception_queue = queue.Queue()
stop_event = threading.Event()
hist = histogram.Histogram(1, 1)
runners = []
@@ -121,7 +121,7 @@ def run_test(args):
if timeout_secs < 0:
timeout_secs = None
raise exception_queue.get(block=True, timeout=timeout_secs)
- except Queue.Empty:
+ except queue.Empty:
# No exceptions thrown, success
pass
finally:
diff --git a/src/python/grpcio/tests/tests.json b/src/python/grpcio/tests/tests.json
index 81458b11da..e384a2fc13 100644
--- a/src/python/grpcio/tests/tests.json
+++ b/src/python/grpcio/tests/tests.json
@@ -1,10 +1,9 @@
[
+ "_api_test.AllTest",
+ "_api_test.ChannelConnectivityTest",
+ "_api_test.ChannelTest",
"_auth_test.AccessTokenCallCredentialsTest",
"_auth_test.GoogleCallCredentialsTest",
- "_base_interface_test.AsyncEasyTest",
- "_base_interface_test.AsyncPeasyTest",
- "_base_interface_test.SyncEasyTest",
- "_base_interface_test.SyncPeasyTest",
"_beta_features_test.BetaFeaturesTest",
"_beta_features_test.ContextManagementAndLifecycleTest",
"_cancel_many_calls_test.CancelManyCallsTest",
@@ -12,22 +11,8 @@
"_channel_ready_future_test.ChannelReadyFutureTest",
"_channel_test.ChannelTest",
"_connectivity_channel_test.ChannelConnectivityTest",
- "_core_over_links_base_interface_test.AsyncEasyTest",
- "_core_over_links_base_interface_test.AsyncPeasyTest",
- "_core_over_links_base_interface_test.SyncEasyTest",
- "_core_over_links_base_interface_test.SyncPeasyTest",
- "_crust_over_core_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
- "_crust_over_core_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
- "_crust_over_core_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
- "_crust_over_core_over_links_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_over_links_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
- "_crust_over_core_over_links_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_over_links_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest",
- "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest",
- "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest",
+ "_connectivity_channel_test.ConnectivityStatesTest",
+ "_empty_message_test.EmptyMessageTest",
"_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest",
"_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest",
"_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest",
@@ -38,21 +23,16 @@
"_implementations_test.CallCredentialsTest",
"_implementations_test.ChannelCredentialsTest",
"_insecure_interop_test.InsecureInteropTest",
- "_intermediary_low_test.CancellationTest",
- "_intermediary_low_test.EchoTest",
- "_intermediary_low_test.ExpirationTest",
- "_intermediary_low_test.LonelyClientTest",
- "_later_test.LaterTest",
"_logging_pool_test.LoggingPoolTest",
- "_lonely_invocation_link_test.LonelyInvocationLinkTest",
- "_low_test.HangingServerShutdown",
- "_low_test.InsecureServerInsecureClient",
+ "_metadata_code_details_test.MetadataCodeDetailsTest",
+ "_metadata_test.MetadataTest",
"_not_found_test.NotFoundTest",
+ "_python_plugin_test.PythonPluginTest",
+ "_read_some_but_not_all_responses_test.ReadSomeButNotAllResponsesTest",
"_rpc_test.RPCTest",
"_sanity_test.Sanity",
"_secure_interop_test.SecureInteropTest",
- "_transmission_test.RoundTripTest",
- "_transmission_test.TransmissionTest",
+ "_thread_cleanup_test.CleanupThreadTest",
"_utilities_test.ChannelConnectivityTest",
"beta_python_plugin_test.PythonPluginTest",
"cygrpc_test.InsecureServerInsecureClient",
diff --git a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
deleted file mode 100644
index 22d4b019c7..0000000000
--- a/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
+++ /dev/null
@@ -1,428 +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.
-
-"""Tests for the old '_low'."""
-
-import threading
-import time
-import unittest
-
-import six
-from six.moves import queue
-
-from grpc._adapter import _intermediary_low as _low
-
-_STREAM_LENGTH = 300
-_TIMEOUT = 5
-_AFTER_DELAY = 2
-_FUTURE = time.time() + 60 * 60 * 24
-_BYTE_SEQUENCE = b'\abcdefghijklmnopqrstuvwxyz0123456789' * 200
-_BYTE_SEQUENCE_SEQUENCE = tuple(
- bytes(bytearray((row + column) % 256 for column in range(row)))
- for row in range(_STREAM_LENGTH))
-
-
-class LonelyClientTest(unittest.TestCase):
-
- def testLonelyClient(self):
- host = 'nosuchhostexists'
- port = 54321
- method = 'test method'
- deadline = time.time() + _TIMEOUT
- after_deadline = deadline + _AFTER_DELAY
- metadata_tag = object()
- finish_tag = object()
-
- completion_queue = _low.CompletionQueue()
- channel = _low.Channel('%s:%d' % (host, port), None)
- client_call = _low.Call(channel, completion_queue, method, host, deadline)
-
- client_call.invoke(completion_queue, metadata_tag, finish_tag)
- first_event = completion_queue.get(after_deadline)
- self.assertIsNotNone(first_event)
- second_event = completion_queue.get(after_deadline)
- self.assertIsNotNone(second_event)
- kinds = [event.kind for event in (first_event, second_event)]
- six.assertCountEqual(self,
- (_low.Event.Kind.METADATA_ACCEPTED, _low.Event.Kind.FINISH),
- kinds)
-
- self.assertIsNone(completion_queue.get(after_deadline))
-
- completion_queue.stop()
- stop_event = completion_queue.get(_FUTURE)
- self.assertEqual(_low.Event.Kind.STOP, stop_event.kind)
-
- del client_call
- del channel
- del completion_queue
-
-
-def _drive_completion_queue(completion_queue, event_queue):
- while True:
- event = completion_queue.get(_FUTURE)
- if event.kind is _low.Event.Kind.STOP:
- break
- event_queue.put(event)
-
-
-class EchoTest(unittest.TestCase):
-
- def setUp(self):
- self.host = 'localhost'
-
- self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue)
- port = self.server.add_http2_addr('[::]:0')
- self.server.start()
- self.server_events = queue.Queue()
- self.server_completion_queue_thread = threading.Thread(
- target=_drive_completion_queue,
- args=(self.server_completion_queue, self.server_events))
- self.server_completion_queue_thread.start()
-
- self.client_completion_queue = _low.CompletionQueue()
- self.channel = _low.Channel('%s:%d' % (self.host, port), None)
- self.client_events = queue.Queue()
- self.client_completion_queue_thread = threading.Thread(
- target=_drive_completion_queue,
- args=(self.client_completion_queue, self.client_events))
- self.client_completion_queue_thread.start()
-
- def tearDown(self):
- self.server.stop()
- self.server.cancel_all_calls()
- self.server_completion_queue.stop()
- self.client_completion_queue.stop()
- self.server_completion_queue_thread.join()
- self.client_completion_queue_thread.join()
- del self.server
-
- def _perform_echo_test(self, test_data):
- method = 'test method'
- details = 'test details'
- server_leading_metadata_key = 'my_server_leading_key'
- server_leading_metadata_value = 'my_server_leading_value'
- server_trailing_metadata_key = 'my_server_trailing_key'
- server_trailing_metadata_value = 'my_server_trailing_value'
- client_metadata_key = 'my_client_key'
- client_metadata_value = 'my_client_value'
- server_leading_binary_metadata_key = 'my_server_leading_key-bin'
- server_leading_binary_metadata_value = b'\0'*2047
- server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
- server_trailing_binary_metadata_value = b'\0'*2047
- client_binary_metadata_key = 'my_client_key-bin'
- client_binary_metadata_value = b'\0'*2047
- deadline = _FUTURE
- metadata_tag = object()
- finish_tag = object()
- write_tag = object()
- complete_tag = object()
- service_tag = object()
- read_tag = object()
- status_tag = object()
-
- server_data = []
- client_data = []
-
- client_call = _low.Call(self.channel, self.client_completion_queue,
- method, self.host, deadline)
- client_call.add_metadata(client_metadata_key, client_metadata_value)
- client_call.add_metadata(client_binary_metadata_key,
- client_binary_metadata_value)
-
- client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
-
- self.server.service(service_tag)
- service_accepted = self.server_events.get()
- self.assertIsNotNone(service_accepted)
- self.assertIs(service_accepted.kind, _low.Event.Kind.SERVICE_ACCEPTED)
- self.assertIs(service_accepted.tag, service_tag)
- self.assertEqual(method, service_accepted.service_acceptance.method)
- self.assertEqual(self.host, service_accepted.service_acceptance.host)
- self.assertIsNotNone(service_accepted.service_acceptance.call)
- metadata = dict(service_accepted.metadata)
- self.assertIn(client_metadata_key, metadata)
- self.assertEqual(client_metadata_value, metadata[client_metadata_key])
- self.assertIn(client_binary_metadata_key, metadata)
- self.assertEqual(client_binary_metadata_value,
- metadata[client_binary_metadata_key])
- server_call = service_accepted.service_acceptance.call
- server_call.accept(self.server_completion_queue, finish_tag)
- server_call.add_metadata(server_leading_metadata_key,
- server_leading_metadata_value)
- server_call.add_metadata(server_leading_binary_metadata_key,
- server_leading_binary_metadata_value)
- server_call.premetadata()
-
- metadata_accepted = self.client_events.get()
- self.assertIsNotNone(metadata_accepted)
- self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
- self.assertEqual(metadata_tag, metadata_accepted.tag)
- metadata = dict(metadata_accepted.metadata)
- self.assertIn(server_leading_metadata_key, metadata)
- self.assertEqual(server_leading_metadata_value,
- metadata[server_leading_metadata_key])
- self.assertIn(server_leading_binary_metadata_key, metadata)
- self.assertEqual(server_leading_binary_metadata_value,
- metadata[server_leading_binary_metadata_key])
-
- for datum in test_data:
- client_call.write(datum, write_tag, _low.WriteFlags.WRITE_NO_COMPRESS)
- write_accepted = self.client_events.get()
- self.assertIsNotNone(write_accepted)
- self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
- self.assertIs(write_accepted.tag, write_tag)
- self.assertIs(write_accepted.write_accepted, True)
-
- server_call.read(read_tag)
- read_accepted = self.server_events.get()
- self.assertIsNotNone(read_accepted)
- self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
- self.assertEqual(read_tag, read_accepted.tag)
- self.assertIsNotNone(read_accepted.bytes)
- server_data.append(read_accepted.bytes)
-
- server_call.write(read_accepted.bytes, write_tag, 0)
- write_accepted = self.server_events.get()
- self.assertIsNotNone(write_accepted)
- self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
- self.assertEqual(write_tag, write_accepted.tag)
- self.assertTrue(write_accepted.write_accepted)
-
- client_call.read(read_tag)
- read_accepted = self.client_events.get()
- self.assertIsNotNone(read_accepted)
- self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
- self.assertEqual(read_tag, read_accepted.tag)
- self.assertIsNotNone(read_accepted.bytes)
- client_data.append(read_accepted.bytes)
-
- client_call.complete(complete_tag)
- complete_accepted = self.client_events.get()
- self.assertIsNotNone(complete_accepted)
- self.assertIs(complete_accepted.kind, _low.Event.Kind.COMPLETE_ACCEPTED)
- self.assertIs(complete_accepted.tag, complete_tag)
- self.assertIs(complete_accepted.complete_accepted, True)
-
- server_call.read(read_tag)
- read_accepted = self.server_events.get()
- self.assertIsNotNone(read_accepted)
- self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
- self.assertEqual(read_tag, read_accepted.tag)
- self.assertIsNone(read_accepted.bytes)
-
- server_call.add_metadata(server_trailing_metadata_key,
- server_trailing_metadata_value)
- server_call.add_metadata(server_trailing_binary_metadata_key,
- server_trailing_binary_metadata_value)
-
- server_call.status(_low.Status(_low.Code.OK, details), status_tag)
- server_terminal_event_one = self.server_events.get()
- server_terminal_event_two = self.server_events.get()
- if server_terminal_event_one.kind == _low.Event.Kind.COMPLETE_ACCEPTED:
- status_accepted = server_terminal_event_one
- rpc_accepted = server_terminal_event_two
- else:
- status_accepted = server_terminal_event_two
- rpc_accepted = server_terminal_event_one
- self.assertIsNotNone(status_accepted)
- self.assertIsNotNone(rpc_accepted)
- self.assertEqual(_low.Event.Kind.COMPLETE_ACCEPTED, status_accepted.kind)
- self.assertEqual(status_tag, status_accepted.tag)
- self.assertTrue(status_accepted.complete_accepted)
- self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
- self.assertEqual(finish_tag, rpc_accepted.tag)
- self.assertEqual(_low.Status(_low.Code.OK, ''), rpc_accepted.status)
-
- client_call.read(read_tag)
- client_terminal_event_one = self.client_events.get()
- client_terminal_event_two = self.client_events.get()
- if client_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
- read_accepted = client_terminal_event_one
- finish_accepted = client_terminal_event_two
- else:
- read_accepted = client_terminal_event_two
- finish_accepted = client_terminal_event_one
- self.assertIsNotNone(read_accepted)
- self.assertIsNotNone(finish_accepted)
- self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
- self.assertEqual(read_tag, read_accepted.tag)
- self.assertIsNone(read_accepted.bytes)
- self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
- self.assertEqual(finish_tag, finish_accepted.tag)
- self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status)
- metadata = dict(finish_accepted.metadata)
- self.assertIn(server_trailing_metadata_key, metadata)
- self.assertEqual(server_trailing_metadata_value,
- metadata[server_trailing_metadata_key])
- self.assertIn(server_trailing_binary_metadata_key, metadata)
- self.assertEqual(server_trailing_binary_metadata_value,
- metadata[server_trailing_binary_metadata_key])
- self.assertSetEqual(set(key for key, _ in finish_accepted.metadata),
- set((server_trailing_metadata_key,
- server_trailing_binary_metadata_key,)))
-
- self.assertSequenceEqual(test_data, server_data)
- self.assertSequenceEqual(test_data, client_data)
-
- def testNoEcho(self):
- self._perform_echo_test(())
-
- def testOneByteEcho(self):
- self._perform_echo_test([b'\x07'])
-
- def testOneManyByteEcho(self):
- self._perform_echo_test([_BYTE_SEQUENCE])
-
- def testManyOneByteEchoes(self):
- self._perform_echo_test(_BYTE_SEQUENCE)
-
- def testManyManyByteEchoes(self):
- self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE)
-
-
-class CancellationTest(unittest.TestCase):
-
- def setUp(self):
- self.host = 'localhost'
-
- self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue)
- port = self.server.add_http2_addr('[::]:0')
- self.server.start()
- self.server_events = queue.Queue()
- self.server_completion_queue_thread = threading.Thread(
- target=_drive_completion_queue,
- args=(self.server_completion_queue, self.server_events))
- self.server_completion_queue_thread.start()
-
- self.client_completion_queue = _low.CompletionQueue()
- self.channel = _low.Channel('%s:%d' % (self.host, port), None)
- self.client_events = queue.Queue()
- self.client_completion_queue_thread = threading.Thread(
- target=_drive_completion_queue,
- args=(self.client_completion_queue, self.client_events))
- self.client_completion_queue_thread.start()
-
- def tearDown(self):
- self.server.stop()
- self.server.cancel_all_calls()
- self.server_completion_queue.stop()
- self.client_completion_queue.stop()
- self.server_completion_queue_thread.join()
- self.client_completion_queue_thread.join()
- del self.server
-
- def testCancellation(self):
- method = 'test method'
- deadline = _FUTURE
- metadata_tag = object()
- finish_tag = object()
- write_tag = object()
- service_tag = object()
- read_tag = object()
- test_data = _BYTE_SEQUENCE_SEQUENCE
-
- server_data = []
- client_data = []
-
- client_call = _low.Call(self.channel, self.client_completion_queue,
- method, self.host, deadline)
-
- client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
-
- self.server.service(service_tag)
- service_accepted = self.server_events.get()
- server_call = service_accepted.service_acceptance.call
-
- server_call.accept(self.server_completion_queue, finish_tag)
- server_call.premetadata()
-
- metadata_accepted = self.client_events.get()
- self.assertIsNotNone(metadata_accepted)
-
- for datum in test_data:
- client_call.write(datum, write_tag, 0)
- write_accepted = self.client_events.get()
-
- server_call.read(read_tag)
- read_accepted = self.server_events.get()
- server_data.append(read_accepted.bytes)
-
- server_call.write(read_accepted.bytes, write_tag, 0)
- write_accepted = self.server_events.get()
- self.assertIsNotNone(write_accepted)
-
- client_call.read(read_tag)
- read_accepted = self.client_events.get()
- client_data.append(read_accepted.bytes)
-
- client_call.cancel()
- # cancel() is idempotent.
- client_call.cancel()
- client_call.cancel()
- client_call.cancel()
-
- server_call.read(read_tag)
-
- server_terminal_event_one = self.server_events.get()
- server_terminal_event_two = self.server_events.get()
- if server_terminal_event_one.kind == _low.Event.Kind.READ_ACCEPTED:
- read_accepted = server_terminal_event_one
- rpc_accepted = server_terminal_event_two
- else:
- read_accepted = server_terminal_event_two
- rpc_accepted = server_terminal_event_one
- self.assertIsNotNone(read_accepted)
- self.assertIsNotNone(rpc_accepted)
- self.assertEqual(_low.Event.Kind.READ_ACCEPTED, read_accepted.kind)
- self.assertIsNone(read_accepted.bytes)
- self.assertEqual(_low.Event.Kind.FINISH, rpc_accepted.kind)
- self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), rpc_accepted.status)
-
- finish_event = self.client_events.get()
- self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
- self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
- finish_event.status)
-
- self.assertSequenceEqual(test_data, server_data)
- self.assertSequenceEqual(test_data, client_data)
-
-
-class ExpirationTest(unittest.TestCase):
-
- @unittest.skip('TODO(nathaniel): Expiration test!')
- def testExpiration(self):
- pass
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
diff --git a/src/python/grpcio/tests/unit/_adapter/_low_test.py b/src/python/grpcio/tests/unit/_adapter/_low_test.py
deleted file mode 100644
index ec46617996..0000000000
--- a/src/python/grpcio/tests/unit/_adapter/_low_test.py
+++ /dev/null
@@ -1,319 +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.
-
-import threading
-import time
-import unittest
-
-from grpc import _grpcio_metadata
-from grpc._adapter import _types
-from grpc._adapter import _low
-from tests.unit import test_common
-
-
-def wait_for_events(completion_queues, deadline):
- """
- Args:
- completion_queues: list of completion queues to wait for events on
- deadline: absolute deadline to wait until
-
- Returns:
- a sequence of events of length len(completion_queues).
- """
-
- results = [None] * len(completion_queues)
- lock = threading.Lock()
- threads = []
- def set_ith_result(i, completion_queue):
- result = completion_queue.next(deadline)
- with lock:
- results[i] = result
- for i, completion_queue in enumerate(completion_queues):
- thread = threading.Thread(target=set_ith_result,
- args=[i, completion_queue])
- thread.start()
- threads.append(thread)
- for thread in threads:
- thread.join()
- return results
-
-
-class InsecureServerInsecureClient(unittest.TestCase):
-
- def setUp(self):
- self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue, [])
- self.port = self.server.add_http2_port('[::]:0')
- self.client_completion_queue = _low.CompletionQueue()
- self.client_channel = _low.Channel('localhost:%d'%self.port, [])
-
- self.server.start()
-
- def tearDown(self):
- self.server.shutdown()
- del self.client_channel
-
- self.client_completion_queue.shutdown()
- while (self.client_completion_queue.next(float('+inf')).type !=
- _types.EventType.QUEUE_SHUTDOWN):
- pass
- self.server_completion_queue.shutdown()
- while (self.server_completion_queue.next(float('+inf')).type !=
- _types.EventType.QUEUE_SHUTDOWN):
- pass
-
- del self.client_completion_queue
- del self.server_completion_queue
- del self.server
-
- def testEcho(self):
- deadline = time.time() + 5
- event_time_tolerance = 2
- deadline_tolerance = 0.25
- client_metadata_ascii_key = 'key'
- client_metadata_ascii_value = 'val'
- client_metadata_bin_key = 'key-bin'
- client_metadata_bin_value = b'\0'*1000
- server_initial_metadata_key = 'init_me_me_me'
- server_initial_metadata_value = 'whodawha?'
- server_trailing_metadata_key = 'california_is_in_a_drought'
- server_trailing_metadata_value = 'zomg it is'
- server_status_code = _types.StatusCode.OK
- server_status_details = 'our work is never over'
- request = 'blarghaflargh'
- response = 'his name is robert paulson'
- method = 'twinkies'
- host = 'hostess'
- server_request_tag = object()
- request_call_result = self.server.request_call(self.server_completion_queue,
- server_request_tag)
-
- self.assertEqual(_types.CallError.OK, request_call_result)
-
- client_call_tag = object()
- client_call = self.client_channel.create_call(
- self.client_completion_queue, method, host, deadline)
- client_initial_metadata = [
- (client_metadata_ascii_key, client_metadata_ascii_value),
- (client_metadata_bin_key, client_metadata_bin_value)
- ]
- client_start_batch_result = client_call.start_batch([
- _types.OpArgs.send_initial_metadata(client_initial_metadata),
- _types.OpArgs.send_message(request, 0),
- _types.OpArgs.send_close_from_client(),
- _types.OpArgs.recv_initial_metadata(),
- _types.OpArgs.recv_message(),
- _types.OpArgs.recv_status_on_client()
- ], client_call_tag)
- self.assertEqual(_types.CallError.OK, client_start_batch_result)
-
- client_no_event, request_event, = wait_for_events(
- [self.client_completion_queue, self.server_completion_queue],
- time.time() + event_time_tolerance)
- self.assertEqual(client_no_event, None)
- self.assertEqual(_types.EventType.OP_COMPLETE, request_event.type)
- self.assertIsInstance(request_event.call, _low.Call)
- self.assertIs(server_request_tag, request_event.tag)
- self.assertEqual(1, len(request_event.results))
- received_initial_metadata = request_event.results[0].initial_metadata
- # Check that our metadata were transmitted
- self.assertTrue(test_common.metadata_transmitted(client_initial_metadata,
- received_initial_metadata))
- # Check that Python's user agent string is a part of the full user agent
- # string
- received_initial_metadata_dict = dict(received_initial_metadata)
- self.assertIn('user-agent', received_initial_metadata_dict)
- self.assertIn('Python-gRPC-{}'.format(_grpcio_metadata.__version__),
- received_initial_metadata_dict['user-agent'])
- self.assertEqual(method, request_event.call_details.method)
- self.assertEqual(host, request_event.call_details.host)
- self.assertLess(abs(deadline - request_event.call_details.deadline),
- deadline_tolerance)
-
- # Check that the channel is connected, and that both it and the call have
- # the proper target and peer; do this after the first flurry of messages to
- # avoid the possibility that connection was delayed by the core until the
- # first message was sent.
- self.assertEqual(_types.ConnectivityState.READY,
- self.client_channel.check_connectivity_state(False))
- self.assertIsNotNone(self.client_channel.target())
- self.assertIsNotNone(client_call.peer())
-
- server_call_tag = object()
- server_call = request_event.call
- server_initial_metadata = [
- (server_initial_metadata_key, server_initial_metadata_value)
- ]
- server_trailing_metadata = [
- (server_trailing_metadata_key, server_trailing_metadata_value)
- ]
- server_start_batch_result = server_call.start_batch([
- _types.OpArgs.send_initial_metadata(server_initial_metadata),
- _types.OpArgs.recv_message(),
- _types.OpArgs.send_message(response, 0),
- _types.OpArgs.recv_close_on_server(),
- _types.OpArgs.send_status_from_server(
- server_trailing_metadata, server_status_code, server_status_details)
- ], server_call_tag)
- self.assertEqual(_types.CallError.OK, server_start_batch_result)
-
- client_event, server_event, = wait_for_events(
- [self.client_completion_queue, self.server_completion_queue],
- time.time() + event_time_tolerance)
-
- self.assertEqual(6, len(client_event.results))
- found_client_op_types = set()
- for client_result in client_event.results:
- # we expect each op type to be unique
- self.assertNotIn(client_result.type, found_client_op_types)
- found_client_op_types.add(client_result.type)
- if client_result.type == _types.OpType.RECV_INITIAL_METADATA:
- self.assertTrue(
- test_common.metadata_transmitted(server_initial_metadata,
- client_result.initial_metadata))
- elif client_result.type == _types.OpType.RECV_MESSAGE:
- self.assertEqual(response, client_result.message)
- elif client_result.type == _types.OpType.RECV_STATUS_ON_CLIENT:
- self.assertTrue(
- test_common.metadata_transmitted(server_trailing_metadata,
- client_result.trailing_metadata))
- self.assertEqual(server_status_details, client_result.status.details)
- self.assertEqual(server_status_code, client_result.status.code)
- self.assertEqual(set([
- _types.OpType.SEND_INITIAL_METADATA,
- _types.OpType.SEND_MESSAGE,
- _types.OpType.SEND_CLOSE_FROM_CLIENT,
- _types.OpType.RECV_INITIAL_METADATA,
- _types.OpType.RECV_MESSAGE,
- _types.OpType.RECV_STATUS_ON_CLIENT
- ]), found_client_op_types)
-
- self.assertEqual(5, len(server_event.results))
- found_server_op_types = set()
- for server_result in server_event.results:
- self.assertNotIn(client_result.type, found_server_op_types)
- found_server_op_types.add(server_result.type)
- if server_result.type == _types.OpType.RECV_MESSAGE:
- self.assertEqual(request, server_result.message)
- elif server_result.type == _types.OpType.RECV_CLOSE_ON_SERVER:
- self.assertFalse(server_result.cancelled)
- self.assertEqual(set([
- _types.OpType.SEND_INITIAL_METADATA,
- _types.OpType.RECV_MESSAGE,
- _types.OpType.SEND_MESSAGE,
- _types.OpType.RECV_CLOSE_ON_SERVER,
- _types.OpType.SEND_STATUS_FROM_SERVER
- ]), found_server_op_types)
-
- del client_call
- del server_call
-
-
-class HangingServerShutdown(unittest.TestCase):
-
- def setUp(self):
- self.server_completion_queue = _low.CompletionQueue()
- self.server = _low.Server(self.server_completion_queue, [])
- self.port = self.server.add_http2_port('[::]:0')
- self.client_completion_queue = _low.CompletionQueue()
- self.client_channel = _low.Channel('localhost:%d'%self.port, [])
-
- self.server.start()
-
- def tearDown(self):
- self.server.shutdown()
- del self.client_channel
-
- self.client_completion_queue.shutdown()
- self.server_completion_queue.shutdown()
- while True:
- client_event, server_event = wait_for_events(
- [self.client_completion_queue, self.server_completion_queue],
- float("+inf"))
- if (client_event.type == _types.EventType.QUEUE_SHUTDOWN and
- server_event.type == _types.EventType.QUEUE_SHUTDOWN):
- break
-
- del self.client_completion_queue
- del self.server_completion_queue
- del self.server
-
- def testHangingServerCall(self):
- deadline = time.time() + 5
- deadline_tolerance = 0.25
- event_time_tolerance = 2
- cancel_all_calls_time_tolerance = 0.5
- request = 'blarghaflargh'
- method = 'twinkies'
- host = 'hostess'
- server_request_tag = object()
- request_call_result = self.server.request_call(self.server_completion_queue,
- server_request_tag)
-
- client_call_tag = object()
- client_call = self.client_channel.create_call(self.client_completion_queue,
- method, host, deadline)
- client_start_batch_result = client_call.start_batch([
- _types.OpArgs.send_initial_metadata([]),
- _types.OpArgs.send_message(request, 0),
- _types.OpArgs.send_close_from_client(),
- _types.OpArgs.recv_initial_metadata(),
- _types.OpArgs.recv_message(),
- _types.OpArgs.recv_status_on_client()
- ], client_call_tag)
-
- client_no_event, request_event, = wait_for_events(
- [self.client_completion_queue, self.server_completion_queue],
- time.time() + event_time_tolerance)
-
- # Now try to shutdown the server and expect that we see server shutdown
- # almost immediately after calling cancel_all_calls.
-
- # First attempt to cancel all calls before shutting down, and expect
- # our state machine to catch the erroneous API use.
- with self.assertRaises(RuntimeError):
- self.server.cancel_all_calls()
-
- shutdown_tag = object()
- self.server.shutdown(shutdown_tag)
- pre_cancel_timestamp = time.time()
- self.server.cancel_all_calls()
- finish_shutdown_timestamp = None
- client_call_event, server_shutdown_event = wait_for_events(
- [self.client_completion_queue, self.server_completion_queue],
- time.time() + event_time_tolerance)
- self.assertIs(shutdown_tag, server_shutdown_event.tag)
- self.assertGreater(pre_cancel_timestamp + cancel_all_calls_time_tolerance,
- time.time())
-
- del client_call
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_api_test.py b/src/python/grpcio/tests/unit/_api_test.py
new file mode 100644
index 0000000000..2fe89499f5
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_api_test.py
@@ -0,0 +1,111 @@
+# 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.
+
+"""Test of gRPC Python's application-layer API."""
+
+import unittest
+
+import six
+
+import grpc
+
+from tests.unit import _from_grpc_import_star
+
+
+class AllTest(unittest.TestCase):
+
+ def testAll(self):
+ expected_grpc_code_elements = (
+ 'FutureTimeoutError',
+ 'FutureCancelledError',
+ 'Future',
+ 'ChannelConnectivity',
+ 'StatusCode',
+ 'RpcError',
+ 'RpcContext',
+ 'Call',
+ 'ChannelCredentials',
+ 'CallCredentials',
+ 'AuthMetadataContext',
+ 'AuthMetadataPluginCallback',
+ 'AuthMetadataPlugin',
+ 'ServerCredentials',
+ 'UnaryUnaryMultiCallable',
+ 'UnaryStreamMultiCallable',
+ 'StreamUnaryMultiCallable',
+ 'StreamStreamMultiCallable',
+ 'Channel',
+ 'ServicerContext',
+ 'RpcMethodHandler',
+ 'HandlerCallDetails',
+ 'GenericRpcHandler',
+ 'Server',
+ 'unary_unary_rpc_method_handler',
+ 'unary_stream_rpc_method_handler',
+ 'stream_unary_rpc_method_handler',
+ 'stream_stream_rpc_method_handler',
+ 'method_handlers_generic_handler',
+ 'ssl_channel_credentials',
+ 'metadata_call_credentials',
+ 'access_token_call_credentials',
+ 'composite_call_credentials',
+ 'composite_channel_credentials',
+ 'ssl_server_credentials',
+ 'channel_ready_future',
+ 'insecure_channel',
+ 'secure_channel',
+ 'server',
+ )
+
+ six.assertCountEqual(
+ self, expected_grpc_code_elements,
+ _from_grpc_import_star.GRPC_ELEMENTS)
+
+
+class ChannelConnectivityTest(unittest.TestCase):
+
+ def testChannelConnectivity(self):
+ self.assertSequenceEqual(
+ (grpc.ChannelConnectivity.IDLE,
+ grpc.ChannelConnectivity.CONNECTING,
+ grpc.ChannelConnectivity.READY,
+ grpc.ChannelConnectivity.TRANSIENT_FAILURE,
+ grpc.ChannelConnectivity.SHUTDOWN,),
+ tuple(grpc.ChannelConnectivity))
+
+
+class ChannelTest(unittest.TestCase):
+
+ def test_secure_channel(self):
+ channel_credentials = grpc.ssl_channel_credentials()
+ channel = grpc.secure_channel('google.com:443', channel_credentials)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/beta/_auth_test.py b/src/python/grpcio/tests/unit/_auth_test.py
index 694928a91b..c31f7b06f7 100644
--- a/src/python/grpcio/tests/unit/beta/_auth_test.py
+++ b/src/python/grpcio/tests/unit/_auth_test.py
@@ -33,7 +33,7 @@ import collections
import threading
import unittest
-from grpc.beta import _auth
+from grpc import _auth
class MockGoogleCreds(object):
diff --git a/src/python/grpcio/tests/unit/_channel_connectivity_test.py b/src/python/grpcio/tests/unit/_channel_connectivity_test.py
index a1575efada..ae8de523ec 100644
--- a/src/python/grpcio/tests/unit/_channel_connectivity_test.py
+++ b/src/python/grpcio/tests/unit/_channel_connectivity_test.py
@@ -135,12 +135,12 @@ class ChannelConnectivityTest(unittest.TestCase):
self.assertNotIn(
grpc.ChannelConnectivity.TRANSIENT_FAILURE, third_connectivities)
self.assertNotIn(
- grpc.ChannelConnectivity.FATAL_FAILURE, third_connectivities)
+ grpc.ChannelConnectivity.SHUTDOWN, third_connectivities)
self.assertNotIn(
grpc.ChannelConnectivity.TRANSIENT_FAILURE,
fourth_connectivities)
self.assertNotIn(
- grpc.ChannelConnectivity.FATAL_FAILURE, fourth_connectivities)
+ grpc.ChannelConnectivity.SHUTDOWN, fourth_connectivities)
def test_reachable_then_unreachable_channel_connectivity(self):
server = _server.Server((), futures.ThreadPoolExecutor(max_workers=0))
diff --git a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
deleted file mode 100644
index 2b8981c752..0000000000
--- a/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
+++ /dev/null
@@ -1,157 +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.
-
-"""Tests Base interface compliance of the core-over-gRPC-links stack."""
-
-import collections
-import logging
-import random
-import time
-import unittest
-
-import six
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.core import implementations
-from grpc.framework.interfaces.base import utilities
-from tests.unit import test_common as grpc_test_common
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.base import test_cases
-from tests.unit.framework.interfaces.base import test_interfaces
-
-
-class _SerializationBehaviors(
- collections.namedtuple(
- '_SerializationBehaviors',
- ('request_serializers', 'request_deserializers', 'response_serializers',
- 'response_deserializers',))):
- pass
-
-
-class _Links(
- collections.namedtuple(
- '_Links',
- ('invocation_end_link', 'invocation_grpc_link', 'service_grpc_link',
- 'service_end_link'))):
- pass
-
-
-def _serialization_behaviors_from_serializations(serializations):
- request_serializers = {}
- request_deserializers = {}
- response_serializers = {}
- response_deserializers = {}
- for (group, method), serialization in six.iteritems(serializations):
- request_serializers[group, method] = serialization.serialize_request
- request_deserializers[group, method] = serialization.deserialize_request
- response_serializers[group, method] = serialization.serialize_response
- response_deserializers[group, method] = serialization.deserialize_response
- return _SerializationBehaviors(
- request_serializers, request_deserializers, response_serializers,
- response_deserializers)
-
-
-class _Implementation(test_interfaces.Implementation):
-
- def instantiate(self, serializations, servicer):
- serialization_behaviors = _serialization_behaviors_from_serializations(
- serializations)
- invocation_end_link = implementations.invocation_end_link()
- service_end_link = implementations.service_end_link(
- servicer, test_constants.DEFAULT_TIMEOUT,
- test_constants.MAXIMUM_TIMEOUT)
- service_grpc_link = service.service_link(
- serialization_behaviors.request_deserializers,
- serialization_behaviors.response_serializers)
- port = service_grpc_link.add_port('[::]:0', None)
- channel = _intermediary_low.Channel('localhost:%d' % port, None)
- invocation_grpc_link = invocation.invocation_link(
- channel, b'localhost', None,
- serialization_behaviors.request_serializers,
- serialization_behaviors.response_deserializers)
-
- invocation_end_link.join_link(invocation_grpc_link)
- invocation_grpc_link.join_link(invocation_end_link)
- service_end_link.join_link(service_grpc_link)
- service_grpc_link.join_link(service_end_link)
- invocation_grpc_link.start()
- service_grpc_link.start()
- return invocation_end_link, service_end_link, (
- invocation_grpc_link, service_grpc_link)
-
- def destantiate(self, memo):
- invocation_grpc_link, service_grpc_link = memo
- invocation_grpc_link.stop()
- service_grpc_link.begin_stop()
- service_grpc_link.end_stop()
-
- def invocation_initial_metadata(self):
- return grpc_test_common.INVOCATION_INITIAL_METADATA
-
- def service_initial_metadata(self):
- return grpc_test_common.SERVICE_INITIAL_METADATA
-
- def invocation_completion(self):
- return utilities.completion(None, None, None)
-
- def service_completion(self):
- return utilities.completion(
- grpc_test_common.SERVICE_TERMINAL_METADATA,
- beta_interfaces.StatusCode.OK, grpc_test_common.DETAILS)
-
- def metadata_transmitted(self, original_metadata, transmitted_metadata):
- return original_metadata is None or grpc_test_common.metadata_transmitted(
- original_metadata, transmitted_metadata)
-
- def completion_transmitted(self, original_completion, transmitted_completion):
- if (original_completion.terminal_metadata is not None and
- not grpc_test_common.metadata_transmitted(
- original_completion.terminal_metadata,
- transmitted_completion.terminal_metadata)):
- return False
- elif original_completion.code is not transmitted_completion.code:
- return False
- elif original_completion.message != transmitted_completion.message:
- return False
- else:
- return True
-
-
-def load_tests(loader, tests, pattern):
- return unittest.TestSuite(
- tests=tuple(
- loader.loadTestsFromTestCase(test_case_class)
- for test_case_class in test_cases.test_cases(_Implementation())))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
deleted file mode 100644
index 50b9a5a824..0000000000
--- a/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
+++ /dev/null
@@ -1,163 +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.
-
-"""Tests Face compliance of the crust-over-core-over-gRPC-links stack."""
-
-import collections
-import unittest
-
-import six
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.core import implementations as core_implementations
-from grpc.framework.crust import implementations as crust_implementations
-from grpc.framework.foundation import logging_pool
-from grpc.framework.interfaces.links import utilities
-from tests.unit import test_common as grpc_test_common
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import test_cases
-from tests.unit.framework.interfaces.face import test_interfaces
-
-
-class _SerializationBehaviors(
- collections.namedtuple(
- '_SerializationBehaviors',
- ('request_serializers', 'request_deserializers', 'response_serializers',
- 'response_deserializers',))):
- pass
-
-
-def _serialization_behaviors_from_test_methods(test_methods):
- request_serializers = {}
- request_deserializers = {}
- response_serializers = {}
- response_deserializers = {}
- for (group, method), test_method in six.iteritems(test_methods):
- request_serializers[group, method] = test_method.serialize_request
- request_deserializers[group, method] = test_method.deserialize_request
- response_serializers[group, method] = test_method.serialize_response
- response_deserializers[group, method] = test_method.deserialize_response
- return _SerializationBehaviors(
- request_serializers, request_deserializers, response_serializers,
- response_deserializers)
-
-
-class _Implementation(test_interfaces.Implementation):
-
- def instantiate(
- self, methods, method_implementations, multi_method_implementation):
- pool = logging_pool.pool(test_constants.POOL_SIZE)
- servicer = crust_implementations.servicer(
- method_implementations, multi_method_implementation, pool)
- serialization_behaviors = _serialization_behaviors_from_test_methods(
- methods)
- invocation_end_link = core_implementations.invocation_end_link()
- service_end_link = core_implementations.service_end_link(
- servicer, test_constants.DEFAULT_TIMEOUT,
- test_constants.MAXIMUM_TIMEOUT)
- service_grpc_link = service.service_link(
- serialization_behaviors.request_deserializers,
- serialization_behaviors.response_serializers)
- port = service_grpc_link.add_port('[::]:0', None)
- channel = _intermediary_low.Channel('localhost:%d' % port, None)
- invocation_grpc_link = invocation.invocation_link(
- channel, b'localhost', None,
- serialization_behaviors.request_serializers,
- serialization_behaviors.response_deserializers)
-
- invocation_end_link.join_link(invocation_grpc_link)
- invocation_grpc_link.join_link(invocation_end_link)
- service_grpc_link.join_link(service_end_link)
- service_end_link.join_link(service_grpc_link)
- service_end_link.start()
- invocation_end_link.start()
- invocation_grpc_link.start()
- service_grpc_link.start()
-
- generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
- # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
- group = next(iter(methods))[0]
- # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
- # _digest.TestServiceDigest.
- cardinalities = {
- method: method_object.cardinality()
- for (group, method), method_object in six.iteritems(methods)}
- dynamic_stub = crust_implementations.dynamic_stub(
- invocation_end_link, group, cardinalities, pool)
-
- return generic_stub, {group: dynamic_stub}, (
- invocation_end_link, invocation_grpc_link, service_grpc_link,
- service_end_link, pool)
-
- def destantiate(self, memo):
- (invocation_end_link, invocation_grpc_link, service_grpc_link,
- service_end_link, pool) = memo
- invocation_end_link.stop(0).wait()
- invocation_grpc_link.stop()
- service_grpc_link.begin_stop()
- service_end_link.stop(0).wait()
- service_grpc_link.end_stop()
- invocation_end_link.join_link(utilities.NULL_LINK)
- invocation_grpc_link.join_link(utilities.NULL_LINK)
- service_grpc_link.join_link(utilities.NULL_LINK)
- service_end_link.join_link(utilities.NULL_LINK)
- pool.shutdown(wait=True)
-
- def invocation_metadata(self):
- return grpc_test_common.INVOCATION_INITIAL_METADATA
-
- def initial_metadata(self):
- return grpc_test_common.SERVICE_INITIAL_METADATA
-
- def terminal_metadata(self):
- return grpc_test_common.SERVICE_TERMINAL_METADATA
-
- def code(self):
- return beta_interfaces.StatusCode.OK
-
- def details(self):
- return grpc_test_common.DETAILS
-
- def metadata_transmitted(self, original_metadata, transmitted_metadata):
- return original_metadata is None or grpc_test_common.metadata_transmitted(
- original_metadata, transmitted_metadata)
-
-
-def load_tests(loader, tests, pattern):
- return unittest.TestSuite(
- tests=tuple(
- loader.loadTestsFromTestCase(test_case_class)
- for test_case_class in test_cases.test_cases(_Implementation())))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_cython/_read_some_but_not_all_responses_test.py b/src/python/grpcio/tests/unit/_cython/_read_some_but_not_all_responses_test.py
new file mode 100644
index 0000000000..6ae7a90fbe
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_cython/_read_some_but_not_all_responses_test.py
@@ -0,0 +1,251 @@
+# 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.
+
+"""Test a corner-case at the level of the Cython API."""
+
+import threading
+import unittest
+
+from grpc._cython import cygrpc
+
+_INFINITE_FUTURE = cygrpc.Timespec(float('+inf'))
+_EMPTY_FLAGS = 0
+_EMPTY_METADATA = cygrpc.Metadata(())
+
+
+class _ServerDriver(object):
+
+ def __init__(self, completion_queue, shutdown_tag):
+ self._condition = threading.Condition()
+ self._completion_queue = completion_queue
+ self._shutdown_tag = shutdown_tag
+ self._events = []
+ self._saw_shutdown_tag = False
+
+ def start(self):
+ def in_thread():
+ while True:
+ event = self._completion_queue.poll()
+ with self._condition:
+ self._events.append(event)
+ self._condition.notify()
+ if event.tag is self._shutdown_tag:
+ self._saw_shutdown_tag = True
+ break
+ thread = threading.Thread(target=in_thread)
+ thread.start()
+
+ def done(self):
+ with self._condition:
+ return self._saw_shutdown_tag
+
+ def first_event(self):
+ with self._condition:
+ while not self._events:
+ self._condition.wait()
+ return self._events[0]
+
+ def events(self):
+ with self._condition:
+ while not self._saw_shutdown_tag:
+ self._condition.wait()
+ return tuple(self._events)
+
+
+class _QueueDriver(object):
+
+ def __init__(self, condition, completion_queue, due):
+ self._condition = condition
+ self._completion_queue = completion_queue
+ self._due = due
+ self._events = []
+ self._returned = False
+
+ def start(self):
+ def in_thread():
+ while True:
+ event = self._completion_queue.poll()
+ with self._condition:
+ self._events.append(event)
+ self._due.remove(event.tag)
+ self._condition.notify_all()
+ if not self._due:
+ self._returned = True
+ return
+ thread = threading.Thread(target=in_thread)
+ thread.start()
+
+ def done(self):
+ with self._condition:
+ return self._returned
+
+ def event_with_tag(self, tag):
+ with self._condition:
+ while True:
+ for event in self._events:
+ if event.tag is tag:
+ return event
+ self._condition.wait()
+
+ def events(self):
+ with self._condition:
+ while not self._returned:
+ self._condition.wait()
+ return tuple(self._events)
+
+
+class ReadSomeButNotAllResponsesTest(unittest.TestCase):
+
+ def testReadSomeButNotAllResponses(self):
+ server_completion_queue = cygrpc.CompletionQueue()
+ server = cygrpc.Server()
+ server.register_completion_queue(server_completion_queue)
+ port = server.add_http2_port('[::]:0')
+ server.start()
+ channel = cygrpc.Channel('localhost:{}'.format(port))
+
+ server_shutdown_tag = 'server_shutdown_tag'
+ server_driver = _ServerDriver(server_completion_queue, server_shutdown_tag)
+ server_driver.start()
+
+ client_condition = threading.Condition()
+ client_due = set()
+ client_completion_queue = cygrpc.CompletionQueue()
+ client_driver = _QueueDriver(
+ client_condition, client_completion_queue, client_due)
+ client_driver.start()
+
+ server_call_condition = threading.Condition()
+ server_send_initial_metadata_tag = 'server_send_initial_metadata_tag'
+ server_send_first_message_tag = 'server_send_first_message_tag'
+ server_send_second_message_tag = 'server_send_second_message_tag'
+ server_complete_rpc_tag = 'server_complete_rpc_tag'
+ server_call_due = set((
+ server_send_initial_metadata_tag,
+ server_send_first_message_tag,
+ server_send_second_message_tag,
+ server_complete_rpc_tag,
+ ))
+ server_call_completion_queue = cygrpc.CompletionQueue()
+ server_call_driver = _QueueDriver(
+ server_call_condition, server_call_completion_queue, server_call_due)
+ server_call_driver.start()
+
+ server_rpc_tag = 'server_rpc_tag'
+ request_call_result = server.request_call(
+ server_call_completion_queue, server_completion_queue, server_rpc_tag)
+
+ client_call = channel.create_call(
+ None, _EMPTY_FLAGS, client_completion_queue, b'/twinkies', None,
+ _INFINITE_FUTURE)
+ client_receive_initial_metadata_tag = 'client_receive_initial_metadata_tag'
+ client_complete_rpc_tag = 'client_complete_rpc_tag'
+ with client_condition:
+ client_receive_initial_metadata_start_batch_result = (
+ client_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
+ ]), client_receive_initial_metadata_tag))
+ client_due.add(client_receive_initial_metadata_tag)
+ client_complete_rpc_start_batch_result = (
+ client_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_send_initial_metadata(
+ _EMPTY_METADATA, _EMPTY_FLAGS),
+ cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
+ cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
+ ]), client_complete_rpc_tag))
+ client_due.add(client_complete_rpc_tag)
+
+ server_rpc_event = server_driver.first_event()
+
+ with server_call_condition:
+ server_send_initial_metadata_start_batch_result = (
+ server_rpc_event.operation_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_send_initial_metadata(
+ _EMPTY_METADATA, _EMPTY_FLAGS),
+ ]), server_send_initial_metadata_tag))
+ server_send_first_message_start_batch_result = (
+ server_rpc_event.operation_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_send_message(b'\x07', _EMPTY_FLAGS),
+ ]), server_send_first_message_tag))
+ server_send_initial_metadata_event = server_call_driver.event_with_tag(
+ server_send_initial_metadata_tag)
+ server_send_first_message_event = server_call_driver.event_with_tag(
+ server_send_first_message_tag)
+ with server_call_condition:
+ server_send_second_message_start_batch_result = (
+ server_rpc_event.operation_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_send_message(b'\x07', _EMPTY_FLAGS),
+ ]), server_send_second_message_tag))
+ server_complete_rpc_start_batch_result = (
+ server_rpc_event.operation_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
+ cygrpc.operation_send_status_from_server(
+ cygrpc.Metadata(()), cygrpc.StatusCode.ok, b'test details',
+ _EMPTY_FLAGS),
+ ]), server_complete_rpc_tag))
+ server_send_second_message_event = server_call_driver.event_with_tag(
+ server_send_second_message_tag)
+ server_complete_rpc_event = server_call_driver.event_with_tag(
+ server_complete_rpc_tag)
+ server_call_driver.events()
+
+ with client_condition:
+ client_receive_first_message_tag = 'client_receive_first_message_tag'
+ client_receive_first_message_start_batch_result = (
+ client_call.start_batch(cygrpc.Operations([
+ cygrpc.operation_receive_message(_EMPTY_FLAGS),
+ ]), client_receive_first_message_tag))
+ client_due.add(client_receive_first_message_tag)
+ client_receive_first_message_event = client_driver.event_with_tag(
+ client_receive_first_message_tag)
+
+ client_call_cancel_result = client_call.cancel()
+ client_driver.events()
+
+ server.shutdown(server_completion_queue, server_shutdown_tag)
+ server.cancel_all_calls()
+ server_driver.events()
+
+ self.assertEqual(cygrpc.CallError.ok, request_call_result)
+ self.assertEqual(
+ cygrpc.CallError.ok, server_send_initial_metadata_start_batch_result)
+ self.assertEqual(
+ cygrpc.CallError.ok, client_receive_initial_metadata_start_batch_result)
+ self.assertEqual(
+ cygrpc.CallError.ok, client_complete_rpc_start_batch_result)
+ self.assertEqual(cygrpc.CallError.ok, client_call_cancel_result)
+ self.assertIs(server_rpc_tag, server_rpc_event.tag)
+ self.assertEqual(
+ cygrpc.CompletionType.operation_complete, server_rpc_event.type)
+ self.assertIsInstance(server_rpc_event.operation_call, cygrpc.Call)
+ self.assertEqual(0, len(server_rpc_event.batch_operations))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
index 0a511101f0..a006a20ce3 100644
--- a/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
@@ -37,7 +37,7 @@ from tests.unit import test_common
from tests.unit import resources
-_SSL_HOST_OVERRIDE = 'foo.test.google.fr'
+_SSL_HOST_OVERRIDE = b'foo.test.google.fr'
_CALL_CREDENTIALS_METADATA_KEY = 'call-creds-key'
_CALL_CREDENTIALS_METADATA_VALUE = 'call-creds-value'
_EMPTY_FLAGS = 0
@@ -143,22 +143,60 @@ class TypeSmokeTest(unittest.TestCase):
del completion_queue
-class InsecureServerInsecureClient(unittest.TestCase):
+class ServerClientMixin(object):
- def setUp(self):
+ def setUpMixin(self, server_credentials, client_credentials, host_override):
self.server_completion_queue = cygrpc.CompletionQueue()
self.server = cygrpc.Server()
self.server.register_completion_queue(self.server_completion_queue)
- self.port = self.server.add_http2_port('[::]:0')
+ if server_credentials:
+ self.port = self.server.add_http2_port('[::]:0', server_credentials)
+ else:
+ self.port = self.server.add_http2_port('[::]:0')
self.server.start()
self.client_completion_queue = cygrpc.CompletionQueue()
- self.client_channel = cygrpc.Channel('localhost:{}'.format(self.port))
-
- def tearDown(self):
+ if client_credentials:
+ client_channel_arguments = cygrpc.ChannelArgs([
+ cygrpc.ChannelArg(cygrpc.ChannelArgKey.ssl_target_name_override,
+ host_override)])
+ self.client_channel = cygrpc.Channel(
+ 'localhost:{}'.format(self.port), client_channel_arguments,
+ client_credentials)
+ else:
+ self.client_channel = cygrpc.Channel('localhost:{}'.format(self.port))
+ if host_override:
+ self.host_argument = None # default host
+ self.expected_host = host_override
+ else:
+ # arbitrary host name necessitating no further identification
+ self.host_argument = b'hostess'
+ self.expected_host = self.host_argument
+
+ def tearDownMixin(self):
del self.server
del self.client_completion_queue
del self.server_completion_queue
+ def _perform_operations(self, operations, call, queue, deadline, description):
+ """Perform the list of operations with given call, queue, and deadline.
+
+ Invocation errors are reported with as an exception with `description` in
+ the message. Performs the operations asynchronously, returning a future.
+ """
+ def performer():
+ tag = object()
+ try:
+ call_result = call.start_batch(cygrpc.Operations(operations), tag)
+ self.assertEqual(cygrpc.CallError.ok, call_result)
+ event = queue.poll(deadline)
+ self.assertEqual(cygrpc.CompletionType.operation_complete, event.type)
+ self.assertTrue(event.success)
+ self.assertIs(tag, event.tag)
+ except Exception as error:
+ raise Exception("Error in '{}': {}".format(description, error.message))
+ return event
+ return test_utilities.SimpleFuture(performer)
+
def testEcho(self):
DEADLINE = time.time()+5
DEADLINE_TOLERANCE = 0.25
@@ -175,7 +213,6 @@ class InsecureServerInsecureClient(unittest.TestCase):
REQUEST = b'in death a member of project mayhem has a name'
RESPONSE = b'his name is robert paulson'
METHOD = b'twinkies'
- HOST = b'hostess'
cygrpc_deadline = cygrpc.Timespec(DEADLINE)
@@ -188,7 +225,8 @@ class InsecureServerInsecureClient(unittest.TestCase):
client_call_tag = object()
client_call = self.client_channel.create_call(
- None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline)
+ None, 0, self.client_completion_queue, METHOD, self.host_argument,
+ cygrpc_deadline)
client_initial_metadata = cygrpc.Metadata([
cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
CLIENT_METADATA_ASCII_VALUE),
@@ -216,7 +254,8 @@ class InsecureServerInsecureClient(unittest.TestCase):
test_common.metadata_transmitted(client_initial_metadata,
request_event.request_metadata))
self.assertEqual(METHOD, request_event.request_call_details.method)
- self.assertEqual(HOST, request_event.request_call_details.host)
+ self.assertEqual(self.expected_host,
+ request_event.request_call_details.host)
self.assertLess(
abs(DEADLINE - float(request_event.request_call_details.deadline)),
DEADLINE_TOLERANCE)
@@ -292,172 +331,101 @@ class InsecureServerInsecureClient(unittest.TestCase):
del client_call
del server_call
-
-class SecureServerSecureClient(unittest.TestCase):
-
- def setUp(self):
- server_credentials = cygrpc.server_credentials_ssl(
- None, [cygrpc.SslPemKeyCertPair(resources.private_key(),
- resources.certificate_chain())], False)
- channel_credentials = cygrpc.channel_credentials_ssl(
- resources.test_root_certificates(), None)
- self.server_completion_queue = cygrpc.CompletionQueue()
- self.server = cygrpc.Server()
- self.server.register_completion_queue(self.server_completion_queue)
- self.port = self.server.add_http2_port('[::]:0', server_credentials)
- self.server.start()
- self.client_completion_queue = cygrpc.CompletionQueue()
- client_channel_arguments = cygrpc.ChannelArgs([
- cygrpc.ChannelArg(cygrpc.ChannelArgKey.ssl_target_name_override,
- _SSL_HOST_OVERRIDE)])
- self.client_channel = cygrpc.Channel(
- 'localhost:{}'.format(self.port), client_channel_arguments,
- channel_credentials)
-
- def tearDown(self):
- del self.server
- del self.client_completion_queue
- del self.server_completion_queue
-
- def testEcho(self):
+ def test6522(self):
DEADLINE = time.time()+5
DEADLINE_TOLERANCE = 0.25
- CLIENT_METADATA_ASCII_KEY = b'key'
- CLIENT_METADATA_ASCII_VALUE = b'val'
- CLIENT_METADATA_BIN_KEY = b'key-bin'
- CLIENT_METADATA_BIN_VALUE = b'\0'*1000
- SERVER_INITIAL_METADATA_KEY = b'init_me_me_me'
- SERVER_INITIAL_METADATA_VALUE = b'whodawha?'
- SERVER_TRAILING_METADATA_KEY = b'california_is_in_a_drought'
- SERVER_TRAILING_METADATA_VALUE = b'zomg it is'
- SERVER_STATUS_CODE = cygrpc.StatusCode.ok
- SERVER_STATUS_DETAILS = b'our work is never over'
- REQUEST = b'in death a member of project mayhem has a name'
- RESPONSE = b'his name is robert paulson'
- METHOD = b'/twinkies'
- HOST = None # Default host
+ METHOD = b'twinkies'
cygrpc_deadline = cygrpc.Timespec(DEADLINE)
+ empty_metadata = cygrpc.Metadata([])
server_request_tag = object()
- request_call_result = self.server.request_call(
+ self.server.request_call(
self.server_completion_queue, self.server_completion_queue,
server_request_tag)
+ client_call = self.client_channel.create_call(
+ None, 0, self.client_completion_queue, METHOD, self.host_argument,
+ cygrpc_deadline)
- self.assertEqual(cygrpc.CallError.ok, request_call_result)
-
- plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
- call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
+ # Prologue
+ def perform_client_operations(operations, description):
+ return self._perform_operations(
+ operations, client_call,
+ self.client_completion_queue, cygrpc_deadline, description)
- client_call_tag = object()
- client_call = self.client_channel.create_call(
- None, 0, self.client_completion_queue, METHOD, HOST, cygrpc_deadline)
- client_call.set_credentials(call_credentials)
- client_initial_metadata = cygrpc.Metadata([
- cygrpc.Metadatum(CLIENT_METADATA_ASCII_KEY,
- CLIENT_METADATA_ASCII_VALUE),
- cygrpc.Metadatum(CLIENT_METADATA_BIN_KEY, CLIENT_METADATA_BIN_VALUE)])
- client_start_batch_result = client_call.start_batch(cygrpc.Operations([
- cygrpc.operation_send_initial_metadata(client_initial_metadata,
- _EMPTY_FLAGS),
- cygrpc.operation_send_message(REQUEST, _EMPTY_FLAGS),
- cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
- cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
- cygrpc.operation_receive_message(_EMPTY_FLAGS),
- cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS)
- ]), client_call_tag)
- self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
- client_event_future = test_utilities.CompletionQueuePollFuture(
- self.client_completion_queue, cygrpc_deadline)
+ client_event_future = perform_client_operations([
+ cygrpc.operation_send_initial_metadata(empty_metadata,
+ _EMPTY_FLAGS),
+ cygrpc.operation_receive_initial_metadata(_EMPTY_FLAGS),
+ ], "Client prologue")
request_event = self.server_completion_queue.poll(cygrpc_deadline)
- self.assertEqual(cygrpc.CompletionType.operation_complete,
- request_event.type)
- self.assertIsInstance(request_event.operation_call, cygrpc.Call)
- self.assertIs(server_request_tag, request_event.tag)
- self.assertEqual(0, len(request_event.batch_operations))
- client_metadata_with_credentials = list(client_initial_metadata) + [
- (_CALL_CREDENTIALS_METADATA_KEY, _CALL_CREDENTIALS_METADATA_VALUE)]
- self.assertTrue(
- test_common.metadata_transmitted(client_metadata_with_credentials,
- request_event.request_metadata))
- self.assertEqual(METHOD, request_event.request_call_details.method)
- self.assertEqual(_SSL_HOST_OVERRIDE,
- request_event.request_call_details.host)
- self.assertLess(
- abs(DEADLINE - float(request_event.request_call_details.deadline)),
- DEADLINE_TOLERANCE)
-
- server_call_tag = object()
server_call = request_event.operation_call
- server_initial_metadata = cygrpc.Metadata([
- cygrpc.Metadatum(SERVER_INITIAL_METADATA_KEY,
- SERVER_INITIAL_METADATA_VALUE)])
- server_trailing_metadata = cygrpc.Metadata([
- cygrpc.Metadatum(SERVER_TRAILING_METADATA_KEY,
- SERVER_TRAILING_METADATA_VALUE)])
- server_start_batch_result = server_call.start_batch([
- cygrpc.operation_send_initial_metadata(server_initial_metadata,
- _EMPTY_FLAGS),
- cygrpc.operation_receive_message(_EMPTY_FLAGS),
- cygrpc.operation_send_message(RESPONSE, _EMPTY_FLAGS),
- cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
- cygrpc.operation_send_status_from_server(
- server_trailing_metadata, SERVER_STATUS_CODE,
- SERVER_STATUS_DETAILS, _EMPTY_FLAGS)
- ], server_call_tag)
- self.assertEqual(cygrpc.CallError.ok, server_start_batch_result)
- client_event = client_event_future.result()
- server_event = self.server_completion_queue.poll(cygrpc_deadline)
+ def perform_server_operations(operations, description):
+ return self._perform_operations(
+ operations, server_call,
+ self.server_completion_queue, cygrpc_deadline, description)
- self.assertEqual(6, len(client_event.batch_operations))
- found_client_op_types = set()
- for client_result in client_event.batch_operations:
- # we expect each op type to be unique
- self.assertNotIn(client_result.type, found_client_op_types)
- found_client_op_types.add(client_result.type)
- if client_result.type == cygrpc.OperationType.receive_initial_metadata:
- self.assertTrue(
- test_common.metadata_transmitted(server_initial_metadata,
- client_result.received_metadata))
- elif client_result.type == cygrpc.OperationType.receive_message:
- self.assertEqual(RESPONSE, client_result.received_message.bytes())
- elif client_result.type == cygrpc.OperationType.receive_status_on_client:
- self.assertTrue(
- test_common.metadata_transmitted(server_trailing_metadata,
- client_result.received_metadata))
- self.assertEqual(SERVER_STATUS_DETAILS,
- client_result.received_status_details)
- self.assertEqual(SERVER_STATUS_CODE, client_result.received_status_code)
- self.assertEqual(set([
- cygrpc.OperationType.send_initial_metadata,
- cygrpc.OperationType.send_message,
- cygrpc.OperationType.send_close_from_client,
- cygrpc.OperationType.receive_initial_metadata,
- cygrpc.OperationType.receive_message,
- cygrpc.OperationType.receive_status_on_client
- ]), found_client_op_types)
+ server_event_future = perform_server_operations([
+ cygrpc.operation_send_initial_metadata(empty_metadata,
+ _EMPTY_FLAGS),
+ ], "Server prologue")
- self.assertEqual(5, len(server_event.batch_operations))
- found_server_op_types = set()
- for server_result in server_event.batch_operations:
- self.assertNotIn(client_result.type, found_server_op_types)
- found_server_op_types.add(server_result.type)
- if server_result.type == cygrpc.OperationType.receive_message:
- self.assertEqual(REQUEST, server_result.received_message.bytes())
- elif server_result.type == cygrpc.OperationType.receive_close_on_server:
- self.assertFalse(server_result.received_cancelled)
- self.assertEqual(set([
- cygrpc.OperationType.send_initial_metadata,
- cygrpc.OperationType.receive_message,
- cygrpc.OperationType.send_message,
- cygrpc.OperationType.receive_close_on_server,
- cygrpc.OperationType.send_status_from_server
- ]), found_server_op_types)
+ client_event_future.result() # force completion
+ server_event_future.result()
- del client_call
- del server_call
+ # Messaging
+ for _ in range(10):
+ client_event_future = perform_client_operations([
+ cygrpc.operation_send_message(b'', _EMPTY_FLAGS),
+ cygrpc.operation_receive_message(_EMPTY_FLAGS),
+ ], "Client message")
+ server_event_future = perform_server_operations([
+ cygrpc.operation_send_message(b'', _EMPTY_FLAGS),
+ cygrpc.operation_receive_message(_EMPTY_FLAGS),
+ ], "Server receive")
+
+ client_event_future.result() # force completion
+ server_event_future.result()
+
+ # Epilogue
+ client_event_future = perform_client_operations([
+ cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
+ cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS)
+ ], "Client epilogue")
+
+ server_event_future = perform_server_operations([
+ cygrpc.operation_receive_close_on_server(_EMPTY_FLAGS),
+ cygrpc.operation_send_status_from_server(
+ empty_metadata, cygrpc.StatusCode.ok, b'', _EMPTY_FLAGS)
+ ], "Server epilogue")
+
+ client_event_future.result() # force completion
+ server_event_future.result()
+
+
+class InsecureServerInsecureClient(unittest.TestCase, ServerClientMixin):
+
+ def setUp(self):
+ self.setUpMixin(None, None, None)
+
+ def tearDown(self):
+ self.tearDownMixin()
+
+
+class SecureServerSecureClient(unittest.TestCase, ServerClientMixin):
+
+ def setUp(self):
+ server_credentials = cygrpc.server_credentials_ssl(
+ None, [cygrpc.SslPemKeyCertPair(resources.private_key(),
+ resources.certificate_chain())], False)
+ client_credentials = cygrpc.channel_credentials_ssl(
+ resources.test_root_certificates(), None)
+ self.setUpMixin(server_credentials, client_credentials, _SSL_HOST_OVERRIDE)
+
+ def tearDown(self):
+ self.tearDownMixin()
if __name__ == '__main__':
diff --git a/src/python/grpcio/tests/unit/_cython/test_utilities.py b/src/python/grpcio/tests/unit/_cython/test_utilities.py
index 6a09739643..6280ce74c4 100644
--- a/src/python/grpcio/tests/unit/_cython/test_utilities.py
+++ b/src/python/grpcio/tests/unit/_cython/test_utilities.py
@@ -32,15 +32,35 @@ import threading
from grpc._cython import cygrpc
-class CompletionQueuePollFuture:
+class SimpleFuture(object):
+ """A simple future mechanism."""
- def __init__(self, completion_queue, deadline):
- def poller_function():
- self._event_result = completion_queue.poll(deadline)
- self._event_result = None
- self._thread = threading.Thread(target=poller_function)
+ def __init__(self, function, *args, **kwargs):
+ def wrapped_function():
+ try:
+ self._result = function(*args, **kwargs)
+ except Exception as error:
+ self._error = error
+ self._result = None
+ self._error = None
+ self._thread = threading.Thread(target=wrapped_function)
self._thread.start()
def result(self):
+ """The resulting value of this future.
+
+ Re-raises any exceptions.
+ """
self._thread.join()
- return self._event_result
+ if self._error:
+ # TODO(atash): re-raise exceptions in a way that preserves tracebacks
+ raise self._error
+ return self._result
+
+
+class CompletionQueuePollFuture(SimpleFuture):
+
+ def __init__(self, completion_queue, deadline):
+ super(CompletionQueuePollFuture, self).__init__(
+ lambda: completion_queue.poll(deadline))
+
diff --git a/src/python/grpcio/tests/unit/_empty_message_test.py b/src/python/grpcio/tests/unit/_empty_message_test.py
new file mode 100644
index 0000000000..f324f6216b
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_empty_message_test.py
@@ -0,0 +1,137 @@
+# 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.
+
+import unittest
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit.framework.common import test_constants
+
+_REQUEST = b''
+_RESPONSE = b''
+
+_UNARY_UNARY = b'/test/UnaryUnary'
+_UNARY_STREAM = b'/test/UnaryStream'
+_STREAM_UNARY = b'/test/StreamUnary'
+_STREAM_STREAM = b'/test/StreamStream'
+
+
+def handle_unary_unary(request, servicer_context):
+ return _RESPONSE
+
+
+def handle_unary_stream(request, servicer_context):
+ for _ in range(test_constants.STREAM_LENGTH):
+ yield _RESPONSE
+
+
+def handle_stream_unary(request_iterator, servicer_context):
+ for request in request_iterator:
+ pass
+ return _RESPONSE
+
+
+def handle_stream_stream(request_iterator, servicer_context):
+ for request in request_iterator:
+ yield _RESPONSE
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+ def __init__(self, request_streaming, response_streaming):
+ self.request_streaming = request_streaming
+ self.response_streaming = response_streaming
+ self.request_deserializer = None
+ self.response_serializer = None
+ self.unary_unary = None
+ self.unary_stream = None
+ self.stream_unary = None
+ self.stream_stream = None
+ if self.request_streaming and self.response_streaming:
+ self.stream_stream = handle_stream_stream
+ elif self.request_streaming:
+ self.stream_unary = handle_stream_unary
+ elif self.response_streaming:
+ self.unary_stream = handle_unary_stream
+ else:
+ self.unary_unary = handle_unary_unary
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def service(self, handler_call_details):
+ if handler_call_details.method == _UNARY_UNARY:
+ return _MethodHandler(False, False)
+ elif handler_call_details.method == _UNARY_STREAM:
+ return _MethodHandler(False, True)
+ elif handler_call_details.method == _STREAM_UNARY:
+ return _MethodHandler(True, False)
+ elif handler_call_details.method == _STREAM_STREAM:
+ return _MethodHandler(True, True)
+ else:
+ return None
+
+
+class EmptyMessageTest(unittest.TestCase):
+
+ def setUp(self):
+ self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+ self._server = grpc.server((_GenericHandler(),), self._server_pool)
+ port = self._server.add_insecure_port('[::]:0')
+ self._server.start()
+ self._channel = grpc.insecure_channel('localhost:%d' % port)
+
+ def tearDown(self):
+ self._server.stop(0)
+
+ def testUnaryUnary(self):
+ response = self._channel.unary_unary(_UNARY_UNARY)(_REQUEST)
+ self.assertEqual(_RESPONSE, response)
+
+ def testUnaryStream(self):
+ response_iterator = self._channel.unary_stream(_UNARY_STREAM)(_REQUEST)
+ self.assertSequenceEqual(
+ [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator))
+
+ def testStreamUnary(self):
+ response = self._channel.stream_unary(_STREAM_UNARY)(
+ [_REQUEST] * test_constants.STREAM_LENGTH)
+ self.assertEqual(_RESPONSE, response)
+
+ def testStreamStream(self):
+ response_iterator = self._channel.stream_stream(_STREAM_STREAM)(
+ [_REQUEST] * test_constants.STREAM_LENGTH)
+ self.assertSequenceEqual(
+ [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
+
diff --git a/src/python/grpcio/tests/unit/_from_grpc_import_star.py b/src/python/grpcio/tests/unit/_from_grpc_import_star.py
new file mode 100644
index 0000000000..78d2fb7dc5
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_from_grpc_import_star.py
@@ -0,0 +1,38 @@
+# 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.
+
+_BEFORE_IMPORT = tuple(globals())
+
+from grpc import *
+
+_AFTER_IMPORT = tuple(globals())
+
+GRPC_ELEMENTS = tuple(
+ element for element in _AFTER_IMPORT
+ if element not in _BEFORE_IMPORT and element != '_BEFORE_IMPORT')
diff --git a/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
deleted file mode 100644
index 890755f81c..0000000000
--- a/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
+++ /dev/null
@@ -1,88 +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.
-
-"""A test of invocation-side code unconnected to an RPC server."""
-
-import unittest
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc.framework.interfaces.links import links
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.links import test_cases
-from tests.unit.framework.interfaces.links import test_utilities
-
-_NULL_BEHAVIOR = lambda unused_argument: None
-
-
-class LonelyInvocationLinkTest(unittest.TestCase):
-
- def testUpAndDown(self):
- channel = _intermediary_low.Channel('nonexistent:54321', None)
- invocation_link = invocation.invocation_link(
- channel, 'nonexistent', None, {}, {})
-
- invocation_link.start()
- invocation_link.stop()
-
- def _test_lonely_invocation_with_termination(self, termination):
- test_operation_id = object()
- test_group = 'test package.Test Service'
- test_method = 'test method'
- invocation_link_mate = test_utilities.RecordingLink()
-
- channel = _intermediary_low.Channel('nonexistent:54321', None)
- invocation_link = invocation.invocation_link(
- channel, 'nonexistent', None, {}, {})
- invocation_link.join_link(invocation_link_mate)
- invocation_link.start()
-
- ticket = links.Ticket(
- test_operation_id, 0, test_group, test_method,
- links.Ticket.Subscription.FULL, test_constants.SHORT_TIMEOUT, 1, None,
- None, None, None, None, termination, None)
- invocation_link.accept_ticket(ticket)
- invocation_link_mate.block_until_tickets_satisfy(test_cases.terminated)
-
- invocation_link.stop()
-
- self.assertIsNot(
- invocation_link_mate.tickets()[-1].termination,
- links.Ticket.Termination.COMPLETION)
-
- def testLonelyInvocationLinkWithCommencementTicket(self):
- self._test_lonely_invocation_with_termination(None)
-
- def testLonelyInvocationLinkWithEntireTicket(self):
- self._test_lonely_invocation_with_termination(
- links.Ticket.Termination.COMPLETION)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/src/python/grpcio/tests/unit/_links/_transmission_test.py b/src/python/grpcio/tests/unit/_links/_transmission_test.py
deleted file mode 100644
index 888684d197..0000000000
--- a/src/python/grpcio/tests/unit/_links/_transmission_test.py
+++ /dev/null
@@ -1,239 +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.
-
-"""Tests transmission of tickets across gRPC-on-the-wire."""
-
-import unittest
-
-from grpc._adapter import _intermediary_low
-from grpc._links import invocation
-from grpc._links import service
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.interfaces.links import links
-from tests.unit import test_common
-from tests.unit._links import _proto_scenarios
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.links import test_cases
-from tests.unit.framework.interfaces.links import test_utilities
-
-_IDENTITY = lambda x: x
-
-
-class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
-
- def create_transmitting_links(self):
- service_link = service.service_link(
- {self.group_and_method(): self.deserialize_request},
- {self.group_and_method(): self.serialize_response})
- port = service_link.add_port('[::]:0', None)
- service_link.start()
- channel = _intermediary_low.Channel('localhost:%d' % port, None)
- invocation_link = invocation.invocation_link(
- channel, 'localhost', None,
- {self.group_and_method(): self.serialize_request},
- {self.group_and_method(): self.deserialize_response})
- invocation_link.start()
- return invocation_link, service_link
-
- def destroy_transmitting_links(self, invocation_side_link, service_side_link):
- invocation_side_link.stop()
- service_side_link.begin_stop()
- service_side_link.end_stop()
-
- def create_invocation_initial_metadata(self):
- return (
- ('first_invocation_initial_metadata_key', 'just a string value'),
- ('second_invocation_initial_metadata_key', '0123456789'),
- ('third_invocation_initial_metadata_key-bin', '\x00\x57' * 100),
- )
-
- def create_invocation_terminal_metadata(self):
- return None
-
- def create_service_initial_metadata(self):
- return (
- ('first_service_initial_metadata_key', 'just another string value'),
- ('second_service_initial_metadata_key', '9876543210'),
- ('third_service_initial_metadata_key-bin', '\x00\x59\x02' * 100),
- )
-
- def create_service_terminal_metadata(self):
- return (
- ('first_service_terminal_metadata_key', 'yet another string value'),
- ('second_service_terminal_metadata_key', 'abcdefghij'),
- ('third_service_terminal_metadata_key-bin', '\x00\x37' * 100),
- )
-
- def create_invocation_completion(self):
- return None, None
-
- def create_service_completion(self):
- return (
- beta_interfaces.StatusCode.OK, b'An exuberant test "details" message!')
-
- def assertMetadataTransmitted(self, original_metadata, transmitted_metadata):
- self.assertTrue(
- test_common.metadata_transmitted(
- original_metadata, transmitted_metadata),
- '%s erroneously transmitted as %s' % (
- original_metadata, transmitted_metadata))
-
-
-class RoundTripTest(unittest.TestCase):
-
- def testZeroMessageRoundTrip(self):
- test_operation_id = object()
- test_group = 'test package.Test Group'
- test_method = 'test method'
- identity_transformation = {(test_group, test_method): _IDENTITY}
- test_code = beta_interfaces.StatusCode.OK
- test_message = 'a test message'
-
- service_link = service.service_link(
- identity_transformation, identity_transformation)
- service_mate = test_utilities.RecordingLink()
- service_link.join_link(service_mate)
- port = service_link.add_port('[::]:0', None)
- service_link.start()
- channel = _intermediary_low.Channel('localhost:%d' % port, None)
- invocation_link = invocation.invocation_link(
- channel, None, None, identity_transformation, identity_transformation)
- invocation_mate = test_utilities.RecordingLink()
- invocation_link.join_link(invocation_mate)
- invocation_link.start()
-
- invocation_ticket = links.Ticket(
- test_operation_id, 0, test_group, test_method,
- links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
- None, None, None, None, links.Ticket.Termination.COMPLETION, None)
- invocation_link.accept_ticket(invocation_ticket)
- service_mate.block_until_tickets_satisfy(test_cases.terminated)
-
- service_ticket = links.Ticket(
- service_mate.tickets()[-1].operation_id, 0, None, None, None, None,
- None, None, None, None, test_code, test_message,
- links.Ticket.Termination.COMPLETION, None)
- service_link.accept_ticket(service_ticket)
- invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
-
- invocation_link.stop()
- service_link.begin_stop()
- service_link.end_stop()
-
- self.assertIs(
- service_mate.tickets()[-1].termination,
- links.Ticket.Termination.COMPLETION)
- self.assertIs(
- invocation_mate.tickets()[-1].termination,
- links.Ticket.Termination.COMPLETION)
- self.assertIs(invocation_mate.tickets()[-1].code, test_code)
- self.assertEqual(invocation_mate.tickets()[-1].message, test_message)
-
- def _perform_scenario_test(self, scenario):
- test_operation_id = object()
- test_group, test_method = scenario.group_and_method()
- test_code = beta_interfaces.StatusCode.OK
- test_message = 'a scenario test message'
-
- service_link = service.service_link(
- {(test_group, test_method): scenario.deserialize_request},
- {(test_group, test_method): scenario.serialize_response})
- service_mate = test_utilities.RecordingLink()
- service_link.join_link(service_mate)
- port = service_link.add_port('[::]:0', None)
- service_link.start()
- channel = _intermediary_low.Channel('localhost:%d' % port, None)
- invocation_link = invocation.invocation_link(
- channel, 'localhost', None,
- {(test_group, test_method): scenario.serialize_request},
- {(test_group, test_method): scenario.deserialize_response})
- invocation_mate = test_utilities.RecordingLink()
- invocation_link.join_link(invocation_mate)
- invocation_link.start()
-
- invocation_ticket = links.Ticket(
- test_operation_id, 0, test_group, test_method,
- links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
- None, None, None, None, None, None)
- invocation_link.accept_ticket(invocation_ticket)
- requests = scenario.requests()
- for request_index, request in enumerate(requests):
- request_ticket = links.Ticket(
- test_operation_id, 1 + request_index, None, None, None, None, 1, None,
- request, None, None, None, None, None)
- invocation_link.accept_ticket(request_ticket)
- service_mate.block_until_tickets_satisfy(
- test_cases.at_least_n_payloads_received_predicate(1 + request_index))
- response_ticket = links.Ticket(
- service_mate.tickets()[0].operation_id, request_index, None, None,
- None, None, 1, None, scenario.response_for_request(request), None,
- None, None, None, None)
- service_link.accept_ticket(response_ticket)
- invocation_mate.block_until_tickets_satisfy(
- test_cases.at_least_n_payloads_received_predicate(1 + request_index))
- request_count = len(requests)
- invocation_completion_ticket = links.Ticket(
- test_operation_id, request_count + 1, None, None, None, None, None,
- None, None, None, None, None, links.Ticket.Termination.COMPLETION,
- None)
- invocation_link.accept_ticket(invocation_completion_ticket)
- service_mate.block_until_tickets_satisfy(test_cases.terminated)
- service_completion_ticket = links.Ticket(
- service_mate.tickets()[0].operation_id, request_count, None, None, None,
- None, None, None, None, None, test_code, test_message,
- links.Ticket.Termination.COMPLETION, None)
- service_link.accept_ticket(service_completion_ticket)
- invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
-
- invocation_link.stop()
- service_link.begin_stop()
- service_link.end_stop()
-
- observed_requests = tuple(
- ticket.payload for ticket in service_mate.tickets()
- if ticket.payload is not None)
- observed_responses = tuple(
- ticket.payload for ticket in invocation_mate.tickets()
- if ticket.payload is not None)
- self.assertTrue(scenario.verify_requests(observed_requests))
- self.assertTrue(scenario.verify_responses(observed_responses))
-
- def testEmptyScenario(self):
- self._perform_scenario_test(_proto_scenarios.EmptyScenario())
-
- def testBidirectionallyUnaryScenario(self):
- self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario())
-
- def testBidirectionallyStreamingScenario(self):
- self._perform_scenario_test(
- _proto_scenarios.BidirectionallyStreamingScenario())
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_metadata_code_details_test.py b/src/python/grpcio/tests/unit/_metadata_code_details_test.py
new file mode 100644
index 0000000000..dd74268cbf
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_metadata_code_details_test.py
@@ -0,0 +1,523 @@
+# 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.
+
+"""Tests application-provided metadata, status code, and details."""
+
+import threading
+import unittest
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+
+_SERIALIZED_REQUEST = b'\x46\x47\x48'
+_SERIALIZED_RESPONSE = b'\x49\x50\x51'
+
+_REQUEST_SERIALIZER = lambda unused_request: _SERIALIZED_REQUEST
+_REQUEST_DESERIALIZER = lambda unused_serialized_request: object()
+_RESPONSE_SERIALIZER = lambda unused_response: _SERIALIZED_RESPONSE
+_RESPONSE_DESERIALIZER = lambda unused_serialized_resopnse: object()
+
+_SERVICE = b'test.TestService'
+_UNARY_UNARY = b'UnaryUnary'
+_UNARY_STREAM = b'UnaryStream'
+_STREAM_UNARY = b'StreamUnary'
+_STREAM_STREAM = b'StreamStream'
+
+_CLIENT_METADATA = (
+ (b'client-md-key', b'client-md-key'),
+ (b'client-md-key-bin', b'\x00\x01')
+)
+
+_SERVER_INITIAL_METADATA = (
+ (b'server-initial-md-key', b'server-initial-md-value'),
+ (b'server-initial-md-key-bin', b'\x00\x02')
+)
+
+_SERVER_TRAILING_METADATA = (
+ (b'server-trailing-md-key', b'server-trailing-md-value'),
+ (b'server-trailing-md-key-bin', b'\x00\x03')
+)
+
+_NON_OK_CODE = grpc.StatusCode.NOT_FOUND
+_DETAILS = b'Test details!'
+
+
+class _Servicer(object):
+
+ def __init__(self):
+ self._lock = threading.Lock()
+ self._code = None
+ self._details = None
+ self._exception = False
+ self._return_none = False
+ self._received_client_metadata = None
+
+ def unary_unary(self, request, context):
+ with self._lock:
+ self._received_client_metadata = context.invocation_metadata()
+ context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ if self._code is not None:
+ context.set_code(self._code)
+ if self._details is not None:
+ context.set_details(self._details)
+ if self._exception:
+ raise test_control.Defect()
+ else:
+ return None if self._return_none else object()
+
+ def unary_stream(self, request, context):
+ with self._lock:
+ self._received_client_metadata = context.invocation_metadata()
+ context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ if self._code is not None:
+ context.set_code(self._code)
+ if self._details is not None:
+ context.set_details(self._details)
+ for _ in range(test_constants.STREAM_LENGTH // 2):
+ yield _SERIALIZED_RESPONSE
+ if self._exception:
+ raise test_control.Defect()
+
+ def stream_unary(self, request_iterator, context):
+ with self._lock:
+ self._received_client_metadata = context.invocation_metadata()
+ context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ if self._code is not None:
+ context.set_code(self._code)
+ if self._details is not None:
+ context.set_details(self._details)
+ # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
+ # request iterator.
+ for ignored_request in request_iterator:
+ pass
+ if self._exception:
+ raise test_control.Defect()
+ else:
+ return None if self._return_none else _SERIALIZED_RESPONSE
+
+ def stream_stream(self, request_iterator, context):
+ with self._lock:
+ self._received_client_metadata = context.invocation_metadata()
+ context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ if self._code is not None:
+ context.set_code(self._code)
+ if self._details is not None:
+ context.set_details(self._details)
+ # TODO(https://github.com/grpc/grpc/issues/6891): just ignore the
+ # request iterator.
+ for ignored_request in request_iterator:
+ pass
+ for _ in range(test_constants.STREAM_LENGTH // 3):
+ yield object()
+ if self._exception:
+ raise test_control.Defect()
+
+ def set_code(self, code):
+ with self._lock:
+ self._code = code
+
+ def set_details(self, details):
+ with self._lock:
+ self._details = details
+
+ def set_exception(self):
+ with self._lock:
+ self._exception = True
+
+ def set_return_none(self):
+ with self._lock:
+ self._return_none = True
+
+ def received_client_metadata(self):
+ with self._lock:
+ return self._received_client_metadata
+
+
+def _generic_handler(servicer):
+ method_handlers = {
+ _UNARY_UNARY: grpc.unary_unary_rpc_method_handler(
+ servicer.unary_unary, request_deserializer=_REQUEST_DESERIALIZER,
+ response_serializer=_RESPONSE_SERIALIZER),
+ _UNARY_STREAM: grpc.unary_stream_rpc_method_handler(
+ servicer.unary_stream),
+ _STREAM_UNARY: grpc.stream_unary_rpc_method_handler(
+ servicer.stream_unary),
+ _STREAM_STREAM: grpc.stream_stream_rpc_method_handler(
+ servicer.stream_stream, request_deserializer=_REQUEST_DESERIALIZER,
+ response_serializer=_RESPONSE_SERIALIZER),
+ }
+ return grpc.method_handlers_generic_handler(_SERVICE, method_handlers)
+
+
+class MetadataCodeDetailsTest(unittest.TestCase):
+
+ def setUp(self):
+ self._servicer = _Servicer()
+ self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+ self._server = grpc.server(
+ (_generic_handler(self._servicer),), self._server_pool)
+ port = self._server.add_insecure_port('[::]:0')
+ self._server.start()
+
+ channel = grpc.insecure_channel('localhost:{}'.format(port))
+ self._unary_unary = channel.unary_unary(
+ b'/'.join((b'', _SERVICE, _UNARY_UNARY,)),
+ request_serializer=_REQUEST_SERIALIZER,
+ response_deserializer=_RESPONSE_DESERIALIZER,)
+ self._unary_stream = channel.unary_stream(
+ b'/'.join((b'', _SERVICE, _UNARY_STREAM,)),)
+ self._stream_unary = channel.stream_unary(
+ b'/'.join((b'', _SERVICE, _STREAM_UNARY,)),)
+ self._stream_stream = channel.stream_stream(
+ b'/'.join((b'', _SERVICE, _STREAM_STREAM,)),
+ request_serializer=_REQUEST_SERIALIZER,
+ response_deserializer=_RESPONSE_DESERIALIZER,)
+
+
+ def testSuccessfulUnaryUnary(self):
+ self._servicer.set_details(_DETAILS)
+
+ unused_response, call = self._unary_unary.with_call(
+ object(), metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(grpc.StatusCode.OK, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testSuccessfulUnaryStream(self):
+ self._servicer.set_details(_DETAILS)
+
+ call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(grpc.StatusCode.OK, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testSuccessfulStreamUnary(self):
+ self._servicer.set_details(_DETAILS)
+
+ unused_response, call = self._stream_unary.with_call(
+ iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(grpc.StatusCode.OK, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testSuccessfulStreamStream(self):
+ self._servicer.set_details(_DETAILS)
+
+ call = self._stream_stream(
+ iter([object()] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(grpc.StatusCode.OK, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testCustomCodeUnaryUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeUnaryStream(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+
+ call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ with self.assertRaises(grpc.RpcError):
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testCustomCodeStreamUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._stream_unary.with_call(
+ iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeStreamStream(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+
+ call = self._stream_stream(
+ iter([object()] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeExceptionUnaryUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_exception()
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeExceptionUnaryStream(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_exception()
+
+ call = self._unary_stream(_SERIALIZED_REQUEST, metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ with self.assertRaises(grpc.RpcError):
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testCustomCodeExceptionStreamUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_exception()
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._stream_unary.with_call(
+ iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeExceptionStreamStream(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_exception()
+
+ call = self._stream_stream(
+ iter([object()] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+ received_initial_metadata = call.initial_metadata()
+ with self.assertRaises(grpc.RpcError):
+ for _ in call:
+ pass
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, received_initial_metadata))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, call.code())
+ self.assertEqual(_DETAILS, call.details())
+
+ def testCustomCodeReturnNoneUnaryUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_return_none()
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._unary_unary.with_call(object(), metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+ def testCustomCodeReturnNoneStreamUnary(self):
+ self._servicer.set_code(_NON_OK_CODE)
+ self._servicer.set_details(_DETAILS)
+ self._servicer.set_return_none()
+
+ with self.assertRaises(grpc.RpcError) as exception_context:
+ self._stream_unary.with_call(
+ iter([_SERIALIZED_REQUEST] * test_constants.STREAM_LENGTH),
+ metadata=_CLIENT_METADATA)
+
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _CLIENT_METADATA, self._servicer.received_client_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA,
+ exception_context.exception.initial_metadata()))
+ self.assertTrue(
+ test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA,
+ exception_context.exception.trailing_metadata()))
+ self.assertIs(_NON_OK_CODE, exception_context.exception.code())
+ self.assertEqual(_DETAILS, exception_context.exception.details())
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_metadata_test.py b/src/python/grpcio/tests/unit/_metadata_test.py
new file mode 100644
index 0000000000..2cb13f236b
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_metadata_test.py
@@ -0,0 +1,216 @@
+# 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.
+"""Tests server and client side metadata API."""
+
+import unittest
+import weakref
+
+import grpc
+from grpc import _grpcio_metadata
+from grpc.framework.foundation import logging_pool
+
+from tests.unit import test_common
+from tests.unit.framework.common import test_constants
+
+_CHANNEL_ARGS = (('grpc.primary_user_agent', 'primary-agent'),
+ ('grpc.secondary_user_agent', 'secondary-agent'))
+
+_REQUEST = b'\x00\x00\x00'
+_RESPONSE = b'\x00\x00\x00'
+
+_UNARY_UNARY = b'/test/UnaryUnary'
+_UNARY_STREAM = b'/test/UnaryStream'
+_STREAM_UNARY = b'/test/StreamUnary'
+_STREAM_STREAM = b'/test/StreamStream'
+
+_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
+
+_CLIENT_METADATA = (
+ (b'client-md-key', b'client-md-key'),
+ (b'client-md-key-bin', b'\x00\x01')
+)
+
+_SERVER_INITIAL_METADATA = (
+ (b'server-initial-md-key', b'server-initial-md-value'),
+ (b'server-initial-md-key-bin', b'\x00\x02')
+)
+
+_SERVER_TRAILING_METADATA = (
+ (b'server-trailing-md-key', b'server-trailing-md-value'),
+ (b'server-trailing-md-key-bin', b'\x00\x03')
+)
+
+
+def user_agent(metadata):
+ for key, val in metadata:
+ if key == b'user-agent':
+ return val.decode('ascii')
+ raise KeyError('No user agent!')
+
+
+def validate_client_metadata(test, servicer_context):
+ test.assertTrue(test_common.metadata_transmitted(
+ _CLIENT_METADATA, servicer_context.invocation_metadata()))
+ test.assertTrue(user_agent(servicer_context.invocation_metadata())
+ .startswith('primary-agent ' + _USER_AGENT))
+ test.assertTrue(user_agent(servicer_context.invocation_metadata())
+ .endswith('secondary-agent'))
+
+
+def handle_unary_unary(test, request, servicer_context):
+ validate_client_metadata(test, servicer_context)
+ servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ return _RESPONSE
+
+
+def handle_unary_stream(test, request, servicer_context):
+ validate_client_metadata(test, servicer_context)
+ servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ for _ in range(test_constants.STREAM_LENGTH):
+ yield _RESPONSE
+
+
+def handle_stream_unary(test, request_iterator, servicer_context):
+ validate_client_metadata(test, servicer_context)
+ servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ # TODO(issue:#6891) We should be able to remove this loop
+ for request in request_iterator:
+ pass
+ return _RESPONSE
+
+
+def handle_stream_stream(test, request_iterator, servicer_context):
+ validate_client_metadata(test, servicer_context)
+ servicer_context.send_initial_metadata(_SERVER_INITIAL_METADATA)
+ servicer_context.set_trailing_metadata(_SERVER_TRAILING_METADATA)
+ # TODO(issue:#6891) We should be able to remove this loop,
+ # and replace with return; yield
+ for request in request_iterator:
+ yield _RESPONSE
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+
+ def __init__(self, test, request_streaming, response_streaming):
+ self.request_streaming = request_streaming
+ self.response_streaming = response_streaming
+ self.request_deserializer = None
+ self.response_serializer = None
+ self.unary_unary = None
+ self.unary_stream = None
+ self.stream_unary = None
+ self.stream_stream = None
+ if self.request_streaming and self.response_streaming:
+ self.stream_stream = lambda x, y: handle_stream_stream(test, x, y)
+ elif self.request_streaming:
+ self.stream_unary = lambda x, y: handle_stream_unary(test, x, y)
+ elif self.response_streaming:
+ self.unary_stream = lambda x, y: handle_unary_stream(test, x, y)
+ else:
+ self.unary_unary = lambda x, y: handle_unary_unary(test, x, y)
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+
+ def __init__(self, test):
+ self._test = test
+
+ def service(self, handler_call_details):
+ if handler_call_details.method == _UNARY_UNARY:
+ return _MethodHandler(self._test, False, False)
+ elif handler_call_details.method == _UNARY_STREAM:
+ return _MethodHandler(self._test, False, True)
+ elif handler_call_details.method == _STREAM_UNARY:
+ return _MethodHandler(self._test, True, False)
+ elif handler_call_details.method == _STREAM_STREAM:
+ return _MethodHandler(self._test, True, True)
+ else:
+ return None
+
+
+class MetadataTest(unittest.TestCase):
+
+ def setUp(self):
+ self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+ self._server = grpc.server((_GenericHandler(weakref.proxy(self)),),
+ self._server_pool)
+ port = self._server.add_insecure_port('[::]:0')
+ self._server.start()
+ self._channel = grpc.insecure_channel('localhost:%d' % port,
+ options=_CHANNEL_ARGS)
+
+ def tearDown(self):
+ self._server.stop(0)
+
+ def testUnaryUnary(self):
+ multi_callable = self._channel.unary_unary(_UNARY_UNARY)
+ unused_response, call = multi_callable.with_call(
+ _REQUEST, metadata=_CLIENT_METADATA)
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+
+ def testUnaryStream(self):
+ multi_callable = self._channel.unary_stream(_UNARY_STREAM)
+ call = multi_callable(_REQUEST, metadata=_CLIENT_METADATA)
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ for _ in call:
+ pass
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+
+ def testStreamUnary(self):
+ multi_callable = self._channel.stream_unary(_STREAM_UNARY)
+ unused_response, call = multi_callable.with_call(
+ [_REQUEST] * test_constants.STREAM_LENGTH,
+ metadata=_CLIENT_METADATA)
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+
+ def testStreamStream(self):
+ multi_callable = self._channel.stream_stream(_STREAM_STREAM)
+ call = multi_callable([_REQUEST] * test_constants.STREAM_LENGTH,
+ metadata=_CLIENT_METADATA)
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_INITIAL_METADATA, call.initial_metadata()))
+ for _ in call:
+ pass
+ self.assertTrue(test_common.metadata_transmitted(
+ _SERVER_TRAILING_METADATA, call.trailing_metadata()))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/_rpc_test.py b/src/python/grpcio/tests/unit/_rpc_test.py
index 1c7a14c5d0..9814504edf 100644
--- a/src/python/grpcio/tests/unit/_rpc_test.py
+++ b/src/python/grpcio/tests/unit/_rpc_test.py
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Test of gRPC Python's application-layer API."""
+"""Test of RPCs made against gRPC Python's application-layer API."""
import itertools
import threading
@@ -41,9 +41,9 @@ from tests.unit.framework.common import test_constants
from tests.unit.framework.common import test_control
_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
-_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) / 2:]
+_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
-_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) / 3]
+_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
_UNARY_UNARY = b'/test/UnaryUnary'
_UNARY_STREAM = b'/test/UnaryStream'
@@ -189,14 +189,7 @@ class RPCTest(unittest.TestCase):
self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),))
self._server.start()
- self._channel = grpc.insecure_channel(b'localhost:%d' % port)
-
- # TODO(nathaniel): Why is this necessary, and only in some development
- # environments?
- def tearDown(self):
- del self._channel
- del self._server
- del self._server_pool
+ self._channel = grpc.insecure_channel('localhost:%d' % port)
def testUnrecognizedMethod(self):
request = b'abc'
@@ -223,10 +216,9 @@ class RPCTest(unittest.TestCase):
expected_response = self._handler.handle_unary_unary(request, None)
multi_callable = _unary_unary_multi_callable(self._channel)
- response, call = multi_callable(
+ response, call = multi_callable.with_call(
request, metadata=(
- (b'test', b'SuccessfulUnaryRequestBlockingUnaryResponseWithCall'),),
- with_call=True)
+ (b'test', b'SuccessfulUnaryRequestBlockingUnaryResponseWithCall'),))
self.assertEqual(expected_response, response)
self.assertIs(grpc.StatusCode.OK, call.code())
@@ -273,11 +265,11 @@ class RPCTest(unittest.TestCase):
request_iterator = iter(requests)
multi_callable = _stream_unary_multi_callable(self._channel)
- response, call = multi_callable(
+ response, call = multi_callable.with_call(
request_iterator,
metadata=(
(b'test', b'SuccessfulStreamRequestBlockingUnaryResponseWithCall'),
- ), with_call=True)
+ ))
self.assertEqual(expected_response, response)
self.assertIs(grpc.StatusCode.OK, call.code())
@@ -532,10 +524,9 @@ class RPCTest(unittest.TestCase):
multi_callable = _unary_unary_multi_callable(self._channel)
with self._control.pause():
with self.assertRaises(grpc.RpcError) as exception_context:
- multi_callable(
+ multi_callable.with_call(
request, timeout=test_constants.SHORT_TIMEOUT,
- metadata=((b'test', b'ExpiredUnaryRequestBlockingUnaryResponse'),),
- with_call=True)
+ metadata=((b'test', b'ExpiredUnaryRequestBlockingUnaryResponse'),))
self.assertIsNotNone(exception_context.exception.initial_metadata())
self.assertIs(
@@ -647,10 +638,9 @@ class RPCTest(unittest.TestCase):
multi_callable = _unary_unary_multi_callable(self._channel)
with self._control.fail():
with self.assertRaises(grpc.RpcError) as exception_context:
- multi_callable(
+ multi_callable.with_call(
request,
- metadata=((b'test', b'FailedUnaryRequestBlockingUnaryResponse'),),
- with_call=True)
+ metadata=((b'test', b'FailedUnaryRequestBlockingUnaryResponse'),))
self.assertIs(grpc.StatusCode.UNKNOWN, exception_context.exception.code())
diff --git a/src/python/grpcio/tests/unit/_thread_cleanup_test.py b/src/python/grpcio/tests/unit/_thread_cleanup_test.py
new file mode 100644
index 0000000000..3e4f317edc
--- /dev/null
+++ b/src/python/grpcio/tests/unit/_thread_cleanup_test.py
@@ -0,0 +1,117 @@
+# 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.
+"""Tests for CleanupThread."""
+
+import threading
+import time
+import unittest
+
+from grpc import _common
+
+_SHORT_TIME = 0.5
+_LONG_TIME = 2.0
+_EPSILON = 0.1
+
+
+def cleanup(timeout):
+ if timeout is not None:
+ time.sleep(timeout)
+ else:
+ time.sleep(_LONG_TIME)
+
+
+def slow_cleanup(timeout):
+ # Don't respect timeout
+ time.sleep(_LONG_TIME)
+
+
+class CleanupThreadTest(unittest.TestCase):
+
+ def testTargetInvocation(self):
+ event = threading.Event()
+ def target(arg1, arg2, arg3=None):
+ self.assertEqual('arg1', arg1)
+ self.assertEqual('arg2', arg2)
+ self.assertEqual('arg3', arg3)
+ event.set()
+
+ cleanup_thread = _common.CleanupThread(behavior=lambda x: None,
+ target=target, name='test-name',
+ args=('arg1', 'arg2'), kwargs={'arg3': 'arg3'})
+ cleanup_thread.start()
+ cleanup_thread.join()
+ self.assertEqual(cleanup_thread.name, 'test-name')
+ self.assertTrue(event.is_set())
+
+ def testJoinNoTimeout(self):
+ cleanup_thread = _common.CleanupThread(behavior=cleanup)
+ cleanup_thread.start()
+ start_time = time.time()
+ cleanup_thread.join()
+ end_time = time.time()
+ self.assertAlmostEqual(_LONG_TIME, end_time - start_time, delta=_EPSILON)
+
+ def testJoinTimeout(self):
+ cleanup_thread = _common.CleanupThread(behavior=cleanup)
+ cleanup_thread.start()
+ start_time = time.time()
+ cleanup_thread.join(_SHORT_TIME)
+ end_time = time.time()
+ self.assertAlmostEqual(_SHORT_TIME, end_time - start_time, delta=_EPSILON)
+
+ def testJoinTimeoutSlowBehavior(self):
+ cleanup_thread = _common.CleanupThread(behavior=slow_cleanup)
+ cleanup_thread.start()
+ start_time = time.time()
+ cleanup_thread.join(_SHORT_TIME)
+ end_time = time.time()
+ self.assertAlmostEqual(_LONG_TIME, end_time - start_time, delta=_EPSILON)
+
+ def testJoinTimeoutSlowTarget(self):
+ event = threading.Event()
+ def target():
+ event.wait(_LONG_TIME)
+ cleanup_thread = _common.CleanupThread(behavior=cleanup, target=target)
+ cleanup_thread.start()
+ start_time = time.time()
+ cleanup_thread.join(_SHORT_TIME)
+ end_time = time.time()
+ self.assertAlmostEqual(_SHORT_TIME, end_time - start_time, delta=_EPSILON)
+ event.set()
+
+ def testJoinZeroTimeout(self):
+ cleanup_thread = _common.CleanupThread(behavior=cleanup)
+ cleanup_thread.start()
+ start_time = time.time()
+ cleanup_thread.join(0)
+ end_time = time.time()
+ self.assertAlmostEqual(0, end_time - start_time, delta=_EPSILON)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
index bb2893a21b..3a9701b8eb 100644
--- a/src/python/grpcio/tests/unit/beta/_beta_features_test.py
+++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
@@ -42,8 +42,8 @@ from tests.unit.framework.common import test_constants
_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
-_PER_RPC_CREDENTIALS_METADATA_KEY = 'my-call-credentials-metadata-key'
-_PER_RPC_CREDENTIALS_METADATA_VALUE = 'my-call-credentials-metadata-value'
+_PER_RPC_CREDENTIALS_METADATA_KEY = b'my-call-credentials-metadata-key'
+_PER_RPC_CREDENTIALS_METADATA_VALUE = b'my-call-credentials-metadata-value'
_GROUP = 'group'
_UNARY_UNARY = 'unary-unary'
diff --git a/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
index 5dc8720639..488f7d7141 100644
--- a/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
+++ b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
@@ -187,5 +187,15 @@ class ChannelConnectivityTest(unittest.TestCase):
server_completion_queue_thread.join()
+class ConnectivityStatesTest(unittest.TestCase):
+
+ def testBetaConnectivityStates(self):
+ self.assertIsNotNone(interfaces.ChannelConnectivity.IDLE)
+ self.assertIsNotNone(interfaces.ChannelConnectivity.CONNECTING)
+ self.assertIsNotNone(interfaces.ChannelConnectivity.READY)
+ self.assertIsNotNone(interfaces.ChannelConnectivity.TRANSIENT_FAILURE)
+ self.assertIsNotNone(interfaces.ChannelConnectivity.FATAL_FAILURE)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/beta/_not_found_test.py b/src/python/grpcio/tests/unit/beta/_not_found_test.py
index 44fcd1e13c..37b8c49120 100644
--- a/src/python/grpcio/tests/unit/beta/_not_found_test.py
+++ b/src/python/grpcio/tests/unit/beta/_not_found_test.py
@@ -61,7 +61,7 @@ class NotFoundTest(unittest.TestCase):
def test_future_stream_unary_not_found(self):
rpc_future = self._generic_stub.future_stream_unary(
- 'grupe', 'mevvod', b'def', test_constants.LONG_TIMEOUT)
+ 'grupe', 'mevvod', [b'def'], test_constants.LONG_TIMEOUT)
with self.assertRaises(face.LocalError) as exception_assertion_context:
rpc_future.result()
self.assertIs(
diff --git a/src/python/grpcio/tests/unit/beta/test_utilities.py b/src/python/grpcio/tests/unit/beta/test_utilities.py
index 0313e06a93..8ccad04e05 100644
--- a/src/python/grpcio/tests/unit/beta/test_utilities.py
+++ b/src/python/grpcio/tests/unit/beta/test_utilities.py
@@ -29,7 +29,7 @@
"""Test-appropriate entry points into the gRPC Python Beta API."""
-from grpc._adapter import _intermediary_low
+import grpc
from grpc.beta import implementations
@@ -48,9 +48,8 @@ def not_really_secure_channel(
An implementations.Channel to the remote host through which RPCs may be
conducted.
"""
- hostport = '%s:%d' % (host, port)
- intermediary_low_channel = _intermediary_low.Channel(
- hostport, channel_credentials._low_credentials,
- server_host_override=server_host_override)
- return implementations.Channel(
- intermediary_low_channel._internal, intermediary_low_channel)
+ target = '%s:%d' % (host, port)
+ channel = grpc.secure_channel(
+ target, channel_credentials,
+ ((b'grpc.ssl_target_name_override', server_host_override,),))
+ return implementations.Channel(channel)
diff --git a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
deleted file mode 100644
index 43457be362..0000000000
--- a/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
+++ /dev/null
@@ -1,113 +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.
-
-"""Tests Face interface compliance of the crust-over-core stack."""
-
-import collections
-import unittest
-
-import six
-
-from grpc.framework.core import implementations as core_implementations
-from grpc.framework.crust import implementations as crust_implementations
-from grpc.framework.foundation import logging_pool
-from grpc.framework.interfaces.links import utilities
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.face import test_cases
-from tests.unit.framework.interfaces.face import test_interfaces
-from tests.unit.framework.interfaces.links import test_utilities
-
-
-class _Implementation(test_interfaces.Implementation):
-
- def instantiate(
- self, methods, method_implementations, multi_method_implementation):
- pool = logging_pool.pool(test_constants.POOL_SIZE)
- servicer = crust_implementations.servicer(
- method_implementations, multi_method_implementation, pool)
-
- service_end_link = core_implementations.service_end_link(
- servicer, test_constants.DEFAULT_TIMEOUT,
- test_constants.MAXIMUM_TIMEOUT)
- invocation_end_link = core_implementations.invocation_end_link()
- invocation_end_link.join_link(service_end_link)
- service_end_link.join_link(invocation_end_link)
- service_end_link.start()
- invocation_end_link.start()
-
- generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
- # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
- group = next(iter(methods))[0]
- # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
- # _digest.TestServiceDigest.
- cardinalities = {
- method: method_object.cardinality()
- for (group, method), method_object in six.iteritems(methods)}
- dynamic_stub = crust_implementations.dynamic_stub(
- invocation_end_link, group, cardinalities, pool)
-
- return generic_stub, {group: dynamic_stub}, (
- invocation_end_link, service_end_link, pool)
-
- def destantiate(self, memo):
- invocation_end_link, service_end_link, pool = memo
- invocation_end_link.stop(0).wait()
- service_end_link.stop(0).wait()
- invocation_end_link.join_link(utilities.NULL_LINK)
- service_end_link.join_link(utilities.NULL_LINK)
- pool.shutdown(wait=True)
-
- def invocation_metadata(self):
- return object()
-
- def initial_metadata(self):
- return object()
-
- def terminal_metadata(self):
- return object()
-
- def code(self):
- return object()
-
- def details(self):
- return object()
-
- def metadata_transmitted(self, original_metadata, transmitted_metadata):
- return original_metadata is transmitted_metadata
-
-
-def load_tests(loader, tests, pattern):
- return unittest.TestSuite(
- tests=tuple(
- loader.loadTestsFromTestCase(test_case_class)
- for test_case_class in test_cases.test_cases(_Implementation())))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
deleted file mode 100644
index 1310292306..0000000000
--- a/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
+++ /dev/null
@@ -1,96 +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.
-
-"""Tests the RPC Framework Core's implementation of the Base interface."""
-
-import logging
-import random
-import time
-import unittest
-
-from grpc.framework.core import implementations
-from grpc.framework.interfaces.base import utilities
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.interfaces.base import test_cases
-from tests.unit.framework.interfaces.base import test_interfaces
-
-
-class _Implementation(test_interfaces.Implementation):
-
- def __init__(self):
- self._invocation_initial_metadata = object()
- self._service_initial_metadata = object()
- self._invocation_terminal_metadata = object()
- self._service_terminal_metadata = object()
-
- def instantiate(self, serializations, servicer):
- invocation = implementations.invocation_end_link()
- service = implementations.service_end_link(
- servicer, test_constants.DEFAULT_TIMEOUT,
- test_constants.MAXIMUM_TIMEOUT)
- invocation.join_link(service)
- service.join_link(invocation)
- return invocation, service, None
-
- def destantiate(self, memo):
- pass
-
- def invocation_initial_metadata(self):
- return self._invocation_initial_metadata
-
- def service_initial_metadata(self):
- return self._service_initial_metadata
-
- def invocation_completion(self):
- return utilities.completion(self._invocation_terminal_metadata, None, None)
-
- def service_completion(self):
- return utilities.completion(self._service_terminal_metadata, None, None)
-
- def metadata_transmitted(self, original_metadata, transmitted_metadata):
- return transmitted_metadata is original_metadata
-
- def completion_transmitted(self, original_completion, transmitted_completion):
- return (
- (original_completion.terminal_metadata is
- transmitted_completion.terminal_metadata) and
- original_completion.code is transmitted_completion.code and
- original_completion.message is transmitted_completion.message
- )
-
-
-def load_tests(loader, tests, pattern):
- return unittest.TestSuite(
- tests=tuple(
- loader.loadTestsFromTestCase(test_case_class)
- for test_case_class in test_cases.test_cases(_Implementation())))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/framework/foundation/_later_test.py b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
deleted file mode 100644
index 6c2459e185..0000000000
--- a/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
+++ /dev/null
@@ -1,151 +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.
-
-"""Tests of the later module."""
-
-import threading
-import time
-import unittest
-
-from grpc.framework.foundation import later
-
-TICK = 0.1
-
-
-class LaterTest(unittest.TestCase):
-
- def test_simple_delay(self):
- lock = threading.Lock()
- cell = [0]
- return_value = object()
-
- def computation():
- with lock:
- cell[0] += 1
- return return_value
- computation_future = later.later(TICK * 2, computation)
-
- self.assertFalse(computation_future.done())
- self.assertFalse(computation_future.cancelled())
- time.sleep(TICK)
- self.assertFalse(computation_future.done())
- self.assertFalse(computation_future.cancelled())
- with lock:
- self.assertEqual(0, cell[0])
- time.sleep(TICK * 2)
- self.assertTrue(computation_future.done())
- self.assertFalse(computation_future.cancelled())
- with lock:
- self.assertEqual(1, cell[0])
- self.assertEqual(return_value, computation_future.result())
-
- def test_callback(self):
- lock = threading.Lock()
- cell = [0]
- callback_called = [False]
- future_passed_to_callback = [None]
- def computation():
- with lock:
- cell[0] += 1
- computation_future = later.later(TICK * 2, computation)
- def callback(outcome):
- with lock:
- callback_called[0] = True
- future_passed_to_callback[0] = outcome
- computation_future.add_done_callback(callback)
- time.sleep(TICK)
- with lock:
- self.assertFalse(callback_called[0])
- time.sleep(TICK * 2)
- with lock:
- self.assertTrue(callback_called[0])
- self.assertTrue(future_passed_to_callback[0].done())
-
- callback_called[0] = False
- future_passed_to_callback[0] = None
-
- computation_future.add_done_callback(callback)
- with lock:
- self.assertTrue(callback_called[0])
- self.assertTrue(future_passed_to_callback[0].done())
-
- def test_cancel(self):
- lock = threading.Lock()
- cell = [0]
- callback_called = [False]
- future_passed_to_callback = [None]
- def computation():
- with lock:
- cell[0] += 1
- computation_future = later.later(TICK * 2, computation)
- def callback(outcome):
- with lock:
- callback_called[0] = True
- future_passed_to_callback[0] = outcome
- computation_future.add_done_callback(callback)
- time.sleep(TICK)
- with lock:
- self.assertFalse(callback_called[0])
- computation_future.cancel()
- self.assertTrue(computation_future.cancelled())
- self.assertFalse(computation_future.running())
- self.assertTrue(computation_future.done())
- with lock:
- self.assertTrue(callback_called[0])
- self.assertTrue(future_passed_to_callback[0].cancelled())
-
- def test_result(self):
- lock = threading.Lock()
- cell = [0]
- callback_called = [False]
- future_passed_to_callback_cell = [None]
- return_value = object()
-
- def computation():
- with lock:
- cell[0] += 1
- return return_value
- computation_future = later.later(TICK * 2, computation)
-
- def callback(future_passed_to_callback):
- with lock:
- callback_called[0] = True
- future_passed_to_callback_cell[0] = future_passed_to_callback
- computation_future.add_done_callback(callback)
- returned_value = computation_future.result()
- self.assertEqual(return_value, returned_value)
-
- # The callback may not yet have been called! Sleep a tick.
- time.sleep(TICK)
- with lock:
- self.assertTrue(callback_called[0])
- self.assertEqual(return_value, future_passed_to_callback_cell[0].result())
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
index 4f8e26c9a2..5d16bf98be 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
@@ -29,6 +29,8 @@
"""Tests of the base interface of RPC Framework."""
+from __future__ import division
+
import logging
import random
import threading
@@ -54,13 +56,13 @@ class _Serialization(test_interfaces.Serialization):
return request + request
def deserialize_request(self, serialized_request):
- return serialized_request[:len(serialized_request) / 2]
+ return serialized_request[:len(serialized_request) // 2]
def serialize_response(self, response):
return response * 3
def deserialize_response(self, serialized_response):
- return serialized_response[2 * len(serialized_response) / 3:]
+ return serialized_response[2 * len(serialized_response) // 3:]
def _advance(quadruples, operator, controller):
diff --git a/src/python/grpcio/tests/unit/test_common.py b/src/python/grpcio/tests/unit/test_common.py
index 7b4d20dccb..b779f65e7e 100644
--- a/src/python/grpcio/tests/unit/test_common.py
+++ b/src/python/grpcio/tests/unit/test_common.py
@@ -61,6 +61,10 @@ def metadata_transmitted(original_metadata, transmitted_metadata):
original = collections.defaultdict(list)
for key_value_pair in original_metadata:
key, value = tuple(key_value_pair)
+ if not isinstance(key, bytes):
+ key = key.encode()
+ if not isinstance(value, bytes):
+ value = value.encode()
original[key].append(value)
transmitted = collections.defaultdict(list)
for key_value_pair in transmitted_metadata:
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 1510191e78..4d9707638f 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -126,7 +126,8 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
grpc_is_binary_header_type grpc_is_binary_header_import;
grpc_call_error_to_string_type grpc_call_error_to_string_import;
-grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
+grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
+grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -259,6 +260,8 @@ gpr_avl_unref_type gpr_avl_unref_import;
gpr_avl_add_type gpr_avl_add_import;
gpr_avl_remove_type gpr_avl_remove_import;
gpr_avl_get_type gpr_avl_get_import;
+gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
+gpr_avl_is_empty_type gpr_avl_is_empty_import;
gpr_cmdline_create_type gpr_cmdline_create_import;
gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
@@ -394,7 +397,8 @@ void grpc_rb_load_imports(HMODULE library) {
grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
- grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create");
+ grpc_insecure_channel_create_from_fd_import = (grpc_insecure_channel_create_from_fd_type) GetProcAddress(library, "grpc_insecure_channel_create_from_fd");
+ grpc_server_add_insecure_channel_from_fd_import = (grpc_server_add_insecure_channel_from_fd_type) GetProcAddress(library, "grpc_server_add_insecure_channel_from_fd");
grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
@@ -527,6 +531,8 @@ void grpc_rb_load_imports(HMODULE library) {
gpr_avl_add_import = (gpr_avl_add_type) GetProcAddress(library, "gpr_avl_add");
gpr_avl_remove_import = (gpr_avl_remove_type) GetProcAddress(library, "gpr_avl_remove");
gpr_avl_get_import = (gpr_avl_get_type) GetProcAddress(library, "gpr_avl_get");
+ gpr_avl_maybe_get_import = (gpr_avl_maybe_get_type) GetProcAddress(library, "gpr_avl_maybe_get");
+ gpr_avl_is_empty_import = (gpr_avl_is_empty_type) GetProcAddress(library, "gpr_avl_is_empty");
gpr_cmdline_create_import = (gpr_cmdline_create_type) GetProcAddress(library, "gpr_cmdline_create");
gpr_cmdline_add_int_import = (gpr_cmdline_add_int_type) GetProcAddress(library, "gpr_cmdline_add_int");
gpr_cmdline_add_flag_import = (gpr_cmdline_add_flag_type) GetProcAddress(library, "gpr_cmdline_add_flag");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index dfaabf1d47..072e29c232 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -43,7 +43,7 @@
#include <grpc/census.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
-#include <grpc/grpc_cronet.h>
+#include <grpc/grpc_posix.h>
#include <grpc/grpc_security.h>
#include <grpc/impl/codegen/alloc.h>
#include <grpc/impl/codegen/byte_buffer.h>
@@ -329,9 +329,12 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import;
typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
#define grpc_call_error_to_string grpc_call_error_to_string_import
-typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved);
-extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import;
-#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import
+typedef grpc_channel *(*grpc_insecure_channel_create_from_fd_type)(const char *target, int fd, const grpc_channel_args *args);
+extern grpc_insecure_channel_create_from_fd_type grpc_insecure_channel_create_from_fd_import;
+#define grpc_insecure_channel_create_from_fd grpc_insecure_channel_create_from_fd_import
+typedef void(*grpc_server_add_insecure_channel_from_fd_type)(grpc_server *server, grpc_completion_queue *cq, int fd);
+extern grpc_server_add_insecure_channel_from_fd_type grpc_server_add_insecure_channel_from_fd_import;
+#define grpc_server_add_insecure_channel_from_fd grpc_server_add_insecure_channel_from_fd_import
typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
@@ -479,7 +482,7 @@ extern grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_impo
typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_from_reader_type)(grpc_byte_buffer_reader *reader);
extern grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
#define grpc_raw_byte_buffer_from_reader grpc_raw_byte_buffer_from_reader_import
-typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...);
+typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...) GPRC_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);
@@ -728,6 +731,12 @@ extern gpr_avl_remove_type gpr_avl_remove_import;
typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key);
extern gpr_avl_get_type gpr_avl_get_import;
#define gpr_avl_get gpr_avl_get_import
+typedef int(*gpr_avl_maybe_get_type)(gpr_avl avl, void *key, void **value);
+extern gpr_avl_maybe_get_type gpr_avl_maybe_get_import;
+#define gpr_avl_maybe_get gpr_avl_maybe_get_import
+typedef int(*gpr_avl_is_empty_type)(gpr_avl avl);
+extern gpr_avl_is_empty_type gpr_avl_is_empty_import;
+#define gpr_avl_is_empty gpr_avl_is_empty_import
typedef gpr_cmdline *(*gpr_cmdline_create_type)(const char *description);
extern gpr_cmdline_create_type gpr_cmdline_create_import;
#define gpr_cmdline_create gpr_cmdline_create_import
@@ -818,7 +827,7 @@ extern gpr_format_message_type gpr_format_message_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, ...);
+typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...) GPRC_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/version.rb b/src/ruby/lib/grpc/version.rb
index 01c8c5ac8f..5e6aaef2eb 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '0.15.0.dev'
+ VERSION = '0.16.0.dev'
end
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index dca7fd7e72..68c1bf369d 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
module GRPC
module Tools
- VERSION = '0.15.0.dev'
+ VERSION = '0.16.0.dev'
end
end