aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar David Garcia Quintas <dgq@google.com>2015-12-16 17:36:04 -0800
committerGravatar David Garcia Quintas <dgq@google.com>2015-12-16 17:36:04 -0800
commit7052ac25e60e137514d9a201a86eeb9b29b03d24 (patch)
tree2ce8f32319129e346a27d3b29a9b8d6b440cdd6c /src
parent886b7d19bafbb61e84141e66a040da8c27781c44 (diff)
parent788767a18f918131268ca88985b3547a8257e973 (diff)
Merge branch 'master' of github.com:grpc/grpc into grpclb_api
Diffstat (limited to 'src')
-rw-r--r--src/core/census/context.h8
-rw-r--r--src/core/census/grpc_filter.c10
-rw-r--r--src/core/channel/channel_stack.c17
-rw-r--r--src/core/channel/channel_stack.h41
-rw-r--r--src/core/channel/client_channel.c163
-rw-r--r--src/core/channel/client_channel.h12
-rw-r--r--src/core/channel/client_uchannel.c82
-rw-r--r--src/core/channel/client_uchannel.h16
-rw-r--r--src/core/channel/compress_filter.c7
-rw-r--r--src/core/channel/connected_channel.c6
-rw-r--r--src/core/channel/http_client_filter.c4
-rw-r--r--src/core/channel/http_server_filter.c6
-rw-r--r--src/core/channel/noop_filter.c118
-rw-r--r--src/core/channel/subchannel_call_holder.c80
-rw-r--r--src/core/channel/subchannel_call_holder.h14
-rw-r--r--src/core/client_config/lb_policies/pick_first.c165
-rw-r--r--src/core/client_config/lb_policies/round_robin.c258
-rw-r--r--src/core/client_config/lb_policy.c83
-rw-r--r--src/core/client_config/lb_policy.h41
-rw-r--r--src/core/client_config/resolver.c7
-rw-r--r--src/core/client_config/resolver.h10
-rw-r--r--src/core/client_config/resolvers/dns_resolver.c8
-rw-r--r--src/core/client_config/resolvers/sockaddr_resolver.c16
-rw-r--r--src/core/client_config/resolvers/zookeeper_resolver.c7
-rw-r--r--src/core/client_config/subchannel.c735
-rw-r--r--src/core/client_config/subchannel.h92
-rw-r--r--src/core/client_config/subchannel_factory_decorators/add_channel_arg.h46
-rw-r--r--src/core/client_config/subchannel_factory_decorators/merge_channel_args.c86
-rw-r--r--src/core/client_config/subchannel_factory_decorators/merge_channel_args.h46
-rw-r--r--src/core/compression/algorithm.c24
-rw-r--r--src/core/compression/message_compress.c28
-rw-r--r--src/core/httpcli/httpcli.c9
-rw-r--r--src/core/httpcli/httpcli.h2
-rw-r--r--src/core/httpcli/httpcli_security_connector.c5
-rw-r--r--src/core/iomgr/endpoint_pair_posix.c3
-rw-r--r--src/core/iomgr/fd_posix.c6
-rw-r--r--src/core/iomgr/fd_posix.h1
-rw-r--r--src/core/iomgr/pollset_multipoller_with_epoll.c22
-rw-r--r--src/core/iomgr/pollset_multipoller_with_poll_posix.c19
-rw-r--r--src/core/iomgr/pollset_posix.c34
-rw-r--r--src/core/iomgr/pollset_posix.h6
-rw-r--r--src/core/iomgr/pollset_set.h22
-rw-r--r--src/core/iomgr/pollset_set_posix.c51
-rw-r--r--src/core/iomgr/pollset_set_posix.h4
-rw-r--r--src/core/iomgr/pollset_set_windows.c8
-rw-r--r--src/core/iomgr/tcp_server_posix.c18
-rw-r--r--src/core/iomgr/tcp_server_windows.c8
-rw-r--r--src/core/iomgr/tcp_windows.c14
-rw-r--r--src/core/iomgr/timer.c12
-rw-r--r--src/core/iomgr/timer_internal.h2
-rw-r--r--src/core/iomgr/udp_server.c2
-rw-r--r--src/core/iomgr/wakeup_fd_posix.c8
-rw-r--r--src/core/iomgr/wakeup_fd_posix.h2
-rw-r--r--src/core/iomgr/workqueue_posix.c3
-rw-r--r--src/core/json/json_reader.c15
-rw-r--r--src/core/json/json_string.c2
-rw-r--r--src/core/profiling/basic_timers.c7
-rw-r--r--src/core/security/client_auth_filter.c6
-rw-r--r--src/core/security/credentials.c21
-rw-r--r--src/core/security/credentials.h9
-rw-r--r--src/core/security/credentials_posix.c2
-rw-r--r--src/core/security/credentials_win32.c2
-rw-r--r--src/core/security/google_default_credentials.c15
-rw-r--r--src/core/security/handshake.c49
-rw-r--r--src/core/security/handshake.h2
-rw-r--r--src/core/security/json_token.c4
-rw-r--r--src/core/security/security_connector.c27
-rw-r--r--src/core/security/security_connector.h15
-rw-r--r--src/core/security/server_secure_chttp2.c77
-rw-r--r--src/core/statistics/window_stats.c2
-rw-r--r--src/core/support/alloc.c20
-rw-r--r--src/core/support/cmdline.c62
-rw-r--r--src/core/support/log.c3
-rw-r--r--src/core/support/log_linux.c4
-rw-r--r--src/core/support/log_posix.c4
-rw-r--r--src/core/support/log_win32.c5
-rw-r--r--src/core/support/slice.c7
-rw-r--r--src/core/support/stack_lockfree.c8
-rw-r--r--src/core/support/string.c29
-rw-r--r--src/core/support/string.h10
-rw-r--r--src/core/support/time.c64
-rw-r--r--src/core/support/time_posix.c17
-rw-r--r--src/core/support/time_precise.c4
-rw-r--r--src/core/support/time_win32.c6
-rw-r--r--src/core/surface/call.c62
-rw-r--r--src/core/surface/call.h14
-rw-r--r--src/core/surface/call_log_batch.c24
-rw-r--r--src/core/surface/channel.c66
-rw-r--r--src/core/surface/channel.h2
-rw-r--r--src/core/surface/channel_connectivity.c41
-rw-r--r--src/core/surface/channel_create.c8
-rw-r--r--src/core/surface/channel_ping.c (renamed from src/core/client_config/subchannel_factory_decorators/add_channel_arg.c)54
-rw-r--r--src/core/surface/completion_queue.c50
-rw-r--r--src/core/surface/completion_queue.h8
-rw-r--r--src/core/surface/init.c7
-rw-r--r--src/core/surface/lame_client.c9
-rw-r--r--src/core/surface/secure_channel_create.c20
-rw-r--r--src/core/surface/server.c6
-rw-r--r--src/core/surface/server_chttp2.c6
-rw-r--r--src/core/surface/server_create.c14
-rw-r--r--src/core/transport/chttp2/frame_data.c11
-rw-r--r--src/core/transport/chttp2/frame_data.h3
-rw-r--r--src/core/transport/chttp2/frame_ping.c11
-rw-r--r--src/core/transport/chttp2/frame_settings.c7
-rw-r--r--src/core/transport/chttp2/hpack_encoder.c14
-rw-r--r--src/core/transport/chttp2/hpack_parser.c66
-rw-r--r--src/core/transport/chttp2/hpack_parser.h2
-rw-r--r--src/core/transport/chttp2/incoming_metadata.c18
-rw-r--r--src/core/transport/chttp2/incoming_metadata.h2
-rw-r--r--src/core/transport/chttp2/internal.h24
-rw-r--r--src/core/transport/chttp2/parsing.c2
-rw-r--r--src/core/transport/chttp2/stream_lists.c46
-rw-r--r--src/core/transport/chttp2/timeout_encoding.c17
-rw-r--r--src/core/transport/chttp2/varint.h6
-rw-r--r--src/core/transport/chttp2/writing.c9
-rw-r--r--src/core/transport/chttp2_transport.c85
-rw-r--r--src/core/transport/connectivity_state.c76
-rw-r--r--src/core/transport/connectivity_state.h13
-rw-r--r--src/core/transport/metadata.c10
-rw-r--r--src/core/transport/metadata_batch.c10
-rw-r--r--src/core/transport/metadata_batch.h2
-rw-r--r--src/core/transport/static_metadata.c125
-rw-r--r--src/core/transport/static_metadata.h136
-rw-r--r--src/core/transport/transport.c21
-rw-r--r--src/core/transport/transport.h17
-rw-r--r--src/core/transport/transport_op_string.c4
-rw-r--r--src/core/tsi/transport_security.c8
-rw-r--r--src/cpp/client/client_context.cc23
-rw-r--r--src/cpp/client/secure_credentials.cc2
-rw-r--r--src/cpp/proto/proto_utils.cc10
-rw-r--r--src/cpp/util/time.cc8
-rw-r--r--src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs6
-rw-r--r--src/csharp/Grpc.Core.Tests/CallOptionsTest.cs88
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs11
-rw-r--r--src/csharp/Grpc.Core.Tests/ClientServerTest.cs60
-rw-r--r--src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs32
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj3
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs105
-rw-r--r--src/csharp/Grpc.Core.Tests/MetadataTest.cs113
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs7
-rw-r--r--src/csharp/Grpc.Core.Tests/PInvokeTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/PerformanceTest.cs8
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs125
-rw-r--r--src/csharp/Grpc.Core.Tests/ShutdownTest.cs11
-rw-r--r--src/csharp/Grpc.Core.Tests/UserAgentStringTest.cs101
-rw-r--r--src/csharp/Grpc.Core/AsyncAuthInterceptor.cs84
-rw-r--r--src/csharp/Grpc.Core/CallCredentials.cs8
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs1
-rw-r--r--src/csharp/Grpc.Core/Channel.cs46
-rw-r--r--src/csharp/Grpc.Core/ChannelOptions.cs7
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj7
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs14
-rw-r--r--src/csharp/Grpc.Core/Internal/ClientResponseStream.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs13
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCallHandler.cs40
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerRequestStream.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/Timespec.cs23
-rw-r--r--src/csharp/Grpc.Core/Server.cs12
-rw-r--r--src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs12
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj3
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj3
-rw-r--r--src/csharp/Grpc.HealthCheck/proto/health.proto52
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs113
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs119
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs22
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs54
-rw-r--r--src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs7
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs39
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config1
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c7
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh22
-rw-r--r--src/csharp/tests.json45
-rw-r--r--src/node/ext/channel_credentials.cc6
-rw-r--r--src/node/ext/server_credentials.cc24
-rw-r--r--src/node/health_check/health.js3
-rw-r--r--src/node/health_check/health.proto49
-rw-r--r--src/node/interop/async_delay_queue.js (renamed from src/python/grpcio/grpc/_adapter/_c/types.c)66
-rw-r--r--src/node/interop/interop_server.js23
-rw-r--r--src/node/performance/benchmark_client.js336
-rw-r--r--src/node/performance/benchmark_server.js162
-rw-r--r--src/node/performance/histogram.js180
-rw-r--r--src/node/performance/perf_test.js119
-rw-r--r--src/node/performance/qps_test.js137
-rw-r--r--src/node/performance/worker_server.js (renamed from src/python/grpcio/grpc/_adapter/_c/module.c)60
-rw-r--r--src/node/performance/worker_service_impl.js132
-rw-r--r--src/node/src/credentials.js5
-rw-r--r--src/node/src/server.js139
-rw-r--r--src/node/test/async_test.js2
-rw-r--r--src/node/test/credentials_test.js147
-rw-r--r--src/node/test/math/math.proto80
-rw-r--r--src/node/test/math/math_server.js3
-rw-r--r--src/node/test/math_client_test.js2
-rw-r--r--src/node/test/server_test.js25
-rw-r--r--src/node/test/surface_test.js51
-rw-r--r--src/objective-c/BoringSSL.podspec1428
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h43
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m2
-rw-r--r--src/objective-c/GRPCClient/private/GRPCRequestHeaders.h13
-rw-r--r--src/objective-c/GRPCClient/private/GRPCRequestHeaders.m43
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.h2
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.m2
-rw-r--r--src/objective-c/examples/Sample/Podfile1
-rw-r--r--src/objective-c/examples/SwiftSample/Podfile1
-rw-r--r--src/objective-c/tests/Podfile1
-rwxr-xr-xsrc/php/bin/run_tests.sh2
-rw-r--r--src/php/ext/grpc/call.c32
-rw-r--r--src/php/ext/grpc/call.h4
-rw-r--r--src/php/ext/grpc/call_credentials.c101
-rwxr-xr-xsrc/php/ext/grpc/call_credentials.h14
-rw-r--r--src/php/ext/grpc/channel.c12
-rw-r--r--src/php/ext/grpc/channel_credentials.c10
-rw-r--r--src/php/ext/grpc/package.xml43
-rw-r--r--src/php/lib/Grpc/AbstractCall.php35
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php86
-rw-r--r--src/php/tests/generated_code/AbstractGeneratedCodeTest.php7
-rwxr-xr-xsrc/php/tests/generated_code/GeneratedCodeTest.php6
-rw-r--r--src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php5
-rw-r--r--src/php/tests/generated_code/math.proto3
-rwxr-xr-xsrc/php/tests/interop/interop_client.php32
-rw-r--r--src/php/tests/unit_tests/CallCredentialsTest.php137
-rw-r--r--src/proto/grpc/health/v1alpha/health.proto (renamed from src/ruby/pb/grpc/health/v1alpha/health.proto)1
-rw-r--r--src/proto/math/math.proto (renamed from src/csharp/Grpc.Examples/proto/math.proto)0
-rw-r--r--src/python/grpcio/.gitignore7
-rw-r--r--src/python/grpcio/MANIFEST.in1
-rw-r--r--src/python/grpcio/commands.py127
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types.h286
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/call.c186
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c203
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/channel.c187
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c165
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c124
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/server.c196
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c137
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/utility.c524
-rw-r--r--src/python/grpcio/grpc/_adapter/_implementations.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_c_test.py)33
-rw-r--r--src/python/grpcio/grpc/_adapter/_intermediary_low.py45
-rw-r--r--src/python/grpcio/grpc/_adapter/_low.py214
-rw-r--r--src/python/grpcio/grpc/_adapter/_types.py94
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/call.pyx28
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx31
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx11
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd23
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx82
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd65
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pxd1
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/records.pyx82
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/server.pyx2
-rw-r--r--src/python/grpcio/grpc/_cython/adapter_low.py102
-rw-r--r--src/python/grpcio/grpc/_cython/cygrpc.pyx6
-rw-r--r--src/python/grpcio/grpc/_links/invocation.py12
-rw-r--r--src/python/grpcio/grpc/_links/service.py6
-rw-r--r--src/python/grpcio/grpc/beta/_server.py175
-rw-r--r--src/python/grpcio/grpc/beta/_stub.py124
-rw-r--r--src/python/grpcio/grpc/beta/implementations.py96
-rw-r--r--src/python/grpcio/grpc/beta/interfaces.py49
-rw-r--r--src/python/grpcio/grpc/framework/core/_end.py60
-rw-r--r--src/python/grpcio/requirements.txt1
-rw-r--r--src/python/grpcio/setup.cfg6
-rw-r--r--src/python/grpcio/setup.py129
-rw-r--r--src/python/grpcio/tests/__init__.py34
-rw-r--r--src/python/grpcio/tests/_loader.py119
-rw-r--r--src/python/grpcio/tests/_result.py451
-rw-r--r--src/python/grpcio/tests/_runner.py224
-rw-r--r--src/python/grpcio/tests/interop/__init__.py (renamed from src/python/grpcio_test/grpc_interop/__init__.py)0
-rw-r--r--src/python/grpcio/tests/interop/_insecure_interop_test.py (renamed from src/python/grpcio_test/grpc_interop/_insecure_interop_test.py)8
-rw-r--r--src/python/grpcio/tests/interop/_interop_test_case.py (renamed from src/python/grpcio_test/grpc_interop/_interop_test_case.py)2
-rw-r--r--src/python/grpcio/tests/interop/_secure_interop_test.py (renamed from src/python/grpcio_test/grpc_interop/_secure_interop_test.py)12
-rw-r--r--src/python/grpcio/tests/interop/client.py (renamed from src/python/grpcio_test/grpc_interop/client.py)17
-rw-r--r--src/python/grpcio/tests/interop/credentials/README (renamed from src/python/grpcio_test/grpc_interop/credentials/README)0
-rwxr-xr-xsrc/python/grpcio/tests/interop/credentials/ca.pem (renamed from src/python/grpcio_test/grpc_interop/credentials/ca.pem)0
-rwxr-xr-xsrc/python/grpcio/tests/interop/credentials/server1.key (renamed from src/python/grpcio_test/grpc_interop/credentials/server1.key)0
-rwxr-xr-xsrc/python/grpcio/tests/interop/credentials/server1.pem (renamed from src/python/grpcio_test/grpc_interop/credentials/server1.pem)0
-rw-r--r--src/python/grpcio/tests/interop/empty.proto (renamed from src/python/grpcio_test/grpc_interop/empty.proto)0
-rw-r--r--src/python/grpcio/tests/interop/messages.proto (renamed from src/python/grpcio_test/grpc_interop/messages.proto)0
-rw-r--r--src/python/grpcio/tests/interop/methods.py (renamed from src/python/grpcio_test/grpc_interop/methods.py)6
-rw-r--r--src/python/grpcio/tests/interop/resources.py (renamed from src/python/grpcio_test/grpc_interop/resources.py)4
-rw-r--r--src/python/grpcio/tests/interop/server.py (renamed from src/python/grpcio_test/grpc_interop/server.py)8
-rw-r--r--src/python/grpcio/tests/interop/test.proto (renamed from src/python/grpcio_test/grpc_interop/test.proto)4
-rw-r--r--src/python/grpcio/tests/protoc_plugin/__init__.py (renamed from src/python/grpcio_test/grpc_protoc_plugin/__init__.py)0
-rw-r--r--src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py (renamed from src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py)73
-rw-r--r--src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto (renamed from src/python/grpcio_test/grpc_protoc_plugin/test.proto)0
-rw-r--r--src/python/grpcio/tests/unit/__init__.py (renamed from src/python/grpcio_test/grpc_test/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/_adapter/.gitignore (renamed from src/python/grpcio_test/grpc_test/_adapter/.gitignore)0
-rw-r--r--src/python/grpcio/tests/unit/_adapter/__init__.py (renamed from src/python/grpcio_test/grpc_test/_adapter/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py)14
-rw-r--r--src/python/grpcio/tests/unit/_adapter/_low_test.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_low_test.py)10
-rw-r--r--src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py (renamed from src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py)2
-rw-r--r--src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py (renamed from src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py)8
-rw-r--r--src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py)8
-rw-r--r--src/python/grpcio/tests/unit/_cython/.gitignore (renamed from src/python/grpcio_test/grpc_test/_cython/.gitignore)0
-rw-r--r--src/python/grpcio/tests/unit/_cython/__init__.py (renamed from src/python/grpcio_test/grpc_test/_cython/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/_cython/cygrpc_test.py (renamed from src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py)194
-rw-r--r--src/python/grpcio/tests/unit/_cython/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/_cython/test_utilities.py)0
-rw-r--r--src/python/grpcio/tests/unit/_junkdrawer/__init__.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py)0
-rw-r--r--src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py (renamed from src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py)0
-rw-r--r--src/python/grpcio/tests/unit/_links/__init__.py (renamed from src/python/grpcio_test/grpc_test/_links/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py (renamed from src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py)6
-rw-r--r--src/python/grpcio/tests/unit/_links/_proto_scenarios.py (renamed from src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py)4
-rw-r--r--src/python/grpcio/tests/unit/_links/_transmission_test.py (renamed from src/python/grpcio_test/grpc_test/_links/_transmission_test.py)10
-rw-r--r--src/python/grpcio/tests/unit/beta/__init__.py (renamed from src/python/grpcio_test/grpc_test/beta/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/beta/_beta_features_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_beta_features_test.py)133
-rw-r--r--src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py)2
-rw-r--r--src/python/grpcio/tests/unit/beta/_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_face_interface_test.py)16
-rw-r--r--src/python/grpcio/tests/unit/beta/_not_found_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_not_found_test.py)2
-rw-r--r--src/python/grpcio/tests/unit/beta/_utilities_test.py (renamed from src/python/grpcio_test/grpc_test/beta/_utilities_test.py)2
-rw-r--r--src/python/grpcio/tests/unit/beta/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/beta/test_utilities.py)6
-rw-r--r--src/python/grpcio/tests/unit/credentials/README (renamed from src/python/grpcio_test/grpc_test/credentials/README)0
-rwxr-xr-xsrc/python/grpcio/tests/unit/credentials/ca.pem (renamed from src/python/grpcio_test/grpc_test/credentials/ca.pem)0
-rwxr-xr-xsrc/python/grpcio/tests/unit/credentials/server1.key (renamed from src/python/grpcio_test/grpc_test/credentials/server1.key)0
-rwxr-xr-xsrc/python/grpcio/tests/unit/credentials/server1.pem (renamed from src/python/grpcio_test/grpc_test/credentials/server1.pem)0
-rw-r--r--src/python/grpcio/tests/unit/framework/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py (renamed from src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py)8
-rw-r--r--src/python/grpcio/tests/unit/framework/common/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/common/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/common/test_constants.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_constants.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/common/test_control.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_control.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/common/test_coverage.py (renamed from src/python/grpcio_test/grpc_test/framework/common/test_coverage.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/core/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/core/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/core/_base_interface_test.py (renamed from src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py)6
-rw-r--r--src/python/grpcio/tests/unit/framework/face/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/face/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/base_util.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py)12
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/callback.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/callback.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/control.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/control.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/coverage.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/digest.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/digest.py)6
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py)14
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py)12
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/service.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/service.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/stock_service.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py)4
-rw-r--r--src/python/grpcio/tests/unit/framework/face/testing/test_case.py (renamed from src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/foundation/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/foundation/_later_test.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/foundation/stream_testing.py (renamed from src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/_control.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py)8
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/_state.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py)7
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py)14
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py)6
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py)16
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py)14
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py)2
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py)6
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py)14
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py)0
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py)4
-rw-r--r--src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py (renamed from src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py)0
-rw-r--r--src/python/grpcio/tests/unit/resources.py (renamed from src/python/grpcio_test/grpc_test/resources.py)4
-rw-r--r--src/python/grpcio/tests/unit/test_common.py (renamed from src/python/grpcio_test/grpc_test/test_common.py)0
-rw-r--r--src/python/grpcio/tox.ini19
-rw-r--r--src/python/grpcio_test/.gitignore12
-rw-r--r--src/python/grpcio_test/MANIFEST.in4
-rw-r--r--src/python/grpcio_test/commands.py106
-rw-r--r--src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py187
-rw-r--r--src/python/grpcio_test/grpc_test/conftest.py60
-rw-r--r--src/python/grpcio_test/requirements.txt6
-rw-r--r--src/python/grpcio_test/setup.cfg2
-rwxr-xr-xsrc/ruby/bin/apis/pubsub_demo.rb22
-rwxr-xr-xsrc/ruby/bin/math.proto80
-rwxr-xr-xsrc/ruby/bin/math.rb29
-rwxr-xr-xsrc/ruby/bin/math_services.rb29
-rw-r--r--src/ruby/ext/grpc/rb_call.c25
-rw-r--r--src/ruby/ext/grpc/rb_call.h6
-rw-r--r--src/ruby/ext/grpc/rb_call_credentials.c312
-rw-r--r--src/ruby/ext/grpc/rb_call_credentials.h (renamed from src/core/channel/noop_filter.h)18
-rw-r--r--src/ruby/ext/grpc/rb_channel_credentials.c64
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c6
-rwxr-xr-xsrc/ruby/grpc.gemspec1
-rw-r--r--src/ruby/lib/grpc/generic/client_stub.rb82
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb2
-rw-r--r--src/ruby/pb/README.md2
-rwxr-xr-xsrc/ruby/pb/generate_proto_ruby.sh51
-rwxr-xr-xsrc/ruby/pb/test/client.rb21
-rw-r--r--src/ruby/pb/test/proto/messages.rb2
-rwxr-xr-xsrc/ruby/pb/test/server.rb2
-rw-r--r--src/ruby/spec/call_credentials_spec.rb (renamed from src/python/grpcio_test/setup.py)93
-rw-r--r--src/ruby/spec/call_spec.rb9
-rw-r--r--src/ruby/spec/channel_credentials_spec.rb38
-rw-r--r--src/ruby/spec/client_server_spec.rb29
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb57
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb19
395 files changed, 9295 insertions, 6697 deletions
diff --git a/src/core/census/context.h b/src/core/census/context.h
index d9907d4da7..700bcf86cf 100644
--- a/src/core/census/context.h
+++ b/src/core/census/context.h
@@ -36,14 +36,12 @@
#include <grpc/census.h>
+#define GRPC_CENSUS_MAX_ON_THE_WIRE_TAG_BYTES 2048
+
/* census_context is the in-memory representation of information needed to
* maintain tracing, RPC statistics and resource usage information. */
struct census_context {
- gpr_uint64 op_id; /* Operation identifier - unique per-context */
- gpr_uint64 trace_id; /* Globally unique trace identifier */
- /* TODO(aveitch) Add census tags:
- const census_tag_set *tags;
- */
+ census_tag_set *tags; /* Opaque data structure for census tags. */
};
#endif /* GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H */
diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
index 61a95ec765..4529ae9bd7 100644
--- a/src/core/census/grpc_filter.c
+++ b/src/core/census/grpc_filter.c
@@ -43,7 +43,6 @@
#include <grpc/support/time.h>
#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/noop_filter.h"
#include "src/core/statistics/census_interface.h"
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/transport/static_metadata.h"
@@ -60,9 +59,7 @@ typedef struct call_data {
grpc_closure finish_recv;
} call_data;
-typedef struct channel_data {
- gpr_uint8 unused;
-} channel_data;
+typedef struct channel_data { gpr_uint8 unused; } channel_data;
static void extract_and_annotate_method_tag(grpc_metadata_batch *md,
call_data *calld,
@@ -118,8 +115,11 @@ static void server_mutate_op(grpc_call_element *elem,
static void server_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
+ /* TODO(ctiller): this code fails. I don't know why. I expect it's
+ incomplete, and someone should look at it soon.
+
call_data *calld = elem->call_data;
- GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
+ GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0)); */
server_mutate_op(elem, op);
grpc_call_next_op(exec_ctx, elem, op);
}
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index 7f7fbf420f..5e09a050ee 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -101,11 +101,12 @@ grpc_call_element *grpc_call_stack_element(grpc_call_stack *call_stack,
return CALL_ELEMS_FROM_STACK(call_stack) + index;
}
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
+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, grpc_channel *master,
+ size_t filter_count,
const grpc_channel_args *channel_args,
- grpc_channel_stack *stack) {
+ const char *name, grpc_channel_stack *stack) {
size_t call_size =
ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
@@ -115,6 +116,8 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
size_t i;
stack->count = filter_count;
+ GRPC_STREAM_REF_INIT(&stack->refcount, initial_refs, destroy, destroy_arg,
+ name);
elems = CHANNEL_ELEMS_FROM_STACK(stack);
user_data =
((char *)elems) +
@@ -122,7 +125,7 @@ void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
/* init per-filter data */
for (i = 0; i < filter_count; i++) {
- args.master = master;
+ args.channel_stack = stack;
args.channel_args = channel_args;
args.is_first = i == 0;
args.is_last = i == (filter_count - 1);
@@ -166,15 +169,15 @@ void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
size_t i;
call_stack->count = count;
- gpr_ref_init(&call_stack->refcount.refs, initial_refs);
- grpc_closure_init(&call_stack->refcount.destroy, destroy, destroy_arg);
+ GRPC_STREAM_REF_INIT(&call_stack->refcount, initial_refs, destroy,
+ destroy_arg, "CALL_STACK");
call_elems = CALL_ELEMS_FROM_STACK(call_stack);
user_data = ((char *)call_elems) +
ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
/* init per-filter data */
for (i = 0; i < count; i++) {
- args.refcount = &call_stack->refcount;
+ args.call_stack = call_stack;
args.server_transport_data = transport_server_data;
args.context = context;
call_elems[i].filter = channel_elems[i].filter;
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index 1db12ead7e..c01050e717 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -51,15 +51,18 @@
typedef struct grpc_channel_element grpc_channel_element;
typedef struct grpc_call_element grpc_call_element;
+typedef struct grpc_channel_stack grpc_channel_stack;
+typedef struct grpc_call_stack grpc_call_stack;
+
typedef struct {
- grpc_channel *master;
+ grpc_channel_stack *channel_stack;
const grpc_channel_args *channel_args;
int is_first;
int is_last;
} grpc_channel_element_args;
typedef struct {
- grpc_stream_refcount *refcount;
+ grpc_call_stack *call_stack;
const void *server_transport_data;
grpc_call_context_element *context;
} grpc_call_element_args;
@@ -144,23 +147,24 @@ struct grpc_call_element {
/* A channel stack tracks a set of related filters for one channel, and
guarantees they live within a single malloc() allocation */
-typedef struct {
+struct grpc_channel_stack {
+ grpc_stream_refcount refcount;
size_t count;
/* Memory required for a call stack (computed at channel stack
initialization) */
size_t call_stack_size;
-} grpc_channel_stack;
+};
/* A call stack tracks a set of related filters for one call, and guarantees
they live within a single malloc() allocation */
-typedef struct {
+struct grpc_call_stack {
/* shared refcount for this channel stack.
MUST be the first element: the underlying code calls destroy
with the address of the refcount, but higher layers prefer to think
about the address of the call stack itself. */
grpc_stream_refcount refcount;
size_t count;
-} grpc_call_stack;
+};
/* Get a channel element given a channel stack and its index */
grpc_channel_element *grpc_channel_stack_element(grpc_channel_stack *stack,
@@ -175,11 +179,11 @@ grpc_call_element *grpc_call_stack_element(grpc_call_stack *stack, size_t i);
size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count);
/* Initialize a channel stack given some filters */
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx,
+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, grpc_channel *master,
- const grpc_channel_args *args,
- grpc_channel_stack *stack);
+ size_t filter_count, const grpc_channel_args *args,
+ const char *name, grpc_channel_stack *stack);
/* Destroy a channel stack */
void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
grpc_channel_stack *stack);
@@ -199,14 +203,23 @@ void grpc_call_stack_set_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define grpc_call_stack_ref(call_stack, reason) \
+#define GRPC_CALL_STACK_REF(call_stack, reason) \
grpc_stream_ref(&(call_stack)->refcount, reason)
-#define grpc_call_stack_unref(exec_ctx, call_stack, reason) \
+#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
grpc_stream_unref(exec_ctx, &(call_stack)->refcount, reason)
+#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
+ grpc_stream_ref(&(channel_stack)->refcount, reason)
+#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
+ grpc_stream_unref(exec_ctx, &(channel_stack)->refcount, reason)
#else
-#define grpc_call_stack_ref(call_stack) grpc_stream_ref(&(call_stack)->refcount)
-#define grpc_call_stack_unref(exec_ctx, call_stack) \
+#define GRPC_CALL_STACK_REF(call_stack, reason) \
+ grpc_stream_ref(&(call_stack)->refcount)
+#define GRPC_CALL_STACK_UNREF(exec_ctx, call_stack, reason) \
grpc_stream_unref(exec_ctx, &(call_stack)->refcount)
+#define GRPC_CHANNEL_STACK_REF(channel_stack, reason) \
+ grpc_stream_ref(&(channel_stack)->refcount)
+#define GRPC_CHANNEL_STACK_UNREF(exec_ctx, channel_stack, reason) \
+ grpc_stream_unref(exec_ctx, &(channel_stack)->refcount)
#endif
/* Destroy a call stack */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 020138bf15..385ae3be9b 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -59,11 +59,6 @@ typedef struct client_channel_channel_data {
grpc_resolver *resolver;
/** have we started resolving this channel */
int started_resolving;
- /** master channel - the grpc_channel instance that ultimately owns
- this channel_data via its channel stack.
- We occasionally use this to bump the refcount on the master channel
- to keep ourselves alive through an asynchronous operation. */
- grpc_channel *master;
/** mutex protecting client configuration, including all
variables below in this data structure */
@@ -81,8 +76,10 @@ typedef struct client_channel_channel_data {
grpc_connectivity_state_tracker state_tracker;
/** when an lb_policy arrives, should we try to exit idle */
int exit_idle_when_lb_policy_arrives;
- /** pollset_set of interested parties in a new connection */
- grpc_pollset_set pollset_set;
+ /** owning stack */
+ grpc_channel_stack *owning_stack;
+ /** interested parties */
+ grpc_pollset_set interested_parties;
} channel_data;
/** We create one watcher for each new lb_policy that is returned from a
@@ -103,9 +100,7 @@ typedef struct {
} waiting_call;
static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
- channel_data *chand = elem->channel_data;
- return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data,
- chand->master);
+ return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
}
static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@@ -121,10 +116,18 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
static void on_lb_policy_state_changed_locked(
grpc_exec_ctx *exec_ctx, lb_policy_connectivity_watcher *w) {
+ 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;
- grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, w->state,
+ if (publish_state == GRPC_CHANNEL_FATAL_FAILURE &&
+ w->chand->resolver != NULL) {
+ publish_state = GRPC_CHANNEL_TRANSIENT_FAILURE;
+ grpc_resolver_channel_saw_error(exec_ctx, w->chand->resolver);
+ GRPC_LB_POLICY_UNREF(exec_ctx, w->chand->lb_policy, "channel");
+ w->chand->lb_policy = NULL;
+ }
+ grpc_connectivity_state_set(exec_ctx, &w->chand->state_tracker, publish_state,
"lb_changed");
if (w->state != GRPC_CHANNEL_FATAL_FAILURE) {
watch_lb_policy(exec_ctx, w->chand, w->lb_policy, w->state);
@@ -139,7 +142,7 @@ static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
on_lb_policy_state_changed_locked(exec_ctx, w);
gpr_mu_unlock(&w->chand->mu_config);
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->chand->master, "watch_lb_policy");
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
gpr_free(w);
}
@@ -147,7 +150,7 @@ static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
grpc_lb_policy *lb_policy,
grpc_connectivity_state current_state) {
lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w));
- GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy");
+ GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
w->chand = chand;
grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
@@ -179,6 +182,11 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->incoming_configuration = NULL;
+ if (lb_policy != NULL) {
+ grpc_pollset_set_add_pollset_set(exec_ctx, &lb_policy->interested_parties,
+ &chand->interested_parties);
+ }
+
gpr_mu_lock(&chand->mu_config);
old_lb_policy = chand->lb_policy;
chand->lb_policy = lb_policy;
@@ -200,7 +208,7 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
watch_lb_policy(exec_ctx, chand, lb_policy, state);
}
gpr_mu_unlock(&chand->mu_config);
- GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+ GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
&chand->on_config_changed);
GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel-next");
@@ -222,7 +230,9 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
if (old_lb_policy != NULL) {
- grpc_lb_policy_shutdown(exec_ctx, old_lb_policy);
+ grpc_pollset_set_del_pollset_set(exec_ctx,
+ &old_lb_policy->interested_parties,
+ &chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel");
}
@@ -230,20 +240,22 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "config_change");
}
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->master, "resolver");
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->owning_stack, "resolver");
}
static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_transport_op *op) {
- grpc_lb_policy *lb_policy = NULL;
channel_data *chand = elem->channel_data;
grpc_resolver *destroy_resolver = NULL;
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
GPR_ASSERT(op->set_accept_stream == NULL);
- GPR_ASSERT(op->bind_pollset == NULL);
+ if (op->bind_pollset != NULL) {
+ grpc_pollset_set_add_pollset(exec_ctx, &chand->interested_parties,
+ op->bind_pollset);
+ }
gpr_mu_lock(&chand->mu_config);
if (op->on_connectivity_state_change != NULL) {
@@ -254,9 +266,14 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
op->connectivity_state = NULL;
}
- lb_policy = chand->lb_policy;
- if (lb_policy) {
- GRPC_LB_POLICY_REF(lb_policy, "broadcast");
+ if (op->send_ping != NULL) {
+ if (chand->lb_policy == NULL) {
+ grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, 0);
+ } else {
+ grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
+ op->bind_pollset = NULL;
+ }
+ op->send_ping = NULL;
}
if (op->disconnect && chand->resolver != NULL) {
@@ -265,7 +282,9 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
destroy_resolver = chand->resolver;
chand->resolver = NULL;
if (chand->lb_policy != NULL) {
- grpc_lb_policy_shutdown(exec_ctx, chand->lb_policy);
+ 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;
}
@@ -276,16 +295,11 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_resolver_shutdown(exec_ctx, destroy_resolver);
GRPC_RESOLVER_UNREF(exec_ctx, destroy_resolver, "channel");
}
-
- if (lb_policy) {
- grpc_lb_policy_broadcast(exec_ctx, lb_policy, op);
- GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "broadcast");
- }
}
typedef struct {
grpc_metadata_batch *initial_metadata;
- grpc_subchannel **subchannel;
+ grpc_connected_subchannel **connected_subchannel;
grpc_closure *on_ready;
grpc_call_element *elem;
grpc_closure closure;
@@ -293,17 +307,17 @@ typedef struct {
static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_metadata_batch *initial_metadata,
- grpc_subchannel **subchannel,
+ grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready);
static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) {
continue_picking_args *cpa = arg;
if (!success) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
- } else if (cpa->subchannel == NULL) {
+ } else if (cpa->connected_subchannel == NULL) {
/* cancelled, do nothing */
} else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
- cpa->subchannel, cpa->on_ready)) {
+ cpa->connected_subchannel, cpa->on_ready)) {
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 1);
}
gpr_free(cpa);
@@ -311,7 +325,7 @@ static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) {
static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
grpc_metadata_batch *initial_metadata,
- grpc_subchannel **subchannel,
+ grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready) {
grpc_call_element *elem = elemp;
channel_data *chand = elem->channel_data;
@@ -319,18 +333,19 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
continue_picking_args *cpa;
grpc_closure *closure;
- GPR_ASSERT(subchannel);
+ GPR_ASSERT(connected_subchannel);
gpr_mu_lock(&chand->mu_config);
if (initial_metadata == NULL) {
if (chand->lb_policy != NULL) {
- grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy, subchannel);
+ grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy,
+ connected_subchannel);
}
for (closure = chand->waiting_for_config_closures.head; closure != NULL;
closure = grpc_closure_next(closure)) {
cpa = closure->cb_arg;
- if (cpa->subchannel == subchannel) {
- cpa->subchannel = NULL;
+ if (cpa->connected_subchannel == connected_subchannel) {
+ cpa->connected_subchannel = NULL;
grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
}
}
@@ -338,21 +353,22 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
return 1;
}
if (chand->lb_policy != NULL) {
- int r = grpc_lb_policy_pick(exec_ctx, chand->lb_policy, calld->pollset,
- initial_metadata, subchannel, on_ready);
+ int r =
+ grpc_lb_policy_pick(exec_ctx, chand->lb_policy, calld->pollset,
+ initial_metadata, connected_subchannel, on_ready);
gpr_mu_unlock(&chand->mu_config);
return r;
}
if (chand->resolver != NULL && !chand->started_resolving) {
chand->started_resolving = 1;
- GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+ GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, chand->resolver,
&chand->incoming_configuration,
&chand->on_config_changed);
}
cpa = gpr_malloc(sizeof(*cpa));
cpa->initial_metadata = initial_metadata;
- cpa->subchannel = subchannel;
+ cpa->connected_subchannel = connected_subchannel;
cpa->on_ready = on_ready;
cpa->elem = elem;
grpc_closure_init(&cpa->closure, continue_picking, cpa);
@@ -364,7 +380,8 @@ static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
/* Constructor for call_data */
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {
- grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem);
+ grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
+ args->call_stack);
}
/* Destructor for call_data */
@@ -385,12 +402,12 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
gpr_mu_init(&chand->mu_config);
- chand->master = args->master;
- grpc_pollset_set_init(&chand->pollset_set);
grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
+ chand->owning_stack = args->channel_stack;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_channel");
+ grpc_pollset_set_init(&chand->interested_parties);
}
/* Destructor for channel_data */
@@ -403,10 +420,13 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
}
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");
}
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
- grpc_pollset_set_destroy(&chand->pollset_set);
+ grpc_pollset_set_destroy(&chand->interested_parties);
gpr_mu_destroy(&chand->mu_config);
}
@@ -435,7 +455,7 @@ void grpc_client_channel_set_resolver(grpc_exec_ctx *exec_ctx,
if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
chand->exit_idle_when_lb_policy_arrives) {
chand->started_resolving = 1;
- GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+ GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}
@@ -454,7 +474,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
} else {
chand->exit_idle_when_lb_policy_arrives = 1;
if (!chand->started_resolving && chand->resolver != NULL) {
- GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
+ GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
chand->started_resolving = 1;
grpc_resolver_next(exec_ctx, chand->resolver,
&chand->incoming_configuration,
@@ -466,32 +486,39 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
return out;
}
+typedef struct {
+ channel_data *chand;
+ grpc_pollset *pollset;
+ grpc_closure *on_complete;
+ grpc_closure my_closure;
+} external_connectivity_watcher;
+
+static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
+ int iomgr_success) {
+ external_connectivity_watcher *w = arg;
+ grpc_closure *follow_up = w->on_complete;
+ grpc_pollset_set_del_pollset(exec_ctx, &w->chand->interested_parties,
+ w->pollset);
+ 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);
+}
+
void grpc_client_channel_watch_connectivity_state(
- grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete) {
channel_data *chand = elem->channel_data;
+ external_connectivity_watcher *w = gpr_malloc(sizeof(*w));
+ w->chand = chand;
+ w->pollset = pollset;
+ w->on_complete = on_complete;
+ grpc_pollset_set_add_pollset(exec_ctx, &chand->interested_parties, pollset);
+ grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
+ GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
+ "external_connectivity_watcher");
gpr_mu_lock(&chand->mu_config);
grpc_connectivity_state_notify_on_state_change(
- exec_ctx, &chand->state_tracker, state, on_complete);
+ exec_ctx, &chand->state_tracker, state, &w->my_closure);
gpr_mu_unlock(&chand->mu_config);
}
-
-grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
- grpc_channel_element *elem) {
- channel_data *chand = elem->channel_data;
- return &chand->pollset_set;
-}
-
-void grpc_client_channel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem,
- grpc_pollset *pollset) {
- channel_data *chand = elem->channel_data;
- grpc_pollset_set_add_pollset(exec_ctx, &chand->pollset_set, pollset);
-}
-
-void grpc_client_channel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem,
- grpc_pollset *pollset) {
- channel_data *chand = elem->channel_data;
- grpc_pollset_set_del_pollset(exec_ctx, &chand->pollset_set, pollset);
-}
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
index 5103f07a43..d9bc4971f1 100644
--- a/src/core/channel/client_channel.h
+++ b/src/core/channel/client_channel.h
@@ -57,17 +57,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
void grpc_client_channel_watch_connectivity_state(
- grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete);
-grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(
- grpc_channel_element *elem);
-
-void grpc_client_channel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *channel,
- grpc_pollset *pollset);
-void grpc_client_channel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *channel,
- grpc_pollset *pollset);
-
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/channel/client_uchannel.c b/src/core/channel/client_uchannel.c
index 456ffb7371..2c0b07d8bf 100644
--- a/src/core/channel/client_uchannel.c
+++ b/src/core/channel/client_uchannel.c
@@ -58,13 +58,13 @@ typedef struct client_uchannel_channel_data {
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
to keep ourselves alive through an asynchronous operation. */
- grpc_channel *master;
+ grpc_channel_stack *owning_stack;
/** connectivity state being tracked */
grpc_connectivity_state_tracker state_tracker;
/** the subchannel wrapped by the microchannel */
- grpc_subchannel *subchannel;
+ grpc_connected_subchannel *connected_subchannel;
/** the callback used to stay subscribed to subchannel connectivity
* notifications */
@@ -84,15 +84,13 @@ static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
chand->subchannel_connectivity,
"uchannel_monitor_subchannel");
- grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel,
- &chand->subchannel_connectivity,
- &chand->connectivity_cb);
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, chand->connected_subchannel, NULL,
+ &chand->subchannel_connectivity, &chand->connectivity_cb);
}
static char *cuc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
- channel_data *chand = elem->channel_data;
- return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data,
- chand->master);
+ return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
}
static void cuc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@@ -128,11 +126,11 @@ static void cuc_start_transport_op(grpc_exec_ctx *exec_ctx,
static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
grpc_metadata_batch *initial_metadata,
- grpc_subchannel **subchannel,
+ grpc_connected_subchannel **connected_subchannel,
grpc_closure *on_ready) {
channel_data *chand = arg;
GPR_ASSERT(initial_metadata != NULL);
- *subchannel = chand->subchannel;
+ *connected_subchannel = chand->connected_subchannel;
return 1;
}
@@ -140,7 +138,7 @@ static int cuc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
static void cuc_init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
grpc_call_element_args *args) {
grpc_subchannel_call_holder_init(elem->call_data, cuc_pick_subchannel,
- elem->channel_data);
+ elem->channel_data, args->call_stack);
}
/* Destructor for call_data */
@@ -158,7 +156,7 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
GPR_ASSERT(args->is_last);
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
- chand->master = args->master;
+ chand->owning_stack = args->channel_stack;
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_uchannel");
gpr_mu_init(&chand->mu_state);
@@ -168,10 +166,14 @@ static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
static void cuc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
channel_data *chand = elem->channel_data;
- grpc_subchannel_state_change_unsubscribe(exec_ctx, chand->subchannel,
- &chand->connectivity_cb);
+ /* cancel subscription */
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, chand->connected_subchannel, NULL, NULL,
+ &chand->connectivity_cb);
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
gpr_mu_destroy(&chand->mu_state);
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, chand->connected_subchannel,
+ "uchannel");
}
static void cuc_set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
@@ -191,23 +193,14 @@ grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
channel_data *chand = elem->channel_data;
grpc_connectivity_state out;
- out = grpc_connectivity_state_check(&chand->state_tracker);
gpr_mu_lock(&chand->mu_state);
- if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
- grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
- GRPC_CHANNEL_CONNECTING,
- "uchannel_connecting_changed");
- chand->subchannel_connectivity = out;
- grpc_subchannel_notify_on_state_change(exec_ctx, chand->subchannel,
- &chand->subchannel_connectivity,
- &chand->connectivity_cb);
- }
+ out = grpc_connectivity_state_check(&chand->state_tracker);
gpr_mu_unlock(&chand->mu_state);
return out;
}
void grpc_client_uchannel_watch_connectivity_state(
- grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete) {
channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu_state);
@@ -216,40 +209,11 @@ void grpc_client_uchannel_watch_connectivity_state(
gpr_mu_unlock(&chand->mu_state);
}
-grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set(
- grpc_channel_element *elem) {
- channel_data *chand = elem->channel_data;
- grpc_channel_element *parent_elem;
- gpr_mu_lock(&chand->mu_state);
- parent_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(
- grpc_subchannel_get_master(chand->subchannel)));
- gpr_mu_unlock(&chand->mu_state);
- return grpc_client_channel_get_connecting_pollset_set(parent_elem);
-}
-
-void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem,
- grpc_pollset *pollset) {
- grpc_pollset_set *master_pollset_set =
- grpc_client_uchannel_get_connecting_pollset_set(elem);
- grpc_pollset_set_add_pollset(exec_ctx, master_pollset_set, pollset);
-}
-
-void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem,
- grpc_pollset *pollset) {
- grpc_pollset_set *master_pollset_set =
- grpc_client_uchannel_get_connecting_pollset_set(elem);
- grpc_pollset_set_del_pollset(exec_ctx, master_pollset_set, pollset);
-}
-
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel_args *args) {
grpc_channel *channel = NULL;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
- grpc_channel *master = grpc_subchannel_get_master(subchannel);
- char *target = grpc_channel_get_target(master);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
size_t n = 0;
@@ -261,19 +225,19 @@ grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
GPR_ASSERT(n <= MAX_FILTERS);
channel =
- grpc_channel_create_from_filters(&exec_ctx, target, filters, n, args, 1);
+ grpc_channel_create_from_filters(&exec_ctx, NULL, filters, n, args, 1);
- gpr_free(target);
return channel;
}
-void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel,
- grpc_subchannel *subchannel) {
+void grpc_client_uchannel_set_connected_subchannel(
+ grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel) {
grpc_channel_element *elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(uchannel));
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
gpr_mu_lock(&chand->mu_state);
- chand->subchannel = subchannel;
+ chand->connected_subchannel = connected_subchannel;
+ GRPC_CONNECTED_SUBCHANNEL_REF(connected_subchannel, "uchannel");
gpr_mu_unlock(&chand->mu_state);
}
diff --git a/src/core/channel/client_uchannel.h b/src/core/channel/client_uchannel.h
index dfe6695ae3..92a831493c 100644
--- a/src/core/channel/client_uchannel.h
+++ b/src/core/channel/client_uchannel.h
@@ -48,23 +48,13 @@ grpc_connectivity_state grpc_client_uchannel_check_connectivity_state(
grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
void grpc_client_uchannel_watch_connectivity_state(
- grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+ grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset,
grpc_connectivity_state *state, grpc_closure *on_complete);
-grpc_pollset_set *grpc_client_uchannel_get_connecting_pollset_set(
- grpc_channel_element *elem);
-
-void grpc_client_uchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *channel,
- grpc_pollset *pollset);
-void grpc_client_uchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *channel,
- grpc_pollset *pollset);
-
grpc_channel *grpc_client_uchannel_create(grpc_subchannel *subchannel,
grpc_channel_args *args);
-void grpc_client_uchannel_set_subchannel(grpc_channel *uchannel,
- grpc_subchannel *subchannel);
+void grpc_client_uchannel_set_connected_subchannel(
+ grpc_channel *uchannel, grpc_connected_subchannel *connected_subchannel);
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_MICROCHANNEL_H */
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index fc8b425e47..cc8e191628 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -39,11 +39,11 @@
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
-#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
-#include "src/core/profiling/timers.h"
+#include "src/core/channel/compress_filter.h"
#include "src/core/compression/algorithm_metadata.h"
#include "src/core/compression/message_compress.h"
+#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
#include "src/core/transport/static_metadata.h"
@@ -288,8 +288,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem) {
-}
+ grpc_channel_element *elem) {}
const grpc_channel_filter grpc_compress_filter = {
compress_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data),
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 0e1efd965a..e8eb9dcfc5 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -89,9 +89,9 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
int r;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
- r = grpc_transport_init_stream(exec_ctx, chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- args->refcount, args->server_transport_data);
+ r = grpc_transport_init_stream(
+ exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+ &args->call_stack->refcount, args->server_transport_data);
GPR_ASSERT(r == 0);
}
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index b9a30cdaf2..65cfb778bb 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -31,12 +31,12 @@
*/
#include "src/core/channel/http_client_filter.h"
-#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include "src/core/support/string.h"
+#include <string.h>
#include "src/core/profiling/timers.h"
+#include "src/core/support/string.h"
#include "src/core/transport/static_metadata.h"
typedef struct call_data {
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index c1645c2ba0..ae8660da92 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -33,9 +33,9 @@
#include "src/core/channel/http_server_filter.h"
-#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <string.h>
#include "src/core/profiling/timers.h"
#include "src/core/transport/static_metadata.h"
@@ -124,7 +124,6 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
omitted */
grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
- GRPC_MDELEM_UNREF(md);
calld->seen_authority = 1;
return authority;
} else {
@@ -225,8 +224,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
/* Destructor for channel data */
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem) {
-}
+ grpc_channel_element *elem) {}
const grpc_channel_filter grpc_http_server_filter = {
hs_start_transport_op, grpc_channel_next_op, sizeof(call_data),
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
deleted file mode 100644
index 2fbf1c06bb..0000000000
--- a/src/core/channel/noop_filter.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/noop_filter.h"
-#include <grpc/support/log.h>
-
-typedef struct call_data {
- int unused; /* C89 requires at least one struct element */
-} call_data;
-
-typedef struct channel_data {
- int unused; /* C89 requires at least one struct element */
-} channel_data;
-
-/* used to silence 'variable not used' warnings */
-static void ignore_unused(void *ignored) {}
-
-static void noop_mutate_op(grpc_call_element *elem,
- grpc_transport_stream_op *op) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(calld);
- ignore_unused(channeld);
-
- /* do nothing */
-}
-
-/* Called either:
- - in response to an API call (or similar) from above, to send something
- - a network event (or similar) from below, to receive something
- op contains type and call direction information, in addition to the data
- that is being sent or received. */
-static void noop_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem,
- grpc_transport_stream_op *op) {
- noop_mutate_op(elem, op);
-
- /* pass control down the stack */
- grpc_call_next_op(exec_ctx, elem, op);
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_call_element_args *args) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- /* initialize members */
- calld->unused = channeld->unused;
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
- grpc_call_element *elem) {}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem,
- grpc_channel_element_args *args) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- /* The last filter tends to be implemented differently to
- handle the case that there's no 'next' filter to call on the down
- path */
- GPR_ASSERT(!args->is_last);
-
- /* initialize members */
- channeld->unused = 0;
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
- grpc_channel_element *elem) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-}
-
-const grpc_channel_filter grpc_no_op_filter = {
- noop_start_transport_stream_op, grpc_channel_next_op, sizeof(call_data),
- init_call_elem, grpc_call_stack_ignore_set_pollset, destroy_call_elem,
- sizeof(channel_data), init_channel_elem, destroy_channel_elem,
- grpc_call_next_get_peer, "no-op"};
diff --git a/src/core/channel/subchannel_call_holder.c b/src/core/channel/subchannel_call_holder.c
index 7251714519..f5da41f3cd 100644
--- a/src/core/channel/subchannel_call_holder.c
+++ b/src/core/channel/subchannel_call_holder.c
@@ -44,7 +44,6 @@
static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
int success);
-static void call_ready(grpc_exec_ctx *exec_ctx, void *holder, int success);
static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
int success);
@@ -58,16 +57,17 @@ static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
void grpc_subchannel_call_holder_init(
grpc_subchannel_call_holder *holder,
grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
- void *pick_subchannel_arg) {
+ void *pick_subchannel_arg, grpc_call_stack *owning_call) {
gpr_atm_rel_store(&holder->subchannel_call, 0);
holder->pick_subchannel = pick_subchannel;
holder->pick_subchannel_arg = pick_subchannel_arg;
gpr_mu_init(&holder->mu);
- holder->subchannel = NULL;
+ holder->connected_subchannel = NULL;
holder->waiting_ops = NULL;
holder->waiting_ops_count = 0;
holder->waiting_ops_capacity = 0;
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+ holder->owning_call = owning_call;
}
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
@@ -125,13 +125,9 @@ retry:
case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
fail_locked(exec_ctx, holder);
break;
- case GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL:
- grpc_subchannel_cancel_create_call(exec_ctx, holder->subchannel,
- &holder->subchannel_call);
- break;
case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
- &holder->subchannel, NULL);
+ &holder->connected_subchannel, NULL);
break;
}
gpr_mu_unlock(&holder->mu);
@@ -142,28 +138,27 @@ retry:
}
/* if we don't have a subchannel, try to get one */
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
- holder->subchannel == NULL && op->send_initial_metadata != NULL) {
+ holder->connected_subchannel == NULL &&
+ op->send_initial_metadata != NULL) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
grpc_closure_init(&holder->next_step, subchannel_ready, holder);
- if (holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg,
- op->send_initial_metadata, &holder->subchannel,
- &holder->next_step)) {
+ GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel");
+ if (holder->pick_subchannel(
+ exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata,
+ &holder->connected_subchannel, &holder->next_step)) {
holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+ GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
}
}
/* if we've got a subchannel, then let's ask it to create a call */
if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
- holder->subchannel != NULL) {
- holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL;
- grpc_closure_init(&holder->next_step, call_ready, holder);
- if (grpc_subchannel_create_call(exec_ctx, holder->subchannel,
- holder->pollset, &holder->subchannel_call,
- &holder->next_step)) {
- /* got one immediately - continue the op (and any waiting ops) */
- holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
- retry_waiting_locked(exec_ctx, holder);
- goto retry;
- }
+ holder->connected_subchannel != NULL) {
+ gpr_atm_rel_store(
+ &holder->subchannel_call,
+ (gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call(
+ exec_ctx, holder->connected_subchannel, holder->pollset));
+ retry_waiting_locked(exec_ctx, holder);
+ goto retry;
}
/* nothing to be done but wait */
add_waiting_locked(holder, op);
@@ -179,36 +174,18 @@ static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) {
GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
call = GET_CALL(holder);
GPR_ASSERT(call == NULL || call == CANCELLED_CALL);
- if (holder->subchannel == NULL) {
- holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+ holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+ if (holder->connected_subchannel == NULL) {
fail_locked(exec_ctx, holder);
} else {
- grpc_closure_init(&holder->next_step, call_ready, holder);
- if (grpc_subchannel_create_call(exec_ctx, holder->subchannel,
- holder->pollset, &holder->subchannel_call,
- &holder->next_step)) {
- holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
- /* got one immediately - continue the op (and any waiting ops) */
- retry_waiting_locked(exec_ctx, holder);
- }
- }
- gpr_mu_unlock(&holder->mu);
-}
-
-static void call_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) {
- grpc_subchannel_call_holder *holder = arg;
- GPR_TIMER_BEGIN("call_ready", 0);
- gpr_mu_lock(&holder->mu);
- GPR_ASSERT(holder->creation_phase ==
- GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL);
- holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
- if (GET_CALL(holder) != NULL) {
+ gpr_atm_rel_store(
+ &holder->subchannel_call,
+ (gpr_atm)(gpr_uintptr)grpc_connected_subchannel_create_call(
+ exec_ctx, holder->connected_subchannel, holder->pollset));
retry_waiting_locked(exec_ctx, holder);
- } else {
- fail_locked(exec_ctx, holder);
}
gpr_mu_unlock(&holder->mu);
- GPR_TIMER_END("call_ready", 0);
+ GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
}
typedef struct {
@@ -270,14 +247,13 @@ static void fail_locked(grpc_exec_ctx *exec_ctx,
holder->waiting_ops_count = 0;
}
-char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
- grpc_subchannel_call_holder *holder,
- grpc_channel *master) {
+char *grpc_subchannel_call_holder_get_peer(
+ grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) {
grpc_subchannel_call *subchannel_call = GET_CALL(holder);
if (subchannel_call) {
return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
} else {
- return grpc_channel_get_target(master);
+ return NULL;
}
}
diff --git a/src/core/channel/subchannel_call_holder.h b/src/core/channel/subchannel_call_holder.h
index bda051c566..9cf72c6cf7 100644
--- a/src/core/channel/subchannel_call_holder.h
+++ b/src/core/channel/subchannel_call_holder.h
@@ -42,12 +42,11 @@
called when the subchannel is available) */
typedef int (*grpc_subchannel_call_holder_pick_subchannel)(
grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata,
- grpc_subchannel **subchannel, grpc_closure *on_ready);
+ grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready);
typedef enum {
GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
- GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL,
- GRPC_SUBCHANNEL_CALL_HOLDER_CREATING_CALL
+ GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
} grpc_subchannel_call_holder_creation_phase;
/** Wrapper for holding a pointer to grpc_subchannel_call, and the
@@ -71,7 +70,7 @@ typedef struct grpc_subchannel_call_holder {
gpr_mu mu;
grpc_subchannel_call_holder_creation_phase creation_phase;
- grpc_subchannel *subchannel;
+ grpc_connected_subchannel *connected_subchannel;
grpc_pollset *pollset;
grpc_transport_stream_op *waiting_ops;
@@ -79,12 +78,14 @@ typedef struct grpc_subchannel_call_holder {
size_t waiting_ops_capacity;
grpc_closure next_step;
+
+ grpc_call_stack *owning_call;
} grpc_subchannel_call_holder;
void grpc_subchannel_call_holder_init(
grpc_subchannel_call_holder *holder,
grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
- void *pick_subchannel_arg);
+ void *pick_subchannel_arg, grpc_call_stack *owning_call);
void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder);
@@ -92,7 +93,6 @@ void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call_holder *holder,
grpc_transport_stream_op *op);
char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
- grpc_subchannel_call_holder *holder,
- grpc_channel *master);
+ grpc_subchannel_call_holder *holder);
#endif
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 93312abb00..37de3e9f68 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -42,7 +42,7 @@
typedef struct pending_pick {
struct pending_pick *next;
grpc_pollset *pollset;
- grpc_subchannel **target;
+ grpc_connected_subchannel **target;
grpc_closure *on_complete;
} pending_pick;
@@ -60,7 +60,7 @@ typedef struct {
/** the selected channel
TODO(ctiller): this should be atomically set so we don't
need to take a mutex in the common case */
- grpc_subchannel *selected;
+ grpc_connected_subchannel *selected;
/** have we started picking? */
int started_picking;
/** are we shut down? */
@@ -76,24 +76,6 @@ typedef struct {
grpc_connectivity_state_tracker state_tracker;
} pick_first_lb_policy;
-static void del_interested_parties_locked(grpc_exec_ctx *exec_ctx,
- pick_first_lb_policy *p) {
- pending_pick *pp;
- for (pp = p->pending_picks; pp; pp = pp->next) {
- grpc_subchannel_del_interested_party(
- exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset);
- }
-}
-
-static void add_interested_parties_locked(grpc_exec_ctx *exec_ctx,
- pick_first_lb_policy *p) {
- pending_pick *pp;
- for (pp = p->pending_picks; pp; pp = pp->next) {
- grpc_subchannel_add_interested_party(
- exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset);
- }
-}
-
void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
size_t i;
@@ -102,7 +84,7 @@ void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
}
if (p->selected) {
- GRPC_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
}
grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
gpr_free(p->subchannels);
@@ -114,16 +96,26 @@ void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
- del_interested_parties_locked(exec_ctx, p);
p->shutdown = 1;
pp = p->pending_picks;
p->pending_picks = NULL;
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
+ /* cancel subscription */
+ if (p->selected != NULL) {
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
+ } else {
+ grpc_subchannel_notify_on_state_change(
+ exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
+ &p->connectivity_changed);
+ }
gpr_mu_unlock(&p->mu);
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, 1);
gpr_free(pp);
pp = next;
@@ -131,7 +123,7 @@ void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_subchannel **target) {
+ grpc_connected_subchannel **target) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
@@ -140,8 +132,8 @@ 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_subchannel_del_interested_party(
- exec_ctx, p->subchannels[p->checking_subchannel], pp->pollset);
+ grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
+ pp->pollset);
*target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
gpr_free(pp);
@@ -158,10 +150,11 @@ static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
p->started_picking = 1;
p->checking_subchannel = 0;
p->checking_connectivity = GRPC_CHANNEL_IDLE;
- GRPC_LB_POLICY_REF(&p->base, "pick_first_connectivity");
+ GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel],
- &p->checking_connectivity, &p->connectivity_changed);
+ &p->base.interested_parties, &p->checking_connectivity,
+ &p->connectivity_changed);
}
void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
@@ -174,8 +167,8 @@ void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
- grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
- grpc_closure *on_complete) {
+ grpc_metadata_batch *initial_metadata,
+ grpc_connected_subchannel **target, grpc_closure *on_complete) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
pending_pick *pp;
gpr_mu_lock(&p->mu);
@@ -187,8 +180,8 @@ int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) {
start_picking(exec_ctx, p);
}
- grpc_subchannel_add_interested_party(
- exec_ctx, p->subchannels[p->checking_subchannel], pollset);
+ grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties,
+ pollset);
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
pp->pollset = pollset;
@@ -204,25 +197,17 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
pick_first_lb_policy *p = arg;
size_t i;
- grpc_transport_op op;
size_t num_subchannels = p->num_subchannels;
grpc_subchannel **subchannels;
- grpc_subchannel *exclude_subchannel;
gpr_mu_lock(&p->mu);
subchannels = p->subchannels;
p->num_subchannels = 0;
p->subchannels = NULL;
- exclude_subchannel = p->selected;
gpr_mu_unlock(&p->mu);
- GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "destroy_subchannels");
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
for (i = 0; i < num_subchannels; i++) {
- if (subchannels[i] != exclude_subchannel) {
- memset(&op, 0, sizeof(op));
- op.disconnect = 1;
- grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], &op);
- }
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
}
@@ -232,23 +217,28 @@ static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
pick_first_lb_policy *p = arg;
+ grpc_subchannel *selected_subchannel;
pending_pick *pp;
gpr_mu_lock(&p->mu);
if (p->shutdown) {
gpr_mu_unlock(&p->mu);
- GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
return;
} else if (p->selected != NULL) {
+ if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
+ /* if the selected channel goes bad, we're done */
+ p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
+ }
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
p->checking_connectivity, "selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
- grpc_subchannel_notify_on_state_change(exec_ctx, p->selected,
- &p->checking_connectivity,
- &p->connectivity_changed);
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, p->selected, &p->base.interested_parties,
+ &p->checking_connectivity, &p->connectivity_changed);
} else {
- GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
}
} else {
loop:
@@ -256,39 +246,41 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready");
- p->selected = p->subchannels[p->checking_subchannel];
- GRPC_SUBCHANNEL_REF(p->selected, "picked_first");
+ selected_subchannel = p->subchannels[p->checking_subchannel];
+ p->selected =
+ grpc_subchannel_get_connected_subchannel(selected_subchannel);
+ GPR_ASSERT(p->selected);
+ GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked_first");
/* drop the pick list: we are connected now */
- GRPC_LB_POLICY_REF(&p->base, "destroy_subchannels");
+ GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
grpc_exec_ctx_enqueue(exec_ctx,
grpc_closure_create(destroy_subchannels, p), 1);
/* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = p->selected;
- grpc_subchannel_del_interested_party(exec_ctx, p->selected,
- pp->pollset);
+ grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
+ pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp);
}
- grpc_subchannel_notify_on_state_change(exec_ctx, p->selected,
- &p->checking_connectivity,
- &p->connectivity_changed);
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, p->selected, &p->base.interested_parties,
+ &p->checking_connectivity, &p->connectivity_changed);
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure");
- del_interested_parties_locked(exec_ctx, p);
p->checking_subchannel =
(p->checking_subchannel + 1) % p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
- add_interested_parties_locked(exec_ctx, p);
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel],
- &p->checking_connectivity, &p->connectivity_changed);
+ &p->base.interested_parties, &p->checking_connectivity,
+ &p->connectivity_changed);
} else {
goto loop;
}
@@ -300,13 +292,13 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"connecting_changed");
grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel],
- &p->checking_connectivity, &p->connectivity_changed);
+ &p->base.interested_parties, &p->checking_connectivity,
+ &p->connectivity_changed);
break;
case GRPC_CHANNEL_FATAL_FAILURE:
- del_interested_parties_locked(exec_ctx, p);
- GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
- p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
+ GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
+ p->subchannels[p->num_subchannels]);
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
"pick_first");
if (p->num_subchannels == 0) {
@@ -319,7 +311,8 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp);
}
- GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
+ 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,
@@ -327,7 +320,6 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
p->checking_subchannel %= p->num_subchannels;
p->checking_connectivity = grpc_subchannel_check_connectivity(
p->subchannels[p->checking_subchannel]);
- add_interested_parties_locked(exec_ctx, p);
goto loop;
}
}
@@ -336,39 +328,6 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&p->mu);
}
-static void pf_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_transport_op *op) {
- pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
- size_t i;
- size_t n;
- grpc_subchannel **subchannels;
- grpc_subchannel *selected;
-
- gpr_mu_lock(&p->mu);
- n = p->num_subchannels;
- subchannels = gpr_malloc(n * sizeof(*subchannels));
- selected = p->selected;
- if (selected) {
- GRPC_SUBCHANNEL_REF(selected, "pf_broadcast_to_selected");
- }
- for (i = 0; i < n; i++) {
- subchannels[i] = p->subchannels[i];
- GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast");
- }
- gpr_mu_unlock(&p->mu);
-
- for (i = 0; i < n; i++) {
- if (selected == subchannels[i]) continue;
- grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], op);
- GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pf_broadcast");
- }
- if (p->selected) {
- grpc_subchannel_process_transport_op(exec_ctx, selected, op);
- GRPC_SUBCHANNEL_UNREF(exec_ctx, selected, "pf_broadcast_to_selected");
- }
- gpr_free(subchannels);
-}
-
static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *pol) {
pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
@@ -389,9 +348,21 @@ void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_unlock(&p->mu);
}
+void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_closure *closure) {
+ pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
+ gpr_mu_lock(&p->mu);
+ if (p->selected) {
+ grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
+ } else {
+ grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+ }
+ gpr_mu_unlock(&p->mu);
+}
+
static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
- pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_exit_idle,
- pf_broadcast, pf_check_connectivity, pf_notify_on_state_change};
+ pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_ping_one, pf_exit_idle,
+ pf_check_connectivity, pf_notify_on_state_change};
static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
diff --git a/src/core/client_config/lb_policies/round_robin.c b/src/core/client_config/lb_policies/round_robin.c
index 1ffe32fff2..d487456363 100644
--- a/src/core/client_config/lb_policies/round_robin.c
+++ b/src/core/client_config/lb_policies/round_robin.c
@@ -38,6 +38,8 @@
#include <grpc/support/alloc.h>
#include "src/core/transport/connectivity_state.h"
+typedef struct round_robin_lb_policy round_robin_lb_policy;
+
int grpc_lb_round_robin_trace = 0;
/** List of entities waiting for a pick.
@@ -46,7 +48,7 @@ int grpc_lb_round_robin_trace = 0;
typedef struct pending_pick {
struct pending_pick *next;
grpc_pollset *pollset;
- grpc_subchannel **target;
+ grpc_connected_subchannel **target;
grpc_closure *on_complete;
} pending_pick;
@@ -58,22 +60,27 @@ typedef struct ready_list {
} ready_list;
typedef struct {
- size_t subchannel_idx; /**< Index over p->subchannels */
- void *p; /**< round_robin_lb_policy instance */
-} connectivity_changed_cb_arg;
-
-typedef struct {
+ /** index within policy->subchannels */
+ size_t index;
+ /** backpointer to owning policy */
+ round_robin_lb_policy *policy;
+ /** subchannel itself */
+ grpc_subchannel *subchannel;
+ /** notification that connectivity has changed on subchannel */
+ grpc_closure connectivity_changed_closure;
+ /** this subchannels current position in subchannel->ready_list */
+ ready_list *ready_list_node;
+ /** last observed connectivity */
+ grpc_connectivity_state connectivity_state;
+} subchannel_data;
+
+struct round_robin_lb_policy {
/** base policy: must be first */
grpc_lb_policy base;
/** all our subchannels */
- grpc_subchannel **subchannels;
size_t num_subchannels;
-
- /** Callbacks, one per subchannel being watched, to be called when their
- * respective connectivity changes */
- grpc_closure *connectivity_changed_cbs;
- connectivity_changed_cb_arg *cb_args;
+ subchannel_data **subchannels;
/** mutex protecting remaining members */
gpr_mu mu;
@@ -81,8 +88,6 @@ typedef struct {
int started_picking;
/** are we shutting down? */
int shutdown;
- /** Connectivity state of the subchannels being watched */
- grpc_connectivity_state *subchannel_connectivity;
/** List of picks that are waiting on connectivity */
pending_pick *pending_picks;
@@ -93,13 +98,7 @@ typedef struct {
ready_list ready_list;
/** Last pick from the ready list. */
ready_list *ready_list_last_pick;
-
- /** Subchannel index to ready_list node.
- *
- * Kept in order to remove nodes from the ready list associated with a
- * subchannel */
- ready_list **subchannel_index_to_readylist_node;
-} round_robin_lb_policy;
+};
/** Returns the next subchannel from the connected list or NULL if the list is
* empty.
@@ -144,9 +143,9 @@ static void advance_last_picked_locked(round_robin_lb_policy *p) {
/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
* csc to the list of ready subchannels. */
static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
- grpc_subchannel *csc) {
+ grpc_subchannel *sc) {
ready_list *new_elem = gpr_malloc(sizeof(ready_list));
- new_elem->subchannel = csc;
+ new_elem->subchannel = sc;
if (p->ready_list.prev == NULL) {
/* first element */
new_elem->next = &p->ready_list;
@@ -160,7 +159,7 @@ static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
p->ready_list.prev = new_elem;
}
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, csc);
+ gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (SC %p)", new_elem, sc);
}
return new_elem;
}
@@ -200,28 +199,15 @@ static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
gpr_free(node);
}
-static void del_interested_parties_locked(grpc_exec_ctx *exec_ctx,
- round_robin_lb_policy *p,
- const size_t subchannel_idx) {
- pending_pick *pp;
- for (pp = p->pending_picks; pp; pp = pp->next) {
- grpc_subchannel_del_interested_party(
- exec_ctx, p->subchannels[subchannel_idx], pp->pollset);
- }
-}
-
void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
size_t i;
ready_list *elem;
for (i = 0; i < p->num_subchannels; i++) {
- del_interested_parties_locked(exec_ctx, p, i);
- }
- for (i = 0; i < p->num_subchannels; i++) {
- GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "round_robin");
+ subchannel_data *sd = p->subchannels[i];
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
+ gpr_free(sd);
}
- gpr_free(p->connectivity_changed_cbs);
- gpr_free(p->subchannel_connectivity);
grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
gpr_free(p->subchannels);
@@ -237,20 +223,15 @@ void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
gpr_free(elem);
elem = tmp;
}
- gpr_free(p->subchannel_index_to_readylist_node);
- gpr_free(p->cb_args);
gpr_free(p);
}
void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
- size_t i;
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
- gpr_mu_lock(&p->mu);
+ size_t i;
- for (i = 0; i < p->num_subchannels; i++) {
- del_interested_parties_locked(exec_ctx, p, i);
- }
+ gpr_mu_lock(&p->mu);
p->shutdown = 1;
while ((pp = p->pending_picks)) {
@@ -261,24 +242,26 @@ void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE, "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,
+ &sd->connectivity_changed_closure);
+ }
gpr_mu_unlock(&p->mu);
}
static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_subchannel **target) {
+ grpc_connected_subchannel **target) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
- size_t i;
gpr_mu_lock(&p->mu);
pp = p->pending_picks;
p->pending_picks = NULL;
while (pp != NULL) {
pending_pick *next = pp->next;
if (pp->target == target) {
- for (i = 0; i < p->num_subchannels; i++) {
- grpc_subchannel_add_interested_party(exec_ctx, p->subchannels[i],
- pp->pollset);
- }
+ grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
+ pp->pollset);
*target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
gpr_free(pp);
@@ -295,12 +278,16 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
size_t i;
p->started_picking = 1;
+ gpr_log(GPR_DEBUG, "LB_POLICY: p=%p num_subchannels=%d", p,
+ p->num_subchannels);
+
for (i = 0; i < p->num_subchannels; i++) {
- p->subchannel_connectivity[i] = GRPC_CHANNEL_IDLE;
- grpc_subchannel_notify_on_state_change(exec_ctx, p->subchannels[i],
- &p->subchannel_connectivity[i],
- &p->connectivity_changed_cbs[i]);
- GRPC_LB_POLICY_REF(&p->base, "round_robin_connectivity");
+ subchannel_data *sd = p->subchannels[i];
+ sd->connectivity_state = GRPC_CHANNEL_IDLE;
+ grpc_subchannel_notify_on_state_change(
+ exec_ctx, sd->subchannel, &p->base.interested_parties,
+ &sd->connectivity_state, &sd->connectivity_changed_closure);
+ GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
}
}
@@ -314,18 +301,18 @@ void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
}
int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
- grpc_metadata_batch *initial_metadata, grpc_subchannel **target,
- grpc_closure *on_complete) {
- size_t i;
+ grpc_metadata_batch *initial_metadata,
+ grpc_connected_subchannel **target, grpc_closure *on_complete) {
round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
pending_pick *pp;
ready_list *selected;
gpr_mu_lock(&p->mu);
if ((selected = peek_next_connected_locked(p))) {
gpr_mu_unlock(&p->mu);
- *target = selected->subchannel;
+ *target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) {
- gpr_log(GPR_DEBUG, "[RR PICK] TARGET <-- SUBCHANNEL %p (NODE %p)",
+ gpr_log(GPR_DEBUG,
+ "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected);
}
/* only advance the last picked pointer if the selection was used */
@@ -335,10 +322,8 @@ int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) {
start_picking(exec_ctx, p);
}
- for (i = 0; i < p->num_subchannels; i++) {
- grpc_subchannel_add_interested_party(exec_ctx, p->subchannels[i],
- pollset);
- }
+ grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties,
+ pollset);
pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks;
pp->pollset = pollset;
@@ -352,33 +337,25 @@ int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
- connectivity_changed_cb_arg *cb_arg = arg;
- round_robin_lb_policy *p = cb_arg->p;
- /* index over p->subchannels of this cb's subchannel */
- const size_t this_idx = cb_arg->subchannel_idx;
+ subchannel_data *sd = arg;
+ round_robin_lb_policy *p = sd->policy;
pending_pick *pp;
ready_list *selected;
int unref = 0;
- /* connectivity state of this cb's subchannel */
- grpc_connectivity_state *this_connectivity;
-
gpr_mu_lock(&p->mu);
- this_connectivity = &p->subchannel_connectivity[this_idx];
-
if (p->shutdown) {
unref = 1;
} else {
- switch (*this_connectivity) {
+ switch (sd->connectivity_state) {
case GRPC_CHANNEL_READY:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready");
/* add the newly connected subchannel to the list of connected ones.
* Note that it goes to the "end of the line". */
- p->subchannel_index_to_readylist_node[this_idx] =
- add_connected_sc_locked(p, p->subchannels[this_idx]);
+ sd->ready_list_node = add_connected_sc_locked(p, sd->subchannel);
/* at this point we know there's at least one suitable subchannel. Go
* ahead and pick one and notify the pending suitors in
* p->pending_picks. This preemtively replicates rr_pick()'s actions. */
@@ -390,60 +367,60 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
}
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
- *pp->target = selected->subchannel;
+ *pp->target =
+ grpc_subchannel_get_connected_subchannel(selected->subchannel);
if (grpc_lb_round_robin_trace) {
gpr_log(GPR_DEBUG,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected);
}
- grpc_subchannel_del_interested_party(exec_ctx, selected->subchannel,
- pp->pollset);
+ grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
+ pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp);
}
grpc_subchannel_notify_on_state_change(
- exec_ctx, p->subchannels[this_idx], this_connectivity,
- &p->connectivity_changed_cbs[this_idx]);
+ exec_ctx, sd->subchannel, &p->base.interested_parties,
+ &sd->connectivity_state, &sd->connectivity_changed_closure);
break;
case GRPC_CHANNEL_CONNECTING:
case GRPC_CHANNEL_IDLE:
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
- *this_connectivity, "connecting_changed");
+ sd->connectivity_state,
+ "connecting_changed");
grpc_subchannel_notify_on_state_change(
- exec_ctx, p->subchannels[this_idx], this_connectivity,
- &p->connectivity_changed_cbs[this_idx]);
+ exec_ctx, sd->subchannel, &p->base.interested_parties,
+ &sd->connectivity_state, &sd->connectivity_changed_closure);
break;
case GRPC_CHANNEL_TRANSIENT_FAILURE:
- del_interested_parties_locked(exec_ctx, p, this_idx);
/* renew state notification */
grpc_subchannel_notify_on_state_change(
- exec_ctx, p->subchannels[this_idx], this_connectivity,
- &p->connectivity_changed_cbs[this_idx]);
+ exec_ctx, sd->subchannel, &p->base.interested_parties,
+ &sd->connectivity_state, &sd->connectivity_changed_closure);
/* remove from ready list if still present */
- if (p->subchannel_index_to_readylist_node[this_idx] != NULL) {
- remove_disconnected_sc_locked(
- p, p->subchannel_index_to_readylist_node[this_idx]);
- p->subchannel_index_to_readylist_node[this_idx] = NULL;
+ if (sd->ready_list_node != NULL) {
+ remove_disconnected_sc_locked(p, sd->ready_list_node);
+ sd->ready_list_node = NULL;
}
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connecting_transient_failure");
break;
case GRPC_CHANNEL_FATAL_FAILURE:
- del_interested_parties_locked(exec_ctx, p, this_idx);
- if (p->subchannel_index_to_readylist_node[this_idx] != NULL) {
- remove_disconnected_sc_locked(
- p, p->subchannel_index_to_readylist_node[this_idx]);
- p->subchannel_index_to_readylist_node[this_idx] = NULL;
+ if (sd->ready_list_node != NULL) {
+ remove_disconnected_sc_locked(p, sd->ready_list_node);
+ sd->ready_list_node = NULL;
}
- GPR_SWAP(grpc_subchannel *, p->subchannels[this_idx],
- p->subchannels[p->num_subchannels - 1]);
p->num_subchannels--;
- GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
- "round_robin");
+ GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
+ p->subchannels[p->num_subchannels]);
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "round_robin");
+ p->subchannels[sd->index]->index = sd->index;
+ gpr_free(sd);
+ unref = 1;
if (p->num_subchannels == 0) {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_FATAL_FAILURE,
@@ -454,7 +431,6 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
gpr_free(pp);
}
- unref = 1;
} else {
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_TRANSIENT_FAILURE,
@@ -466,31 +442,8 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
gpr_mu_unlock(&p->mu);
if (unref) {
- GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
- }
-}
-
-static void rr_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
- grpc_transport_op *op) {
- round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
- size_t i;
- size_t n;
- grpc_subchannel **subchannels;
-
- gpr_mu_lock(&p->mu);
- n = p->num_subchannels;
- subchannels = gpr_malloc(n * sizeof(*subchannels));
- for (i = 0; i < n; i++) {
- subchannels[i] = p->subchannels[i];
- GRPC_SUBCHANNEL_REF(subchannels[i], "rr_broadcast");
- }
- gpr_mu_unlock(&p->mu);
-
- for (i = 0; i < n; i++) {
- grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], op);
- GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "rr_broadcast");
+ GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "round_robin_connectivity");
}
- gpr_free(subchannels);
}
static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
@@ -514,9 +467,25 @@ static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&p->mu);
}
+static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+ grpc_closure *closure) {
+ round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
+ ready_list *selected;
+ grpc_connected_subchannel *target;
+ gpr_mu_lock(&p->mu);
+ if ((selected = peek_next_connected_locked(p))) {
+ gpr_mu_unlock(&p->mu);
+ target = grpc_subchannel_get_connected_subchannel(selected->subchannel);
+ grpc_connected_subchannel_ping(exec_ctx, target, closure);
+ } else {
+ gpr_mu_unlock(&p->mu);
+ grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+ }
+}
+
static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
- rr_destroy, rr_shutdown, rr_pick, rr_cancel_pick, rr_exit_idle,
- rr_broadcast, rr_check_connectivity, rr_notify_on_state_change};
+ rr_destroy, rr_shutdown, rr_pick, rr_cancel_pick, rr_ping_one, rr_exit_idle,
+ rr_check_connectivity, rr_notify_on_state_change};
static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
@@ -529,27 +498,22 @@ static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
GPR_ASSERT(args->num_subchannels > 0);
memset(p, 0, sizeof(*p));
grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
- p->subchannels =
- gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
p->num_subchannels = args->num_subchannels;
+ p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels);
+ memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels);
grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
"round_robin");
- memcpy(p->subchannels, args->subchannels,
- sizeof(grpc_subchannel *) * args->num_subchannels);
gpr_mu_init(&p->mu);
- p->connectivity_changed_cbs =
- gpr_malloc(sizeof(grpc_closure) * args->num_subchannels);
- p->subchannel_connectivity =
- gpr_malloc(sizeof(grpc_connectivity_state) * args->num_subchannels);
-
- p->cb_args =
- gpr_malloc(sizeof(connectivity_changed_cb_arg) * args->num_subchannels);
for (i = 0; i < args->num_subchannels; i++) {
- p->cb_args[i].subchannel_idx = i;
- p->cb_args[i].p = p;
- grpc_closure_init(&p->connectivity_changed_cbs[i], rr_connectivity_changed,
- &p->cb_args[i]);
+ subchannel_data *sd = gpr_malloc(sizeof(*sd));
+ memset(sd, 0, sizeof(*sd));
+ p->subchannels[i] = sd;
+ sd->policy = p;
+ sd->index = i;
+ sd->subchannel = args->subchannels[i];
+ grpc_closure_init(&sd->connectivity_changed_closure,
+ rr_connectivity_changed, sd);
}
/* The (dummy node) root of the ready list */
@@ -558,10 +522,6 @@ static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
p->ready_list.next = NULL;
p->ready_list_last_pick = &p->ready_list;
- p->subchannel_index_to_readylist_node =
- gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
- memset(p->subchannel_index_to_readylist_node, 0,
- sizeof(grpc_subchannel *) * args->num_subchannels);
return &p->base;
}
diff --git a/src/core/client_config/lb_policy.c b/src/core/client_config/lb_policy.c
index 36a2454309..d4672f6b25 100644
--- a/src/core/client_config/lb_policy.c
+++ b/src/core/client_config/lb_policy.c
@@ -33,63 +33,94 @@
#include "src/core/client_config/lb_policy.h"
+#define WEAK_REF_BITS 16
+
void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable) {
policy->vtable = vtable;
- gpr_ref_init(&policy->refs, 1);
+ gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS);
+ grpc_pollset_set_init(&policy->interested_parties);
}
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
-void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
- const char *reason) {
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p ref %d -> %d %s",
- policy, (int)policy->refs.count, (int)policy->refs.count + 1, reason);
+#define REF_FUNC_EXTRA_ARGS , const char *file, int line, const char *reason
+#define REF_MUTATE_EXTRA_ARGS REF_FUNC_EXTRA_ARGS, const char *purpose
+#define REF_FUNC_PASS_ARGS(new_reason) , file, line, new_reason
+#define REF_MUTATE_PASS_ARGS(purpose) , file, line, reason, purpose
#else
-void grpc_lb_policy_ref(grpc_lb_policy *policy) {
+#define REF_FUNC_EXTRA_ARGS
+#define REF_MUTATE_EXTRA_ARGS
+#define REF_FUNC_PASS_ARGS(new_reason)
+#define REF_MUTATE_PASS_ARGS(x)
#endif
- gpr_ref(&policy->refs);
-}
+static gpr_atm ref_mutate(grpc_lb_policy *c, gpr_atm delta,
+ int barrier REF_MUTATE_EXTRA_ARGS) {
+ gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
+ : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
-void grpc_lb_policy_unref(grpc_lb_policy *policy,
- grpc_closure_list *closure_list, const char *file,
- int line, const char *reason) {
- gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "LB_POLICY:%p unref %d -> %d %s",
- policy, (int)policy->refs.count, (int)policy->refs.count - 1, reason);
-#else
-void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
+ 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);
#endif
- if (gpr_unref(&policy->refs)) {
- policy->vtable->destroy(exec_ctx, policy);
+ return old_val;
+}
+
+void grpc_lb_policy_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+ ref_mutate(policy, 1 << WEAK_REF_BITS, 0 REF_MUTATE_PASS_ARGS("STRONG_REF"));
+}
+
+void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx,
+ grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+ gpr_atm old_val =
+ ref_mutate(policy, (gpr_atm)1 - (gpr_atm)(1 << WEAK_REF_BITS),
+ 1 REF_MUTATE_PASS_ARGS("STRONG_UNREF"));
+ gpr_atm mask = ~(gpr_atm)((1 << WEAK_REF_BITS) - 1);
+ gpr_atm check = 1 << WEAK_REF_BITS;
+ if ((old_val & mask) == check) {
+ policy->vtable->shutdown(exec_ctx, policy);
}
+ grpc_lb_policy_weak_unref(exec_ctx,
+ policy REF_FUNC_PASS_ARGS("strong-unref"));
}
-void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
- policy->vtable->shutdown(exec_ctx, policy);
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+ ref_mutate(policy, 1, 0 REF_MUTATE_PASS_ARGS("WEAK_REF"));
+}
+
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
+ grpc_lb_policy *policy REF_FUNC_EXTRA_ARGS) {
+ gpr_atm old_val =
+ ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF"));
+ if (old_val == 1) {
+ grpc_pollset_set_destroy(&policy->interested_parties);
+ policy->vtable->destroy(exec_ctx, policy);
+ }
}
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata,
- grpc_subchannel **target, grpc_closure *on_complete) {
+ grpc_connected_subchannel **target,
+ grpc_closure *on_complete) {
return policy->vtable->pick(exec_ctx, policy, pollset, initial_metadata,
target, on_complete);
}
void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_subchannel **target) {
+ grpc_connected_subchannel **target) {
policy->vtable->cancel_pick(exec_ctx, policy, target);
}
-void grpc_lb_policy_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_transport_op *op) {
- policy->vtable->broadcast(exec_ctx, policy, op);
-}
-
void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy) {
policy->vtable->exit_idle(exec_ctx, policy);
}
+void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_closure *closure) {
+ policy->vtable->ping_one(exec_ctx, policy, closure);
+}
+
void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy,
grpc_connectivity_state *state,
diff --git a/src/core/client_config/lb_policy.h b/src/core/client_config/lb_policy.h
index a696c3ce64..db5238c8ca 100644
--- a/src/core/client_config/lb_policy.h
+++ b/src/core/client_config/lb_policy.h
@@ -47,7 +47,8 @@ typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel,
struct grpc_lb_policy {
const grpc_lb_policy_vtable *vtable;
- gpr_refcount refs;
+ gpr_atm ref_pair;
+ grpc_pollset_set interested_parties;
};
struct grpc_lb_policy_vtable {
@@ -58,17 +59,16 @@ 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_subchannel **target, grpc_closure *on_complete);
+ grpc_connected_subchannel **target, grpc_closure *on_complete);
void (*cancel_pick)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_subchannel **target);
+ grpc_connected_subchannel **target);
+
+ void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_closure *closure);
/** try to enter a READY connectivity state */
void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
- /** broadcast a transport op to all subchannels */
- void (*broadcast)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_transport_op *op);
-
/** check the current connectivity of the lb_policy */
grpc_connectivity_state (*check_connectivity)(grpc_exec_ctx *exec_ctx,
grpc_lb_policy *policy);
@@ -81,29 +81,39 @@ struct grpc_lb_policy_vtable {
grpc_closure *closure);
};
+/*#define GRPC_LB_POLICY_REFCOUNT_DEBUG*/
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
#define GRPC_LB_POLICY_REF(p, r) \
grpc_lb_policy_ref((p), __FILE__, __LINE__, (r))
#define GRPC_LB_POLICY_UNREF(exec_ctx, p, r) \
grpc_lb_policy_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
+#define GRPC_LB_POLICY_WEAK_REF(p, r) \
+ grpc_lb_policy_weak_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, p, r) \
+ grpc_lb_policy_weak_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
void grpc_lb_policy_ref(grpc_lb_policy *policy, const char *file, int line,
const char *reason);
void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
const char *file, int line, const char *reason);
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy, const char *file, int line,
+ const char *reason);
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ const char *file, int line, const char *reason);
#else
#define GRPC_LB_POLICY_REF(p, r) grpc_lb_policy_ref((p))
#define GRPC_LB_POLICY_UNREF(cl, p, r) grpc_lb_policy_unref((cl), (p))
+#define GRPC_LB_POLICY_WEAK_REF(p, r) grpc_lb_policy_weak_ref((p))
+#define GRPC_LB_POLICY_WEAK_UNREF(cl, p, r) grpc_lb_policy_weak_unref((cl), (p))
void grpc_lb_policy_ref(grpc_lb_policy *policy);
void grpc_lb_policy_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
+void grpc_lb_policy_weak_ref(grpc_lb_policy *policy);
+void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
#endif
/** called by concrete implementations to initialize the base struct */
void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable);
-/** Start shutting down (fail any pending picks) */
-void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
-
/** Given initial metadata in \a initial_metadata, find an appropriate
target for this rpc, and 'return' it by calling \a on_complete after setting
\a target.
@@ -111,13 +121,14 @@ void grpc_lb_policy_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
grpc_pollset *pollset,
grpc_metadata_batch *initial_metadata,
- grpc_subchannel **target, grpc_closure *on_complete);
+ grpc_connected_subchannel **target,
+ grpc_closure *on_complete);
-void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_subchannel **target);
+void grpc_lb_policy_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_closure *closure);
-void grpc_lb_policy_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
- grpc_transport_op *op);
+void grpc_lb_policy_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
+ grpc_connected_subchannel **target);
void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
diff --git a/src/core/client_config/resolver.c b/src/core/client_config/resolver.c
index 081097eb19..eda01e72ba 100644
--- a/src/core/client_config/resolver.c
+++ b/src/core/client_config/resolver.c
@@ -71,11 +71,8 @@ void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
}
void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver,
- struct sockaddr *failing_address,
- int failing_address_len) {
- resolver->vtable->channel_saw_error(exec_ctx, resolver, failing_address,
- failing_address_len);
+ grpc_resolver *resolver) {
+ resolver->vtable->channel_saw_error(exec_ctx, resolver);
}
void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
diff --git a/src/core/client_config/resolver.h b/src/core/client_config/resolver.h
index 7ba0cd5bd4..e612eaf3b3 100644
--- a/src/core/client_config/resolver.h
+++ b/src/core/client_config/resolver.h
@@ -35,8 +35,8 @@
#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_H
#include "src/core/client_config/client_config.h"
+#include "src/core/client_config/subchannel.h"
#include "src/core/iomgr/iomgr.h"
-#include "src/core/iomgr/sockaddr.h"
typedef struct grpc_resolver grpc_resolver;
typedef struct grpc_resolver_vtable grpc_resolver_vtable;
@@ -51,9 +51,7 @@ struct grpc_resolver {
struct grpc_resolver_vtable {
void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
- void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
- struct sockaddr *failing_address,
- int failing_address_len);
+ void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
grpc_client_config **target_config, grpc_closure *on_complete);
};
@@ -81,9 +79,7 @@ void grpc_resolver_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
/** Notification that the channel has seen an error on some address.
Can be used as a hint that re-resolution is desirable soon. */
void grpc_resolver_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver,
- struct sockaddr *failing_address,
- int failing_address_len);
+ grpc_resolver *resolver);
/** Get the next client config. Called by the channel to fetch a new
configuration. Expected to set *target_config with a new configuration,
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 7f9dd2543f..28ca30b946 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -40,7 +40,6 @@
#include <grpc/support/string_util.h>
#include "src/core/client_config/lb_policy_registry.h"
-#include "src/core/client_config/subchannel_factory_decorators/add_channel_arg.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/support/string.h"
@@ -81,9 +80,7 @@ static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
dns_resolver *r);
static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
-static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
- struct sockaddr *failing_address,
- int failing_address_len);
+static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config,
grpc_closure *on_complete);
@@ -103,8 +100,7 @@ static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
}
static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver, struct sockaddr *sa,
- int len) {
+ grpc_resolver *resolver) {
dns_resolver *r = (dns_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (!r->resolving) {
diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c
index 0b017f06c7..81d6627ecc 100644
--- a/src/core/client_config/resolvers/sockaddr_resolver.c
+++ b/src/core/client_config/resolvers/sockaddr_resolver.c
@@ -83,9 +83,7 @@ static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *r,
- struct sockaddr *failing_address,
- int failing_address_len);
+ grpc_resolver *r);
static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config,
grpc_closure *on_complete);
@@ -107,8 +105,13 @@ static void sockaddr_shutdown(grpc_exec_ctx *exec_ctx,
}
static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver,
- struct sockaddr *sa, int len) {}
+ grpc_resolver *resolver) {
+ sockaddr_resolver *r = (sockaddr_resolver *)resolver;
+ gpr_mu_lock(&r->mu);
+ r->published = 0;
+ sockaddr_maybe_finish_next_locked(exec_ctx, r);
+ gpr_mu_unlock(&r->mu);
+}
static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
grpc_client_config **target_config,
@@ -344,6 +347,9 @@ static grpc_resolver *sockaddr_create(
gpr_slice_buffer_destroy(&path_parts);
gpr_slice_unref(path_slice);
if (errors_found) {
+ gpr_free(r->lb_policy_name);
+ gpr_free(r->addrs);
+ gpr_free(r->addrs_len);
gpr_free(r);
return NULL;
}
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c
index 136197d4c6..4924ca77d6 100644
--- a/src/core/client_config/resolvers/zookeeper_resolver.c
+++ b/src/core/client_config/resolvers/zookeeper_resolver.c
@@ -96,9 +96,7 @@ static void zookeeper_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
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,
- struct sockaddr *failing_address,
- int failing_address_len);
+ grpc_resolver *r);
static void zookeeper_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
grpc_client_config **target_config,
grpc_closure *on_complete);
@@ -125,8 +123,7 @@ static void zookeeper_shutdown(grpc_exec_ctx *exec_ctx,
}
static void zookeeper_channel_saw_error(grpc_exec_ctx *exec_ctx,
- grpc_resolver *resolver,
- struct sockaddr *sa, int len) {
+ grpc_resolver *resolver) {
zookeeper_resolver *r = (zookeeper_resolver *)resolver;
gpr_mu_lock(&r->mu);
if (r->resolving == 0) {
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index 28496ac2c9..afb1cdbd6d 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -47,39 +47,44 @@
#include "src/core/transport/connectivity_state.h"
#include "src/core/transport/connectivity_state.h"
+#define INTERNAL_REF_BITS 16
+#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 1
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2
-typedef struct {
- /* all fields protected by subchannel->mu */
- /** refcount */
- int refs;
- /** parent subchannel */
- grpc_subchannel *subchannel;
-} connection;
+#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \
+ ((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \
+ &(subchannel)->connected_subchannel)))
typedef struct {
grpc_closure closure;
- size_t version;
grpc_subchannel *subchannel;
grpc_connectivity_state connectivity_state;
} state_watcher;
-typedef struct waiting_for_connect {
- struct waiting_for_connect *next;
- grpc_closure *notify;
- grpc_pollset *pollset;
- gpr_atm *target;
+typedef struct external_state_watcher {
grpc_subchannel *subchannel;
- grpc_closure continuation;
-} waiting_for_connect;
+ grpc_pollset_set *pollset_set;
+ grpc_closure *notify;
+ grpc_closure closure;
+ struct external_state_watcher *next;
+ struct external_state_watcher *prev;
+} external_state_watcher;
struct grpc_subchannel {
grpc_connector *connector;
+ /** refcount
+ - lower INTERNAL_REF_BITS bits are for internal references:
+ these do not keep the subchannel open.
+ - upper remaining bits are for public references: these do
+ keep the subchannel open */
+ gpr_atm ref_pair;
+
/** non-transport related channel filters */
const grpc_channel_filter **filters;
size_t num_filters;
@@ -88,15 +93,9 @@ struct grpc_subchannel {
/** address to connect to */
struct sockaddr *addr;
size_t addr_len;
+
/** initial string to send to peer */
gpr_slice initial_connect_string;
- /** master channel - the grpc_channel instance that ultimately owns
- this channel_data via its channel stack.
- We occasionally use this to bump the refcount on the master channel
- to keep ourselves alive through an asynchronous operation. */
- grpc_channel *master;
- /** have we seen a disconnection? */
- int disconnected;
/** set during connection */
grpc_connect_out_args connecting_result;
@@ -105,27 +104,24 @@ struct grpc_subchannel {
grpc_closure connected;
/** pollset_set tracking who's interested in a connection
- being setup - owned by the master channel (in particular the
- client_channel
- filter there-in) */
- grpc_pollset_set *pollset_set;
+ being setup */
+ grpc_pollset_set pollset_set;
+
+ /** active connection, or null; of type grpc_connected_subchannel */
+ gpr_atm connected_subchannel;
/** mutex protecting remaining elements */
gpr_mu mu;
- /** active connection */
- connection *active;
- /** version number for the active connection */
- size_t active_version;
- /** refcount */
- int refs;
+ /** have we seen a disconnection? */
+ int disconnected;
/** are we connecting */
int connecting;
- /** things waiting for a connection */
- waiting_for_connect *waiting;
/** connectivity state tracking */
grpc_connectivity_state_tracker state_tracker;
+ external_state_watcher root_external_state_watcher;
+
/** next connect attempt time */
gpr_timespec next_attempt;
/** amount to backoff each failure */
@@ -139,151 +135,141 @@ struct grpc_subchannel {
};
struct grpc_subchannel_call {
- connection *connection;
+ grpc_connected_subchannel *connection;
};
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
-#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1))
+#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con))
#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \
(((grpc_subchannel_call *)(callstack)) - 1)
-static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx,
- connection *con,
- grpc_pollset *pollset);
-static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- const char *reason);
-static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c);
static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
int iomgr_success);
-static void subchannel_ref_locked(grpc_subchannel *c
- GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-static int subchannel_unref_locked(
- grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
-static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-static grpc_subchannel *connection_unref_locked(
- grpc_exec_ctx *exec_ctx,
- connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT;
-static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c);
-
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define SUBCHANNEL_REF_LOCKED(p, r) \
- subchannel_ref_locked((p), __FILE__, __LINE__, (r))
-#define SUBCHANNEL_UNREF_LOCKED(p, r) \
- subchannel_unref_locked((p), __FILE__, __LINE__, (r))
-#define CONNECTION_REF_LOCKED(p, r) \
- connection_ref_locked((p), __FILE__, __LINE__, (r))
-#define CONNECTION_UNREF_LOCKED(cl, p, r) \
- connection_unref_locked((cl), (p), __FILE__, __LINE__, (r))
-#define REF_PASS_ARGS , file, line, reason
-#define REF_PASS_REASON , reason
+#define REF_REASON reason
#define REF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \
- (name), (p), (p)->refs, (p)->refs + 1, reason)
+ (name), (p), (p)->refs.count, (p)->refs.count + 1, reason)
#define UNREF_LOG(name, p) \
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
- (name), (p), (p)->refs, (p)->refs - 1, reason)
+ (name), (p), (p)->refs.count, (p)->refs.count - 1, reason)
+#define REF_MUTATE_EXTRA_ARGS \
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose
+#define REF_MUTATE_PURPOSE(x) , file, line, reason, x
#else
-#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p))
-#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p))
-#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p))
-#define CONNECTION_UNREF_LOCKED(cl, p, r) connection_unref_locked((cl), (p))
-#define REF_PASS_ARGS
-#define REF_PASS_REASON
+#define REF_REASON ""
#define REF_LOG(name, p) \
do { \
} while (0)
#define UNREF_LOG(name, p) \
do { \
} while (0)
+#define REF_MUTATE_EXTRA_ARGS
+#define REF_MUTATE_PURPOSE(x)
#endif
/*
* connection implementation
*/
-static void connection_destroy(grpc_exec_ctx *exec_ctx, connection *c) {
- GPR_ASSERT(c->refs == 0);
+static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+ int success) {
+ grpc_connected_subchannel *c = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
gpr_free(c);
}
-static void connection_ref_locked(connection *c
- GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- REF_LOG("CONNECTION", c);
- subchannel_ref_locked(c->subchannel REF_PASS_ARGS);
- ++c->refs;
+void grpc_connected_subchannel_ref(grpc_connected_subchannel *c
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+ GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON);
}
-static grpc_subchannel *connection_unref_locked(
- grpc_exec_ctx *exec_ctx, connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- grpc_subchannel *destroy = NULL;
- UNREF_LOG("CONNECTION", c);
- if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) {
- destroy = c->subchannel;
- }
- if (--c->refs == 0 && c->subchannel->active != c) {
- connection_destroy(exec_ctx, c);
- }
- return destroy;
+void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
+ grpc_connected_subchannel *c
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c),
+ REF_REASON);
}
/*
* grpc_subchannel implementation
*/
-static void subchannel_ref_locked(grpc_subchannel *c
- GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- REF_LOG("SUBCHANNEL", c);
- ++c->refs;
+static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+ int success) {
+ grpc_subchannel *c = arg;
+ gpr_free((void *)c->filters);
+ grpc_channel_args_destroy(c->args);
+ gpr_free(c->addr);
+ gpr_slice_unref(c->initial_connect_string);
+ grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
+ grpc_connector_unref(exec_ctx, c->connector);
+ grpc_pollset_set_destroy(&c->pollset_set);
+ gpr_free(c);
}
-static int subchannel_unref_locked(grpc_subchannel *c
- GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- UNREF_LOG("SUBCHANNEL", c);
- return --c->refs == 0;
+static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta,
+ int barrier REF_MUTATE_EXTRA_ARGS) {
+ gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
+ : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
+ "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
+ old_val + delta, reason);
+#endif
+ return old_val;
}
void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- gpr_mu_lock(&c->mu);
- subchannel_ref_locked(c REF_PASS_ARGS);
- gpr_mu_unlock(&c->mu);
+ gpr_atm old_refs;
+ old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS),
+ 0 REF_MUTATE_PURPOSE("STRONG_REF"));
+ GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
}
-void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
- int destroy;
- gpr_mu_lock(&c->mu);
- destroy = subchannel_unref_locked(c REF_PASS_ARGS);
- gpr_mu_unlock(&c->mu);
- if (destroy) subchannel_destroy(exec_ctx, c);
+void grpc_subchannel_weak_ref(grpc_subchannel *c
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+ gpr_atm old_refs;
+ old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF"));
+ GPR_ASSERT(old_refs != 0);
}
-static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
- if (c->active != NULL) {
- connection_destroy(exec_ctx, c->active);
+static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
+ grpc_connected_subchannel *con;
+ gpr_mu_lock(&c->mu);
+ GPR_ASSERT(!c->disconnected);
+ c->disconnected = 1;
+ grpc_connector_shutdown(exec_ctx, c->connector);
+ con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
+ if (con != NULL) {
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection");
+ gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef);
}
- gpr_free((void *)c->filters);
- grpc_channel_args_destroy(c->args);
- gpr_free(c->addr);
- gpr_slice_unref(c->initial_connect_string);
- grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
- grpc_connector_unref(exec_ctx, c->connector);
- gpr_free(c);
+ gpr_mu_unlock(&c->mu);
}
-void grpc_subchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- grpc_pollset *pollset) {
- grpc_pollset_set_add_pollset(exec_ctx, c->pollset_set, pollset);
+void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
+ grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+ gpr_atm old_refs;
+ old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS),
+ 1 REF_MUTATE_PURPOSE("STRONG_UNREF"));
+ if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
+ disconnect(exec_ctx, c);
+ }
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref");
}
-void grpc_subchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- grpc_pollset *pollset) {
- grpc_pollset_set_del_pollset(exec_ctx, c->pollset_set, pollset);
+void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
+ grpc_subchannel *c
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
+ 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),
+ 1);
+ }
}
static gpr_uint32 random_seed() {
@@ -293,10 +279,8 @@ static gpr_uint32 random_seed() {
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args) {
grpc_subchannel *c = gpr_malloc(sizeof(*c));
- grpc_channel_element *parent_elem = grpc_channel_stack_last_element(
- grpc_channel_get_channel_stack(args->master));
memset(c, 0, sizeof(*c));
- c->refs = 1;
+ gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS);
c->connector = connector;
grpc_connector_ref(c->connector);
c->num_filters = args->filter_count;
@@ -305,13 +289,14 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
sizeof(grpc_channel_filter *) * c->num_filters);
c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len);
+ grpc_pollset_set_init(&c->pollset_set);
c->addr_len = args->addr_len;
grpc_set_initial_connect_string(&c->addr, &c->addr_len,
&c->initial_connect_string);
c->args = grpc_channel_args_copy(args->args);
- c->master = args->master;
- c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem);
c->random = random_seed();
+ c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
+ &c->root_external_state_watcher;
grpc_closure_init(&c->connected, subchannel_connected, c);
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
"subchannel");
@@ -319,70 +304,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
return c;
}
-static void cancel_waiting_calls(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- int iomgr_success) {
- waiting_for_connect *w4c;
- gpr_mu_lock(&subchannel->mu);
- w4c = subchannel->waiting;
- subchannel->waiting = NULL;
- gpr_mu_unlock(&subchannel->mu);
- while (w4c != NULL) {
- waiting_for_connect *next = w4c->next;
- grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel,
- w4c->pollset);
- if (w4c->notify) {
- w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
- }
-
- GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
- gpr_free(w4c);
-
- w4c = next;
- }
-}
-
-void grpc_subchannel_cancel_create_call(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- gpr_atm *target) {
- waiting_for_connect *w4c;
- int unref_count = 0;
- gpr_mu_lock(&subchannel->mu);
- w4c = subchannel->waiting;
- subchannel->waiting = NULL;
- while (w4c != NULL) {
- waiting_for_connect *next = w4c->next;
- if (w4c->target == target) {
- grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel,
- w4c->pollset);
- grpc_exec_ctx_enqueue(exec_ctx, w4c->notify, 0);
-
- unref_count++;
- gpr_free(w4c);
- } else {
- w4c->next = subchannel->waiting;
- subchannel->waiting = w4c;
- }
-
- w4c = next;
- }
- gpr_mu_unlock(&subchannel->mu);
-
- while (unref_count-- > 0) {
- GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "waiting_for_connect");
- }
-}
-
static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_connect_in_args args;
- args.interested_parties = c->pollset_set;
+ args.interested_parties = &c->pollset_set;
args.addr = c->addr;
args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c);
args.channel_args = c->args;
args.initial_connect_string = c->initial_connect_string;
+ grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+ GRPC_CHANNEL_CONNECTING, "state_change");
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result,
&c->connected);
}
@@ -395,66 +328,6 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
continue_connect(exec_ctx, c);
}
-static void continue_creating_call(grpc_exec_ctx *exec_ctx, void *arg,
- int iomgr_success) {
- int call_creation_finished_ok;
- waiting_for_connect *w4c = arg;
- grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, w4c->pollset);
- call_creation_finished_ok = grpc_subchannel_create_call(
- exec_ctx, w4c->subchannel, w4c->pollset, w4c->target, w4c->notify);
- GPR_ASSERT(call_creation_finished_ok == 1);
- w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
- GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
- gpr_free(w4c);
-}
-
-int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
- grpc_pollset *pollset, gpr_atm *target,
- grpc_closure *notify) {
- connection *con;
- grpc_subchannel_call *call;
- GPR_TIMER_BEGIN("grpc_subchannel_create_call", 0);
- gpr_mu_lock(&c->mu);
- if (c->active != NULL) {
- con = c->active;
- CONNECTION_REF_LOCKED(con, "call");
- gpr_mu_unlock(&c->mu);
-
- call = create_call(exec_ctx, con, pollset);
- if (!gpr_atm_rel_cas(target, 0, (gpr_atm)(gpr_uintptr)call)) {
- GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "failed to set");
- }
- GPR_TIMER_END("grpc_subchannel_create_call", 0);
- return 1;
- } else {
- waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
- w4c->next = c->waiting;
- w4c->notify = notify;
- w4c->pollset = pollset;
- w4c->target = target;
- w4c->subchannel = c;
- /* released when clearing w4c */
- SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect");
- grpc_closure_init(&w4c->continuation, continue_creating_call, w4c);
- c->waiting = w4c;
- grpc_subchannel_add_interested_party(exec_ctx, c, pollset);
- if (!c->connecting) {
- c->connecting = 1;
- connectivity_state_changed_locked(exec_ctx, c, "create_call");
- /* released by connection */
- SUBCHANNEL_REF_LOCKED(c, "connecting");
- GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
- gpr_mu_unlock(&c->mu);
-
- start_connect(exec_ctx, c);
- } else {
- gpr_mu_unlock(&c->mu);
- }
- GPR_TIMER_END("grpc_subchannel_create_call", 0);
- return 0;
- }
-}
-
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
grpc_connectivity_state state;
gpr_mu_lock(&c->mu);
@@ -463,153 +336,149 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) {
return state;
}
-void grpc_subchannel_notify_on_state_change(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- grpc_connectivity_state *state,
- grpc_closure *notify) {
+static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
+ int success) {
+ external_state_watcher *w = arg;
+ grpc_closure *follow_up = w->notify;
+ if (w->pollset_set != NULL) {
+ grpc_pollset_set_del_pollset_set(exec_ctx, &w->subchannel->pollset_set,
+ w->pollset_set);
+ }
+ gpr_mu_lock(&w->subchannel->mu);
+ w->next->prev = w->prev;
+ w->prev->next = w->next;
+ 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);
+}
+
+void grpc_subchannel_notify_on_state_change(
+ grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
+ grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+ grpc_closure *notify) {
int do_connect = 0;
- gpr_mu_lock(&c->mu);
- if (grpc_connectivity_state_notify_on_state_change(
- exec_ctx, &c->state_tracker, state, notify)) {
- do_connect = 1;
- c->connecting = 1;
- /* released by connection */
- SUBCHANNEL_REF_LOCKED(c, "connecting");
- GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting");
- connectivity_state_changed_locked(exec_ctx, c, "state_change");
+ external_state_watcher *w;
+
+ if (state == NULL) {
+ gpr_mu_lock(&c->mu);
+ for (w = c->root_external_state_watcher.next;
+ w != &c->root_external_state_watcher; w = w->next) {
+ if (w->notify == notify) {
+ grpc_connectivity_state_notify_on_state_change(
+ exec_ctx, &c->state_tracker, NULL, &w->closure);
+ }
+ }
+ gpr_mu_unlock(&c->mu);
+ } else {
+ w = gpr_malloc(sizeof(*w));
+ w->subchannel = c;
+ w->pollset_set = interested_parties;
+ w->notify = notify;
+ grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
+ if (interested_parties != NULL) {
+ grpc_pollset_set_add_pollset_set(exec_ctx, &c->pollset_set,
+ interested_parties);
+ }
+ GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher");
+ gpr_mu_lock(&c->mu);
+ w->next = &c->root_external_state_watcher;
+ w->prev = w->next->prev;
+ w->next->prev = w->prev->next = w;
+ if (grpc_connectivity_state_notify_on_state_change(
+ exec_ctx, &c->state_tracker, state, &w->closure)) {
+ do_connect = 1;
+ c->connecting = 1;
+ /* released by connection */
+ GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
+ }
+ gpr_mu_unlock(&c->mu);
}
- gpr_mu_unlock(&c->mu);
if (do_connect) {
start_connect(exec_ctx, c);
}
}
-int grpc_subchannel_state_change_unsubscribe(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- grpc_closure *subscribed_notify) {
- int success;
- gpr_mu_lock(&c->mu);
- success = grpc_connectivity_state_change_unsubscribe(
- exec_ctx, &c->state_tracker, subscribed_notify);
- gpr_mu_unlock(&c->mu);
- return success;
+void grpc_connected_subchannel_process_transport_op(
+ grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+ grpc_transport_op *op) {
+ grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
+ grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0);
+ top_elem->filter->start_transport_op(exec_ctx, top_elem, op);
}
-void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- grpc_transport_op *op) {
- connection *con = NULL;
- grpc_subchannel *destroy;
- int cancel_alarm = 0;
- gpr_mu_lock(&c->mu);
- if (c->active != NULL) {
- con = c->active;
- CONNECTION_REF_LOCKED(con, "transport-op");
- }
- if (op->disconnect) {
- c->disconnected = 1;
- connectivity_state_changed_locked(exec_ctx, c, "disconnect");
- if (c->have_alarm) {
- cancel_alarm = 1;
- }
- }
- gpr_mu_unlock(&c->mu);
+static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
+ int iomgr_success) {
+ state_watcher *sw = p;
+ grpc_subchannel *c = sw->subchannel;
+ gpr_mu *mu = &c->mu;
- if (con != NULL) {
- grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con);
- grpc_channel_element *top_elem =
- grpc_channel_stack_element(channel_stack, 0);
- top_elem->filter->start_transport_op(exec_ctx, top_elem, op);
+ gpr_mu_lock(mu);
- gpr_mu_lock(&c->mu);
- destroy = CONNECTION_UNREF_LOCKED(exec_ctx, con, "transport-op");
- gpr_mu_unlock(&c->mu);
- if (destroy) {
- subchannel_destroy(exec_ctx, destroy);
+ /* 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_FATAL_FAILURE;
+ }
+ grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+ sw->connectivity_state, "reflect_child");
+ if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
+ 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 (cancel_alarm) {
- grpc_timer_cancel(exec_ctx, &c->alarm);
- }
-
- if (op->disconnect) {
- grpc_connector_shutdown(exec_ctx, c->connector);
- }
+ gpr_mu_unlock(mu);
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher");
+ gpr_free(sw);
}
-static void on_state_changed(grpc_exec_ctx *exec_ctx, void *p,
- int iomgr_success) {
- state_watcher *sw = p;
- grpc_subchannel *c = sw->subchannel;
- gpr_mu *mu = &c->mu;
- int destroy;
+static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx,
+ grpc_connected_subchannel *con,
+ grpc_pollset_set *interested_parties,
+ grpc_connectivity_state *state,
+ grpc_closure *closure) {
grpc_transport_op op;
grpc_channel_element *elem;
- connection *destroy_connection = NULL;
-
- gpr_mu_lock(mu);
-
- /* if we failed or there is a version number mismatch, just leave
- this closure */
- if (!iomgr_success || sw->subchannel->active_version != sw->version) {
- goto done;
- }
+ memset(&op, 0, sizeof(op));
+ op.connectivity_state = state;
+ op.on_connectivity_state_change = closure;
+ op.bind_pollset_set = interested_parties;
+ elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
+ elem->filter->start_transport_op(exec_ctx, elem, &op);
+}
- switch (sw->connectivity_state) {
- case GRPC_CHANNEL_CONNECTING:
- case GRPC_CHANNEL_READY:
- case GRPC_CHANNEL_IDLE:
- /* all is still good: keep watching */
- memset(&op, 0, sizeof(op));
- op.connectivity_state = &sw->connectivity_state;
- op.on_connectivity_state_change = &sw->closure;
- elem = grpc_channel_stack_element(
- CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
- elem->filter->start_transport_op(exec_ctx, elem, &op);
- /* early out */
- gpr_mu_unlock(mu);
- return;
- case GRPC_CHANNEL_FATAL_FAILURE:
- case GRPC_CHANNEL_TRANSIENT_FAILURE:
- /* things have gone wrong, deactivate and enter idle */
- if (sw->subchannel->active->refs == 0) {
- destroy_connection = sw->subchannel->active;
- }
- sw->subchannel->active = NULL;
- grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
- c->disconnected
- ? GRPC_CHANNEL_FATAL_FAILURE
- : GRPC_CHANNEL_TRANSIENT_FAILURE,
- "connection_failed");
- break;
- }
+void grpc_connected_subchannel_notify_on_state_change(
+ grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+ grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+ grpc_closure *closure) {
+ connected_subchannel_state_op(exec_ctx, con, interested_parties, state,
+ closure);
+}
-done:
- connectivity_state_changed_locked(exec_ctx, c, "transport_state_changed");
- destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher");
- gpr_free(sw);
- gpr_mu_unlock(mu);
- if (destroy) {
- subchannel_destroy(exec_ctx, c);
- }
- if (destroy_connection != NULL) {
- connection_destroy(exec_ctx, destroy_connection);
- }
+void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
+ grpc_connected_subchannel *con,
+ grpc_closure *closure) {
+ grpc_transport_op op;
+ grpc_channel_element *elem;
+ memset(&op, 0, sizeof(op));
+ op.send_ping = closure;
+ elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
+ elem->filter->start_transport_op(exec_ctx, elem, &op);
}
static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
size_t channel_stack_size;
- connection *con;
+ grpc_connected_subchannel *con;
grpc_channel_stack *stk;
size_t num_filters;
const grpc_channel_filter **filters;
- waiting_for_connect *w4c;
- grpc_transport_op op;
- state_watcher *sw;
- connection *destroy_connection = NULL;
- grpc_channel_element *elem;
+ state_watcher *sw_subchannel;
/* build final filter list */
num_filters = c->num_filters + c->connecting_result.num_filters + 1;
@@ -621,74 +490,52 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
/* construct channel stack */
channel_stack_size = grpc_channel_stack_size(filters, num_filters);
- con = gpr_malloc(sizeof(connection) + channel_stack_size);
- stk = (grpc_channel_stack *)(con + 1);
- con->refs = 0;
- con->subchannel = c;
- grpc_channel_stack_init(exec_ctx, filters, num_filters, c->master, c->args,
- stk);
+ con = gpr_malloc(channel_stack_size);
+ stk = CHANNEL_STACK_FROM_CONNECTION(con);
+ grpc_channel_stack_init(exec_ctx, 1, connection_destroy, con, filters,
+ num_filters, c->args, "CONNECTED_SUBCHANNEL", stk);
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport);
gpr_free((void *)c->connecting_result.filters);
memset(&c->connecting_result, 0, sizeof(c->connecting_result));
/* initialize state watcher */
- sw = gpr_malloc(sizeof(*sw));
- grpc_closure_init(&sw->closure, on_state_changed, sw);
- sw->subchannel = c;
- sw->connectivity_state = GRPC_CHANNEL_READY;
+ sw_subchannel = gpr_malloc(sizeof(*sw_subchannel));
+ sw_subchannel->subchannel = c;
+ sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
+ grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
+ sw_subchannel);
gpr_mu_lock(&c->mu);
if (c->disconnected) {
gpr_mu_unlock(&c->mu);
- gpr_free(sw);
+ gpr_free(sw_subchannel);
gpr_free((void *)filters);
grpc_channel_stack_destroy(exec_ctx, stk);
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting");
- GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting");
+ gpr_free(con);
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
return;
}
/* publish */
- if (c->active != NULL && c->active->refs == 0) {
- destroy_connection = c->active;
- }
- c->active = con;
- c->active_version++;
- sw->version = c->active_version;
+ GPR_ASSERT(gpr_atm_no_barrier_cas(&c->connected_subchannel, 0, (gpr_atm)con));
c->connecting = 0;
- /* watch for changes; subchannel ref for connecting is donated
+ /* setup subchannel watching connected subchannel for changes; subchannel ref
+ for connecting is donated
to the state watcher */
- memset(&op, 0, sizeof(op));
- op.connectivity_state = &sw->connectivity_state;
- op.on_connectivity_state_change = &sw->closure;
- op.bind_pollset_set = c->pollset_set;
- SUBCHANNEL_REF_LOCKED(c, "state_watcher");
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting");
- GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
- elem =
- grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
- elem->filter->start_transport_op(exec_ctx, elem, &op);
+ GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
+ grpc_connected_subchannel_notify_on_state_change(
+ exec_ctx, con, &c->pollset_set, &sw_subchannel->connectivity_state,
+ &sw_subchannel->closure);
/* signal completion */
- connectivity_state_changed_locked(exec_ctx, c, "connected");
- w4c = c->waiting;
- c->waiting = NULL;
+ grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY,
+ "connected");
gpr_mu_unlock(&c->mu);
-
- while (w4c != NULL) {
- waiting_for_connect *next = w4c->next;
- grpc_exec_ctx_enqueue(exec_ctx, &w4c->continuation, 1);
- w4c = next;
- }
-
gpr_free((void *)filters);
-
- if (destroy_connection != NULL) {
- connection_destroy(exec_ctx, destroy_connection);
- }
}
/* Generate a random number between 0 and 1. */
@@ -742,29 +589,31 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, int iomgr_success) {
if (c->disconnected) {
iomgr_success = 0;
}
- connectivity_state_changed_locked(exec_ctx, c, "alarm");
gpr_mu_unlock(&c->mu);
if (iomgr_success) {
update_reconnect_parameters(c);
continue_connect(exec_ctx, c);
} else {
- cancel_waiting_calls(exec_ctx, c, iomgr_success);
- GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting");
- GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting");
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
}
}
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
grpc_subchannel *c = arg;
+
if (c->connecting_result.transport != NULL) {
publish_transport(exec_ctx, c);
+ } else if (c->disconnected) {
+ GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} else {
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
gpr_mu_lock(&c->mu);
GPR_ASSERT(!c->have_alarm);
c->have_alarm = 1;
- connectivity_state_changed_locked(exec_ctx, c, "connect_failed");
+ grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
+ GRPC_CHANNEL_TRANSIENT_FAILURE,
+ "connect_failed");
grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
gpr_mu_unlock(&c->mu);
}
@@ -781,29 +630,6 @@ static gpr_timespec compute_connect_deadline(grpc_subchannel *c) {
: min_deadline;
}
-static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) {
- if (c->disconnected) {
- return GRPC_CHANNEL_FATAL_FAILURE;
- }
- if (c->connecting) {
- if (c->have_alarm) {
- return GRPC_CHANNEL_TRANSIENT_FAILURE;
- }
- return GRPC_CHANNEL_CONNECTING;
- }
- if (c->active) {
- return GRPC_CHANNEL_READY;
- }
- return GRPC_CHANNEL_IDLE;
-}
-
-static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *c,
- const char *reason) {
- grpc_connectivity_state current = compute_connectivity_locked(c);
- grpc_connectivity_state_set(exec_ctx, &c->state_tracker, current, reason);
-}
-
/*
* grpc_subchannel_call implementation
*/
@@ -811,37 +637,22 @@ static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx,
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
int success) {
grpc_subchannel_call *c = call;
- gpr_mu *mu = &c->connection->subchannel->mu;
- grpc_subchannel *destroy;
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
- gpr_mu_lock(mu);
- destroy = CONNECTION_UNREF_LOCKED(exec_ctx, c->connection, "call");
- gpr_mu_unlock(mu);
+ GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
gpr_free(c);
- if (destroy != NULL) {
- subchannel_destroy(exec_ctx, destroy);
- }
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
}
void grpc_subchannel_call_ref(grpc_subchannel_call *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
- grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c), reason);
-#else
- grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c));
-#endif
+ GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
}
void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *c
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
-#ifdef GRPC_STREAM_REFCOUNT_DEBUG
- grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), reason);
-#else
- grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
-#endif
+ GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON);
}
char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx,
@@ -859,24 +670,26 @@ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op);
}
-static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx,
- connection *con,
- grpc_pollset *pollset) {
+grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
+ grpc_subchannel *c) {
+ return GET_CONNECTED_SUBCHANNEL(c, acq);
+}
+
+grpc_subchannel_call *grpc_connected_subchannel_create_call(
+ grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
+ grpc_pollset *pollset) {
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
grpc_subchannel_call *call =
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call);
call->connection = con;
+ 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);
return call;
}
-grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel) {
- return subchannel->master;
-}
-
grpc_call_stack *grpc_subchannel_call_get_call_stack(
grpc_subchannel_call *subchannel_call) {
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call);
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
index 85ea3739e4..57c7c9dc67 100644
--- a/src/core/client_config/subchannel.h
+++ b/src/core/client_config/subchannel.h
@@ -41,6 +41,7 @@
/** A (sub-)channel that knows how to connect to exactly one target
address. Provides a target for load balancing. */
typedef struct grpc_subchannel grpc_subchannel;
+typedef struct grpc_connected_subchannel grpc_connected_subchannel;
typedef struct grpc_subchannel_call grpc_subchannel_call;
typedef struct grpc_subchannel_args grpc_subchannel_args;
@@ -49,6 +50,14 @@ typedef struct grpc_subchannel_args grpc_subchannel_args;
grpc_subchannel_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_UNREF(cl, p, r) \
grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_WEAK_REF(p, r) \
+ grpc_subchannel_weak_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
+ grpc_subchannel_weak_unref((cl), (p), __FILE__, __LINE__, (r))
+#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) \
+ grpc_connected_subchannel_ref((p), __FILE__, __LINE__, (r))
+#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
+ grpc_connected_subchannel_unref((cl), (p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) \
grpc_subchannel_call_ref((p), __FILE__, __LINE__, (r))
#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
@@ -58,6 +67,12 @@ typedef struct grpc_subchannel_args grpc_subchannel_args;
#else
#define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p))
#define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p))
+#define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p))
+#define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \
+ grpc_subchannel_weak_unref((cl), (p))
+#define GRPC_CONNECTED_SUBCHANNEL_REF(p, r) grpc_connected_subchannel_ref((p))
+#define GRPC_CONNECTED_SUBCHANNEL_UNREF(cl, p, r) \
+ grpc_connected_subchannel_unref((cl), (p))
#define GRPC_SUBCHANNEL_CALL_REF(p, r) grpc_subchannel_call_ref((p))
#define GRPC_SUBCHANNEL_CALL_UNREF(cl, p, r) \
grpc_subchannel_call_unref((cl), (p))
@@ -69,33 +84,31 @@ void grpc_subchannel_ref(grpc_subchannel *channel
void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel *channel
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_weak_ref(grpc_subchannel *channel
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx,
+ grpc_subchannel *channel
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_connected_subchannel_ref(grpc_connected_subchannel *channel
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
+void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx,
+ grpc_connected_subchannel *channel
+ GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_ref(grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-/** construct a subchannel call (possibly asynchronously).
- *
- * If the returned status is 1, the call will return immediately and \a target
- * will point to a connected \a subchannel_call instance. Note that \a notify
- * will \em not be invoked in this case.
- * Otherwise, if the returned status is 0, the subchannel call will be created
- * asynchronously, invoking the \a notify callback upon completion. */
-int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- grpc_pollset *pollset, gpr_atm *target,
- grpc_closure *notify);
-
-/** cancel \a call in the waiting state. */
-void grpc_subchannel_cancel_create_call(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- gpr_atm *target);
+/** 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);
/** process a transport level op */
-void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- grpc_transport_op *op);
+void grpc_connected_subchannel_process_transport_op(
+ grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *subchannel,
+ grpc_transport_op *op);
/** poll the current connectivity state of a channel */
grpc_connectivity_state grpc_subchannel_check_connectivity(
@@ -103,26 +116,22 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(
/** call notify when the connectivity state of a channel changes from *state.
Updates *state with the new state of the channel */
-void grpc_subchannel_notify_on_state_change(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *channel,
- grpc_connectivity_state *state,
- grpc_closure *notify);
-
-/** Remove \a subscribed_notify from the list of closures to be called on a
- * state change if present, returning 1. Otherwise, nothing is done and return
- * 0. */
-int grpc_subchannel_state_change_unsubscribe(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *channel,
- grpc_closure *subscribed_notify);
-
-/** express interest in \a channel's activities through \a pollset. */
-void grpc_subchannel_add_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *channel,
- grpc_pollset *pollset);
-/** stop following \a channel's activity through \a pollset. */
-void grpc_subchannel_del_interested_party(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *channel,
- grpc_pollset *pollset);
+void grpc_subchannel_notify_on_state_change(
+ grpc_exec_ctx *exec_ctx, grpc_subchannel *channel,
+ grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+ grpc_closure *notify);
+void grpc_connected_subchannel_notify_on_state_change(
+ grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *channel,
+ grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
+ grpc_closure *notify);
+void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
+ grpc_connected_subchannel *channel,
+ grpc_closure *notify);
+
+/** retrieve the grpc_connected_subchannel - or NULL if called before
+ the subchannel becomes connected */
+grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel(
+ grpc_subchannel *subchannel);
/** continue processing a transport op */
void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx,
@@ -147,15 +156,10 @@ struct grpc_subchannel_args {
/** Address to connect to */
struct sockaddr *addr;
size_t addr_len;
- /** master channel */
- grpc_channel *master;
};
/** create a subchannel given a connector */
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector,
grpc_subchannel_args *args);
-/** Return the master channel associated with the subchannel */
-grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel);
-
#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */
diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h b/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
deleted file mode 100644
index 76a535ebed..0000000000
--- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.h
+++ /dev/null
@@ -1,46 +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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H
-
-#include "src/core/client_config/subchannel_factory.h"
-
-/** Takes a subchannel factory, returns a new one that mutates incoming
- channel_args by adding a new argument; ownership of input, arg is retained
- by the caller. */
-grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg(
- grpc_subchannel_factory *input, const grpc_arg *arg);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_ADD_CHANNEL_ARG_H \
- */
diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
deleted file mode 100644
index cd25fdcf0f..0000000000
--- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/client_config/subchannel_factory_decorators/merge_channel_args.h"
-#include <grpc/support/alloc.h>
-#include "src/core/channel/channel_args.h"
-
-typedef struct {
- grpc_subchannel_factory base;
- gpr_refcount refs;
- grpc_subchannel_factory *wrapped;
- grpc_channel_args *merge_args;
-} merge_args_factory;
-
-static void merge_args_factory_ref(grpc_subchannel_factory *scf) {
- merge_args_factory *f = (merge_args_factory *)scf;
- gpr_ref(&f->refs);
-}
-
-static void merge_args_factory_unref(grpc_exec_ctx *exec_ctx,
- grpc_subchannel_factory *scf) {
- merge_args_factory *f = (merge_args_factory *)scf;
- if (gpr_unref(&f->refs)) {
- grpc_subchannel_factory_unref(exec_ctx, f->wrapped);
- grpc_channel_args_destroy(f->merge_args);
- gpr_free(f);
- }
-}
-
-static grpc_subchannel *merge_args_factory_create_subchannel(
- grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *scf,
- grpc_subchannel_args *args) {
- merge_args_factory *f = (merge_args_factory *)scf;
- grpc_channel_args *final_args =
- grpc_channel_args_merge(args->args, f->merge_args);
- grpc_subchannel *s;
- args->args = final_args;
- s = grpc_subchannel_factory_create_subchannel(exec_ctx, f->wrapped, args);
- grpc_channel_args_destroy(final_args);
- return s;
-}
-
-static const grpc_subchannel_factory_vtable merge_args_factory_vtable = {
- merge_args_factory_ref, merge_args_factory_unref,
- merge_args_factory_create_subchannel};
-
-grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args(
- grpc_subchannel_factory *input, const grpc_channel_args *args) {
- merge_args_factory *f = gpr_malloc(sizeof(*f));
- f->base.vtable = &merge_args_factory_vtable;
- gpr_ref_init(&f->refs, 1);
- grpc_subchannel_factory_ref(input);
- f->wrapped = input;
- f->merge_args = grpc_channel_args_copy(args);
- return &f->base;
-}
diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
deleted file mode 100644
index a9e1691871..0000000000
--- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.h
+++ /dev/null
@@ -1,46 +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.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H
-#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H
-
-#include "src/core/client_config/subchannel_factory.h"
-
-/** Takes a subchannel factory, returns a new one that mutates incoming
- channel_args by adding a new argument; ownership of input, args is retained
- by the caller. */
-grpc_subchannel_factory *grpc_subchannel_factory_merge_channel_args(
- grpc_subchannel_factory *input, const grpc_channel_args *args);
-
-#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_FACTORY_DECORATORS_MERGE_CHANNEL_ARGS_H \
- */
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index 73d91fa8ea..8e4e5c91d4 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -119,8 +119,8 @@ grpc_mdelem *grpc_compression_encoding_mdelem(
return GRPC_MDELEM_GRPC_ENCODING_DEFLATE;
case GRPC_COMPRESS_GZIP:
return GRPC_MDELEM_GRPC_ENCODING_GZIP;
- case GRPC_COMPRESS_ALGORITHMS_COUNT:
- return NULL;
+ default:
+ break;
}
return NULL;
}
@@ -139,25 +139,9 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
case GRPC_COMPRESS_LEVEL_HIGH:
return GRPC_COMPRESS_DEFLATE;
default:
- /* we shouldn't be making it here */
- abort();
- return GRPC_COMPRESS_NONE;
- }
-}
-
-grpc_compression_level grpc_compression_level_for_algorithm(
- grpc_compression_algorithm algorithm) {
- grpc_compression_level clevel;
- GRPC_API_TRACE("grpc_compression_level_for_algorithm(algorithm=%d)", 1,
- ((int)algorithm));
- for (clevel = GRPC_COMPRESS_LEVEL_NONE; clevel < GRPC_COMPRESS_LEVEL_COUNT;
- ++clevel) {
- if (grpc_compression_algorithm_for_level(clevel) == algorithm) {
- return clevel;
- }
+ break;
}
- abort();
- return GRPC_COMPRESS_LEVEL_NONE;
+ GPR_UNREACHABLE_CODE(return GRPC_COMPRESS_NONE);
}
void grpc_compression_options_init(grpc_compression_options *opts) {
diff --git a/src/core/compression/message_compress.c b/src/core/compression/message_compress.c
index 209c1f0ff1..edc21a9eb7 100644
--- a/src/core/compression/message_compress.c
+++ b/src/core/compression/message_compress.c
@@ -69,8 +69,8 @@ static int zlib_body(z_stream* zs, gpr_slice_buffer* input,
zs->next_out = GPR_SLICE_START_PTR(outbuf);
}
r = flate(zs, flush);
- if (r == Z_STREAM_ERROR) {
- gpr_log(GPR_INFO, "zlib: stream error");
+ if (r < 0 && r != Z_BUF_ERROR /* not fatal */) {
+ gpr_log(GPR_INFO, "zlib error (%d)", r);
goto error;
}
} while (zs->avail_out == 0);
@@ -91,6 +91,12 @@ error:
return 0;
}
+static void* zalloc_gpr(void* opaque, unsigned int items, unsigned int size) {
+ return gpr_malloc(items * size);
+}
+
+static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
+
static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
int gzip) {
z_stream zs;
@@ -99,12 +105,11 @@ static int zlib_compress(gpr_slice_buffer* input, gpr_slice_buffer* output,
size_t count_before = output->count;
size_t length_before = output->length;
memset(&zs, 0, sizeof(zs));
+ zs.zalloc = zalloc_gpr;
+ zs.zfree = zfree_gpr;
r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
8, Z_DEFAULT_STRATEGY);
- if (r != Z_OK) {
- gpr_log(GPR_ERROR, "deflateInit2 returns %d", r);
- return 0;
- }
+ GPR_ASSERT(r == Z_OK);
r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
if (!r) {
for (i = count_before; i < output->count; i++) {
@@ -125,11 +130,10 @@ static int zlib_decompress(gpr_slice_buffer* input, gpr_slice_buffer* output,
size_t count_before = output->count;
size_t length_before = output->length;
memset(&zs, 0, sizeof(zs));
+ zs.zalloc = zalloc_gpr;
+ zs.zfree = zfree_gpr;
r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
- if (r != Z_OK) {
- gpr_log(GPR_ERROR, "inflateInit2 returns %d", r);
- return 0;
- }
+ GPR_ASSERT(r == Z_OK);
r = zlib_body(&zs, input, output, inflate);
if (!r) {
for (i = count_before; i < output->count; i++) {
@@ -150,8 +154,8 @@ static int copy(gpr_slice_buffer* input, gpr_slice_buffer* output) {
return 1;
}
-int compress_inner(grpc_compression_algorithm algorithm,
- gpr_slice_buffer* input, gpr_slice_buffer* output) {
+static int compress_inner(grpc_compression_algorithm algorithm,
+ gpr_slice_buffer* input, gpr_slice_buffer* output) {
switch (algorithm) {
case GRPC_COMPRESS_NONE:
/* the fallback path always needs to be send uncompressed: we simply
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index a87f1aa87b..b5cd8d8d2a 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -53,6 +53,7 @@ typedef struct {
size_t next_address;
grpc_endpoint *ep;
char *host;
+ char *ssl_host_override;
gpr_timespec deadline;
int have_read_byte;
const grpc_httpcli_handshaker *handshaker;
@@ -106,6 +107,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
}
gpr_slice_unref(req->request_text);
gpr_free(req->host);
+ gpr_free(req->ssl_host_override);
grpc_iomgr_unregister_object(&req->iomgr_obj);
gpr_slice_buffer_destroy(&req->incoming);
gpr_slice_buffer_destroy(&req->outgoing);
@@ -180,8 +182,10 @@ static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
next_address(exec_ctx, req);
return;
}
- req->handshaker->handshake(exec_ctx, req, req->ep, req->host,
- on_handshake_done);
+ req->handshaker->handshake(
+ exec_ctx, req, req->ep,
+ req->ssl_host_override ? req->ssl_host_override : req->host,
+ on_handshake_done);
}
static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
@@ -231,6 +235,7 @@ static void internal_request_begin(
gpr_slice_buffer_init(&req->outgoing);
grpc_iomgr_register_object(&req->iomgr_obj, name);
req->host = gpr_strdup(request->host);
+ req->ssl_host_override = gpr_strdup(request->ssl_host_override);
grpc_pollset_set_add_pollset(exec_ctx, &req->context->pollset_set,
req->pollset);
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
index 6469c2f03e..30875d71f1 100644
--- a/src/core/httpcli/httpcli.h
+++ b/src/core/httpcli/httpcli.h
@@ -74,6 +74,8 @@ extern const grpc_httpcli_handshaker grpc_httpcli_ssl;
typedef struct grpc_httpcli_request {
/* The host name to connect to */
char *host;
+ /* The host to verify in the SSL handshake (or NULL) */
+ char *ssl_host_override;
/* The path of the resource to fetch */
char *path;
/* Additional headers: count and key/values; the following are supplied
diff --git a/src/core/httpcli/httpcli_security_connector.c b/src/core/httpcli/httpcli_security_connector.c
index fc6699c918..a5aa551373 100644
--- a/src/core/httpcli/httpcli_security_connector.c
+++ b/src/core/httpcli/httpcli_security_connector.c
@@ -68,7 +68,7 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
tsi_result result = TSI_OK;
tsi_handshaker *handshaker;
if (c->handshaker_factory == NULL) {
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
+ cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
return;
}
result = tsi_ssl_handshaker_factory_create_handshaker(
@@ -76,7 +76,7 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
tsi_result_to_string(result));
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
+ cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
user_data);
@@ -149,7 +149,6 @@ typedef struct {
static void on_secure_transport_setup_done(grpc_exec_ctx *exec_ctx, void *rp,
grpc_security_status status,
- grpc_endpoint *wrapped_endpoint,
grpc_endpoint *secure_endpoint) {
on_done_closure *c = rp;
if (status != GRPC_SECURITY_OK) {
diff --git a/src/core/iomgr/endpoint_pair_posix.c b/src/core/iomgr/endpoint_pair_posix.c
index deae9c6875..56f6f146fd 100644
--- a/src/core/iomgr/endpoint_pair_posix.c
+++ b/src/core/iomgr/endpoint_pair_posix.c
@@ -36,6 +36,7 @@
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/endpoint_pair.h"
+#include "src/core/iomgr/socket_utils_posix.h"
#include <errno.h>
#include <fcntl.h>
@@ -56,6 +57,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]));
}
grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 2be0ea235f..00710d83bd 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -43,6 +43,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
#include <grpc/support/useful.h>
#define CLOSURE_NOT_READY ((grpc_closure *)0)
@@ -158,7 +159,10 @@ void grpc_fd_global_shutdown(void) {
grpc_fd *grpc_fd_create(int fd, const char *name) {
grpc_fd *r = alloc_fd(fd);
- grpc_iomgr_register_object(&r->iomgr_object, name);
+ char *name2;
+ gpr_asprintf(&name2, "%s fd=%d", name, fd);
+ grpc_iomgr_register_object(&r->iomgr_object, name2);
+ gpr_free(name2);
#ifdef GRPC_FD_REF_COUNT_DEBUG
gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, r, name);
#endif
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
index d628ef3aaf..df4eb64d4c 100644
--- a/src/core/iomgr/fd_posix.h
+++ b/src/core/iomgr/fd_posix.h
@@ -170,6 +170,7 @@ void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd);
/* Reference counting for fds */
+/*#define GRPC_FD_REF_COUNT_DEBUG*/
#ifdef GRPC_FD_REF_COUNT_DEBUG
void grpc_fd_ref(grpc_fd *fd, const char *reason, const char *file, int line);
void grpc_fd_unref(grpc_fd *fd, const char *reason, const char *file, int line);
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index 1f1bf47e98..6e31efa013 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -123,26 +123,6 @@ static void multipoll_with_epoll_pollset_add_fd(grpc_exec_ctx *exec_ctx,
}
}
-static void multipoll_with_epoll_pollset_del_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_fd *fd,
- int and_unlock_pollset) {
- pollset_hdr *h = pollset->data.ptr;
- int err;
-
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- }
-
- /* Note that this can race with concurrent poll, but that should be fine since
- * at worst it creates a spurious read event on a reused grpc_fd object. */
- err = epoll_ctl(h->epoll_fd, EPOLL_CTL_DEL, fd->fd, NULL);
- if (err < 0) {
- gpr_log(GPR_ERROR, "epoll_ctl del for %d failed: %s", fd->fd,
- strerror(errno));
- }
-}
-
/* TODO(klempner): We probably want to turn this down a bit */
#define GRPC_EPOLL_MAX_EVENTS 1000
@@ -235,7 +215,7 @@ static void multipoll_with_epoll_pollset_destroy(grpc_pollset *pollset) {
}
static const grpc_pollset_vtable multipoll_with_epoll_pollset = {
- multipoll_with_epoll_pollset_add_fd, multipoll_with_epoll_pollset_del_fd,
+ multipoll_with_epoll_pollset_add_fd,
multipoll_with_epoll_pollset_maybe_work_and_unlock,
multipoll_with_epoll_pollset_finish_shutdown,
multipoll_with_epoll_pollset_destroy};
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index 09f04b64b9..b619b8c3db 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -82,23 +82,6 @@ exit:
}
}
-static void multipoll_with_poll_pollset_del_fd(grpc_exec_ctx *exec_ctx,
- grpc_pollset *pollset,
- grpc_fd *fd,
- int and_unlock_pollset) {
- /* will get removed next poll cycle */
- pollset_hdr *h = pollset->data.ptr;
- if (h->del_count == h->del_capacity) {
- h->del_capacity = GPR_MAX(h->del_capacity + 8, h->del_count * 3 / 2);
- h->dels = gpr_realloc(h->dels, sizeof(grpc_fd *) * h->del_capacity);
- }
- h->dels[h->del_count++] = fd;
- GRPC_FD_REF(fd, "multipoller_del");
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- }
-}
-
static void 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) {
@@ -212,7 +195,7 @@ static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
}
static const grpc_pollset_vtable multipoll_with_poll_pollset = {
- multipoll_with_poll_pollset_add_fd, multipoll_with_poll_pollset_del_fd,
+ multipoll_with_poll_pollset_add_fd,
multipoll_with_poll_pollset_maybe_work_and_unlock,
multipoll_with_poll_pollset_finish_shutdown,
multipoll_with_poll_pollset_destroy};
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 0a5577baea..9195344758 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -232,21 +232,7 @@ void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
gpr_mu_lock(&pollset->mu);
pollset->vtable->add_fd(exec_ctx, pollset, fd, 1);
/* the following (enabled only in debug) will reacquire and then release
- our lock - meaning that if the unlocking flag passed to del_fd above is
- not respected, the code will deadlock (in a way that we have a chance of
- debugging) */
-#ifndef NDEBUG
- gpr_mu_lock(&pollset->mu);
- gpr_mu_unlock(&pollset->mu);
-#endif
-}
-
-void grpc_pollset_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_fd *fd) {
- gpr_mu_lock(&pollset->mu);
- pollset->vtable->del_fd(exec_ctx, pollset, fd, 1);
-/* the following (enabled only in debug) will reacquire and then release
- our lock - meaning that if the unlocking flag passed to del_fd above is
+ our lock - meaning that if the unlocking flag passed to add_fd above is
not respected, the code will deadlock (in a way that we have a chance of
debugging) */
#ifndef NDEBUG
@@ -547,19 +533,6 @@ exit:
}
}
-static void basic_pollset_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- grpc_fd *fd, int and_unlock_pollset) {
- GPR_ASSERT(fd);
- if (fd == pollset->data.ptr) {
- GRPC_FD_UNREF(pollset->data.ptr, "basicpoll");
- pollset->data.ptr = NULL;
- }
-
- if (and_unlock_pollset) {
- gpr_mu_unlock(&pollset->mu);
- }
-}
-
static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
grpc_pollset_worker *worker,
@@ -651,9 +624,8 @@ static void basic_pollset_destroy(grpc_pollset *pollset) {
}
static const grpc_pollset_vtable basic_pollset = {
- basic_pollset_add_fd, basic_pollset_del_fd,
- basic_pollset_maybe_work_and_unlock, basic_pollset_destroy,
- basic_pollset_destroy};
+ basic_pollset_add_fd, basic_pollset_maybe_work_and_unlock,
+ basic_pollset_destroy, basic_pollset_destroy};
static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null) {
pollset->vtable = &basic_pollset;
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index e4593728bd..29de4a2026 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -86,8 +86,6 @@ typedef 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 (*del_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);
@@ -100,10 +98,6 @@ struct grpc_pollset_vtable {
/* Add an fd to a pollset */
void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd);
-/* Force remove an fd from a pollset (normally they are removed on the next
- poll after an fd is orphaned) */
-void grpc_pollset_del_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
- struct grpc_fd *fd);
/* Returns the fd to listen on for kicks */
int grpc_kick_read_fd(grpc_pollset *p);
diff --git a/src/core/iomgr/pollset_set.h b/src/core/iomgr/pollset_set.h
index 0fdcba01a4..09c04438f7 100644
--- a/src/core/iomgr/pollset_set.h
+++ b/src/core/iomgr/pollset_set.h
@@ -49,13 +49,19 @@
#include "src/core/iomgr/pollset_set_windows.h"
#endif
-void grpc_pollset_set_init(grpc_pollset_set* pollset_set);
-void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set);
-void grpc_pollset_set_add_pollset(grpc_exec_ctx* exec_ctx,
- grpc_pollset_set* pollset_set,
- grpc_pollset* pollset);
-void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
- grpc_pollset_set* pollset_set,
- grpc_pollset* pollset);
+void grpc_pollset_set_init(grpc_pollset_set *pollset_set);
+void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
+void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *pollset_set,
+ grpc_pollset *pollset);
+void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *pollset_set,
+ grpc_pollset *pollset);
+void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *bag,
+ grpc_pollset_set *item);
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *bag,
+ grpc_pollset_set *item);
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_H */
diff --git a/src/core/iomgr/pollset_set_posix.c b/src/core/iomgr/pollset_set_posix.c
index c86ed3d5da..4ec92202e3 100644
--- a/src/core/iomgr/pollset_set_posix.c
+++ b/src/core/iomgr/pollset_set_posix.c
@@ -52,9 +52,10 @@ void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
size_t i;
gpr_mu_destroy(&pollset_set->mu);
for (i = 0; i < pollset_set->fd_count; i++) {
- GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
+ GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
}
gpr_free(pollset_set->pollsets);
+ gpr_free(pollset_set->pollset_sets);
gpr_free(pollset_set->fds);
}
@@ -73,7 +74,7 @@ void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
pollset_set->pollsets[pollset_set->pollset_count++] = pollset;
for (i = 0, j = 0; i < pollset_set->fd_count; i++) {
if (grpc_fd_is_orphaned(pollset_set->fds[i])) {
- GRPC_FD_UNREF(pollset_set->fds[i], "pollset");
+ GRPC_FD_UNREF(pollset_set->fds[i], "pollset_set");
} else {
grpc_pollset_add_fd(exec_ctx, pollset, pollset_set->fds[i]);
pollset_set->fds[j++] = pollset_set->fds[i];
@@ -99,6 +100,46 @@ void grpc_pollset_set_del_pollset(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&pollset_set->mu);
}
+void grpc_pollset_set_add_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *bag,
+ grpc_pollset_set *item) {
+ size_t i, j;
+ gpr_mu_lock(&bag->mu);
+ if (bag->pollset_set_count == bag->pollset_set_capacity) {
+ bag->pollset_set_capacity = GPR_MAX(8, 2 * bag->pollset_set_capacity);
+ bag->pollset_sets =
+ gpr_realloc(bag->pollset_sets,
+ bag->pollset_set_capacity * sizeof(*bag->pollset_sets));
+ }
+ bag->pollset_sets[bag->pollset_set_count++] = item;
+ for (i = 0, j = 0; i < bag->fd_count; i++) {
+ if (grpc_fd_is_orphaned(bag->fds[i])) {
+ GRPC_FD_UNREF(bag->fds[i], "pollset_set");
+ } else {
+ grpc_pollset_set_add_fd(exec_ctx, item, bag->fds[i]);
+ bag->fds[j++] = bag->fds[i];
+ }
+ }
+ bag->fd_count = j;
+ gpr_mu_unlock(&bag->mu);
+}
+
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx *exec_ctx,
+ grpc_pollset_set *bag,
+ grpc_pollset_set *item) {
+ size_t i;
+ gpr_mu_lock(&bag->mu);
+ for (i = 0; i < bag->pollset_set_count; i++) {
+ if (bag->pollset_sets[i] == item) {
+ bag->pollset_set_count--;
+ GPR_SWAP(grpc_pollset_set *, bag->pollset_sets[i],
+ bag->pollset_sets[bag->pollset_set_count]);
+ break;
+ }
+ }
+ gpr_mu_unlock(&bag->mu);
+}
+
void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_fd *fd) {
size_t i;
@@ -113,6 +154,9 @@ void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
for (i = 0; i < pollset_set->pollset_count; i++) {
grpc_pollset_add_fd(exec_ctx, pollset_set->pollsets[i], fd);
}
+ for (i = 0; i < pollset_set->pollset_set_count; i++) {
+ grpc_pollset_set_add_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
+ }
gpr_mu_unlock(&pollset_set->mu);
}
@@ -129,6 +173,9 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
break;
}
}
+ for (i = 0; i < pollset_set->pollset_set_count; i++) {
+ grpc_pollset_set_del_fd(exec_ctx, pollset_set->pollset_sets[i], fd);
+ }
gpr_mu_unlock(&pollset_set->mu);
}
diff --git a/src/core/iomgr/pollset_set_posix.h b/src/core/iomgr/pollset_set_posix.h
index 05234fb642..4820a61e4b 100644
--- a/src/core/iomgr/pollset_set_posix.h
+++ b/src/core/iomgr/pollset_set_posix.h
@@ -44,6 +44,10 @@ typedef struct grpc_pollset_set {
size_t pollset_capacity;
grpc_pollset **pollsets;
+ size_t pollset_set_count;
+ size_t pollset_set_capacity;
+ struct grpc_pollset_set **pollset_sets;
+
size_t fd_count;
size_t fd_capacity;
grpc_fd **fds;
diff --git a/src/core/iomgr/pollset_set_windows.c b/src/core/iomgr/pollset_set_windows.c
index 53d5d3dcd4..157b46ec32 100644
--- a/src/core/iomgr/pollset_set_windows.c
+++ b/src/core/iomgr/pollset_set_windows.c
@@ -49,4 +49,12 @@ void grpc_pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
grpc_pollset_set* pollset_set,
grpc_pollset* pollset) {}
+void grpc_pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx,
+ grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
+
+void grpc_pollset_set_del_pollset_set(grpc_exec_ctx* exec_ctx,
+ grpc_pollset_set* bag,
+ grpc_pollset_set* item) {}
+
#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index a89ee02d34..835675c390 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -411,7 +411,6 @@ static grpc_tcp_listener *add_socket_to_server(grpc_tcp_server *s, int fd,
grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
const void *addr, size_t addr_len) {
- int allocated_port = -1;
grpc_tcp_listener *sp;
grpc_tcp_listener *sp2 = NULL;
int fd;
@@ -464,14 +463,13 @@ grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
addr_len = sizeof(wild6);
fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
sp = add_socket_to_server(s, fd, addr, addr_len);
- allocated_port = sp->port;
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
goto done;
}
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
- if (port == 0 && allocated_port > 0) {
- grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port);
+ if (port == 0 && sp != NULL) {
+ grpc_sockaddr_set_port((struct sockaddr *)&wild4, sp->port);
sp2 = sp;
}
addr = (struct sockaddr *)&wild4;
@@ -488,8 +486,8 @@ grpc_tcp_listener *grpc_tcp_server_add_port(grpc_tcp_server *s,
addr_len = sizeof(addr4_copy);
}
sp = add_socket_to_server(s, fd, addr, addr_len);
- sp->sibling = sp2;
- if (sp2) sp2->is_sibling = 1;
+ if (sp != NULL) sp->sibling = sp2;
+ if (sp2 != NULL) sp2->is_sibling = 1;
done:
gpr_free(allocated_addr);
@@ -534,8 +532,12 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
}
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
- grpc_tcp_listener *sp = listener;
- return sp->port;
+ if (listener != NULL) {
+ grpc_tcp_listener *sp = listener;
+ return sp->port;
+ } else {
+ return 0;
+ }
}
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index a2425cd4d2..583cab4890 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -486,8 +486,12 @@ void grpc_tcp_server_start(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s,
}
int grpc_tcp_listener_get_port(grpc_tcp_listener *listener) {
- grpc_tcp_listener *sp = listener;
- return sp->port;
+ if (listener != NULL) {
+ grpc_tcp_listener *sp = listener;
+ return sp->port;
+ } else {
+ return 0;
+ }
}
void grpc_tcp_listener_ref(grpc_tcp_listener *listener) {
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 5ff78231bd..cc7f7ff8d2 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -197,7 +197,8 @@ static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
tcp->read_slice = gpr_slice_malloc(8192);
- buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
+ buffer.len = (ULONG)GPR_SLICE_LENGTH(
+ tcp->read_slice); // we know slice size fits in 32bit.
buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
TCP_REF(tcp, "read");
@@ -273,6 +274,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
WSABUF local_buffers[16];
WSABUF *allocated = NULL;
WSABUF *buffers = local_buffers;
+ size_t len;
if (tcp->shutting_down) {
grpc_exec_ctx_enqueue(exec_ctx, cb, 0);
@@ -281,19 +283,21 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
tcp->write_cb = cb;
tcp->write_slices = slices;
-
+ GPR_ASSERT(tcp->write_slices->count <= UINT_MAX);
if (tcp->write_slices->count > GPR_ARRAY_SIZE(local_buffers)) {
buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices->count);
allocated = buffers;
}
for (i = 0; i < tcp->write_slices->count; i++) {
- buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
+ len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
+ GPR_ASSERT(len <= ULONG_MAX);
+ buffers[i].len = (ULONG)len;
buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices->slices[i]);
}
/* First, let's try a synchronous, non-blocking write. */
- status = WSASend(socket->socket, buffers, tcp->write_slices->count,
+ status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
&bytes_sent, 0, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
@@ -322,7 +326,7 @@ static void win_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
/* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
operation, this time asynchronously. */
memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
- status = WSASend(socket->socket, buffers, tcp->write_slices->count,
+ status = WSASend(socket->socket, buffers, (DWORD)tcp->write_slices->count,
&bytes_sent, 0, &socket->write_info.overlapped, NULL);
if (allocated) gpr_free(allocated);
diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c
index 66fafe75ad..bbf9800049 100644
--- a/src/core/iomgr/timer.c
+++ b/src/core/iomgr/timer.c
@@ -126,8 +126,8 @@ static double ts_to_dbl(gpr_timespec ts) {
static gpr_timespec dbl_to_ts(double d) {
gpr_timespec ts;
- ts.tv_sec = (time_t)d;
- ts.tv_nsec = (int)(1e9 * (d - (double)ts.tv_sec));
+ ts.tv_sec = (gpr_int64)d;
+ ts.tv_nsec = (gpr_int32)(1e9 * (d - (double)ts.tv_sec));
ts.clock_type = GPR_TIMESPAN;
return ts;
}
@@ -343,11 +343,3 @@ int grpc_timer_check(grpc_exec_ctx *exec_ctx, gpr_timespec now,
exec_ctx, now, next,
gpr_time_cmp(now, gpr_inf_future(now.clock_type)) != 0);
}
-
-gpr_timespec grpc_timer_list_next_timeout(void) {
- gpr_timespec out;
- gpr_mu_lock(&g_mu);
- out = g_shard_queue[0]->min_deadline;
- gpr_mu_unlock(&g_mu);
- return out;
-}
diff --git a/src/core/iomgr/timer_internal.h b/src/core/iomgr/timer_internal.h
index f180eca36e..f182e73764 100644
--- a/src/core/iomgr/timer_internal.h
+++ b/src/core/iomgr/timer_internal.h
@@ -54,8 +54,6 @@ int grpc_timer_check(grpc_exec_ctx* exec_ctx, gpr_timespec now,
void grpc_timer_list_init(gpr_timespec now);
void grpc_timer_list_shutdown(grpc_exec_ctx* exec_ctx);
-gpr_timespec grpc_timer_list_next_timeout(void);
-
/* the following must be implemented by each iomgr implementation */
void grpc_kick_poller(void);
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
index 782fbd9f46..28f1bfae26 100644
--- a/src/core/iomgr/udp_server.c
+++ b/src/core/iomgr/udp_server.c
@@ -38,6 +38,7 @@
#include <grpc/support/port_platform.h>
+#ifdef GRPC_NEED_UDP
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/udp_server.h"
@@ -435,3 +436,4 @@ void grpc_udp_server_write(server_port *sp, const char *buffer, size_t buf_len,
}
#endif
+#endif
diff --git a/src/core/iomgr/wakeup_fd_posix.c b/src/core/iomgr/wakeup_fd_posix.c
index d09fb78d12..f40be081b0 100644
--- a/src/core/iomgr/wakeup_fd_posix.c
+++ b/src/core/iomgr/wakeup_fd_posix.c
@@ -40,19 +40,17 @@
#include <stddef.h>
static const grpc_wakeup_fd_vtable *wakeup_fd_vtable = NULL;
+int grpc_allow_specialized_wakeup_fd = 1;
void grpc_wakeup_fd_global_init(void) {
- if (grpc_specialized_wakeup_fd_vtable.check_availability()) {
+ if (grpc_allow_specialized_wakeup_fd &&
+ grpc_specialized_wakeup_fd_vtable.check_availability()) {
wakeup_fd_vtable = &grpc_specialized_wakeup_fd_vtable;
} else {
wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
}
}
-void grpc_wakeup_fd_global_init_force_fallback(void) {
- wakeup_fd_vtable = &grpc_pipe_wakeup_fd_vtable;
-}
-
void grpc_wakeup_fd_global_destroy(void) { wakeup_fd_vtable = NULL; }
void grpc_wakeup_fd_init(grpc_wakeup_fd *fd_info) {
diff --git a/src/core/iomgr/wakeup_fd_posix.h b/src/core/iomgr/wakeup_fd_posix.h
index fe71b5abe9..ffd60d1d4e 100644
--- a/src/core/iomgr/wakeup_fd_posix.h
+++ b/src/core/iomgr/wakeup_fd_posix.h
@@ -85,6 +85,8 @@ struct grpc_wakeup_fd {
int write_fd;
};
+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);
diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c
index 2e30178131..d2a1c34612 100644
--- a/src/core/iomgr/workqueue_posix.c
+++ b/src/core/iomgr/workqueue_posix.c
@@ -103,6 +103,9 @@ 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_closure_list_move(&exec_ctx->closure_list, &workqueue->closure_list);
gpr_mu_unlock(&workqueue->mu);
}
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
index 8abad01252..256995240a 100644
--- a/src/core/json/json_reader.c
+++ b/src/core/json/json_reader.c
@@ -35,6 +35,8 @@
#include <grpc/support/port_platform.h>
+#include <grpc/support/log.h>
+
#include "src/core/json/json_reader.h"
static void json_reader_string_clear(grpc_json_reader *reader) {
@@ -224,13 +226,13 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
reader->in_array = 1;
break;
case GRPC_JSON_TOP_LEVEL:
- if (reader->depth != 0) return GRPC_JSON_INTERNAL_ERROR;
+ GPR_ASSERT(reader->depth == 0);
reader->in_object = 0;
reader->in_array = 0;
reader->state = GRPC_JSON_STATE_END;
break;
default:
- return GRPC_JSON_INTERNAL_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
}
}
break;
@@ -279,8 +281,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
break;
case GRPC_JSON_STATE_OBJECT_KEY_STRING:
- if (reader->unicode_high_surrogate != 0)
- return GRPC_JSON_PARSE_ERROR;
+ GPR_ASSERT(reader->unicode_high_surrogate == 0);
if (c == '"') {
reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
json_reader_set_key(reader);
@@ -461,7 +462,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
}
break;
default:
- return GRPC_JSON_INTERNAL_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
}
break;
@@ -641,7 +642,7 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
case ',':
case '}':
case ']':
- return GRPC_JSON_INTERNAL_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
break;
default:
@@ -655,5 +656,5 @@ grpc_json_reader_status grpc_json_reader_run(grpc_json_reader *reader) {
}
}
- return GRPC_JSON_INTERNAL_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_JSON_INTERNAL_ERROR);
}
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
index 0461c2703f..06c157dc98 100644
--- a/src/core/json/json_string.c
+++ b/src/core/json/json_string.c
@@ -353,7 +353,7 @@ static void json_dump_recursive(grpc_json_writer *writer, grpc_json *json,
grpc_json_writer_value_raw_with_len(writer, "null", 4);
break;
default:
- abort();
+ GPR_UNREACHABLE_CODE(abort());
}
json = json->next;
}
diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c
index f0fce7858d..eedd387ebc 100644
--- a/src/core/profiling/basic_timers.c
+++ b/src/core/profiling/basic_timers.c
@@ -141,10 +141,11 @@ static void write_log(gpr_timer_log *log) {
entry->tm = gpr_time_0(entry->tm.clock_type);
}
fprintf(output_file,
- "{\"t\": %ld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
+ "{\"t\": %lld.%09d, \"thd\": \"%d\", \"type\": \"%c\", \"tag\": "
"\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
- entry->tm.tv_sec, entry->tm.tv_nsec, entry->thd, entry->type,
- entry->tagstr, entry->file, entry->line, entry->important);
+ (long long)entry->tm.tv_sec, (int)entry->tm.tv_nsec, entry->thd,
+ entry->type, entry->tagstr, entry->file, entry->line,
+ entry->important);
}
}
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 4e5be03d85..b1fd733c91 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -39,11 +39,11 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-#include "src/core/support/string.h"
#include "src/core/channel/channel_stack.h"
-#include "src/core/security/security_context.h"
-#include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h"
+#include "src/core/security/security_connector.h"
+#include "src/core/security/security_context.h"
+#include "src/core/support/string.h"
#include "src/core/surface/call.h"
#include "src/core/transport/static_metadata.h"
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 543c75044b..a0054741ad 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -39,7 +39,7 @@
#include "src/core/channel/channel_args.h"
#include "src/core/channel/http_client_filter.h"
#include "src/core/httpcli/httpcli.h"
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/iomgr/executor.h"
#include "src/core/json/json.h"
#include "src/core/support/string.h"
#include "src/core/surface/api_trace.h"
@@ -48,7 +48,6 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
#include <grpc/support/time.h>
/* -- Common. -- */
@@ -511,10 +510,11 @@ 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: %ld, tv_nsec: %d, clock_type: %d }, "
+ "gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
- 5, (json_key, (long)token_lifetime.tv_sec, token_lifetime.tv_nsec,
- (int)token_lifetime.clock_type, reserved));
+ 5,
+ (json_key, (long long)token_lifetime.tv_sec, (int)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(
grpc_auth_json_key_create_from_string(json_key), token_lifetime);
@@ -792,15 +792,14 @@ static void md_only_test_destruct(grpc_call_credentials *creds) {
grpc_credentials_md_store_unref(c->md_store);
}
-static void on_simulated_token_fetch_done(void *user_data) {
+static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
+ void *user_data, int success) {
grpc_credentials_metadata_request *r =
(grpc_credentials_metadata_request *)user_data;
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
- grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- r->cb(&exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
+ r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
GRPC_CREDENTIALS_OK);
grpc_credentials_metadata_request_destroy(r);
- grpc_exec_ctx_finish(&exec_ctx);
}
static void md_only_test_get_request_metadata(
@@ -810,10 +809,10 @@ static void md_only_test_get_request_metadata(
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
if (c->is_async) {
- gpr_thd_id thd_id;
grpc_credentials_metadata_request *cb_arg =
grpc_credentials_metadata_request_create(creds, cb, user_data);
- gpr_thd_new(&thd_id, on_simulated_token_fetch_done, cb_arg, NULL);
+ grpc_executor_enqueue(
+ grpc_closure_create(on_simulated_token_fetch_done, cb_arg), 1);
} else {
cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
}
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 6d45895e77..3cd652cd57 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -93,6 +93,14 @@ typedef enum {
/* It is the caller's responsibility to gpr_free the result if not NULL. */
char *grpc_get_well_known_google_credentials_file_path(void);
+/* Implementation function for the different platforms. */
+char *grpc_get_well_known_google_credentials_file_path_impl(void);
+
+/* Override for testing only. Not thread-safe */
+typedef char *(*grpc_well_known_credentials_path_getter)(void);
+void grpc_override_well_known_credentials_path_getter(
+ grpc_well_known_credentials_path_getter getter);
+
/* --- grpc_channel_credentials. --- */
typedef struct {
@@ -201,6 +209,7 @@ grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response(
const struct grpc_httpcli_response *response,
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
+
void grpc_flush_cached_google_default_credentials(void);
/* Metadata-only credentials with the specified key and value where
diff --git a/src/core/security/credentials_posix.c b/src/core/security/credentials_posix.c
index 20f67a7f14..0c92bd4a96 100644
--- a/src/core/security/credentials_posix.c
+++ b/src/core/security/credentials_posix.c
@@ -44,7 +44,7 @@
#include "src/core/support/env.h"
#include "src/core/support/string.h"
-char *grpc_get_well_known_google_credentials_file_path(void) {
+char *grpc_get_well_known_google_credentials_file_path_impl(void) {
char *result = NULL;
char *home = gpr_getenv("HOME");
if (home == NULL) {
diff --git a/src/core/security/credentials_win32.c b/src/core/security/credentials_win32.c
index 92dfd9bdfe..8ee9f706a1 100644
--- a/src/core/security/credentials_win32.c
+++ b/src/core/security/credentials_win32.c
@@ -44,7 +44,7 @@
#include "src/core/support/env.h"
#include "src/core/support/string.h"
-char *grpc_get_well_known_google_credentials_file_path(void) {
+char *grpc_get_well_known_google_credentials_file_path_impl(void) {
char *result = NULL;
char *appdata_path = gpr_getenv("APPDATA");
if (appdata_path == NULL) {
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 6a54fe4e47..5385e41130 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -241,5 +241,20 @@ void grpc_flush_cached_google_default_credentials(void) {
grpc_channel_credentials_unref(default_credentials);
default_credentials = NULL;
}
+ compute_engine_detection_done = 0;
gpr_mu_unlock(&g_mu);
}
+
+/* -- Well known credentials path. -- */
+
+static grpc_well_known_credentials_path_getter creds_path_getter = NULL;
+
+char *grpc_get_well_known_google_credentials_file_path(void) {
+ if (creds_path_getter != NULL) return creds_path_getter();
+ return grpc_get_well_known_google_credentials_file_path_impl();
+}
+
+void grpc_override_well_known_credentials_path_getter(
+ grpc_well_known_credentials_path_getter getter) {
+ creds_path_getter = getter;
+}
diff --git a/src/core/security/handshake.c b/src/core/security/handshake.c
index adbdd0b40e..6734187fce 100644
--- a/src/core/security/handshake.c
+++ b/src/core/security/handshake.c
@@ -64,12 +64,39 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
int success);
+static void security_connector_remove_handshake(grpc_security_handshake *h) {
+ grpc_security_connector_handshake_list *node;
+ grpc_security_connector_handshake_list *tmp;
+ grpc_security_connector *sc = h->connector;
+ gpr_mu_lock(&sc->mu);
+ node = sc->handshaking_handshakes;
+ if (node && node->handshake == h) {
+ sc->handshaking_handshakes = node->next;
+ gpr_free(node);
+ gpr_mu_unlock(&sc->mu);
+ return;
+ }
+ while (node) {
+ if (node->next->handshake == h) {
+ tmp = node->next;
+ node->next = node->next->next;
+ gpr_free(tmp);
+ gpr_mu_unlock(&sc->mu);
+ return;
+ }
+ node = node->next;
+ }
+ gpr_mu_unlock(&sc->mu);
+}
+
static void security_handshake_done(grpc_exec_ctx *exec_ctx,
grpc_security_handshake *h,
int is_success) {
+ if (!h->connector->is_client_side) {
+ security_connector_remove_handshake(h);
+ }
if (is_success) {
- h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->wrapped_endpoint,
- h->secure_endpoint);
+ h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint);
} else {
if (h->secure_endpoint != NULL) {
grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint);
@@ -77,8 +104,7 @@ static void security_handshake_done(grpc_exec_ctx *exec_ctx,
} else {
grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint);
}
- h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, h->wrapped_endpoint,
- NULL);
+ h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL);
}
if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker);
if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer);
@@ -268,6 +294,7 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data) {
+ grpc_security_connector_handshake_list *handshake_node;
grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
memset(h, 0, sizeof(grpc_security_handshake));
h->handshaker = handshaker;
@@ -284,5 +311,19 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
gpr_slice_buffer_init(&h->left_overs);
gpr_slice_buffer_init(&h->outgoing);
gpr_slice_buffer_init(&h->incoming);
+ if (!connector->is_client_side) {
+ handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
+ handshake_node->handshake = h;
+ gpr_mu_lock(&connector->mu);
+ handshake_node->next = connector->handshaking_handshakes;
+ connector->handshaking_handshakes = handshake_node;
+ gpr_mu_unlock(&connector->mu);
+ }
send_handshake_bytes_to_peer(exec_ctx, h);
}
+
+void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
+ void *handshake) {
+ grpc_security_handshake *h = handshake;
+ grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint);
+}
diff --git a/src/core/security/handshake.h b/src/core/security/handshake.h
index 28eaa79dc3..44215d16ef 100644
--- a/src/core/security/handshake.h
+++ b/src/core/security/handshake.h
@@ -45,4 +45,6 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_handshake_done_cb cb,
void *user_data);
+void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
+
#endif /* GRPC_INTERNAL_CORE_SECURITY_HANDSHAKE_H */
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 021912f333..92775d885d 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -215,8 +215,8 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
expiration = gpr_time_add(now, grpc_max_auth_token_lifetime);
}
- gpr_ltoa(now.tv_sec, now_str);
- gpr_ltoa(expiration.tv_sec, expiration_str);
+ gpr_int64toa(now.tv_sec, now_str);
+ gpr_int64toa(expiration.tv_sec, expiration_str);
child =
create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING);
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 3c54a4deae..8c6ab0b8a4 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -102,13 +102,29 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
return NULL;
}
+void grpc_security_connector_shutdown(grpc_exec_ctx *exec_ctx,
+ grpc_security_connector *connector) {
+ grpc_security_connector_handshake_list *tmp;
+ if (!connector->is_client_side) {
+ gpr_mu_lock(&connector->mu);
+ while (connector->handshaking_handshakes) {
+ tmp = connector->handshaking_handshakes;
+ grpc_security_handshake_shutdown(
+ exec_ctx, connector->handshaking_handshakes->handshake);
+ connector->handshaking_handshakes = tmp->next;
+ gpr_free(tmp);
+ }
+ gpr_mu_unlock(&connector->mu);
+ }
+}
+
void grpc_security_connector_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
- cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, nonsecure_endpoint, NULL);
+ cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL);
} else {
sc->vtable->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
}
@@ -219,6 +235,7 @@ static void fake_channel_destroy(grpc_security_connector *sc) {
static void fake_server_destroy(grpc_security_connector *sc) {
GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
+ gpr_mu_destroy(&sc->mu);
gpr_free(sc);
}
@@ -319,6 +336,7 @@ grpc_security_connector *grpc_fake_server_security_connector_create(void) {
c->is_client_side = 0;
c->vtable = &fake_server_vtable;
c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
+ gpr_mu_init(&c->mu);
return c;
}
@@ -354,10 +372,12 @@ static void ssl_channel_destroy(grpc_security_connector *sc) {
static void ssl_server_destroy(grpc_security_connector *sc) {
grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
+
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
+ gpr_mu_destroy(&sc->mu);
gpr_free(sc);
}
@@ -390,7 +410,7 @@ static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
: c->target_name,
&handshaker);
if (status != GRPC_SECURITY_OK) {
- cb(exec_ctx, user_data, status, nonsecure_endpoint, NULL);
+ cb(exec_ctx, user_data, status, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
user_data);
@@ -408,7 +428,7 @@ static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_status status =
ssl_create_handshaker(c->handshaker_factory, 0, NULL, &handshaker);
if (status != GRPC_SECURITY_OK) {
- cb(exec_ctx, user_data, status, nonsecure_endpoint, NULL);
+ cb(exec_ctx, user_data, status, NULL);
} else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb,
user_data);
@@ -691,6 +711,7 @@ grpc_security_status grpc_ssl_server_security_connector_create(
*sc = NULL;
goto error;
}
+ gpr_mu_init(&c->base.mu);
*sc = &c->base;
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 24095cddde..7edb05a662 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -67,7 +67,6 @@ typedef void (*grpc_security_check_cb)(grpc_exec_ctx *exec_ctx, void *user_data,
typedef void (*grpc_security_handshake_done_cb)(grpc_exec_ctx *exec_ctx,
void *user_data,
grpc_security_status status,
- grpc_endpoint *wrapped_endpoint,
grpc_endpoint *secure_endpoint);
typedef struct {
@@ -80,13 +79,22 @@ typedef struct {
void *user_data);
} grpc_security_connector_vtable;
+typedef struct grpc_security_connector_handshake_list {
+ void *handshake;
+ struct grpc_security_connector_handshake_list *next;
+} grpc_security_connector_handshake_list;
+
struct grpc_security_connector {
const grpc_security_connector_vtable *vtable;
gpr_refcount refcount;
int is_client_side;
const char *url_scheme;
grpc_auth_context *auth_context; /* Populated after the peer is checked. */
- const grpc_channel_args *channel_args; /* Server side only. */
+ /* Used on server side only. */
+ /* TODO(yangg) maybe create a grpc_server_security_connector with these */
+ gpr_mu mu;
+ grpc_security_connector_handshake_list *handshaking_handshakes;
+ const grpc_channel_args *channel_args;
};
/* Refcounting. */
@@ -127,6 +135,9 @@ grpc_security_status grpc_security_connector_check_peer(
grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
void *user_data);
+void grpc_security_connector_shutdown(grpc_exec_ctx *exec_ctx,
+ grpc_security_connector *connector);
+
/* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 71965f7d96..d1468e40e0 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -52,17 +52,11 @@
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
-typedef struct tcp_endpoint_list {
- grpc_endpoint *tcp_endpoint;
- struct tcp_endpoint_list *next;
-} tcp_endpoint_list;
-
typedef struct grpc_server_secure_state {
grpc_server *server;
grpc_tcp_server *tcp;
grpc_security_connector *sc;
grpc_server_credentials *creds;
- tcp_endpoint_list *handshaking_tcp_endpoints;
int is_shutdown;
gpr_mu mu;
gpr_refcount refcount;
@@ -103,52 +97,28 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_channel_args_destroy(args_copy);
}
-static int remove_tcp_from_list_locked(grpc_server_secure_state *state,
- grpc_endpoint *tcp) {
- tcp_endpoint_list *node = state->handshaking_tcp_endpoints;
- tcp_endpoint_list *tmp = NULL;
- if (node && node->tcp_endpoint == tcp) {
- state->handshaking_tcp_endpoints = state->handshaking_tcp_endpoints->next;
- gpr_free(node);
- return 0;
- }
- while (node) {
- if (node->next->tcp_endpoint == tcp) {
- tmp = node->next;
- node->next = node->next->next;
- gpr_free(tmp);
- return 0;
- }
- node = node->next;
- }
- return -1;
-}
-
static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
grpc_security_status status,
- grpc_endpoint *wrapped_endpoint,
grpc_endpoint *secure_endpoint) {
grpc_server_secure_state *state = statep;
grpc_transport *transport;
if (status == GRPC_SECURITY_OK) {
- gpr_mu_lock(&state->mu);
- remove_tcp_from_list_locked(state, wrapped_endpoint);
- if (!state->is_shutdown) {
- transport = grpc_create_chttp2_transport(
- exec_ctx, grpc_server_get_channel_args(state->server),
- secure_endpoint, 0);
- setup_transport(exec_ctx, state, transport);
- grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
- } else {
- /* We need to consume this here, because the server may already have gone
- * away. */
- grpc_endpoint_destroy(exec_ctx, secure_endpoint);
+ if (secure_endpoint) {
+ gpr_mu_lock(&state->mu);
+ if (!state->is_shutdown) {
+ transport = grpc_create_chttp2_transport(
+ exec_ctx, grpc_server_get_channel_args(state->server),
+ secure_endpoint, 0);
+ setup_transport(exec_ctx, state, transport);
+ grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+ } else {
+ /* We need to consume this here, because the server may already have
+ * gone away. */
+ grpc_endpoint_destroy(exec_ctx, secure_endpoint);
+ }
+ gpr_mu_unlock(&state->mu);
}
- gpr_mu_unlock(&state->mu);
} else {
- gpr_mu_lock(&state->mu);
- remove_tcp_from_list_locked(state, wrapped_endpoint);
- gpr_mu_unlock(&state->mu);
gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
}
state_unref(state);
@@ -157,14 +127,7 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *statep,
static void on_accept(grpc_exec_ctx *exec_ctx, void *statep,
grpc_endpoint *tcp) {
grpc_server_secure_state *state = statep;
- tcp_endpoint_list *node;
state_ref(state);
- node = gpr_malloc(sizeof(tcp_endpoint_list));
- node->tcp_endpoint = tcp;
- gpr_mu_lock(&state->mu);
- node->next = state->handshaking_tcp_endpoints;
- state->handshaking_tcp_endpoints = node;
- gpr_mu_unlock(&state->mu);
grpc_security_connector_do_handshake(exec_ctx, state->sc, tcp,
on_secure_handshake_done, state);
}
@@ -181,14 +144,7 @@ static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, int success) {
grpc_server_secure_state *state = statep;
state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
success);
- gpr_mu_lock(&state->mu);
- while (state->handshaking_tcp_endpoints != NULL) {
- grpc_endpoint_shutdown(exec_ctx,
- state->handshaking_tcp_endpoints->tcp_endpoint);
- remove_tcp_from_list_locked(state,
- state->handshaking_tcp_endpoints->tcp_endpoint);
- }
- gpr_mu_unlock(&state->mu);
+ grpc_security_connector_shutdown(exec_ctx, state->sc);
state_unref(state);
}
@@ -253,7 +209,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
port_temp = grpc_tcp_listener_get_port(listener);
- if (port_temp >= 0) {
+ if (port_temp > 0) {
if (port_num == -1) {
port_num = port_temp;
} else {
@@ -281,7 +237,6 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
state->sc = sc;
state->creds = grpc_server_credentials_ref(creds);
- state->handshaking_tcp_endpoints = NULL;
state->is_shutdown = 0;
gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1);
diff --git a/src/core/statistics/window_stats.c b/src/core/statistics/window_stats.c
index 4d0d3cca4a..e744006bb5 100644
--- a/src/core/statistics/window_stats.c
+++ b/src/core/statistics/window_stats.c
@@ -94,7 +94,7 @@ static gpr_int64 timespec_to_ns(const gpr_timespec ts) {
if (ts.tv_sec > max_seconds) {
return GPR_INT64_MAX - 1;
}
- return (gpr_int64)ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
+ return ts.tv_sec * GPR_NS_PER_SEC + ts.tv_nsec;
}
static void cws_initialize_statistic(void *statistic,
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
index bfcb77956b..ca72379b1d 100644
--- a/src/core/support/alloc.c
+++ b/src/core/support/alloc.c
@@ -34,13 +34,27 @@
#include <grpc/support/alloc.h>
#include <stdlib.h>
+#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include "src/core/profiling/timers.h"
+static gpr_allocation_functions g_alloc_functions = {malloc, realloc, free};
+
+gpr_allocation_functions gpr_get_allocation_functions() {
+ return g_alloc_functions;
+}
+
+void gpr_set_allocation_functions(gpr_allocation_functions functions) {
+ GPR_ASSERT(functions.malloc_fn != NULL);
+ GPR_ASSERT(functions.realloc_fn != NULL);
+ GPR_ASSERT(functions.free_fn != NULL);
+ g_alloc_functions = functions;
+}
+
void *gpr_malloc(size_t size) {
void *p;
GPR_TIMER_BEGIN("gpr_malloc", 0);
- p = malloc(size);
+ p = g_alloc_functions.malloc_fn(size);
if (!p) {
abort();
}
@@ -50,13 +64,13 @@ void *gpr_malloc(size_t size) {
void gpr_free(void *p) {
GPR_TIMER_BEGIN("gpr_free", 0);
- free(p);
+ g_alloc_functions.free_fn(p);
GPR_TIMER_END("gpr_free", 0);
}
void *gpr_realloc(void *p, size_t size) {
GPR_TIMER_BEGIN("gpr_realloc", 0);
- p = realloc(p, size);
+ p = g_alloc_functions.realloc_fn(p, size);
if (!p) {
abort();
}
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
index 87f60bca2e..b517f30b2d 100644
--- a/src/core/support/cmdline.c
+++ b/src/core/support/cmdline.c
@@ -62,11 +62,13 @@ struct gpr_cmdline {
void (*extra_arg)(void *user_data, const char *arg);
void *extra_arg_user_data;
- void (*state)(gpr_cmdline *cl, char *arg);
+ int (*state)(gpr_cmdline *cl, char *arg);
arg *cur_arg;
+
+ int survive_failure;
};
-static void normal_state(gpr_cmdline *cl, char *arg);
+static int normal_state(gpr_cmdline *cl, char *arg);
gpr_cmdline *gpr_cmdline_create(const char *description) {
gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
@@ -78,6 +80,10 @@ gpr_cmdline *gpr_cmdline_create(const char *description) {
return cl;
}
+void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) {
+ cl->survive_failure = 1;
+}
+
void gpr_cmdline_destroy(gpr_cmdline *cl) {
while (cl->args) {
arg *a = cl->args;
@@ -185,16 +191,22 @@ char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) {
return tmp;
}
-static void print_usage_and_die(gpr_cmdline *cl) {
+static int print_usage_and_die(gpr_cmdline *cl) {
char *usage = gpr_cmdline_usage_string(cl, cl->argv0);
fprintf(stderr, "%s", usage);
gpr_free(usage);
- exit(1);
+ if (!cl->survive_failure) {
+ exit(1);
+ }
+ return 0;
}
-static void extra_state(gpr_cmdline *cl, char *str) {
- if (!cl->extra_arg) print_usage_and_die(cl);
+static int extra_state(gpr_cmdline *cl, char *str) {
+ if (!cl->extra_arg) {
+ return print_usage_and_die(cl);
+ }
cl->extra_arg(cl->extra_arg_user_data, str);
+ return 1;
}
static arg *find_arg(gpr_cmdline *cl, char *name) {
@@ -208,13 +220,13 @@ static arg *find_arg(gpr_cmdline *cl, char *name) {
if (!a) {
fprintf(stderr, "Unknown argument: %s\n", name);
- print_usage_and_die(cl);
+ return NULL;
}
return a;
}
-static void value_state(gpr_cmdline *cl, char *str) {
+static int value_state(gpr_cmdline *cl, char *str) {
long intval;
char *end;
@@ -226,7 +238,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
if (*end || intval < INT_MIN || intval > INT_MAX) {
fprintf(stderr, "expected integer, got '%s' for %s\n", str,
cl->cur_arg->name);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
*(int *)cl->cur_arg->value = (int)intval;
break;
@@ -238,7 +250,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
} else {
fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
cl->cur_arg->name);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
break;
case ARGTYPE_STRING:
@@ -247,16 +259,18 @@ static void value_state(gpr_cmdline *cl, char *str) {
}
cl->state = normal_state;
+ return 1;
}
-static void normal_state(gpr_cmdline *cl, char *str) {
+static int normal_state(gpr_cmdline *cl, char *str) {
char *eq = NULL;
char *tmp = NULL;
char *arg_name = NULL;
+ int r = 1;
if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
0 == strcmp(str, "-h")) {
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
cl->cur_arg = NULL;
@@ -266,7 +280,7 @@ static void normal_state(gpr_cmdline *cl, char *str) {
if (str[2] == 0) {
/* handle '--' to move to just extra args */
cl->state = extra_state;
- return;
+ return 1;
}
str += 2;
} else {
@@ -277,12 +291,15 @@ static void normal_state(gpr_cmdline *cl, char *str) {
/* str is of the form '--no-foo' - it's a flag disable */
str += 3;
cl->cur_arg = find_arg(cl, str);
+ if (cl->cur_arg == NULL) {
+ return print_usage_and_die(cl);
+ }
if (cl->cur_arg->type != ARGTYPE_BOOL) {
fprintf(stderr, "%s is not a flag argument\n", str);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
*(int *)cl->cur_arg->value = 0;
- return; /* early out */
+ return 1; /* early out */
}
eq = strchr(str, '=');
if (eq != NULL) {
@@ -294,9 +311,12 @@ static void normal_state(gpr_cmdline *cl, char *str) {
arg_name = str;
}
cl->cur_arg = find_arg(cl, arg_name);
+ if (cl->cur_arg == NULL) {
+ return print_usage_and_die(cl);
+ }
if (eq != NULL) {
/* str was of the type --foo=value, parse the value */
- value_state(cl, eq + 1);
+ r = value_state(cl, eq + 1);
} else if (cl->cur_arg->type != ARGTYPE_BOOL) {
/* flag types don't have a '--foo value' variant, other types do */
cl->state = value_state;
@@ -305,19 +325,23 @@ static void normal_state(gpr_cmdline *cl, char *str) {
*(int *)cl->cur_arg->value = 1;
}
} else {
- extra_state(cl, str);
+ r = extra_state(cl, str);
}
gpr_free(tmp);
+ return r;
}
-void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
+int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
int i;
GPR_ASSERT(argc >= 1);
cl->argv0 = argv[0];
for (i = 1; i < argc; i++) {
- cl->state(cl, argv[i]);
+ if (!cl->state(cl, argv[i])) {
+ return 0;
+ }
}
+ return 1;
}
diff --git a/src/core/support/log.c b/src/core/support/log.c
index f52c2035b9..04156a5b1f 100644
--- a/src/core/support/log.c
+++ b/src/core/support/log.c
@@ -32,6 +32,7 @@
*/
#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
#include <stdio.h>
#include <string.h>
@@ -48,7 +49,7 @@ const char *gpr_log_severity_string(gpr_log_severity severity) {
case GPR_LOG_SEVERITY_ERROR:
return "E";
}
- return "UNKNOWN";
+ GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
void gpr_log_message(const char *file, int line, gpr_log_severity severity,
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 02f64d8b7e..d66b7a3cc0 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -76,16 +76,18 @@ void gpr_default_log(gpr_log_func_args *args) {
char *prefix;
const char *display_file;
char time_buffer[64];
+ time_t timer;
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
+ timer = (time_t)now.tv_sec;
final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = args->file;
else
display_file = final_slash + 1;
- if (!localtime_r(&now.tv_sec, &tm)) {
+ if (!localtime_r(&timer, &tm)) {
strcpy(time_buffer, "error:localtime");
} else if (0 ==
strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index 8b050dbee7..8986254e4e 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -75,16 +75,18 @@ void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
+ time_t timer;
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
+ timer = (time_t)now.tv_sec;
final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = args->file;
else
display_file = final_slash + 1;
- if (!localtime_r(&now.tv_sec, &tm)) {
+ if (!localtime_r(&timer, &tm)) {
strcpy(time_buffer, "error:localtime");
} else if (0 ==
strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index b68239f8f5..40adcd1b50 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -84,16 +84,18 @@ void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
+ time_t timer;
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
+ timer = (time_t)now.tv_sec;
final_slash = strrchr(args->file, '\\');
if (final_slash == NULL)
display_file = args->file;
else
display_file = final_slash + 1;
- if (localtime_s(&tm, &now.tv_sec)) {
+ if (localtime_s(&tm, &timer)) {
strcpy(time_buffer, "error:localtime");
} else if (0 ==
strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) {
@@ -104,6 +106,7 @@ void gpr_default_log(gpr_log_func_args *args) {
gpr_log_severity_string(args->severity), time_buffer,
(int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line,
args->message);
+ fflush(stderr);
}
char *gpr_format_message(DWORD messageid) {
diff --git a/src/core/support/slice.c b/src/core/support/slice.c
index 5b091f17b0..9f0ded4932 100644
--- a/src/core/support/slice.c
+++ b/src/core/support/slice.c
@@ -341,10 +341,3 @@ int gpr_slice_str_cmp(gpr_slice a, const char *b) {
if (d != 0) return d;
return memcmp(GPR_SLICE_START_PTR(a), b, b_length);
}
-
-char *gpr_slice_to_cstring(gpr_slice slice) {
- char *result = gpr_malloc(GPR_SLICE_LENGTH(slice) + 1);
- memcpy(result, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
- result[GPR_SLICE_LENGTH(slice)] = '\0';
- return result;
-}
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index df9a09894c..fc934d404c 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -128,8 +128,8 @@ int gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
- (gpr_atm)(1UL << pushed_bit));
- GPR_ASSERT((old_val & (gpr_atm)(1UL << pushed_bit)) == 0);
+ ((gpr_atm)1 << pushed_bit));
+ GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) == 0);
}
#endif
@@ -166,8 +166,8 @@ int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
gpr_atm old_val;
old_val = gpr_atm_no_barrier_fetch_add(&stack->pushed[pushed_index],
- -(gpr_atm)(1UL << pushed_bit));
- GPR_ASSERT((old_val & (gpr_atm)(1UL << pushed_bit)) != 0);
+ -((gpr_atm)1 << pushed_bit));
+ GPR_ASSERT((old_val & (((gpr_atm)1) << pushed_bit)) != 0);
}
#endif
diff --git a/src/core/support/string.c b/src/core/support/string.c
index e0ffeb8a4a..46a7ca3d46 100644
--- a/src/core/support/string.c
+++ b/src/core/support/string.c
@@ -153,8 +153,8 @@ void gpr_reverse_bytes(char *str, int len) {
}
int gpr_ltoa(long value, char *string) {
+ long sign;
int i = 0;
- int neg = value < 0;
if (value == 0) {
string[0] = '0';
@@ -162,12 +162,33 @@ int gpr_ltoa(long value, char *string) {
return 1;
}
- if (neg) value = -value;
+ sign = value < 0 ? -1 : 1;
while (value) {
- string[i++] = (char)('0' + value % 10);
+ string[i++] = (char)('0' + sign * (value % 10));
value /= 10;
}
- if (neg) string[i++] = '-';
+ if (sign < 0) string[i++] = '-';
+ gpr_reverse_bytes(string, i);
+ string[i] = 0;
+ return i;
+}
+
+int gpr_int64toa(gpr_int64 value, char *string) {
+ gpr_int64 sign;
+ int i = 0;
+
+ if (value == 0) {
+ string[0] = '0';
+ string[1] = 0;
+ return 1;
+ }
+
+ sign = value < 0 ? -1 : 1;
+ while (value) {
+ string[i++] = (char)('0' + sign * (value % 10));
+ value /= 10;
+ }
+ if (sign < 0) string[i++] = '-';
gpr_reverse_bytes(string, i);
string[i] = 0;
return i;
diff --git a/src/core/support/string.h b/src/core/support/string.h
index a28e00fd3e..9b604ac5bf 100644
--- a/src/core/support/string.h
+++ b/src/core/support/string.h
@@ -70,6 +70,16 @@ int gpr_parse_bytes_to_uint32(const char *data, size_t length,
output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */
int gpr_ltoa(long value, char *output);
+/* Minimum buffer size for calling int64toa */
+#define GPR_INT64TOA_MIN_BUFSIZE (3 * sizeof(gpr_int64))
+
+/* Convert an int64 to a string in base 10; returns the length of the
+output string (or 0 on failure).
+output must be at least GPR_INT64TOA_MIN_BUFSIZE bytes long.
+NOTE: This function ensures sufficient bit width even on Win x64,
+where long is 32bit is size.*/
+int gpr_int64toa(gpr_int64 value, char *output);
+
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
diff --git a/src/core/support/time.c b/src/core/support/time.c
index 929adac918..197fa9ad44 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -56,22 +56,6 @@ gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
return gpr_time_cmp(a, b) > 0 ? a : b;
}
-/* There's no standard TIME_T_MIN and TIME_T_MAX, so we construct them. The
- following assumes that signed types are two's-complement and that bytes are
- 8 bits. */
-
-/* The top bit of integral type t. */
-#define TOP_BIT_OF_TYPE(t) (((gpr_uintmax)1) << ((8 * sizeof(t)) - 1))
-
-/* Return whether integral type t is signed. */
-#define TYPE_IS_SIGNED(t) (((t)1) > (t) ~(t)0)
-
-/* The minimum and maximum value of integral type t. */
-#define TYPE_MIN(t) ((t)(TYPE_IS_SIGNED(t) ? TOP_BIT_OF_TYPE(t) : 0))
-#define TYPE_MAX(t) \
- ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \
- : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1))
-
gpr_timespec gpr_time_0(gpr_clock_type type) {
gpr_timespec out;
out.tv_sec = 0;
@@ -82,7 +66,7 @@ gpr_timespec gpr_time_0(gpr_clock_type type) {
gpr_timespec gpr_inf_future(gpr_clock_type type) {
gpr_timespec out;
- out.tv_sec = TYPE_MAX(time_t);
+ out.tv_sec = INT64_MAX;
out.tv_nsec = 0;
out.clock_type = type;
return out;
@@ -90,7 +74,7 @@ gpr_timespec gpr_inf_future(gpr_clock_type type) {
gpr_timespec gpr_inf_past(gpr_clock_type type) {
gpr_timespec out;
- out.tv_sec = TYPE_MIN(time_t);
+ out.tv_sec = INT64_MIN;
out.tv_nsec = 0;
out.clock_type = type;
return out;
@@ -108,11 +92,11 @@ gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
result = gpr_inf_past(type);
} else if (ns >= 0) {
result.tv_sec = ns / GPR_NS_PER_SEC;
- result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
+ result.tv_nsec = (gpr_int32)(ns - result.tv_sec * GPR_NS_PER_SEC);
} else {
/* Calculation carefully formulated to avoid any possible under/overflow. */
result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1;
- result.tv_nsec = (int)(ns - result.tv_sec * GPR_NS_PER_SEC);
+ result.tv_nsec = (gpr_int32)(ns - result.tv_sec * GPR_NS_PER_SEC);
}
return result;
}
@@ -126,11 +110,11 @@ gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
result = gpr_inf_past(type);
} else if (us >= 0) {
result.tv_sec = us / 1000000;
- result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
+ result.tv_nsec = (gpr_int32)((us - result.tv_sec * 1000000) * 1000);
} else {
/* Calculation carefully formulated to avoid any possible under/overflow. */
result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1;
- result.tv_nsec = (int)((us - result.tv_sec * 1000000) * 1000);
+ result.tv_nsec = (gpr_int32)((us - result.tv_sec * 1000000) * 1000);
}
return result;
}
@@ -144,11 +128,11 @@ gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
result = gpr_inf_past(type);
} else if (ms >= 0) {
result.tv_sec = ms / 1000;
- result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
+ result.tv_nsec = (gpr_int32)((ms - result.tv_sec * 1000) * 1000000);
} else {
/* Calculation carefully formulated to avoid any possible under/overflow. */
result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1;
- result.tv_nsec = (int)((ms - result.tv_sec * 1000) * 1000000);
+ result.tv_nsec = (gpr_int32)((ms - result.tv_sec * 1000) * 1000000);
}
return result;
}
@@ -197,7 +181,7 @@ gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
gpr_timespec sum;
- int inc = 0;
+ gpr_int64 inc = 0;
GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
sum.clock_type = a.clock_type;
sum.tv_nsec = a.tv_nsec + b.tv_nsec;
@@ -205,17 +189,17 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
sum.tv_nsec -= GPR_NS_PER_SEC;
inc++;
}
- if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+ if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
sum = a;
- } else if (b.tv_sec == TYPE_MAX(time_t) ||
- (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) {
+ } else if (b.tv_sec == INT64_MAX ||
+ (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
sum = gpr_inf_future(sum.clock_type);
- } else if (b.tv_sec == TYPE_MIN(time_t) ||
- (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) {
+ } else if (b.tv_sec == INT64_MIN ||
+ (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
sum = gpr_inf_past(sum.clock_type);
} else {
sum.tv_sec = a.tv_sec + b.tv_sec;
- if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) {
+ if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
sum = gpr_inf_future(sum.clock_type);
} else {
sum.tv_sec += inc;
@@ -226,7 +210,7 @@ gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
gpr_timespec diff;
- int dec = 0;
+ gpr_int64 dec = 0;
if (b.clock_type == GPR_TIMESPAN) {
diff.clock_type = a.clock_type;
} else {
@@ -238,17 +222,17 @@ gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
diff.tv_nsec += GPR_NS_PER_SEC;
dec++;
}
- if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) {
+ if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
diff = a;
- } else if (b.tv_sec == TYPE_MIN(time_t) ||
- (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) {
+ } else if (b.tv_sec == INT64_MIN ||
+ (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
diff = gpr_inf_future(GPR_CLOCK_REALTIME);
- } else if (b.tv_sec == TYPE_MAX(time_t) ||
- (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) {
+ } else if (b.tv_sec == INT64_MAX ||
+ (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
diff = gpr_inf_past(GPR_CLOCK_REALTIME);
} else {
diff.tv_sec = a.tv_sec - b.tv_sec;
- if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) {
+ if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
diff = gpr_inf_past(GPR_CLOCK_REALTIME);
} else {
diff.tv_sec -= dec;
@@ -297,11 +281,11 @@ gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
}
if (t.tv_nsec == 0) {
- if (t.tv_sec == TYPE_MAX(time_t)) {
+ if (t.tv_sec == INT64_MAX) {
t.clock_type = clock_type;
return t;
}
- if (t.tv_sec == TYPE_MIN(time_t)) {
+ if (t.tv_sec == INT64_MIN) {
t.clock_type = clock_type;
return t;
}
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 02cfca8555..ba72572e05 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -45,7 +45,11 @@
static struct timespec timespec_from_gpr(gpr_timespec gts) {
struct timespec rv;
- rv.tv_sec = gts.tv_sec;
+ if (sizeof(time_t) < sizeof(gpr_int64)) {
+ /* fine to assert, as this is only used in gpr_sleep_until */
+ GPR_ASSERT(gts.tv_sec <= INT32_MAX && gts.tv_sec >= INT32_MIN);
+ }
+ rv.tv_sec = (time_t)gts.tv_sec;
rv.tv_nsec = gts.tv_nsec;
return rv;
}
@@ -53,9 +57,14 @@ static struct timespec timespec_from_gpr(gpr_timespec gts) {
#if _POSIX_TIMERS > 0
static gpr_timespec gpr_from_timespec(struct timespec ts,
gpr_clock_type clock_type) {
+ /*
+ * timespec.tv_sec can have smaller size than gpr_timespec.tv_sec,
+ * but we are only using this function to implement gpr_now
+ * so there's no need to handle "infinity" values.
+ */
gpr_timespec rv;
rv.tv_sec = ts.tv_sec;
- rv.tv_nsec = (int)ts.tv_nsec;
+ rv.tv_nsec = (gpr_int32)ts.tv_nsec;
rv.clock_type = clock_type;
return rv;
}
@@ -110,8 +119,8 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
break;
case GPR_CLOCK_MONOTONIC:
now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale;
- now.tv_sec = (time_t)(now_dbl * 1e-9);
- now.tv_nsec = (int)(now_dbl - ((double)now.tv_sec) * 1e9);
+ now.tv_sec = (gpr_int64)(now_dbl * 1e-9);
+ now.tv_nsec = (gpr_int32)(now_dbl - ((double)now.tv_sec) * 1e9);
break;
case GPR_CLOCK_PRECISE:
gpr_precise_clock_now(&now);
diff --git a/src/core/support/time_precise.c b/src/core/support/time_precise.c
index b37517e639..4de1d9b071 100644
--- a/src/core/support/time_precise.c
+++ b/src/core/support/time_precise.c
@@ -75,8 +75,8 @@ void gpr_precise_clock_now(gpr_timespec *clk) {
gpr_get_cycle_counter(&counter);
secs = (double)(counter - start_cycle) / cycles_per_second;
clk->clock_type = GPR_CLOCK_PRECISE;
- clk->tv_sec = (time_t)secs;
- clk->tv_nsec = (int)(1e9 * (secs - (double)clk->tv_sec));
+ clk->tv_sec = (gpr_int64)secs;
+ clk->tv_nsec = (gpr_int32)(1e9 * (secs - (double)clk->tv_sec));
}
#else /* GRPC_TIMERS_RDTSC */
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index 623a8d9233..7ccaaa248d 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -62,15 +62,15 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
switch (clock) {
case GPR_CLOCK_REALTIME:
_ftime_s(&now_tb);
- now_tv.tv_sec = now_tb.time;
+ now_tv.tv_sec = (gpr_int64)now_tb.time;
now_tv.tv_nsec = now_tb.millitm * 1000000;
break;
case GPR_CLOCK_MONOTONIC:
case GPR_CLOCK_PRECISE:
QueryPerformanceCounter(&timestamp);
now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
- now_tv.tv_sec = (time_t)now_dbl;
- now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
+ now_tv.tv_sec = (gpr_int64)now_dbl;
+ now_tv.tv_nsec = (gpr_int32)((now_dbl - (double)now_tv.tv_sec) * 1e9);
break;
}
return now_tv;
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 4affafa585..f8dde0748b 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -336,26 +336,19 @@ void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
grpc_cq_pollset(cq));
}
-grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
- return call->cq;
-}
-
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_call_internal_ref(grpc_call *c, const char *reason) {
- grpc_call_stack_ref(CALL_STACK_FROM_CALL(c), reason);
-}
-void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c,
- const char *reason) {
- grpc_call_stack_unref(exec_ctx, CALL_STACK_FROM_CALL(c), reason);
-}
+#define REF_REASON reason
+#define REF_ARG , const char *reason
#else
-void grpc_call_internal_ref(grpc_call *c) {
- grpc_call_stack_ref(CALL_STACK_FROM_CALL(c));
+#define REF_REASON ""
+#define REF_ARG
+#endif
+void grpc_call_internal_ref(grpc_call *c REF_ARG) {
+ GRPC_CALL_STACK_REF(CALL_STACK_FROM_CALL(c), REF_REASON);
}
-void grpc_call_internal_unref(grpc_exec_ctx *exec_ctx, grpc_call *c) {
- grpc_call_stack_unref(exec_ctx, CALL_STACK_FROM_CALL(c));
+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);
}
-#endif
static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, int success) {
size_t i;
@@ -742,8 +735,15 @@ static void execute_op(grpc_exec_ctx *exec_ctx, grpc_call *call,
char *grpc_call_get_peer(grpc_call *call) {
grpc_call_element *elem = CALL_ELEM_FROM_CALL(call, 0);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- char *result = elem->filter->get_peer(&exec_ctx, elem);
+ char *result;
GRPC_API_TRACE("grpc_call_get_peer(%p)", 1, (call));
+ result = elem->filter->get_peer(&exec_ctx, elem);
+ if (result == NULL) {
+ result = grpc_channel_get_target(call->channel);
+ }
+ if (result == NULL) {
+ result = gpr_strdup("unknown");
+ }
grpc_exec_ctx_finish(&exec_ctx);
return result;
}
@@ -974,11 +974,19 @@ static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
batch_control *bctl = bctlp;
grpc_call *call = bctl->call;
- GPR_ASSERT(success);
- gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
- call->receiving_slice);
-
- continue_receiving_slices(exec_ctx, bctl);
+ if (success) {
+ gpr_slice_buffer_add(&(*call->receiving_buffer)->data.raw.slice_buffer,
+ call->receiving_slice);
+ continue_receiving_slices(exec_ctx, bctl);
+ } else {
+ grpc_byte_stream_destroy(call->receiving_stream);
+ call->receiving_stream = NULL;
+ grpc_byte_buffer_destroy(*call->receiving_buffer);
+ *call->receiving_buffer = NULL;
+ if (gpr_unref(&bctl->steps_to_complete)) {
+ post_batch_completion(exec_ctx, bctl);
+ }
+ }
}
static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, int success) {
@@ -1060,6 +1068,7 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
if (call->receiving_stream == NULL) {
*call->receiving_buffer = NULL;
+ call->receiving_message = 0;
if (gpr_unref(&bctl->steps_to_complete)) {
post_batch_completion(exec_ctx, bctl);
}
@@ -1070,6 +1079,7 @@ static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
grpc_byte_stream_destroy(call->receiving_stream);
call->receiving_stream = NULL;
*call->receiving_buffer = NULL;
+ call->receiving_message = 0;
if (gpr_unref(&bctl->steps_to_complete)) {
post_batch_completion(exec_ctx, bctl);
}
@@ -1119,11 +1129,12 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
GRPC_CALL_INTERNAL_REF(call, "completion");
bctl->success = 1;
if (!is_notify_tag_closure) {
- grpc_cq_begin_op(call->cq);
+ grpc_cq_begin_op(call->cq, notify_tag);
}
gpr_mu_unlock(&call->mu);
post_batch_completion(exec_ctx, bctl);
- return GRPC_CALL_OK;
+ error = GRPC_CALL_OK;
+ goto done;
}
/* rewrite batch ops into a transport op */
@@ -1270,6 +1281,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
}
if (call->receiving_message) {
error = GRPC_CALL_ERROR_TOO_MANY_OPERATIONS;
+ goto done_with_error;
}
call->receiving_message = 1;
bctl->recv_message = 1;
@@ -1332,7 +1344,7 @@ static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
GRPC_CALL_INTERNAL_REF(call, "completion");
if (!is_notify_tag_closure) {
- grpc_cq_begin_op(call->cq);
+ grpc_cq_begin_op(call->cq, notify_tag);
}
gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 24ab9c33bb..b53340df8e 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -58,7 +58,6 @@ 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);
-grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call);
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_call_internal_ref(grpc_call *call, const char *reason);
@@ -91,19 +90,6 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
grpc_call *call, const grpc_op *ops, size_t nops,
void *tag);
-void grpc_server_log_request_call(char *file, int line,
- gpr_log_severity severity,
- grpc_server *server, grpc_call **call,
- grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- grpc_completion_queue *cq_bound_to_call,
- grpc_completion_queue *cq_for_notification,
- void *tag);
-
-void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity,
- grpc_server *server, grpc_completion_queue *cq,
- void *tag);
-
/* Set a context pointer.
No thread safety guarantees are made wrt this value. */
void grpc_call_context_set(grpc_call *call, grpc_context_index elem,
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
index 16212f6386..46756f418b 100644
--- a/src/core/surface/call_log_batch.c
+++ b/src/core/surface/call_log_batch.c
@@ -116,27 +116,3 @@ void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
gpr_free(tmp);
}
}
-
-void grpc_server_log_request_call(char *file, int line,
- gpr_log_severity severity,
- grpc_server *server, grpc_call **call,
- grpc_call_details *details,
- grpc_metadata_array *initial_metadata,
- grpc_completion_queue *cq_bound_to_call,
- grpc_completion_queue *cq_for_notification,
- void *tag) {
- gpr_log(file, line, severity,
- "grpc_server_request_call(server=%p, call=%p, details=%p, "
- "initial_metadata=%p, cq_bound_to_call=%p, cq_for_notification=%p, "
- "tag=%p)",
- server, call, details, initial_metadata, cq_bound_to_call,
- cq_for_notification, tag);
-}
-
-void grpc_server_log_shutdown(char *file, int line, gpr_log_severity severity,
- grpc_server *server, grpc_completion_queue *cq,
- void *tag) {
- gpr_log(file, line, severity,
- "grpc_server_shutdown_and_notify(server=%p, cq=%p, tag=%p)", server,
- cq, tag);
-}
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 859197412b..d0a8b0be09 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -63,7 +63,6 @@ typedef struct registered_call {
struct grpc_channel {
int is_client;
- gpr_refcount refs;
gpr_uint32 max_message_length;
grpc_mdelem *default_authority;
@@ -81,6 +80,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, int success);
+
grpc_channel *grpc_channel_create_from_filters(
grpc_exec_ctx *exec_ctx, const char *target,
const grpc_channel_filter **filters, size_t num_filters,
@@ -93,8 +94,6 @@ grpc_channel *grpc_channel_create_from_filters(
channel->target = gpr_strdup(target);
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client;
- /* decremented by grpc_channel_destroy */
- gpr_ref_init(&channel->refs, 1);
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
@@ -113,7 +112,7 @@ grpc_channel *grpc_channel_create_from_filters(
}
} else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
if (args->args[i].type != GRPC_ARG_STRING) {
- gpr_log(GPR_ERROR, "%s: must be an string",
+ gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_ARG_DEFAULT_AUTHORITY);
} else {
if (channel->default_authority) {
@@ -126,13 +125,14 @@ grpc_channel *grpc_channel_create_from_filters(
} else if (0 ==
strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
if (args->args[i].type != GRPC_ARG_STRING) {
- gpr_log(GPR_ERROR, "%s: must be an string",
+ gpr_log(GPR_ERROR, "%s ignored: it must be a string",
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
if (channel->default_authority) {
/* other ways of setting this (notably ssl) take precedence */
- gpr_log(GPR_ERROR, "%s: default host already set some other way",
- GRPC_ARG_DEFAULT_AUTHORITY);
+ gpr_log(GPR_ERROR,
+ "%s ignored: default host already set some other way",
+ GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
} else {
channel->default_authority = grpc_mdelem_from_strings(
":authority", args->args[i].value.string);
@@ -152,7 +152,9 @@ grpc_channel *grpc_channel_create_from_filters(
gpr_free(default_authority);
}
- grpc_channel_stack_init(exec_ctx, filters, num_filters, channel, args,
+ grpc_channel_stack_init(exec_ctx, 1, destroy_channel, channel, filters,
+ num_filters, args,
+ is_client ? "CLIENT_CHANNEL" : "SERVER_CHANNEL",
CHANNEL_STACK_FROM_CHANNEL(channel));
return channel;
@@ -193,11 +195,11 @@ 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: %ld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
10, (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
- (long)deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type,
- reserved));
+ (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+ (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, cq,
@@ -237,11 +239,11 @@ 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: %ld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
9, (channel, parent_call, (unsigned)propagation_mask, completion_queue,
- registered_call_handle, (long)deadline.tv_sec, deadline.tv_nsec,
- (int)deadline.clock_type, reserved));
+ registered_call_handle, (long long)deadline.tv_sec,
+ (int)deadline.tv_nsec, (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
return grpc_channel_create_call_internal(
channel, parent_call, propagation_mask, completion_queue,
@@ -249,17 +251,25 @@ grpc_call *grpc_channel_create_registered_call(
rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
}
-#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
-void grpc_channel_internal_ref(grpc_channel *c, const char *reason) {
- gpr_log(GPR_DEBUG, "CHANNEL: ref %p %d -> %d [%s]", c, c->refs.count,
- c->refs.count + 1, reason);
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+#define REF_REASON reason
+#define REF_ARG , const char *reason
#else
-void grpc_channel_internal_ref(grpc_channel *c) {
+#define REF_REASON ""
+#define REF_ARG
#endif
- gpr_ref(&c->refs);
+void grpc_channel_internal_ref(grpc_channel *c REF_ARG) {
+ GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
}
-static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
+void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
+ grpc_channel *c REF_ARG) {
+ GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(c), REF_REASON);
+}
+
+static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
+ int iomgr_success) {
+ grpc_channel *channel = arg;
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
while (channel->registered_calls) {
registered_call *rc = channel->registered_calls;
@@ -278,20 +288,6 @@ static void destroy_channel(grpc_exec_ctx *exec_ctx, grpc_channel *channel) {
gpr_free(channel);
}
-#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
-void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
- const char *reason) {
- gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel,
- channel->refs.count, channel->refs.count - 1, reason);
-#else
-void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx,
- grpc_channel *channel) {
-#endif
- if (gpr_unref(&channel->refs)) {
- destroy_channel(exec_ctx, channel);
- }
-}
-
void grpc_channel_destroy(grpc_channel *channel) {
grpc_transport_op op;
grpc_channel_element *elem;
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 7dea609ebc..3d2ff23542 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -53,7 +53,7 @@ grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
int status_code);
gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
-#ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
void grpc_channel_internal_unref(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
const char *reason);
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index df2774b527..10f5c4da4d 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -83,7 +83,6 @@ typedef struct {
gpr_mu mu;
callback_phase phase;
int success;
- int removed;
grpc_closure on_complete;
grpc_timer alarm;
grpc_connectivity_state state;
@@ -135,30 +134,15 @@ 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) {
int delete = 0;
- grpc_channel_element *client_channel_elem = NULL;
- gpr_mu_lock(&w->mu);
- if (w->removed == 0) {
- w->removed = 1;
- client_channel_elem = grpc_channel_stack_last_element(
- grpc_channel_get_channel_stack(w->channel));
- if (client_channel_elem->filter == &grpc_client_channel_filter) {
- grpc_client_channel_del_interested_party(exec_ctx, client_channel_elem,
- grpc_cq_pollset(w->cq));
- } else {
- grpc_client_uchannel_del_interested_party(exec_ctx, client_channel_elem,
- grpc_cq_pollset(w->cq));
- }
- }
- gpr_mu_unlock(&w->mu);
if (due_to_completion) {
- gpr_mu_lock(&w->mu);
- w->success = 1;
- gpr_mu_unlock(&w->mu);
grpc_timer_cancel(exec_ctx, &w->alarm);
}
gpr_mu_lock(&w->mu);
+ if (due_to_completion) {
+ w->success = 1;
+ }
switch (w->phase) {
case WAITING:
w->phase = CALLING_BACK;
@@ -200,19 +184,18 @@ 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: %ld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"cq=%p, tag=%p)",
- 7, (channel, (int)last_observed_state, (long)deadline.tv_sec,
- deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
+ 7, (channel, (int)last_observed_state, (long long)deadline.tv_sec,
+ (int)deadline.tv_nsec, (int)deadline.clock_type, cq, tag));
- grpc_cq_begin_op(cq);
+ grpc_cq_begin_op(cq, tag);
gpr_mu_init(&w->mu);
grpc_closure_init(&w->on_complete, watch_complete, w);
w->phase = WAITING;
w->state = last_observed_state;
w->success = 0;
- w->removed = 0;
w->cq = cq;
w->tag = tag;
w->channel = channel;
@@ -223,16 +206,14 @@ void grpc_channel_watch_connectivity_state(
if (client_channel_elem->filter == &grpc_client_channel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
- grpc_client_channel_add_interested_party(&exec_ctx, client_channel_elem,
- grpc_cq_pollset(cq));
grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
- &w->state, &w->on_complete);
+ grpc_cq_pollset(cq), &w->state,
+ &w->on_complete);
} else if (client_channel_elem->filter == &grpc_client_uchannel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_uchannel_connectivity");
- grpc_client_uchannel_add_interested_party(&exec_ctx, client_channel_elem,
- grpc_cq_pollset(cq));
grpc_client_uchannel_watch_connectivity_state(
- &exec_ctx, client_channel_elem, &w->state, &w->on_complete);
+ &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
+ &w->on_complete);
}
grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 6d40780497..97ec23408f 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -99,8 +99,8 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent);
}
- c->result->transport = grpc_create_chttp2_transport(
- exec_ctx, c->args.channel_args, tcp, 1);
+ c->result->transport =
+ grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
0);
GPR_ASSERT(c->result->transport);
@@ -171,7 +171,6 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
c->base.vtable = &connector_vtable;
gpr_ref_init(&c->refs, 1);
args->args = final_args;
- args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args);
@@ -218,6 +217,9 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
resolver = grpc_resolver_create(target, &f->base);
if (!resolver) {
+ GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, f->master, "subchannel_factory");
+ grpc_subchannel_factory_unref(&exec_ctx, &f->base);
+ grpc_exec_ctx_finish(&exec_ctx);
return NULL;
}
diff --git a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c b/src/core/surface/channel_ping.c
index 585e465fa4..b4ce282787 100644
--- a/src/core/client_config/subchannel_factory_decorators/add_channel_arg.c
+++ b/src/core/surface/channel_ping.c
@@ -31,13 +31,49 @@
*
*/
-#include "src/core/client_config/subchannel_factory_decorators/add_channel_arg.h"
-#include "src/core/client_config/subchannel_factory_decorators/merge_channel_args.h"
-
-grpc_subchannel_factory *grpc_subchannel_factory_add_channel_arg(
- grpc_subchannel_factory *input, const grpc_arg *arg) {
- grpc_channel_args args;
- args.num_args = 1;
- args.args = (grpc_arg *)arg;
- return grpc_subchannel_factory_merge_channel_args(input, &args);
+#include "src/core/surface/channel.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/surface/api_trace.h"
+#include "src/core/surface/completion_queue.h"
+
+typedef struct {
+ grpc_closure closure;
+ void *tag;
+ grpc_completion_queue *cq;
+ grpc_cq_completion completion_storage;
+} ping_result;
+
+static void ping_destroy(grpc_exec_ctx *exec_ctx, void *arg,
+ grpc_cq_completion *storage) {
+ gpr_free(arg);
+}
+
+static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+ ping_result *pr = arg;
+ grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr,
+ &pr->completion_storage);
+}
+
+void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
+ void *tag, void *reserved) {
+ grpc_transport_op op;
+ ping_result *pr = gpr_malloc(sizeof(*pr));
+ grpc_channel_element *top_elem =
+ grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GPR_ASSERT(reserved == NULL);
+ memset(&op, 0, sizeof(op));
+ pr->tag = tag;
+ pr->cq = cq;
+ grpc_closure_init(&pr->closure, ping_done, pr);
+ op.send_ping = &pr->closure;
+ op.bind_pollset = grpc_cq_pollset(cq);
+ grpc_cq_begin_op(cq, tag);
+ top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op);
+ grpc_exec_ctx_finish(&exec_ctx);
}
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index d56e5cbe84..848a33adc3 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -73,6 +73,12 @@ struct grpc_completion_queue {
plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
grpc_closure pollset_shutdown_done;
+#ifndef NDEBUG
+ void **outstanding_tags;
+ size_t outstanding_tag_count;
+ size_t outstanding_tag_capacity;
+#endif
+
grpc_completion_queue *next_free;
};
@@ -89,6 +95,9 @@ void grpc_cq_global_shutdown(void) {
while (g_freelist) {
grpc_completion_queue *next = g_freelist->next_free;
grpc_pollset_destroy(&g_freelist->pollset);
+#ifndef NDEBUG
+ gpr_free(g_freelist->outstanding_tags);
+#endif
gpr_free(g_freelist);
g_freelist = next;
}
@@ -117,6 +126,10 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
cc = gpr_malloc(sizeof(grpc_completion_queue));
grpc_pollset_init(&cc->pollset);
+#ifndef NDEBUG
+ cc->outstanding_tags = NULL;
+ cc->outstanding_tag_capacity = 0;
+#endif
} else {
cc = g_freelist;
g_freelist = g_freelist->next_free;
@@ -134,6 +147,9 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
cc->shutdown_called = 0;
cc->is_server_cq = 0;
cc->num_pluckers = 0;
+#ifndef NDEBUG
+ cc->outstanding_tag_count = 0;
+#endif
grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc);
GPR_TIMER_END("grpc_completion_queue_create", 0);
@@ -176,10 +192,17 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
}
}
-void grpc_cq_begin_op(grpc_completion_queue *cc) {
+void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
#ifndef NDEBUG
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
GPR_ASSERT(!cc->shutdown_called);
+ if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) {
+ cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity);
+ cc->outstanding_tags =
+ gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) *
+ cc->outstanding_tag_capacity);
+ }
+ cc->outstanding_tags[cc->outstanding_tag_count++] = tag;
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
#endif
gpr_ref(&cc->pending_events);
@@ -196,6 +219,9 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
int shutdown;
int i;
grpc_pollset_worker *pluck_worker;
+#ifndef NDEBUG
+ int found = 0;
+#endif
GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
@@ -206,6 +232,18 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
((gpr_uintptr)&cc->completed_head) | ((gpr_uintptr)(success != 0));
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+#ifndef NDEBUG
+ for (i = 0; i < (int)cc->outstanding_tag_count; i++) {
+ if (cc->outstanding_tags[i] == tag) {
+ cc->outstanding_tag_count--;
+ GPR_SWAP(void *, cc->outstanding_tags[i],
+ cc->outstanding_tags[cc->outstanding_tag_count]);
+ found = 1;
+ break;
+ }
+ }
+ GPR_ASSERT(found);
+#endif
shutdown = gpr_unref(&cc->pending_events);
if (!shutdown) {
cc->completed_tail->next =
@@ -247,10 +285,10 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
GRPC_API_TRACE(
"grpc_completion_queue_next("
"cc=%p, "
- "deadline=gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
- 5, (cc, (long)deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type,
- reserved));
+ 5, (cc, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
+ (int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
@@ -335,9 +373,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: %ld, tv_nsec: %d, clock_type: %d }, "
+ "deadline=gpr_timespec { tv_sec: %lld, tv_nsec: %d, clock_type: %d }, "
"reserved=%p)",
- 6, (cc, tag, (long)deadline.tv_sec, deadline.tv_nsec,
+ 6, (cc, tag, (long long)deadline.tv_sec, (int)deadline.tv_nsec,
(int)deadline.clock_type, reserved));
GPR_ASSERT(!reserved);
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index a40bb048ac..1e40c48bea 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -68,10 +68,12 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc);
#endif
/* Flag that an operation is beginning: the completion channel will not finish
- shutdown until a corrensponding grpc_cq_end_* call is made */
-void grpc_cq_begin_op(grpc_completion_queue *cc);
+ shutdown until a corrensponding grpc_cq_end_* call is made.
+ \a tag is currently used only in debug builds. */
+void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag);
-/* Queue a GRPC_OP_COMPLETED operation */
+/* 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 (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index 04d68620f1..82027af651 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -58,6 +58,10 @@
#include "src/core/transport/chttp2_transport.h"
#include "src/core/transport/connectivity_state.h"
+#ifndef GRPC_DEFAULT_NAME_PREFIX
+#define GRPC_DEFAULT_NAME_PREFIX "dns:///"
+#endif
+
#define MAX_PLUGINS 128
static gpr_once g_basic_init = GPR_ONCE_INIT;
@@ -97,7 +101,7 @@ void grpc_init(void) {
grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
- grpc_resolver_registry_init("dns:///");
+ grpc_resolver_registry_init(GRPC_DEFAULT_NAME_PREFIX);
grpc_register_resolver_type(grpc_dns_resolver_factory_create());
grpc_register_resolver_type(grpc_ipv4_resolver_factory_create());
grpc_register_resolver_type(grpc_ipv6_resolver_factory_create());
@@ -143,6 +147,7 @@ void grpc_shutdown(void) {
gpr_timers_global_destroy();
grpc_tracer_shutdown();
grpc_resolver_registry_shutdown();
+ grpc_lb_policy_registry_shutdown();
for (i = 0; i < g_number_of_plugins; i++) {
if (g_all_of_the_plugins[i].destroy != NULL) {
g_all_of_the_plugins[i].destroy();
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index 0247116ebb..a60e9d20da 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -49,7 +49,6 @@ typedef struct {
} call_data;
typedef struct {
- grpc_channel *master;
grpc_status_code error_code;
const char *error_message;
} channel_data;
@@ -84,8 +83,7 @@ static void lame_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
}
static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
- channel_data *chand = elem->channel_data;
- return grpc_channel_get_target(chand->master);
+ return NULL;
}
static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -103,8 +101,7 @@ static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
}
static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
- grpc_call_element_args *args) {
-}
+ grpc_call_element_args *args) {}
static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem) {}
@@ -112,10 +109,8 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem,
grpc_channel_element_args *args) {
- channel_data *chand = elem->channel_data;
GPR_ASSERT(args->is_first);
GPR_ASSERT(args->is_last);
- chand->master = args->master;
}
static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 374b44b406..92bd53411d 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -88,7 +88,6 @@ static void connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *con) {
static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
grpc_security_status status,
- grpc_endpoint *wrapped_endpoint,
grpc_endpoint *secure_endpoint) {
connector *c = arg;
grpc_closure *notify;
@@ -97,13 +96,11 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
memset(c->result, 0, sizeof(*c->result));
gpr_mu_unlock(&c->mu);
} else if (status != GRPC_SECURITY_OK) {
- GPR_ASSERT(c->connecting_endpoint == wrapped_endpoint);
gpr_log(GPR_ERROR, "Secure handshake failed with error %d.", status);
memset(c->result, 0, sizeof(*c->result));
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
} else {
- GPR_ASSERT(c->connecting_endpoint == wrapped_endpoint);
c->connecting_endpoint = NULL;
gpr_mu_unlock(&c->mu);
c->result->transport = grpc_create_chttp2_transport(
@@ -231,7 +228,6 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
gpr_mu_init(&c->mu);
gpr_ref_init(&c->refs, 1);
args->args = final_args;
- args->master = f->master;
s = grpc_subchannel_create(&c->base, args);
grpc_connector_unref(exec_ctx, &c->base);
grpc_channel_args_destroy(final_args);
@@ -308,22 +304,22 @@ grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
f->master = channel;
GRPC_CHANNEL_INTERNAL_REF(channel, "subchannel_factory");
resolver = grpc_resolver_create(target, &f->base);
- if (!resolver) {
- grpc_exec_ctx_finish(&exec_ctx);
- return NULL;
+ if (resolver) {
+ grpc_client_channel_set_resolver(
+ &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
+ GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
}
-
- grpc_client_channel_set_resolver(
- &exec_ctx, grpc_channel_get_channel_stack(channel), resolver);
- GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "create");
grpc_subchannel_factory_unref(&exec_ctx, &f->base);
GRPC_SECURITY_CONNECTOR_UNREF(&security_connector->base, "channel_create");
-
grpc_channel_args_destroy(args_copy);
if (new_args_from_connector != NULL) {
grpc_channel_args_destroy(new_args_from_connector);
}
+ if (!resolver) {
+ GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "subchannel_factory");
+ channel = NULL;
+ }
grpc_exec_ctx_finish(&exec_ctx);
return channel;
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index cdbd542d9a..1e1cde3648 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -1007,7 +1007,7 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
/* lock, and gather up some stuff to do */
gpr_mu_lock(&server->mu_global);
- grpc_cq_begin_op(cq);
+ 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)));
@@ -1176,7 +1176,7 @@ grpc_call_error grpc_server_request_call(
error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
goto done;
}
- grpc_cq_begin_op(cq_for_notification);
+ grpc_cq_begin_op(cq_for_notification, tag);
details->reserved = NULL;
rc->type = BATCH_CALL;
rc->server = server;
@@ -1213,7 +1213,7 @@ grpc_call_error grpc_server_request_registered_call(
error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
goto done;
}
- grpc_cq_begin_op(cq_for_notification);
+ grpc_cq_begin_op(cq_for_notification, tag);
rc->type = REGISTERED_CALL;
rc->server = server;
rc->tag = tag;
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 990bc4aa23..5ce7c1955b 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -101,9 +101,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
}
tcp = grpc_tcp_server_create();
- if (!tcp) {
- goto error;
- }
+ GPR_ASSERT(tcp);
for (i = 0; i < resolved->naddrs; i++) {
grpc_tcp_listener *listener;
@@ -111,7 +109,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
tcp, (struct sockaddr *)&resolved->addrs[i].addr,
resolved->addrs[i].len);
port_temp = grpc_tcp_listener_get_port(listener);
- if (port_temp >= 0) {
+ if (port_temp > 0) {
if (port_num == -1) {
port_num = port_temp;
} else {
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
index c7811a6d88..f30093e06b 100644
--- a/src/core/surface/server_create.c
+++ b/src/core/surface/server_create.c
@@ -32,14 +32,20 @@
*/
#include <grpc/grpc.h>
+#include "src/core/census/grpc_filter.h"
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/compress_filter.h"
#include "src/core/surface/api_trace.h"
#include "src/core/surface/completion_queue.h"
#include "src/core/surface/server.h"
-#include "src/core/channel/compress_filter.h"
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved) {
- const grpc_channel_filter *filters[] = {&grpc_compress_filter};
+ const grpc_channel_filter *filters[3];
+ size_t num_filters = 0;
+ filters[num_filters++] = &grpc_compress_filter;
+ if (grpc_channel_args_is_census_enabled(args)) {
+ filters[num_filters++] = &grpc_server_census_filter;
+ }
GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
- return grpc_server_create_from_filters(filters, GPR_ARRAY_SIZE(filters),
- args);
+ return grpc_server_create_from_filters(filters, num_filters, args);
}
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index e07fbb2cc7..60a3ce23d5 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -53,7 +53,8 @@ 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);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, parser->parsing_frame,
+ 0, 1);
}
while (
(bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
@@ -118,7 +119,7 @@ void grpc_chttp2_encode_data(gpr_uint32 id, gpr_slice_buffer *inbuf,
hdr = gpr_slice_malloc(9);
p = GPR_SLICE_START_PTR(hdr);
- GPR_ASSERT(write_bytes < 16777316);
+ GPR_ASSERT(write_bytes < (1 << 24));
*p++ = (gpr_uint8)(write_bytes >> 16);
*p++ = (gpr_uint8)(write_bytes >> 8);
*p++ = (gpr_uint8)(write_bytes);
@@ -218,7 +219,8 @@ 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);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
+ 1);
p->parsing_frame = NULL;
p->state = GRPC_CHTTP2_DATA_FH_0;
return GRPC_CHTTP2_PARSE_OK;
@@ -227,7 +229,8 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
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);
+ grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame, 1,
+ 1);
p->parsing_frame = NULL;
cur += p->frame_size;
goto fh_0; /* loop */
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
index 472f9cebdb..27d4d0043b 100644
--- a/src/core/transport/chttp2/frame_data.h
+++ b/src/core/transport/chttp2/frame_data.h
@@ -94,9 +94,6 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
grpc_chttp2_transport_parsing *transport_parsing,
grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
-/* create a slice with an empty data frame and is_last set */
-gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
-
void grpc_chttp2_encode_data(gpr_uint32 id, gpr_slice_buffer *inbuf,
gpr_uint32 write_bytes, int is_eof,
gpr_slice_buffer *outbuf);
diff --git a/src/core/transport/chttp2/frame_ping.c b/src/core/transport/chttp2/frame_ping.c
index 4d2c54269d..8e763278ff 100644
--- a/src/core/transport/chttp2/frame_ping.c
+++ b/src/core/transport/chttp2/frame_ping.c
@@ -76,7 +76,6 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
gpr_uint8 *cur = beg;
grpc_chttp2_ping_parser *p = parser;
- grpc_chttp2_outstanding_ping *ping;
while (p->byte != 8 && cur != end) {
p->opaque_8bytes[p->byte] = *cur;
@@ -87,15 +86,7 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
if (p->byte == 8) {
GPR_ASSERT(is_last);
if (p->is_ack) {
- for (ping = transport_parsing->pings.next;
- ping != &transport_parsing->pings; ping = ping->next) {
- if (0 == memcmp(p->opaque_8bytes, ping->id, 8)) {
- grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, 1);
- }
- ping->next->prev = ping->prev;
- ping->prev->next = ping->next;
- gpr_free(ping);
- }
+ grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes);
} else {
gpr_slice_buffer_add(&transport_parsing->qbuf,
grpc_chttp2_ping_create(1, p->opaque_8bytes));
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
index d7c9f7ed69..383b6e7f93 100644
--- a/src/core/transport/chttp2/frame_settings.c
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -44,6 +44,8 @@
#include "src/core/transport/chttp2/http2_errors.h"
#include "src/core/transport/chttp2_transport.h"
+#define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024)
+
/* HTTP/2 mandated initial connection settings */
const grpc_chttp2_setting_parameters
grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
@@ -60,8 +62,9 @@ const grpc_chttp2_setting_parameters
GRPC_CHTTP2_FLOW_CONTROL_ERROR},
{"MAX_FRAME_SIZE", 16384, 16384, 16777215,
GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
- {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu,
- GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
+ {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0,
+ MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE,
+ GRPC_CHTTP2_PROTOCOL_ERROR},
};
static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c
index 28d5433d15..6c558bc1cb 100644
--- a/src/core/transport/chttp2/hpack_encoder.c
+++ b/src/core/transport/chttp2/hpack_encoder.c
@@ -365,10 +365,10 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
GPR_ASSERT(GPR_SLICE_LENGTH(elem->key->slice) > 0);
if (GPR_SLICE_START_PTR(elem->key->slice)[0] != ':') { /* regular header */
st->seen_regular_header = 1;
- } else if (st->seen_regular_header != 0) { /* reserved header */
- gpr_log(GPR_ERROR,
- "Reserved header (colon-prefixed) happening after regular ones.");
- abort();
+ } else {
+ GPR_ASSERT(
+ st->seen_regular_header == 0 &&
+ "Reserved header (colon-prefixed) happening after regular ones.");
}
inc_filter(HASH_FRAGMENT_1(elem_hash), &c->filter_elems_sum, c->filter_elems);
@@ -458,12 +458,6 @@ static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
GRPC_MDELEM_UNREF(mdelem);
}
-gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
- gpr_slice slice = gpr_slice_malloc(9);
- fill_header(GPR_SLICE_START_PTR(slice), GRPC_CHTTP2_FRAME_DATA, id, 0, 1);
- return slice;
-}
-
static gpr_uint32 elems_for_bytes(gpr_uint32 bytes) {
return (bytes + 31) / 32;
}
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index d38ff68754..fea0000896 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -728,6 +728,7 @@ static int finish_indexed_field(grpc_chttp2_hpack_parser *p,
/* parse an indexed field with index < 127 */
static int parse_indexed_field(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
+ p->dynamic_table_update_allowed = 0;
p->index = (*cur) & 0x7f;
return finish_indexed_field(p, cur + 1, end);
}
@@ -737,6 +738,7 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_indexed_field};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
p->index = 0x7f;
p->parsing.value = &p->index;
@@ -748,6 +750,7 @@ static int parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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) &&
@@ -768,6 +771,7 @@ static int parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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;
p->next_state = and_then;
p->index = (*cur) & 0x3f;
return parse_string_prefix(p, cur + 1, end);
@@ -779,6 +783,7 @@ static int parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_incidx};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
p->index = 0x3f;
p->parsing.value = &p->index;
@@ -791,6 +796,7 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
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};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end);
}
@@ -799,6 +805,7 @@ static int parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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) &&
@@ -819,6 +826,7 @@ static int parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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;
p->next_state = and_then;
p->index = (*cur) & 0xf;
return parse_string_prefix(p, cur + 1, end);
@@ -830,6 +838,7 @@ static int parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_notidx};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
p->index = 0xf;
p->parsing.value = &p->index;
@@ -842,6 +851,7 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
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};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end);
}
@@ -850,6 +860,7 @@ static int parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
static int finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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) &&
@@ -870,6 +881,7 @@ static int parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *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;
p->next_state = and_then;
p->index = (*cur) & 0xf;
return parse_string_prefix(p, cur + 1, end);
@@ -881,6 +893,7 @@ static int parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
static const grpc_chttp2_hpack_parser_state and_then[] = {
parse_string_prefix, parse_value_string_with_indexed_key,
finish_lithdr_nvridx};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
p->index = 0xf;
p->parsing.value = &p->index;
@@ -893,6 +906,7 @@ static int parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
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};
+ p->dynamic_table_update_allowed = 0;
p->next_state = and_then;
return parse_string_prefix(p, cur + 1, end);
}
@@ -908,6 +922,10 @@ static int finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
/* parse a max table size change, max size < 15 */
static int parse_max_tbl_size(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
const gpr_uint8 *end) {
+ if (p->dynamic_table_update_allowed == 0) {
+ return 0;
+ }
+ p->dynamic_table_update_allowed--;
p->index = (*cur) & 0x1f;
return finish_max_tbl_size(p, cur + 1, end);
}
@@ -917,6 +935,10 @@ static int parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
const gpr_uint8 *cur, const gpr_uint8 *end) {
static const grpc_chttp2_hpack_parser_state and_then[] = {
finish_max_tbl_size};
+ if (p->dynamic_table_update_allowed == 0) {
+ return 0;
+ }
+ p->dynamic_table_update_allowed--;
p->next_state = and_then;
p->index = 0x1f;
p->parsing.value = &p->index;
@@ -1044,7 +1066,7 @@ static int parse_value4(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
error:
gpr_log(GPR_ERROR,
"integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x",
+ "got byte 0x%02x on byte 5",
*p->parsing.value, *cur);
return parse_error(p, cur, end);
}
@@ -1069,7 +1091,8 @@ static int parse_value5up(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
gpr_log(GPR_ERROR,
"integer overflow in hpack integer decoding: have 0x%08x, "
- "got byte 0x%02x sometime after byte 4");
+ "got byte 0x%02x sometime after byte 5",
+ *p->parsing.value, *cur);
return parse_error(p, cur, end);
}
@@ -1300,7 +1323,10 @@ static is_binary_header is_binary_literal_header(grpc_chttp2_hpack_parser *p) {
static is_binary_header is_binary_indexed_header(grpc_chttp2_hpack_parser *p) {
grpc_mdelem *elem = grpc_chttp2_hptbl_lookup(&p->table, p->index);
- if (!elem) return ERROR_HEADER;
+ if (!elem) {
+ gpr_log(GPR_ERROR, "Invalid HPACK index received: %d", p->index);
+ return ERROR_HEADER;
+ }
return grpc_is_binary_header(
(const char *)GPR_SLICE_START_PTR(elem->key->slice),
GPR_SLICE_LENGTH(elem->key->slice))
@@ -1338,15 +1364,7 @@ static int parse_value_string_with_literal_key(grpc_chttp2_hpack_parser *p,
/* PUBLIC INTERFACE */
static void on_header_not_set(void *user_data, grpc_mdelem *md) {
- char *keyhex = gpr_dump_slice(md->key->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
- char *valuehex =
- gpr_dump_slice(md->value->slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
- gpr_log(GPR_ERROR, "on_header callback not set; key=%s value=%s", keyhex,
- valuehex);
- gpr_free(keyhex);
- gpr_free(valuehex);
- GRPC_MDELEM_UNREF(md);
- abort();
+ GPR_UNREACHABLE_CODE(return );
}
void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
@@ -1359,6 +1377,7 @@ void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
p->value.str = NULL;
p->value.capacity = 0;
p->value.length = 0;
+ p->dynamic_table_update_allowed = 2;
grpc_chttp2_hptbl_init(&p->table);
}
@@ -1400,20 +1419,25 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return GRPC_CHTTP2_CONNECTION_ERROR;
}
- if (parser->is_boundary) {
- stream_parsing
- ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
- stream_parsing->header_frames_received++;
- grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
- stream_parsing);
- }
- if (parser->is_eof) {
- stream_parsing->received_close = 1;
+ /* need to check for null stream: this can occur if we receive an invalid
+ stream id on a header */
+ if (stream_parsing != NULL) {
+ if (parser->is_boundary) {
+ stream_parsing
+ ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
+ stream_parsing->header_frames_received++;
+ grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
+ stream_parsing);
+ }
+ if (parser->is_eof) {
+ stream_parsing->received_close = 1;
+ }
}
parser->on_header = on_header_not_set;
parser->on_header_user_data = NULL;
parser->is_boundary = 0xde;
parser->is_eof = 0xde;
+ parser->dynamic_table_update_allowed = 2;
}
GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
return GRPC_CHTTP2_PARSE_OK;
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index fb894b5735..bd36357124 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -85,6 +85,8 @@ struct grpc_chttp2_hpack_parser {
gpr_uint8 binary;
/* is the current string huffman encoded? */
gpr_uint8 huff;
+ /* is a dynamic table update allowed? */
+ gpr_uint8 dynamic_table_update_allowed;
/* set by higher layers, used by grpc_chttp2_header_parser_parse to signal
it should append a metadata boundary at the end of frame */
gpr_uint8 is_boundary;
diff --git a/src/core/transport/chttp2/incoming_metadata.c b/src/core/transport/chttp2/incoming_metadata.c
index 956afc8e9d..315bc2faa1 100644
--- a/src/core/transport/chttp2/incoming_metadata.c
+++ b/src/core/transport/chttp2/incoming_metadata.c
@@ -56,16 +56,6 @@ void grpc_chttp2_incoming_metadata_buffer_destroy(
gpr_free(buffer->elems);
}
-void grpc_chttp2_incoming_metadata_buffer_reset(
- grpc_chttp2_incoming_metadata_buffer *buffer) {
- size_t i;
- GPR_ASSERT(!buffer->published);
- for (i = 0; i < buffer->count; i++) {
- GRPC_MDELEM_UNREF(buffer->elems[i].md);
- }
- buffer->count = 0;
-}
-
void grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer *buffer, grpc_mdelem *elem) {
GPR_ASSERT(!buffer->published);
@@ -83,14 +73,6 @@ void grpc_chttp2_incoming_metadata_buffer_set_deadline(
buffer->deadline = deadline;
}
-void grpc_chttp2_incoming_metadata_buffer_swap(
- grpc_chttp2_incoming_metadata_buffer *a,
- grpc_chttp2_incoming_metadata_buffer *b) {
- GPR_ASSERT(!a->published);
- GPR_ASSERT(!b->published);
- GPR_SWAP(grpc_chttp2_incoming_metadata_buffer, *a, *b);
-}
-
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch) {
GPR_ASSERT(!buffer->published);
diff --git a/src/core/transport/chttp2/incoming_metadata.h b/src/core/transport/chttp2/incoming_metadata.h
index 0e1dabe825..ea74cfc64b 100644
--- a/src/core/transport/chttp2/incoming_metadata.h
+++ b/src/core/transport/chttp2/incoming_metadata.h
@@ -49,8 +49,6 @@ void grpc_chttp2_incoming_metadata_buffer_init(
grpc_chttp2_incoming_metadata_buffer *buffer);
void grpc_chttp2_incoming_metadata_buffer_destroy(
grpc_chttp2_incoming_metadata_buffer *buffer);
-void grpc_chttp2_incoming_metadata_buffer_reset(
- grpc_chttp2_incoming_metadata_buffer *buffer);
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 3952f8a0e8..4ad900378b 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -65,6 +65,7 @@ typedef enum {
GRPC_CHTTP2_LIST_WRITTEN,
GRPC_CHTTP2_LIST_PARSING_SEEN,
GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
+ GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING,
GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
/** streams that are waiting to start because there are too many concurrent
streams on the connection */
@@ -151,6 +152,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_chttp2_transport *transport;
grpc_chttp2_stream *stream;
@@ -283,9 +285,6 @@ struct grpc_chttp2_transport_parsing {
gpr_slice goaway_text;
gpr_int64 outgoing_window;
-
- /** pings awaiting responses */
- grpc_chttp2_outstanding_ping pings;
};
struct grpc_chttp2_transport {
@@ -394,8 +393,6 @@ typedef struct {
gpr_uint8 write_closed;
/** is this stream reading half-closed (boolean) */
gpr_uint8 read_closed;
- /** is this stream finished closing (and reportably closed) */
- gpr_uint8 finished_close;
/** is this stream in the stream map? (boolean) */
gpr_uint8 in_stream_map;
/** has this stream seen an error? if 1, then pending incoming frames
@@ -512,9 +509,6 @@ void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
void grpc_chttp2_list_add_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_list_add_first_writable_stream(
- grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global);
int grpc_chttp2_list_pop_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_transport_writing *transport_writing,
@@ -592,6 +586,13 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global **stream_global);
+void grpc_chttp2_list_add_closed_waiting_for_writing(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global);
+int grpc_chttp2_list_pop_closed_waiting_for_writing(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global **stream_global);
+
grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
grpc_chttp2_transport_parsing *transport_parsing, gpr_uint32 id);
grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
@@ -748,6 +749,11 @@ 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);
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
+ int from_parsing_thread);
+
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport_parsing *parsing,
+ const gpr_uint8 *opaque_8bytes);
#endif
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index eb2cb6b4c2..7604e7b681 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -604,7 +604,7 @@ static void on_initial_header(void *tp, grpc_mdelem *md) {
cached_timeout)) {
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
grpc_mdstr_as_c_string(md->value));
- *cached_timeout = gpr_inf_future(GPR_CLOCK_REALTIME);
+ *cached_timeout = gpr_inf_future(GPR_TIMESPAN);
}
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
index a81ffcce79..49f951d08b 100644
--- a/src/core/transport/chttp2/stream_lists.c
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -108,23 +108,6 @@ static void stream_list_maybe_remove(grpc_chttp2_transport *t,
}
}
-static void stream_list_add_head(grpc_chttp2_transport *t,
- grpc_chttp2_stream *s,
- grpc_chttp2_stream_list_id id) {
- grpc_chttp2_stream *old_head;
- GPR_ASSERT(!s->included[id]);
- old_head = t->lists[id].head;
- s->links[id].next = old_head;
- s->links[id].prev = NULL;
- if (old_head) {
- old_head->links[id].prev = s;
- } else {
- t->lists[id].tail = s;
- }
- t->lists[id].head = s;
- s->included[id] = 1;
-}
-
static void stream_list_add_tail(grpc_chttp2_transport *t,
grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) {
@@ -161,15 +144,6 @@ void grpc_chttp2_list_add_writable_stream(
STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE);
}
-void grpc_chttp2_list_add_first_writable_stream(
- grpc_chttp2_transport_global *transport_global,
- grpc_chttp2_stream_global *stream_global) {
- GPR_ASSERT(stream_global->id != 0);
- stream_list_add_head(TRANSPORT_FROM_GLOBAL(transport_global),
- STREAM_FROM_GLOBAL(stream_global),
- GRPC_CHTTP2_LIST_WRITABLE);
-}
-
int grpc_chttp2_list_pop_writable_stream(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_transport_writing *transport_writing,
@@ -379,6 +353,26 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing(
return r;
}
+void grpc_chttp2_list_add_closed_waiting_for_writing(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global *stream_global) {
+ stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
+ STREAM_FROM_GLOBAL(stream_global),
+ GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING);
+}
+
+int grpc_chttp2_list_pop_closed_waiting_for_writing(
+ grpc_chttp2_transport_global *transport_global,
+ grpc_chttp2_stream_global **stream_global) {
+ grpc_chttp2_stream *stream;
+ int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
+ GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING);
+ if (r != 0) {
+ *stream_global = &stream->global;
+ }
+ return r;
+}
+
void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
grpc_chttp2_stream *s) {
stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
diff --git a/src/core/transport/chttp2/timeout_encoding.c b/src/core/transport/chttp2/timeout_encoding.c
index 8a9b290ecb..7ec8b4e8bf 100644
--- a/src/core/transport/chttp2/timeout_encoding.c
+++ b/src/core/transport/chttp2/timeout_encoding.c
@@ -36,14 +36,15 @@
#include <stdio.h>
#include <string.h>
+#include <grpc/support/port_platform.h>
#include "src/core/support/string.h"
-static int round_up(int x, int divisor) {
+static gpr_int64 round_up(gpr_int64 x, gpr_int64 divisor) {
return (x / divisor + (x % divisor != 0)) * divisor;
}
/* round an integer up to the next value with three significant figures */
-static int round_up_to_three_sig_figs(int x) {
+static gpr_int64 round_up_to_three_sig_figs(gpr_int64 x) {
if (x < 1000) return x;
if (x < 10000) return round_up(x, 10);
if (x < 100000) return round_up(x, 100);
@@ -57,13 +58,13 @@ static int round_up_to_three_sig_figs(int x) {
/* encode our minimum viable timeout value */
static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
-static void enc_ext(char *buffer, long value, char ext) {
- int n = gpr_ltoa(value, buffer);
+static void enc_ext(char *buffer, gpr_int64 value, char ext) {
+ int n = gpr_int64toa(value, buffer);
buffer[n] = ext;
buffer[n + 1] = 0;
}
-static void enc_seconds(char *buffer, long sec) {
+static void enc_seconds(char *buffer, gpr_int64 sec) {
if (sec % 3600 == 0) {
enc_ext(buffer, sec / 3600, 'H');
} else if (sec % 60 == 0) {
@@ -73,7 +74,7 @@ static void enc_seconds(char *buffer, long sec) {
}
}
-static void enc_nanos(char *buffer, int x) {
+static void enc_nanos(char *buffer, gpr_int64 x) {
x = round_up_to_three_sig_figs(x);
if (x < 100000) {
if (x % 1000 == 0) {
@@ -97,7 +98,7 @@ static void enc_nanos(char *buffer, int x) {
}
}
-static void enc_micros(char *buffer, int x) {
+static void enc_micros(char *buffer, gpr_int64 x) {
x = round_up_to_three_sig_figs(x);
if (x < 100000) {
if (x % 1000 == 0) {
@@ -123,7 +124,7 @@ void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
enc_nanos(buffer, timeout.tv_nsec);
} else if (timeout.tv_sec < 1000 && timeout.tv_nsec != 0) {
enc_micros(buffer,
- (int)(timeout.tv_sec * 1000000) +
+ (gpr_int64)(timeout.tv_sec * 1000000) +
(timeout.tv_nsec / 1000 + (timeout.tv_nsec % 1000 != 0)));
} else {
enc_seconds(buffer, timeout.tv_sec + (timeout.tv_nsec != 0));
diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h
index 4dfcc76773..5acb15d032 100644
--- a/src/core/transport/chttp2/varint.h
+++ b/src/core/transport/chttp2/varint.h
@@ -50,7 +50,8 @@ void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value,
/* maximum value that can be bitpacked with the opcode if the opcode has a
prefix
of length prefix_bits */
-#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) ((1 << (8 - (prefix_bits))) - 1)
+#define GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits) \
+ ((gpr_uint32)((1 << (8 - (prefix_bits))) - 1))
/* length required to bitpack a value */
#define GRPC_CHTTP2_VARINT_LENGTH(n, prefix_bits) \
@@ -65,7 +66,8 @@ void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value,
if ((length) == 1u) { \
(tgt)[0] = (gpr_uint8)((prefix_or) | (n)); \
} else { \
- (tgt)[0] = (prefix_or) | GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits); \
+ (tgt)[0] = \
+ (prefix_or) | (gpr_uint8)GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits); \
grpc_chttp2_hpack_write_varint_tail( \
(n)-GRPC_CHTTP2_MAX_IN_PREFIX(prefix_bits), (tgt) + 1, (length)-1); \
} \
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 805d05222d..b5ca42d69c 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -332,17 +332,12 @@ void grpc_chttp2_cleanup_writing(
while (grpc_chttp2_list_pop_written_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) {
- if (stream_writing->sent_trailing_metadata) {
- grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
- !transport_global->is_client, 1);
- }
if (stream_writing->sent_initial_metadata) {
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_initial_metadata_finished, 1);
}
if (stream_writing->sent_message) {
GPR_ASSERT(stream_writing->send_message == NULL);
- GPR_ASSERT(stream_global->send_message_finished);
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_message_finished, 1);
stream_writing->sent_message = 0;
@@ -351,6 +346,10 @@ void grpc_chttp2_cleanup_writing(
grpc_chttp2_complete_closure_step(
exec_ctx, &stream_global->send_trailing_metadata_finished, 1);
}
+ if (stream_writing->sent_trailing_metadata) {
+ grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
+ !transport_global->is_client, 1);
+ }
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
}
gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 3e88f69abf..c3847bb6c5 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -134,6 +134,9 @@ static void connectivity_state_set(
static void check_read_ops(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *transport_global);
+static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_stream_global *stream_global);
+
/*
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
@@ -625,6 +628,7 @@ void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
void *transport_writing_ptr, int success) {
grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
+ grpc_chttp2_stream_global *stream_global;
GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
@@ -638,6 +642,11 @@ void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
+ while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global, &stream_global)) {
+ fail_pending_writes(exec_ctx, stream_global);
+ GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
+ }
+
/* leave the writing flag up on shutdown to prevent further writes in unlock()
from starting */
t->writing_active = 0;
@@ -901,6 +910,26 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
}
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+ grpc_chttp2_transport_parsing *transport_parsing,
+ const gpr_uint8 *opaque_8bytes) {
+ grpc_chttp2_outstanding_ping *ping;
+ grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
+ grpc_chttp2_transport_global *transport_global = &t->global;
+ lock(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, 1);
+ ping->next->prev = ping->prev;
+ ping->prev->next = ping->next;
+ gpr_free(ping);
+ break;
+ }
+ }
+ unlock(exec_ctx, t);
+}
+
static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_transport_op *op) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
@@ -910,7 +939,7 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
- if (op->on_connectivity_state_change) {
+ if (op->on_connectivity_state_change != NULL) {
grpc_connectivity_state_notify_on_state_change(
exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state,
op->on_connectivity_state_change);
@@ -1020,6 +1049,12 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->parsing.incoming_stream = NULL;
grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing);
}
+ if (s->parsing.data_parser.parsing_frame != NULL) {
+ grpc_chttp2_incoming_byte_stream_finished(
+ exec_ctx, s->parsing.data_parser.parsing_frame, 0, 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);
}
@@ -1087,6 +1122,16 @@ 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_complete_closure_step(
+ exec_ctx, &stream_global->send_initial_metadata_finished, 0);
+ grpc_chttp2_complete_closure_step(
+ exec_ctx, &stream_global->send_trailing_metadata_finished, 0);
+ grpc_chttp2_complete_closure_step(exec_ctx,
+ &stream_global->send_message_finished, 0);
+}
+
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,
@@ -1103,6 +1148,13 @@ void grpc_chttp2_mark_stream_closed(
}
if (close_writes && !stream_global->write_closed) {
stream_global->write_closed = 1;
+ if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
+ GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
+ grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
+ stream_global);
+ } else {
+ fail_pending_writes(exec_ctx, stream_global);
+ }
}
if (stream_global->read_closed && stream_global->write_closed) {
if (stream_global->id != 0 &&
@@ -1114,7 +1166,6 @@ void grpc_chttp2_mark_stream_closed(
remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
stream_global->id);
}
- stream_global->finished_close = 1;
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
}
@@ -1328,7 +1379,6 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
GPR_ASSERT(stream_global->write_closed);
GPR_ASSERT(stream_global->read_closed);
remove_stream(exec_ctx, t, stream_global->id);
- stream_global->finished_close = 1;
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
}
}
@@ -1459,6 +1509,10 @@ static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
*slice = gpr_slice_buffer_take_first(&bs->slices);
unlock(exec_ctx, bs->transport);
return 1;
+ } else if (bs->failed) {
+ grpc_exec_ctx_enqueue(exec_ctx, on_complete, 0);
+ unlock(exec_ctx, bs->transport);
+ return 0;
} else {
bs->on_next = on_complete;
bs->next = slice;
@@ -1493,7 +1547,29 @@ void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
}
void grpc_chttp2_incoming_byte_stream_finished(
- grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs) {
+ grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
+ int from_parsing_thread) {
+ if (!success) {
+ if (from_parsing_thread) {
+ gpr_mu_lock(&bs->transport->mu);
+ }
+ grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, 0);
+ bs->on_next = NULL;
+ bs->failed = 1;
+ if (from_parsing_thread) {
+ gpr_mu_unlock(&bs->transport->mu);
+ }
+ } else {
+#ifndef NDEBUG
+ if (from_parsing_thread) {
+ gpr_mu_lock(&bs->transport->mu);
+ }
+ GPR_ASSERT(bs->on_next == NULL);
+ if (from_parsing_thread) {
+ gpr_mu_unlock(&bs->transport->mu);
+ }
+#endif
+ }
incoming_byte_stream_unref(bs);
}
@@ -1514,6 +1590,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;
if (add_to_queue->head == NULL) {
add_to_queue->head = incoming_byte_stream;
} else {
diff --git a/src/core/transport/connectivity_state.c b/src/core/transport/connectivity_state.c
index 09b298c131..3c3fd4671d 100644
--- a/src/core/transport/connectivity_state.c
+++ b/src/core/transport/connectivity_state.c
@@ -54,8 +54,7 @@ const char *grpc_connectivity_state_name(grpc_connectivity_state state) {
case GRPC_CHANNEL_FATAL_FAILURE:
return "FATAL_FAILURE";
}
- abort();
- return "UNKNOWN";
+ GPR_UNREACHABLE_CODE(return "UNKNOWN");
}
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
@@ -88,7 +87,7 @@ void grpc_connectivity_state_destroy(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker) {
if (grpc_connectivity_state_trace) {
- gpr_log(GPR_DEBUG, "CONWATCH: %s: get %s", tracker->name,
+ gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
grpc_connectivity_state_name(tracker->current_state));
}
return tracker->current_state;
@@ -98,42 +97,47 @@ int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify) {
if (grpc_connectivity_state_trace) {
- gpr_log(GPR_DEBUG, "CONWATCH: %s: from %s [cur=%s] notify=%p",
- tracker->name, grpc_connectivity_state_name(*current),
- grpc_connectivity_state_name(tracker->current_state), notify);
+ if (current == NULL) {
+ gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
+ tracker->name, notify);
+ } else {
+ gpr_log(GPR_DEBUG, "CONWATCH: %p %s: from %s [cur=%s] notify=%p", tracker,
+ tracker->name, grpc_connectivity_state_name(*current),
+ grpc_connectivity_state_name(tracker->current_state), notify);
+ }
}
- if (tracker->current_state != *current) {
- *current = tracker->current_state;
- grpc_exec_ctx_enqueue(exec_ctx, notify, 1);
+ if (current == NULL) {
+ grpc_connectivity_state_watcher *w = tracker->watchers;
+ if (w != NULL && w->notify == notify) {
+ grpc_exec_ctx_enqueue(exec_ctx, notify, 0);
+ tracker->watchers = w->next;
+ gpr_free(w);
+ return 0;
+ }
+ 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, 0);
+ w->next = w->next->next;
+ gpr_free(rm_candidate);
+ return 0;
+ }
+ w = w->next;
+ }
+ return 0;
} else {
- grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
- w->current = current;
- w->notify = notify;
- w->next = tracker->watchers;
- tracker->watchers = w;
- }
- return tracker->current_state == GRPC_CHANNEL_IDLE;
-}
-
-int grpc_connectivity_state_change_unsubscribe(
- grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
- grpc_closure *subscribed_notify) {
- grpc_connectivity_state_watcher *w = tracker->watchers;
- if (w != NULL && w->notify == subscribed_notify) {
- tracker->watchers = w->next;
- gpr_free(w);
- return 1;
- }
- while (w != NULL) {
- grpc_connectivity_state_watcher *rm_candidate = w->next;
- if (rm_candidate != NULL && rm_candidate->notify == subscribed_notify) {
- w->next = w->next->next;
- gpr_free(rm_candidate);
- return 1;
+ if (tracker->current_state != *current) {
+ *current = tracker->current_state;
+ grpc_exec_ctx_enqueue(exec_ctx, notify, 1);
+ } else {
+ grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
+ w->current = current;
+ w->notify = notify;
+ w->next = tracker->watchers;
+ tracker->watchers = w;
}
- w = w->next;
+ return tracker->current_state == GRPC_CHANNEL_IDLE;
}
- return 0;
}
void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
@@ -142,7 +146,7 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
const char *reason) {
grpc_connectivity_state_watcher *w;
if (grpc_connectivity_state_trace) {
- gpr_log(GPR_DEBUG, "SET: %s: %s --> %s [%s]", tracker->name,
+ 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);
}
diff --git a/src/core/transport/connectivity_state.h b/src/core/transport/connectivity_state.h
index 119b1c1554..a4eb6652e5 100644
--- a/src/core/transport/connectivity_state.h
+++ b/src/core/transport/connectivity_state.h
@@ -57,6 +57,8 @@ typedef struct {
extern int grpc_connectivity_state_trace;
+const char *grpc_connectivity_state_name(grpc_connectivity_state state);
+
void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state init_state,
const char *name);
@@ -73,16 +75,11 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state grpc_connectivity_state_check(
grpc_connectivity_state_tracker *tracker);
-/** Return 1 if the channel should start connecting, 0 otherwise */
+/** Return 1 if the channel should start connecting, 0 otherwise.
+ If current==NULL cancel notify if it is already queued (success==0 in that
+ case) */
int grpc_connectivity_state_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
grpc_connectivity_state *current, grpc_closure *notify);
-/** Remove \a subscribed_notify from the list of closures to be called on a
- * state change if present, returning 1. Otherwise, nothing is done and return
- * 0. */
-int grpc_connectivity_state_change_unsubscribe(
- grpc_exec_ctx *exec_ctx, grpc_connectivity_state_tracker *tracker,
- grpc_closure *subscribed_notify);
-
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index d6fb255eb6..02b2402820 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -225,7 +225,8 @@ 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", shard->count);
+ gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
+ shard->count);
}
gpr_free(shard->elems);
}
@@ -234,7 +235,8 @@ 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", shard->count);
+ gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
+ shard->count);
}
gpr_free(shard->strs);
}
@@ -701,7 +703,7 @@ static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) {
int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
static const gpr_uint8 legal_header_bits[256 / 8] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return conforms_to(s, legal_header_bits);
@@ -709,7 +711,7 @@ int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) {
static const gpr_uint8 legal_header_bits[256 / 8] = {
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return conforms_to(s, legal_header_bits);
diff --git a/src/core/transport/metadata_batch.c b/src/core/transport/metadata_batch.c
index c5d39e0c9f..1266862f82 100644
--- a/src/core/transport/metadata_batch.c
+++ b/src/core/transport/metadata_batch.c
@@ -133,16 +133,6 @@ void grpc_metadata_batch_link_tail(grpc_metadata_batch *batch,
link_tail(&batch->list, storage);
}
-void grpc_metadata_batch_merge(grpc_metadata_batch *target,
- grpc_metadata_batch *to_add) {
- grpc_linked_mdelem *l;
- grpc_linked_mdelem *next;
- for (l = to_add->list.head; l; l = next) {
- next = l->next;
- link_tail(&target->list, l);
- }
-}
-
void grpc_metadata_batch_move(grpc_metadata_batch *dst,
grpc_metadata_batch *src) {
*dst = *src;
diff --git a/src/core/transport/metadata_batch.h b/src/core/transport/metadata_batch.h
index fc3a46004f..1b0d1fda3e 100644
--- a/src/core/transport/metadata_batch.h
+++ b/src/core/transport/metadata_batch.h
@@ -63,8 +63,6 @@ typedef struct grpc_metadata_batch {
void grpc_metadata_batch_init(grpc_metadata_batch *batch);
void grpc_metadata_batch_destroy(grpc_metadata_batch *batch);
-void grpc_metadata_batch_merge(grpc_metadata_batch *target,
- grpc_metadata_batch *add);
void grpc_metadata_batch_clear(grpc_metadata_batch *batch);
int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
index e7aff325c2..6e42379eee 100644
--- a/src/core/transport/static_metadata.c
+++ b/src/core/transport/static_metadata.c
@@ -33,11 +33,11 @@
* WARNING: Auto-generated code.
*
* To make changes to this file, change
- * tools/codegen/core/gen_static_metadata.py,
+ *tools/codegen/core/gen_static_metadata.py,
* and then re-run it.
*
* See metadata.h for an explanation of the interface here, and metadata.c for
- * an
+ *an
* explanation of what's going on.
*/
@@ -54,103 +54,34 @@ gpr_uintptr grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
const gpr_uint8
grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] = {
- 11, 33, 10, 33, 12, 33, 12, 47, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
- 19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
- 28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
- 40, 32, 40, 46, 40, 51, 40, 52, 40, 53, 40, 54, 41, 31, 41, 46, 41, 51,
- 44, 0, 44, 1, 44, 2, 48, 33, 55, 33, 56, 33, 57, 33, 58, 33, 59, 33,
- 60, 33, 61, 33, 62, 33, 63, 33, 64, 38, 64, 66, 65, 76, 65, 77, 67, 33,
- 68, 33, 69, 33, 70, 33, 71, 33, 72, 33, 73, 39, 73, 49, 73, 50, 74, 33,
- 75, 33, 78, 3, 78, 4, 78, 5, 78, 6, 78, 7, 78, 8, 78, 9, 79, 33,
- 80, 81, 82, 33, 83, 33, 84, 33, 85, 33, 86, 33};
+ 11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35,
+ 19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35,
+ 30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33,
+ 42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53,
+ 46, 0, 46, 1, 46, 2, 50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35,
+ 62, 35, 63, 35, 64, 35, 65, 35, 66, 40, 66, 68, 67, 78, 67, 79, 69, 35,
+ 70, 35, 71, 35, 72, 35, 73, 35, 74, 35, 75, 41, 75, 51, 75, 52, 76, 35,
+ 77, 35, 80, 3, 80, 4, 80, 5, 80, 6, 80, 7, 80, 8, 80, 9, 81, 35,
+ 82, 83, 84, 35, 85, 35, 86, 35, 87, 35, 88, 35};
const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
- "0",
- "1",
- "2",
- "200",
- "204",
- "206",
- "304",
- "400",
- "404",
- "500",
- "accept",
- "accept-charset",
- "accept-encoding",
- "accept-language",
- "accept-ranges",
- "access-control-allow-origin",
- "age",
- "allow",
- "application/grpc",
- ":authority",
- "authorization",
- "cache-control",
- "content-disposition",
- "content-encoding",
- "content-language",
- "content-length",
- "content-location",
- "content-range",
- "content-type",
- "cookie",
- "date",
- "deflate",
- "deflate,gzip",
- "",
- "etag",
- "expect",
- "expires",
- "from",
- "GET",
- "grpc",
- "grpc-accept-encoding",
- "grpc-encoding",
- "grpc-internal-encoding-request",
- "grpc-message",
- "grpc-status",
- "grpc-timeout",
- "gzip",
- "gzip, deflate",
- "host",
- "http",
- "https",
- "identity",
- "identity,deflate",
- "identity,deflate,gzip",
- "identity,gzip",
- "if-match",
- "if-modified-since",
- "if-none-match",
- "if-range",
- "if-unmodified-since",
- "last-modified",
- "link",
- "location",
- "max-forwards",
- ":method",
- ":path",
- "POST",
- "proxy-authenticate",
- "proxy-authorization",
- "range",
- "referer",
- "refresh",
- "retry-after",
- ":scheme",
- "server",
- "set-cookie",
- "/",
- "/index.html",
- ":status",
- "strict-transport-security",
- "te",
- "trailers",
- "transfer-encoding",
- "user-agent",
- "vary",
- "via",
+ "0", "1", "2", "200", "204", "206", "304", "400", "404", "500", "accept",
+ "accept-charset", "accept-encoding", "accept-language", "accept-ranges",
+ "access-control-allow-origin", "age", "allow", "application/grpc",
+ ":authority", "authorization", "cache-control", "census", "census-bin",
+ "content-disposition", "content-encoding", "content-language",
+ "content-length", "content-location", "content-range", "content-type",
+ "cookie", "date", "deflate", "deflate,gzip", "", "etag", "expect",
+ "expires", "from", "GET", "grpc", "grpc-accept-encoding", "grpc-encoding",
+ "grpc-internal-encoding-request", "grpc-message", "grpc-status",
+ "grpc-timeout", "gzip", "gzip, deflate", "host", "http", "https",
+ "identity", "identity,deflate", "identity,deflate,gzip", "identity,gzip",
+ "if-match", "if-modified-since", "if-none-match", "if-range",
+ "if-unmodified-since", "last-modified", "link", "location", "max-forwards",
+ ":method", ":path", "POST", "proxy-authenticate", "proxy-authorization",
+ "range", "referer", "refresh", "retry-after", ":scheme", "server",
+ "set-cookie", "/", "/index.html", ":status", "strict-transport-security",
+ "te", "trailers", "transfer-encoding", "user-agent", "vary", "via",
"www-authenticate"};
const gpr_uint8 grpc_static_accept_encoding_metadata[8] = {0, 29, 26, 30,
diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h
index e9055fb45c..0e630b1b03 100644
--- a/src/core/transport/static_metadata.h
+++ b/src/core/transport/static_metadata.h
@@ -46,7 +46,7 @@
#include "src/core/transport/metadata.h"
-#define GRPC_STATIC_MDSTR_COUNT 87
+#define GRPC_STATIC_MDSTR_COUNT 89
extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
/* "0" */
#define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
@@ -92,137 +92,141 @@ extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
#define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
/* "cache-control" */
#define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
+/* "census" */
+#define GRPC_MDSTR_CENSUS (&grpc_static_mdstr_table[22])
+/* "census-bin" */
+#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[23])
/* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24])
/* "content-encoding" */
-#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23])
+#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25])
/* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26])
/* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25])
+#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27])
/* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26])
+#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28])
/* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27])
+#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29])
/* "content-type" */
-#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28])
+#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30])
/* "cookie" */
-#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29])
+#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31])
/* "date" */
-#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[30])
+#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32])
/* "deflate" */
-#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[31])
+#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33])
/* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[32])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34])
/* "" */
-#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[33])
+#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35])
/* "etag" */
-#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34])
+#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36])
/* "expect" */
-#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35])
+#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37])
/* "expires" */
-#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36])
+#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38])
/* "from" */
-#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[37])
+#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39])
/* "GET" */
-#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[38])
+#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40])
/* "grpc" */
-#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[39])
+#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41])
/* "grpc-accept-encoding" */
-#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[40])
+#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42])
/* "grpc-encoding" */
-#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[41])
+#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43])
/* "grpc-internal-encoding-request" */
-#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[42])
+#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44])
/* "grpc-message" */
-#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[43])
+#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45])
/* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[44])
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
/* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[45])
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
/* "gzip" */
-#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[46])
+#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
/* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[47])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49])
/* "host" */
-#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[48])
+#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50])
/* "http" */
-#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[49])
+#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51])
/* "https" */
-#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[50])
+#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52])
/* "identity" */
-#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[51])
+#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53])
/* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[52])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54])
/* "identity,deflate,gzip" */
#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
- (&grpc_static_mdstr_table[53])
+ (&grpc_static_mdstr_table[55])
/* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[54])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56])
/* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[55])
+#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57])
/* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[56])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58])
/* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[57])
+#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59])
/* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[58])
+#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60])
/* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[59])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61])
/* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[60])
+#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
/* "link" */
-#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[61])
+#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
/* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[62])
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[64])
/* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[63])
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[65])
/* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[64])
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[66])
/* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[65])
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[67])
/* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[66])
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[68])
/* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[67])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[69])
/* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[68])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[70])
/* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[69])
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[71])
/* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[70])
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[72])
/* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[73])
/* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[74])
/* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[73])
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[75])
/* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[76])
/* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[77])
/* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[78])
/* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[79])
/* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[78])
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[80])
/* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[81])
/* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[82])
/* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[81])
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[83])
/* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[82])
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[84])
/* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[83])
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[85])
/* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[86])
/* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[85])
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[87])
/* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[86])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[88])
#define GRPC_STATIC_MDELEM_COUNT 78
extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
index f2bebc62f3..2ab978be46 100644
--- a/src/core/transport/transport.c
+++ b/src/core/transport/transport.c
@@ -40,8 +40,8 @@
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
- gpr_log(GPR_DEBUG, "STREAM %p:%p REF %d->%d %s", refcount,
- refcount->destroy.cb_arg, val, val + 1, reason);
+ gpr_log(GPR_DEBUG, "%s %p:%p REF %d->%d %s", refcount->object_type,
+ refcount, refcount->destroy.cb_arg, val, val + 1, reason);
#else
void grpc_stream_ref(grpc_stream_refcount *refcount) {
#endif
@@ -52,8 +52,8 @@ void grpc_stream_ref(grpc_stream_refcount *refcount) {
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
const char *reason) {
gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
- gpr_log(GPR_DEBUG, "STREAM %p:%p UNREF %d->%d %s", refcount,
- refcount->destroy.cb_arg, val, val - 1, reason);
+ gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type,
+ refcount, refcount->destroy.cb_arg, val, val - 1, reason);
#else
void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
grpc_stream_refcount *refcount) {
@@ -63,6 +63,19 @@ void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
}
}
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+ grpc_iomgr_cb_func cb, void *cb_arg,
+ const char *object_type) {
+ refcount->object_type = object_type;
+#else
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+ grpc_iomgr_cb_func cb, void *cb_arg) {
+#endif
+ gpr_ref_init(&refcount->refs, initial_refs);
+ grpc_closure_init(&refcount->destroy, cb, cb_arg);
+}
+
size_t grpc_transport_stream_size(grpc_transport *transport) {
return transport->vtable->sizeof_stream;
}
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index f296ce8251..f94f0ae76e 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -50,19 +50,32 @@ typedef struct grpc_transport grpc_transport;
for a stream. */
typedef struct grpc_stream grpc_stream;
+/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
+
typedef struct grpc_stream_refcount {
gpr_refcount refs;
grpc_closure destroy;
+#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+ const char *object_type;
+#endif
} grpc_stream_refcount;
-/*#define GRPC_STREAM_REFCOUNT_DEBUG*/
#ifdef GRPC_STREAM_REFCOUNT_DEBUG
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+ grpc_iomgr_cb_func cb, void *cb_arg,
+ const char *object_type);
void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason);
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
const char *reason);
+#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
+ grpc_stream_ref_init(rc, ir, cb, cb_arg, objtype)
#else
+void grpc_stream_ref_init(grpc_stream_refcount *refcount, int initial_refs,
+ grpc_iomgr_cb_func cb, void *cb_arg);
void grpc_stream_ref(grpc_stream_refcount *refcount);
void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount);
+#define GRPC_STREAM_REF_INIT(rc, ir, cb, cb_arg, objtype) \
+ grpc_stream_ref_init(rc, ir, cb, cb_arg)
#endif
/* Transport stream op: a set of operations to perform on a transport
@@ -96,7 +109,7 @@ typedef struct grpc_transport_stream_op {
typedef struct grpc_transport_op {
/** called when processing of this op is done */
grpc_closure *on_consumed;
- /** connectivity monitoring */
+ /** connectivity monitoring - set connectivity_state to NULL to unsubscribe */
grpc_closure *on_connectivity_state_change;
grpc_connectivity_state *connectivity_state;
/** should the transport be disconnected */
diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c
index f3b6db29d6..98b51afc88 100644
--- a/src/core/transport/transport_op_string.c
+++ b/src/core/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=%d.%09d", md.deadline.tv_sec,
- md.deadline.tv_nsec);
+ gpr_asprintf(&tmp, " deadline=%lld.%09d", (long long)md.deadline.tv_sec,
+ (int)md.deadline.tv_nsec);
gpr_strvec_add(b, tmp);
}
}
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
index c39e584496..db219a50a6 100644
--- a/src/core/tsi/transport_security.c
+++ b/src/core/tsi/transport_security.c
@@ -145,7 +145,9 @@ void tsi_frame_protector_destroy(tsi_frame_protector *self) {
tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
unsigned char *bytes,
size_t *bytes_size) {
- if (self == NULL) return TSI_INVALID_ARGUMENT;
+ if (self == NULL || bytes == NULL || bytes_size == NULL) {
+ return TSI_INVALID_ARGUMENT;
+ }
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
}
@@ -153,7 +155,9 @@ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker *self,
const unsigned char *bytes,
size_t *bytes_size) {
- if (self == NULL) return TSI_INVALID_ARGUMENT;
+ if (self == NULL || bytes == NULL || bytes_size == NULL) {
+ return TSI_INVALID_ARGUMENT;
+ }
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
}
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 9bb358b233..2aa532808c 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -45,17 +45,31 @@
namespace grpc {
+class DefaultGlobalClientCallbacks GRPC_FINAL
+ : public ClientContext::GlobalCallbacks {
+ public:
+ void DefaultConstructor(ClientContext* context) GRPC_OVERRIDE {}
+ void Destructor(ClientContext* context) GRPC_OVERRIDE {}
+};
+
+static DefaultGlobalClientCallbacks g_default_client_callbacks;
+static ClientContext::GlobalCallbacks* g_client_callbacks =
+ &g_default_client_callbacks;
+
ClientContext::ClientContext()
: initial_metadata_received_(false),
call_(nullptr),
call_canceled_(false),
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
- propagate_from_call_(nullptr) {}
+ propagate_from_call_(nullptr) {
+ g_client_callbacks->DefaultConstructor(this);
+}
ClientContext::~ClientContext() {
if (call_) {
grpc_call_destroy(call_);
}
+ g_client_callbacks->Destructor(this);
}
std::unique_ptr<ClientContext> ClientContext::FromServerContext(
@@ -124,4 +138,11 @@ grpc::string ClientContext::peer() const {
return peer;
}
+void ClientContext::SetGlobalCallbacks(GlobalCallbacks* client_callbacks) {
+ GPR_ASSERT(g_client_callbacks == &g_default_client_callbacks);
+ GPR_ASSERT(client_callbacks != NULL);
+ GPR_ASSERT(client_callbacks != &g_default_client_callbacks);
+ g_client_callbacks = client_callbacks;
+}
+
} // namespace grpc
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 6409323262..96ae25b761 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,10 +31,10 @@
*
*/
-#include <grpc/support/log.h>
#include <grpc++/channel.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>
+#include <grpc/support/log.h>
#include "src/cpp/client/create_channel_internal.h"
#include "src/cpp/client/secure_credentials.h"
#include "src/cpp/common/secure_auth_context.h"
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index b1330fde7f..898a1d4f58 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -33,6 +33,8 @@
#include <grpc++/impl/proto_utils.h>
+#include <climits>
+
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h>
#include <grpc/byte_buffer_reader.h>
@@ -70,7 +72,9 @@ class GrpcBufferWriter GRPC_FINAL
slice_ = gpr_slice_malloc(block_size_);
}
*data = GPR_SLICE_START_PTR(slice_);
- byte_count_ += * size = GPR_SLICE_LENGTH(slice_);
+ // On win x64, int is only 32bit
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+ byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
gpr_slice_buffer_add(slice_buffer_, slice_);
return true;
}
@@ -124,7 +128,9 @@ class GrpcBufferReader GRPC_FINAL
}
gpr_slice_unref(slice_);
*data = GPR_SLICE_START_PTR(slice_);
- byte_count_ += * size = GPR_SLICE_LENGTH(slice_);
+ // On win x64, int is only 32bit
+ GPR_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
+ byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
return true;
}
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 6157a37745..9c38b34879 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -57,8 +57,8 @@ void Timepoint2Timespec(const system_clock::time_point& from,
return;
}
nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
- to->tv_sec = (time_t)secs.count();
- to->tv_nsec = (int)nsecs.count();
+ to->tv_sec = (gpr_int64)secs.count();
+ to->tv_nsec = (gpr_int32)nsecs.count();
to->clock_type = GPR_CLOCK_REALTIME;
}
@@ -73,8 +73,8 @@ void TimepointHR2Timespec(const high_resolution_clock::time_point& from,
return;
}
nanoseconds nsecs = duration_cast<nanoseconds>(deadline - secs);
- to->tv_sec = (time_t)secs.count();
- to->tv_nsec = (int)nsecs.count();
+ to->tv_sec = (gpr_int64)secs.count();
+ to->tv_nsec = (gpr_int32)nsecs.count();
to->clock_type = GPR_CLOCK_REALTIME;
}
diff --git a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
index 1c14c5bb5b..f77e9c6573 100644
--- a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
+++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
@@ -57,9 +57,9 @@ namespace Grpc.Auth
/// <returns>The interceptor.</returns>
public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
{
- return new AsyncAuthInterceptor(async (authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (context, metadata) =>
{
- var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false);
+ var accessToken = await credential.GetAccessTokenForRequestAsync(context.ServiceUrl, CancellationToken.None).ConfigureAwait(false);
metadata.Add(CreateBearerTokenHeader(accessToken));
});
}
@@ -72,7 +72,7 @@ namespace Grpc.Auth
public static AsyncAuthInterceptor FromAccessToken(string accessToken)
{
Preconditions.CheckNotNull(accessToken);
- return new AsyncAuthInterceptor(async (authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (context, metadata) =>
{
metadata.Add(CreateBearerTokenHeader(accessToken));
});
diff --git a/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
new file mode 100644
index 0000000000..a3a613be74
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/CallOptionsTest.cs
@@ -0,0 +1,88 @@
+#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.Threading;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class CallOptionsTest
+ {
+ [Test]
+ public void WithMethods()
+ {
+ var options = new CallOptions();
+
+ var metadata = new Metadata();
+ Assert.AreSame(metadata, options.WithHeaders(metadata).Headers);
+
+ var deadline = DateTime.UtcNow;
+ Assert.AreEqual(deadline, options.WithDeadline(deadline).Deadline.Value);
+
+ var token = new CancellationTokenSource().Token;
+ Assert.AreEqual(token, options.WithCancellationToken(token).CancellationToken);
+
+ // Change original instance is unchanged.
+ Assert.IsNull(options.Headers);
+ Assert.IsNull(options.Deadline);
+ Assert.AreEqual(CancellationToken.None, options.CancellationToken);
+ Assert.IsNull(options.WriteOptions);
+ Assert.IsNull(options.PropagationToken);
+ Assert.IsNull(options.Credentials);
+ }
+
+ [Test]
+ public void Normalize()
+ {
+ Assert.AreSame(Metadata.Empty, new CallOptions().Normalize().Headers);
+ Assert.AreEqual(DateTime.MaxValue, new CallOptions().Normalize().Deadline.Value);
+
+ var deadline = DateTime.UtcNow;
+ var propagationToken1 = new ContextPropagationToken(CallSafeHandle.NullInstance, deadline, CancellationToken.None,
+ new ContextPropagationOptions(propagateDeadline: true, propagateCancellation: false));
+ Assert.AreEqual(deadline, new CallOptions(propagationToken: propagationToken1).Normalize().Deadline.Value);
+ Assert.Throws(typeof(ArgumentException), () => new CallOptions(deadline: deadline, propagationToken: propagationToken1).Normalize());
+
+ var token = new CancellationTokenSource().Token;
+ var propagationToken2 = new ContextPropagationToken(CallSafeHandle.NullInstance, deadline, token,
+ new ContextPropagationOptions(propagateDeadline: false, propagateCancellation: true));
+ Assert.AreEqual(token, new CallOptions(propagationToken: propagationToken2).Normalize().CancellationToken);
+ Assert.Throws(typeof(ArgumentException), () => new CallOptions(cancellationToken: token, propagationToken: propagationToken2).Normalize());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
index 52be77c846..d2b5a436fd 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelOptionsTest.cs
@@ -38,7 +38,7 @@ using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
-namespace Grpc.Core.Internal.Tests
+namespace Grpc.Core.Tests
{
public class ChannelOptionsTest
{
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index f4ae9abefd..ed0ec14df5 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -48,6 +48,17 @@ namespace Grpc.Core.Tests
}
[Test]
+ public void Constructor_RejectsDuplicateOptions()
+ {
+ var options = new ChannelOption[]
+ {
+ new ChannelOption(ChannelOptions.PrimaryUserAgentString, "ABC"),
+ new ChannelOption(ChannelOptions.PrimaryUserAgentString, "XYZ")
+ };
+ Assert.Throws(typeof(ArgumentException), () => new Channel("127.0.0.1", ChannelCredentials.Insecure, options));
+ }
+
+ [Test]
public void State_IdleAfterCreation()
{
var channel = new Channel("localhost", ChannelCredentials.Insecure);
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 25a5a27c8e..77f6a63156 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -144,6 +145,45 @@ namespace Grpc.Core.Tests
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
Assert.AreEqual("ABC", await call.ResponseAsync);
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull(call.GetTrailers());
+ }
+
+ [Test]
+ public async Task ServerStreamingCall()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ await responseStream.WriteAllAsync(request.Split(new []{' '}));
+ context.ResponseTrailers.Add("xyz", "");
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "A B C");
+ CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull("xyz", call.GetTrailers()[0].Key);
+ }
+
+ [Test]
+ public async Task DuplexStreamingCall()
+ {
+ helper.DuplexStreamingHandler = new DuplexStreamingServerMethod<string, string>(async (requestStream, responseStream, context) =>
+ {
+ while (await requestStream.MoveNext())
+ {
+ await responseStream.WriteAsync(requestStream.Current);
+ }
+ context.ResponseTrailers.Add("xyz", "xyz-value");
+ });
+
+ var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
+ await call.RequestStream.WriteAllAsync(new string[] { "A", "B", "C" });
+ CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, await call.ResponseStream.ToListAsync());
+
+ Assert.AreEqual(StatusCode.OK, call.GetStatus().StatusCode);
+ Assert.IsNotNull("xyz-value", call.GetTrailers()[0].Value);
}
[Test]
@@ -201,7 +241,7 @@ namespace Grpc.Core.Tests
Assert.AreEqual(headers[1].Key, trailers[1].Key);
CollectionAssert.AreEqual(headers[1].ValueBytes, trailers[1].ValueBytes);
}
-
+
[Test]
public void UnknownMethodHandler()
{
@@ -219,27 +259,27 @@ namespace Grpc.Core.Tests
}
[Test]
- public void UserAgentStringPresent()
+ public void ServerCallContext_PeerInfoPresent()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
- return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value;
+ return context.Peer;
});
- string userAgent = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc");
- Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
+ string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc");
+ Assert.IsTrue(peer.Contains(Host));
}
[Test]
- public void PeerInfoPresent()
+ public void ServerCallContext_HostAndMethodPresent()
{
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
- return context.Peer;
+ Assert.IsTrue(context.Host.Contains(Host));
+ Assert.AreEqual("/tests.Test/Unary", context.Method);
+ return "PASS";
});
-
- string peer = Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc");
- Assert.IsTrue(peer.Contains(Host));
+ Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "abc"));
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
index 2db3f286f7..90c510ec61 100644
--- a/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ContextPropagationTest.cs
@@ -69,11 +69,19 @@ namespace Grpc.Core.Tests
[Test]
public async Task PropagateCancellation()
{
+ var readyToCancelTcs = new TaskCompletionSource<object>();
+ var successTcs = new TaskCompletionSource<string>();
+
helper.UnaryHandler = new UnaryServerMethod<string, string>(async (request, context) =>
{
- // check that we didn't obtain the default cancellation token.
- Assert.IsTrue(context.CancellationToken.CanBeCanceled);
- return "PASS";
+ readyToCancelTcs.SetResult(null); // child call running, ready to parent call
+
+ while (!context.CancellationToken.IsCancellationRequested)
+ {
+ await Task.Delay(10);
+ }
+ successTcs.SetResult("CHILD_CALL_CANCELLED");
+ return "";
});
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
@@ -82,13 +90,23 @@ namespace Grpc.Core.Tests
Assert.IsNotNull(propagationToken.ParentCall);
var callOptions = new CallOptions(propagationToken: propagationToken);
- return await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
+ try
+ {
+ await Calls.AsyncUnaryCall(helper.CreateUnaryCall(callOptions), "xyz");
+ }
+ catch(RpcException)
+ {
+ // Child call will get cancelled, eat the exception.
+ }
+ return "";
});
var cts = new CancellationTokenSource();
- var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
- await call.RequestStream.CompleteAsync();
- Assert.AreEqual("PASS", await call);
+ var parentCall = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+ await readyToCancelTcs.Task;
+ cts.Cancel();
+ Assert.Throws(typeof(RpcException), async () => await parentCall);
+ Assert.AreEqual("CHILD_CALL_CANCELLED", await successTcs.Task);
}
[Test]
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index e5ffa31989..475c792347 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -64,6 +64,8 @@
<Link>Version.cs</Link>
</Compile>
<Compile Include="CallCredentialsTest.cs" />
+ <Compile Include="CallOptionsTest.cs" />
+ <Compile Include="UserAgentStringTest.cs" />
<Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
<Compile Include="ChannelCredentialsTest.cs" />
@@ -89,6 +91,7 @@
<Compile Include="ContextPropagationTest.cs" />
<Compile Include="MetadataTest.cs" />
<Compile Include="PerformanceTest.cs" />
+ <Compile Include="SanityTest.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
index 9be5450d81..74f7f2497a 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs
@@ -82,17 +82,17 @@ namespace Grpc.Core.Internal.Tests
public void ToDateTime()
{
Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
- new Timespec(IntPtr.Zero, 0).ToDateTime());
+ new Timespec(0, 0).ToDateTime());
Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
- new Timespec(new IntPtr(10), 5000).ToDateTime());
+ new Timespec(10, 5000).ToDateTime());
Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
- new Timespec(new IntPtr(1437452508), 0).ToDateTime());
+ new Timespec(1437452508, 0).ToDateTime());
// before epoch
Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10),
- new Timespec(new IntPtr(-5), 1000).ToDateTime());
+ new Timespec(-5, 1000).ToDateTime());
// infinity
Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime());
@@ -100,80 +100,62 @@ namespace Grpc.Core.Internal.Tests
// nanos are rounded to ticks are rounded up
Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1),
- new Timespec(IntPtr.Zero, 99).ToDateTime());
+ new Timespec(0, 99).ToDateTime());
// Illegal inputs
Assert.Throws(typeof(InvalidOperationException),
- () => new Timespec(new IntPtr(0), -2).ToDateTime());
+ () => new Timespec(0, -2).ToDateTime());
Assert.Throws(typeof(InvalidOperationException),
- () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime());
+ () => new Timespec(0, 1000 * 1000 * 1000).ToDateTime());
Assert.Throws(typeof(InvalidOperationException),
- () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime());
+ () => new Timespec(0, 0, GPRClockType.Monotonic).ToDateTime());
}
[Test]
public void ToDateTime_ReturnsUtc()
{
- Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
- Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind);
+ Assert.AreEqual(DateTimeKind.Utc, new Timespec(1437452508, 0).ToDateTime().Kind);
+ Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(1437452508, 0).ToDateTime().Kind);
}
[Test]
public void ToDateTime_Overflow()
- {
- // we can only get overflow in ticks arithmetic on 64-bit
- if (IntPtr.Size == 8)
- {
- var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0);
- Assert.AreNotEqual(Timespec.InfFuture, timespec);
- Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
-
- Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime());
- }
- else
- {
- Console.WriteLine("Test cannot be run on this platform, skipping the test.");
- }
+ {
+ var timespec = new Timespec(long.MaxValue - 100, 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(long.MinValue + 100, 0).ToDateTime());
}
[Test]
public void ToDateTime_OutOfDateTimeRange()
{
- // we can only get out of range on 64-bit, on 32 bit the max
- // timestamp is ~ Jan 19 2038, which is far within range of DateTime
- // same case for min value.
- if (IntPtr.Size == 8)
- {
- // DateTime range goes up to year 9999, 20000 years from now should
- // be out of range.
- long seconds = 20000L * 365L * 24L * 3600L;
-
- var timespec = new Timespec(new IntPtr(seconds), 0);
- Assert.AreNotEqual(Timespec.InfFuture, timespec);
- Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
-
- Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime());
- }
- else
- {
- Console.WriteLine("Test cannot be run on this platform, skipping the test");
- }
+ // DateTime range goes up to year 9999, 20000 years from now should
+ // be out of range.
+ long seconds = 20000L * 365L * 24L * 3600L;
+
+ var timespec = new Timespec(seconds, 0);
+ Assert.AreNotEqual(Timespec.InfFuture, timespec);
+ Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime());
+
+ Assert.AreEqual(DateTime.MinValue, new Timespec(-seconds, 0).ToDateTime());
}
[Test]
public void FromDateTime()
{
- Assert.AreEqual(new Timespec(IntPtr.Zero, 0),
+ Assert.AreEqual(new Timespec(0, 0),
Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
- Assert.AreEqual(new Timespec(new IntPtr(10), 5000),
+ Assert.AreEqual(new Timespec(10, 5000),
Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50)));
- Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0),
+ Assert.AreEqual(new Timespec(1437452508, 0),
Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc)));
// before epoch
- Assert.AreEqual(new Timespec(new IntPtr(-5), 1000),
+ Assert.AreEqual(new Timespec(-5, 1000),
Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10)));
// infinity
@@ -184,34 +166,19 @@ namespace Grpc.Core.Internal.Tests
Assert.Throws(typeof(ArgumentException),
() => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)));
}
-
- [Test]
- public void FromDateTime_OutOfTimespecRange()
- {
- // we can only get overflow in Timespec on 32-bit
- if (IntPtr.Size == 4)
- {
- Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
- Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)));
- }
- else
- {
- Console.WriteLine("Test cannot be run on this platform, skipping the test.");
- }
- }
- // Test attribute commented out to prevent running as part of the default test suite.
- // [Test]
- // [Category("Performance")]
+ [Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void NowBenchmark()
{
// approx Timespec.Now latency <33ns
BenchmarkUtil.RunBenchmark(10000000, 1000000000, () => { var now = Timespec.Now; });
}
-
- // Test attribute commented out to prevent running as part of the default test suite.
- // [Test]
- // [Category("Performance")]
+
+ [Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void PreciseNowBenchmark()
{
// approx Timespec.PreciseNow latency <18ns (when compiled with GRPC_TIMERS_RDTSC)
diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
index ddeb7d0926..49e9de1174 100644
--- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
@@ -127,5 +127,118 @@ namespace Grpc.Core.Tests
Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; });
CollectionAssert.AreEqual(bytes, entry.ValueBytes);
}
+
+ [Test]
+ public void IndexOf()
+ {
+ var metadata = CreateMetadata();
+ Assert.AreEqual(0, metadata.IndexOf(metadata[0]));
+ Assert.AreEqual(1, metadata.IndexOf(metadata[1]));
+ }
+
+ [Test]
+ public void Insert()
+ {
+ var metadata = CreateMetadata();
+ metadata.Insert(0, new Metadata.Entry("new-key", "new-value"));
+ Assert.AreEqual(3, metadata.Count);
+ Assert.AreEqual("new-key", metadata[0].Key);
+ Assert.AreEqual("abc", metadata[1].Key);
+ }
+
+ [Test]
+ public void RemoveAt()
+ {
+ var metadata = CreateMetadata();
+ metadata.RemoveAt(0);
+ Assert.AreEqual(1, metadata.Count);
+ Assert.AreEqual("xyz", metadata[0].Key);
+ }
+
+ [Test]
+ public void Remove()
+ {
+ var metadata = CreateMetadata();
+ metadata.Remove(metadata[0]);
+ Assert.AreEqual(1, metadata.Count);
+ Assert.AreEqual("xyz", metadata[0].Key);
+ }
+
+ [Test]
+ public void Indexer_Set()
+ {
+ var metadata = CreateMetadata();
+ var entry = new Metadata.Entry("new-key", "new-value");
+
+ metadata[1] = entry;
+ Assert.AreEqual(entry, metadata[1]);
+ }
+
+ [Test]
+ public void Clear()
+ {
+ var metadata = CreateMetadata();
+ metadata.Clear();
+ Assert.AreEqual(0, metadata.Count);
+ }
+
+ [Test]
+ public void Contains()
+ {
+ var metadata = CreateMetadata();
+ Assert.IsTrue(metadata.Contains(metadata[0]));
+ Assert.IsFalse(metadata.Contains(new Metadata.Entry("new-key", "new-value")));
+ }
+
+ [Test]
+ public void CopyTo()
+ {
+ var metadata = CreateMetadata();
+ var array = new Metadata.Entry[metadata.Count + 1];
+
+ metadata.CopyTo(array, 1);
+ Assert.AreEqual(default(Metadata.Entry), array[0]);
+ Assert.AreEqual(metadata[0], array[1]);
+ }
+
+ [Test]
+ public void IEnumerableGetEnumerator()
+ {
+ var metadata = CreateMetadata();
+ var enumerator = (metadata as System.Collections.IEnumerable).GetEnumerator();
+
+ int i = 0;
+ while (enumerator.MoveNext())
+ {
+ Assert.AreEqual(metadata[i], enumerator.Current);
+ i++;
+ }
+ }
+
+ [Test]
+ public void FreezeMakesReadOnly()
+ {
+ var entry = new Metadata.Entry("new-key", "new-value");
+ var metadata = CreateMetadata().Freeze();
+
+ Assert.IsTrue(metadata.IsReadOnly);
+ Assert.Throws<InvalidOperationException>(() => metadata.Insert(0, entry));
+ Assert.Throws<InvalidOperationException>(() => metadata.RemoveAt(0));
+ Assert.Throws<InvalidOperationException>(() => metadata[0] = entry);
+ Assert.Throws<InvalidOperationException>(() => metadata.Add(entry));
+ Assert.Throws<InvalidOperationException>(() => metadata.Add("new-key", "new-value"));
+ Assert.Throws<InvalidOperationException>(() => metadata.Add("new-key-bin", new byte[] { 0xaa }));
+ Assert.Throws<InvalidOperationException>(() => metadata.Clear());
+ Assert.Throws<InvalidOperationException>(() => metadata.Remove(metadata[0]));
+ }
+
+ private Metadata CreateMetadata()
+ {
+ return new Metadata
+ {
+ { "abc", "abc-value" },
+ { "xyz", "xyz-value" },
+ };
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 567e04eddc..3047314345 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -32,6 +32,7 @@
#endregion
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -52,6 +53,7 @@ namespace Grpc.Core.Tests
readonly string host;
readonly ServerServiceDefinition serviceDefinition;
+ readonly IEnumerable<ChannelOption> channelOptions;
readonly Method<string, string> unaryMethod;
readonly Method<string, string> clientStreamingMethod;
@@ -66,9 +68,10 @@ namespace Grpc.Core.Tests
Server server;
Channel channel;
- public MockServiceHelper(string host = null, Marshaller<string> marshaller = null)
+ public MockServiceHelper(string host = null, Marshaller<string> marshaller = null, IEnumerable<ChannelOption> channelOptions = null)
{
this.host = host ?? "localhost";
+ this.channelOptions = channelOptions;
marshaller = marshaller ?? Marshallers.StringMarshaller;
unaryMethod = new Method<string, string>(
@@ -154,7 +157,7 @@ namespace Grpc.Core.Tests
{
if (channel == null)
{
- channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure);
+ channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure, channelOptions);
}
return channel;
}
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 073c502daf..af55cb0566 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -59,6 +59,8 @@ namespace Grpc.Core.Tests
[Test]
public void CompletionQueueCreateDestroyBenchmark()
{
+ GrpcEnvironment.AddRef(); // completion queue requires gRPC environment being initialized.
+
BenchmarkUtil.RunBenchmark(
10, 10,
() =>
@@ -66,6 +68,8 @@ namespace Grpc.Core.Tests
CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create();
cq.Dispose();
});
+
+ GrpcEnvironment.Release();
}
/// <summary>
diff --git a/src/csharp/Grpc.Core.Tests/PerformanceTest.cs b/src/csharp/Grpc.Core.Tests/PerformanceTest.cs
index 5516cd3377..6815839992 100644
--- a/src/csharp/Grpc.Core.Tests/PerformanceTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PerformanceTest.cs
@@ -67,10 +67,10 @@ namespace Grpc.Core.Tests
channel.ShutdownAsync().Wait();
server.ShutdownAsync().Wait();
}
-
- // Test attribute commented out to prevent running as part of the default test suite.
- //[Test]
- //[Category("Performance")]
+
+ [Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public void UnaryCallPerformance()
{
var profiler = new BasicProfiler();
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
new file mode 100644
index 0000000000..343ab1e85a
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -0,0 +1,125 @@
+#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.IO;
+using System.Reflection;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class SanityTest
+ {
+ /// <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,
+ /// the NUnit tests are run by run_tests.py script in a separate process per test class.
+ /// The list of tests to run is stored in src/csharp/tests.json.
+ /// This test checks that the tests.json file is up to date by discovering all the
+ /// existing NUnit tests in all test assemblies and comparing to contents of tests.json.
+ /// </summary>
+ [Test]
+ public void TestsJsonUpToDate()
+ {
+ var testClasses = DiscoverAllTestClasses();
+ string testsJson = GetTestsJson();
+
+ // we don't have a JSON parser at hand, but check that the test class
+ // name is contained in the file instead.
+ foreach (var className in testClasses) {
+ Assert.IsTrue(testsJson.Contains(className),
+ string.Format("Test class \"{0}\" is missing in C# tests.json file", className));
+ }
+ }
+
+ /// <summary>
+ /// Gets list of all test classes obtained by inspecting all the test assemblies.
+ /// </summary>
+ private List<string> DiscoverAllTestClasses()
+ {
+ var assemblies = GetTestAssemblies();
+
+ var testClasses = new List<string>();
+ foreach (var assembly in assemblies)
+ {
+ foreach (var t in assembly.GetTypes())
+ {
+ foreach (var m in t.GetMethods())
+ {
+ var attributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true);
+ if (attributes.Length > 0)
+ {
+ testClasses.Add(t.FullName);
+ break;
+ }
+
+ }
+ }
+ }
+ testClasses.Sort();
+ return testClasses;
+ }
+
+ private string GetTestsJson()
+ {
+ var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ var testsJsonFile = Path.Combine(assemblyDir, "..", "..", "..", "tests.json");
+
+ return File.ReadAllText(testsJsonFile);
+ }
+
+ private List<Assembly> GetTestAssemblies()
+ {
+ var result = new List<Assembly>();
+ var executingAssembly = Assembly.GetExecutingAssembly();
+
+ result.Add(executingAssembly);
+
+ var otherAssemblies = new[] {
+ "Grpc.Examples.Tests",
+ "Grpc.HealthCheck.Tests",
+ "Grpc.IntegrationTesting"
+ };
+ foreach (var assemblyName in otherAssemblies)
+ {
+ var location = executingAssembly.Location.Replace("Grpc.Core.Tests", assemblyName);
+ result.Add(Assembly.LoadFrom(location));
+ }
+ return result;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ShutdownTest.cs b/src/csharp/Grpc.Core.Tests/ShutdownTest.cs
index a2be7ddd5e..10d666d109 100644
--- a/src/csharp/Grpc.Core.Tests/ShutdownTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ShutdownTest.cs
@@ -61,17 +61,20 @@ namespace Grpc.Core.Tests
}
[Test]
- public async Task AbandonedCall()
+ public async Task AbandonedCall_ServerKillAsync()
{
+ 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(new CallOptions(deadline: DateTime.UtcNow.AddMilliseconds(1))));
+ var call = Calls.AsyncDuplexStreamingCall(helper.CreateDuplexStreamingCall());
+ await readyToShutdown.Task; // make sure handler is running
- channel.ShutdownAsync().Wait();
- server.ShutdownAsync().Wait();
+ await channel.ShutdownAsync(); // channel.ShutdownAsync() works even if there's a pending call.
+ await server.KillAsync(); // server.ShutdownAsync() would hang waiting for the call to finish.
}
}
}
diff --git a/src/csharp/Grpc.Core.Tests/UserAgentStringTest.cs b/src/csharp/Grpc.Core.Tests/UserAgentStringTest.cs
new file mode 100644
index 0000000000..cc830086a6
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/UserAgentStringTest.cs
@@ -0,0 +1,101 @@
+#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.Profiling;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class UserAgentStringTest
+ {
+ const string Host = "127.0.0.1";
+
+ MockServiceHelper helper;
+ Server server;
+ Channel channel;
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void DefaultUserAgentString()
+ {
+ helper = new MockServiceHelper(Host);
+ server = helper.GetServer();
+ server.Start();
+ channel = helper.GetChannel();
+
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ var userAgentString = context.RequestHeaders.First(m => (m.Key == "user-agent")).Value;
+ var parts = userAgentString.Split(new [] {' '}, 2);
+ Assert.AreEqual(string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion), parts[0]);
+ Assert.IsTrue(parts[1].StartsWith("grpc-c/"));
+ return Task.FromResult("PASS");
+ });
+ Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), ""));
+ }
+
+ [Test]
+ public void ApplicationUserAgentString()
+ {
+ helper = new MockServiceHelper(Host,
+ channelOptions: new[] { new ChannelOption(ChannelOptions.PrimaryUserAgentString, "XYZ") });
+ server = helper.GetServer();
+ server.Start();
+ channel = helper.GetChannel();
+
+ channel = helper.GetChannel();
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ var userAgentString = context.RequestHeaders.First(m => (m.Key == "user-agent")).Value;
+ var parts = userAgentString.Split(new[] { ' ' }, 3);
+ Assert.AreEqual("XYZ", parts[0]);
+ return Task.FromResult("PASS");
+ });
+ Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), ""));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
new file mode 100644
index 0000000000..5c9ab04812
--- /dev/null
+++ b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
@@ -0,0 +1,84 @@
+#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.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
+ /// </summary>
+ /// <param name="context">The interceptor context.</param>
+ /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
+ /// <returns></returns>
+ public delegate Task AsyncAuthInterceptor(AuthInterceptorContext context, Metadata metadata);
+
+ /// <summary>
+ /// Context for an RPC being intercepted by <see cref="AsyncAuthInterceptor"/>.
+ /// </summary>
+ public class AuthInterceptorContext
+ {
+ readonly string serviceUrl;
+ readonly string methodName;
+
+ /// <summary>
+ /// Initializes a new instance of <c>AuthInterceptorContext</c>.
+ /// </summary>
+ public AuthInterceptorContext(string serviceUrl, string methodName)
+ {
+ this.serviceUrl = Preconditions.CheckNotNull(serviceUrl);
+ this.methodName = Preconditions.CheckNotNull(methodName);
+ }
+
+ /// <summary>
+ /// The fully qualified service URL for the RPC being called.
+ /// </summary>
+ public string ServiceUrl
+ {
+ get { return serviceUrl; }
+ }
+
+ /// <summary>
+ /// The method name of the RPC being called.
+ /// </summary>
+ public string MethodName
+ {
+ get { return methodName; }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
index 5ea179dfea..a71c8904fe 100644
--- a/src/csharp/Grpc.Core/CallCredentials.cs
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -41,14 +41,6 @@ using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
- /// </summary>
- /// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
- /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
- /// <returns></returns>
- public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
-
- /// <summary>
/// Client-side call credentials. Provide authorization with per-call granularity.
/// </summary>
public abstract class CallCredentials
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index c0f94c63c2..1fda80cb90 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -184,6 +184,7 @@ namespace Grpc.Core
{
Preconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled,
"Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value.");
+ newOptions.cancellationToken = propagationToken.ParentCancellationToken;
}
}
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index f5eec969f5..d8d43c7998 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -32,8 +32,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.InteropServices;
-using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
@@ -57,7 +55,7 @@ namespace Grpc.Core
readonly string target;
readonly GrpcEnvironment environment;
readonly ChannelSafeHandle handle;
- readonly List<ChannelOption> options;
+ readonly Dictionary<string, ChannelOption> options;
bool shutdownRequested;
@@ -71,12 +69,12 @@ namespace Grpc.Core
public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
{
this.target = Preconditions.CheckNotNull(target, "target");
+ this.options = CreateOptionsDictionary(options);
+ EnsureUserAgentChannelOption(this.options);
this.environment = GrpcEnvironment.AddRef();
- this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
- EnsureUserAgentChannelOption(this.options);
using (var nativeCredentials = credentials.ToNativeCredentials())
- using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
+ using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options.Values))
{
if (nativeCredentials != null)
{
@@ -173,7 +171,7 @@ namespace Grpc.Core
{
throw new OperationCanceledException("Channel has reached FatalFailure state.");
}
- await WaitForStateChangedAsync(currentState, deadline);
+ await WaitForStateChangedAsync(currentState, deadline).ConfigureAwait(false);
currentState = handle.CheckConnectivityState(false);
}
}
@@ -198,7 +196,7 @@ namespace Grpc.Core
handle.Dispose();
- await Task.Run(() => GrpcEnvironment.Release());
+ await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
}
internal ChannelSafeHandle Handle
@@ -233,18 +231,36 @@ namespace Grpc.Core
activeCallCounter.Decrement();
}
- private static void EnsureUserAgentChannelOption(List<ChannelOption> options)
+ private static void EnsureUserAgentChannelOption(Dictionary<string, ChannelOption> options)
{
- if (!options.Any((option) => option.Name == ChannelOptions.PrimaryUserAgentString))
+ var key = ChannelOptions.PrimaryUserAgentString;
+ var userAgentString = "";
+
+ ChannelOption option;
+ if (options.TryGetValue(key, out option))
{
- options.Add(new ChannelOption(ChannelOptions.PrimaryUserAgentString, GetUserAgentString()));
- }
+ // user-provided userAgentString needs to be at the beginning
+ userAgentString = option.StringValue + " ";
+ };
+
+ // TODO(jtattermusch): it would be useful to also provide .NET/mono version.
+ userAgentString += string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion);
+
+ options[ChannelOptions.PrimaryUserAgentString] = new ChannelOption(key, userAgentString);
}
- private static string GetUserAgentString()
+ private static Dictionary<string, ChannelOption> CreateOptionsDictionary(IEnumerable<ChannelOption> options)
{
- // TODO(jtattermusch): it would be useful to also provide .NET/mono version.
- return string.Format("grpc-csharp/{0}", VersionInfo.CurrentVersion);
+ var dict = new Dictionary<string, ChannelOption>();
+ if (options == null)
+ {
+ return dict;
+ }
+ foreach (var option in options)
+ {
+ dict.Add(option.Name, option);
+ }
+ return dict;
}
}
}
diff --git a/src/csharp/Grpc.Core/ChannelOptions.cs b/src/csharp/Grpc.Core/ChannelOptions.cs
index f5ef63af54..d70673cf78 100644
--- a/src/csharp/Grpc.Core/ChannelOptions.cs
+++ b/src/csharp/Grpc.Core/ChannelOptions.cs
@@ -169,7 +169,7 @@ namespace Grpc.Core
/// Creates native object for a collection of channel options.
/// </summary>
/// <returns>The native channel arguments.</returns>
- internal static ChannelArgsSafeHandle CreateChannelArgs(List<ChannelOption> options)
+ internal static ChannelArgsSafeHandle CreateChannelArgs(ICollection<ChannelOption> options)
{
if (options == null || options.Count == 0)
{
@@ -179,9 +179,9 @@ namespace Grpc.Core
try
{
nativeArgs = ChannelArgsSafeHandle.Create(options.Count);
- for (int i = 0; i < options.Count; i++)
+ int i = 0;
+ foreach (var option in options)
{
- var option = options[i];
if (option.Type == ChannelOption.OptionType.Integer)
{
nativeArgs.SetInteger(i, option.Name, option.IntValue);
@@ -194,6 +194,7 @@ namespace Grpc.Core
{
throw new InvalidOperationException("Unknown option type");
}
+ i++;
}
return nativeArgs;
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 56a06f4a9b..5b3da7c6c9 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -46,6 +46,7 @@
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" />
+ <Compile Include="AsyncAuthInterceptor.cs" />
<Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" />
<Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
@@ -148,8 +149,8 @@
<Error Condition="!Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets'))" />
<Error Condition="!Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets'))" />
</Target>
- <ItemGroup />
- <ItemGroup />
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" />
-</Project> \ No newline at end of file
+ <ItemGroup />
+ <ItemGroup />
+</Project>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 953f61aa1e..92f8d77e85 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -238,20 +238,6 @@ namespace Grpc.Core.Internal
}
}
- protected Exception TrySerialize(TWrite msg, out byte[] payload)
- {
- try
- {
- payload = serializer(msg);
- return null;
- }
- catch (Exception e)
- {
- payload = null;
- return e;
- }
- }
-
protected Exception TryDeserialize(byte[] payload, out TRead msg)
{
using (Profilers.ForCurrentThread().NewScope("AsyncCallBase.TryDeserialize"))
diff --git a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
index b4a7335c7c..d6e34a0f04 100644
--- a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
@@ -70,12 +70,12 @@ namespace Grpc.Core.Internal
}
var taskSource = new AsyncCompletionTaskSource<TResponse>();
call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task;
+ var result = await taskSource.Task.ConfigureAwait(false);
this.current = result;
if (result == null)
{
- await call.StreamingCallFinishedTask;
+ await call.StreamingCallFinishedTask.ConfigureAwait(false);
return false;
}
return true;
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index 2a571cd6c9..8bb646d303 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -38,7 +38,7 @@ using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
- internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
+ internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
internal class NativeMetadataCredentialsPlugin
{
@@ -71,7 +71,7 @@ namespace Grpc.Core.Internal
get { return credentials; }
}
- private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
+ private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
{
if (isDestroy)
{
@@ -81,8 +81,9 @@ namespace Grpc.Core.Internal
try
{
- string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr);
- StartGetMetadata(serviceUrl, callbackPtr, userDataPtr);
+ var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr),
+ Marshal.PtrToStringAnsi(methodNamePtr));
+ StartGetMetadata(context, callbackPtr, userDataPtr);
}
catch (Exception e)
{
@@ -91,12 +92,12 @@ namespace Grpc.Core.Internal
}
}
- private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr)
+ private async void StartGetMetadata(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
{
try
{
var metadata = new Metadata();
- await interceptor(serviceUrl, metadata);
+ await interceptor(context, metadata).ConfigureAwait(false);
using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
{
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 59f4c5727c..de66759b94 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -78,13 +78,13 @@ namespace Grpc.Core.Internal
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- Preconditions.CheckArgument(await requestStream.MoveNext());
+ Preconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
// TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- Preconditions.CheckArgument(!await requestStream.MoveNext());
- var result = await handler(request, context);
+ Preconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
+ var result = await handler(request, context).ConfigureAwait(false);
status = context.Status;
- await responseStream.WriteAsync(result);
+ await responseStream.WriteAsync(result).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -93,13 +93,13 @@ namespace Grpc.Core.Internal
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers);
+ await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Call has been already cancelled.
}
- await finishedTask;
+ await finishedTask.ConfigureAwait(false);
}
}
@@ -134,11 +134,11 @@ namespace Grpc.Core.Internal
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- Preconditions.CheckArgument(await requestStream.MoveNext());
+ Preconditions.CheckArgument(await requestStream.MoveNext().ConfigureAwait(false));
var request = requestStream.Current;
// TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
- Preconditions.CheckArgument(!await requestStream.MoveNext());
- await handler(request, responseStream, context);
+ Preconditions.CheckArgument(!await requestStream.MoveNext().ConfigureAwait(false));
+ await handler(request, responseStream, context).ConfigureAwait(false);
status = context.Status;
}
catch (Exception e)
@@ -149,13 +149,13 @@ namespace Grpc.Core.Internal
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers);
+ await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Call has been already cancelled.
}
- await finishedTask;
+ await finishedTask.ConfigureAwait(false);
}
}
@@ -190,11 +190,11 @@ namespace Grpc.Core.Internal
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- var result = await handler(requestStream, context);
+ var result = await handler(requestStream, context).ConfigureAwait(false);
status = context.Status;
try
{
- await responseStream.WriteAsync(result);
+ await responseStream.WriteAsync(result).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
@@ -209,13 +209,13 @@ namespace Grpc.Core.Internal
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers);
+ await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Call has been already cancelled.
}
- await finishedTask;
+ await finishedTask.ConfigureAwait(false);
}
}
@@ -250,7 +250,7 @@ namespace Grpc.Core.Internal
var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, responseStream, asyncCall.CancellationToken);
try
{
- await handler(requestStream, responseStream, context);
+ await handler(requestStream, responseStream, context).ConfigureAwait(false);
status = context.Status;
}
catch (Exception e)
@@ -260,13 +260,13 @@ namespace Grpc.Core.Internal
}
try
{
- await responseStream.WriteStatusAsync(status, context.ResponseTrailers);
+ await responseStream.WriteStatusAsync(status, context.ResponseTrailers).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
// Call has been already cancelled.
}
- await finishedTask;
+ await finishedTask.ConfigureAwait(false);
}
}
@@ -284,8 +284,8 @@ namespace Grpc.Core.Internal
var finishedTask = asyncCall.ServerSideCallAsync();
var responseStream = new ServerResponseStream<byte[], byte[]>(asyncCall);
- await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, "No such method."), Metadata.Empty);
- await finishedTask;
+ await responseStream.WriteStatusAsync(new Status(StatusCode.Unimplemented, ""), Metadata.Empty).ConfigureAwait(false);
+ await finishedTask.ConfigureAwait(false);
}
}
diff --git a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
index 3fccb88abb..e7be82c318 100644
--- a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
@@ -70,7 +70,7 @@ namespace Grpc.Core.Internal
}
var taskSource = new AsyncCompletionTaskSource<TRequest>();
call.StartReadMessage(taskSource.CompletionDelegate);
- var result = await taskSource.Task;
+ var result = await taskSource.Task.ConfigureAwait(false);
this.current = result;
return result != null;
}
diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs
index 38fc067d9f..3031175c8a 100644
--- a/src/csharp/Grpc.Core/Internal/Timespec.cs
+++ b/src/csharp/Grpc.Core/Internal/Timespec.cs
@@ -63,20 +63,18 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern int gprsharp_sizeof_timespec();
- public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
+ public Timespec(long tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime)
{
}
- public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type)
+ public Timespec(long tv_sec, int tv_nsec, GPRClockType clock_type)
{
this.tv_sec = tv_sec;
this.tv_nsec = tv_nsec;
this.clock_type = clock_type;
}
- // NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
- // so IntPtr seems to have the right size to work on both.
- private System.IntPtr tv_sec;
+ private long tv_sec;
private int tv_nsec;
private GPRClockType clock_type;
@@ -116,7 +114,7 @@ namespace Grpc.Core.Internal
/// <summary>
/// Seconds since unix epoch.
/// </summary>
- public IntPtr TimevalSeconds
+ public long TimevalSeconds
{
get
{
@@ -176,18 +174,18 @@ namespace Grpc.Core.Internal
{
// convert nanos to ticks, round up to the nearest tick
long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0);
- long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos);
+ long ticksTotal = checked(tv_sec * TicksPerSecond + ticksFromNanos);
return UnixEpoch.AddTicks(ticksTotal);
}
catch (OverflowException)
{
// ticks out of long range
- return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue;
}
catch (ArgumentOutOfRangeException)
{
// resulting date time would be larger than MaxValue
- return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue;
+ return tv_sec > 0 ? DateTime.MaxValue : DateTime.MinValue;
}
}
@@ -226,12 +224,7 @@ namespace Grpc.Core.Internal
seconds--;
nanos += (int)NanosPerSecond;
}
- // new IntPtr possibly throws OverflowException
- return new Timespec(new IntPtr(seconds), nanos);
- }
- catch (OverflowException)
- {
- return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast;
+ return new Timespec(seconds, nanos);
}
catch (ArgumentOutOfRangeException)
{
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 7c94d21561..d120f95fdf 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -148,10 +148,10 @@ namespace Grpc.Core
}
handle.ShutdownAndNotify(HandleServerShutdown, environment);
- await shutdownTcs.Task;
+ await shutdownTcs.Task.ConfigureAwait(false);
DisposeHandle();
- await Task.Run(() => GrpcEnvironment.Release());
+ await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
}
/// <summary>
@@ -169,8 +169,10 @@ namespace Grpc.Core
handle.ShutdownAndNotify(HandleServerShutdown, environment);
handle.CancelAllCalls();
- await shutdownTcs.Task;
+ await shutdownTcs.Task.ConfigureAwait(false);
DisposeHandle();
+
+ await Task.Run(() => GrpcEnvironment.Release()).ConfigureAwait(false);
}
internal void AddCallReference(object call)
@@ -268,7 +270,7 @@ namespace Grpc.Core
{
callHandler = NoSuchMethodCallHandler.Instance;
}
- await callHandler.HandleCall(newRpc, environment);
+ await callHandler.HandleCall(newRpc, environment).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -288,7 +290,7 @@ namespace Grpc.Core
// after server shutdown, the callback returns with null call
if (!newRpc.Call.IsInvalid)
{
- Task.Run(async () => await HandleCallAsync(newRpc));
+ Task.Run(async () => await HandleCallAsync(newRpc)).ConfigureAwait(false);
}
}
diff --git a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
index cdf1e51026..02a47568e7 100644
--- a/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
+++ b/src/csharp/Grpc.Core/Utils/AsyncStreamExtensions.cs
@@ -48,9 +48,9 @@ namespace Grpc.Core.Utils
public static async Task ForEachAsync<T>(this IAsyncStreamReader<T> streamReader, Func<T, Task> asyncAction)
where T : class
{
- while (await streamReader.MoveNext())
+ while (await streamReader.MoveNext().ConfigureAwait(false))
{
- await asyncAction(streamReader.Current);
+ await asyncAction(streamReader.Current).ConfigureAwait(false);
}
}
@@ -61,7 +61,7 @@ namespace Grpc.Core.Utils
where T : class
{
var result = new List<T>();
- while (await streamReader.MoveNext())
+ while (await streamReader.MoveNext().ConfigureAwait(false))
{
result.Add(streamReader.Current);
}
@@ -77,11 +77,11 @@ namespace Grpc.Core.Utils
{
foreach (var element in elements)
{
- await streamWriter.WriteAsync(element);
+ await streamWriter.WriteAsync(element).ConfigureAwait(false);
}
if (complete)
{
- await streamWriter.CompleteAsync();
+ await streamWriter.CompleteAsync().ConfigureAwait(false);
}
}
@@ -93,7 +93,7 @@ namespace Grpc.Core.Utils
{
foreach (var element in elements)
{
- await streamWriter.WriteAsync(element);
+ await streamWriter.WriteAsync(element).ConfigureAwait(false);
}
}
}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 55462e02fd..53b2bb78c4 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -66,6 +66,5 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
- <None Include="proto\math.proto" />
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 8fce5d39aa..4e775a7a0c 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -65,7 +65,6 @@
<ItemGroup>
<None Include="Grpc.HealthCheck.nuspec" />
<None Include="packages.config" />
- <None Include="proto\health.proto" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
@@ -81,4 +80,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto
deleted file mode 100644
index 01aa3fcf57..0000000000
--- a/src/csharp/Grpc.HealthCheck/proto/health.proto
+++ /dev/null
@@ -1,52 +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.
-
-// TODO(jtattermusch): switch to proto3 once C# supports that.
-syntax = "proto3";
-
-package grpc.health.v1alpha;
-option csharp_namespace = "Grpc.Health.V1Alpha";
-
-message HealthCheckRequest {
- string host = 1;
- string service = 2;
-}
-
-message HealthCheckResponse {
- enum ServingStatus {
- UNKNOWN = 0;
- SERVING = 1;
- NOT_SERVING = 2;
- }
- ServingStatus status = 1;
-}
-
-service Health {
- rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
-} \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 012de45524..b0d920a34c 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -41,6 +41,9 @@
<Reference Include="CommandLine">
<HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
+ <Reference Include="Moq">
+ <HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
+ </Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
@@ -83,6 +86,7 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
+ <Compile Include="HeaderInterceptorTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
diff --git a/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs b/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs
new file mode 100644
index 0000000000..1d758b7540
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/HeaderInterceptorTest.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class HeaderInterceptorTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ TestService.TestServiceClient client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
+ };
+ server.Start();
+
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
+ client = TestService.NewClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public async Task HeaderInterceptor_CreateMetadata()
+ {
+ var key = "x-grpc-test-echo-initial";
+ client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
+ {
+ metadata.Add(key, "ABC");
+ });
+
+ var call = client.UnaryCallAsync(new SimpleRequest());
+ await call;
+
+ var responseHeaders = await call.ResponseHeadersAsync;
+ Assert.AreEqual("ABC", responseHeaders.First((entry) => entry.Key == key).Value);
+ }
+
+ [Test]
+ public async Task HeaderInterceptor_AppendMetadata()
+ {
+ var initialKey = "x-grpc-test-echo-initial";
+ var trailingKey = "x-grpc-test-echo-trailing-bin";
+
+ client.HeaderInterceptor = new HeaderInterceptor((method, metadata) =>
+ {
+ metadata.Add(initialKey, "ABC");
+ });
+
+ var headers = new Metadata
+ {
+ { trailingKey, new byte[] {0xaa} }
+ };
+ var call = client.UnaryCallAsync(new SimpleRequest(), headers: headers);
+ await call;
+
+ var responseHeaders = await call.ResponseHeadersAsync;
+ Assert.AreEqual("ABC", responseHeaders.First((entry) => entry.Key == initialKey).Value);
+ CollectionAssert.AreEqual(new byte[] {0xaa}, call.GetTrailers().First((entry) => entry.Key == trailingKey).ValueBytes);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 5eec11abf7..b0e33e49f7 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -34,6 +34,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -130,8 +131,7 @@ namespace Grpc.IntegrationTesting
};
}
var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions);
- TestService.TestServiceClient client = new TestService.TestServiceClient(channel);
- await RunTestCaseAsync(client, options);
+ await RunTestCaseAsync(channel, options);
await channel.ShutdownAsync();
}
@@ -159,8 +159,9 @@ namespace Grpc.IntegrationTesting
return credentials;
}
- private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options)
+ private async Task RunTestCaseAsync(Channel channel, ClientOptions options)
{
+ var client = new TestService.TestServiceClient(channel);
switch (options.TestCase)
{
case "empty_unary":
@@ -202,8 +203,14 @@ namespace Grpc.IntegrationTesting
case "timeout_on_sleeping_server":
await RunTimeoutOnSleepingServerAsync(client);
break;
- case "benchmark_empty_unary":
- RunBenchmarkEmptyUnary(client);
+ case "custom_metadata":
+ await RunCustomMetadataAsync(client);
+ break;
+ case "status_code_and_message":
+ await RunStatusCodeAndMessageAsync(client);
+ break;
+ case "unimplemented_method":
+ RunUnimplementedMethod(new UnimplementedService.UnimplementedServiceClient(channel));
break;
default:
throw new ArgumentException("Unknown test case " + options.TestCase);
@@ -227,7 +234,6 @@ namespace Grpc.IntegrationTesting
ResponseSize = 314159,
Payload = CreateZerosPayload(271828)
};
-
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
@@ -493,11 +499,95 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- // This is not an official interop test, but it's useful.
- public static void RunBenchmarkEmptyUnary(TestService.ITestServiceClient client)
+ public static async Task RunCustomMetadataAsync(TestService.ITestServiceClient client)
{
- BenchmarkUtil.RunBenchmark(10000, 10000,
- () => { client.EmptyCall(new Empty()); });
+ Console.WriteLine("running custom_metadata");
+ {
+ // step 1: test unary call
+ var request = new SimpleRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828)
+ };
+
+ var call = client.UnaryCallAsync(request, headers: CreateTestMetadata());
+ await call.ResponseAsync;
+
+ var responseHeaders = await call.ResponseHeadersAsync;
+ var responseTrailers = call.GetTrailers();
+
+ Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value);
+ CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes);
+ }
+
+ {
+ // step 2: test full duplex call
+ var request = new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 31415 } },
+ Payload = CreateZerosPayload(27182)
+ };
+
+ var call = client.FullDuplexCall(headers: CreateTestMetadata());
+ var responseHeaders = await call.ResponseHeadersAsync;
+
+ await call.RequestStream.WriteAsync(request);
+ await call.RequestStream.CompleteAsync();
+ await call.ResponseStream.ToListAsync();
+
+ var responseTrailers = call.GetTrailers();
+
+ Assert.AreEqual("test_initial_metadata_value", responseHeaders.First((entry) => entry.Key == "x-grpc-test-echo-initial").Value);
+ CollectionAssert.AreEqual(new byte[] { 0xab, 0xab, 0xab }, responseTrailers.First((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ValueBytes);
+ }
+
+ Console.WriteLine("Passed!");
+ }
+
+ public static async Task RunStatusCodeAndMessageAsync(TestService.ITestServiceClient client)
+ {
+ Console.WriteLine("running status_code_and_message");
+ var echoStatus = new EchoStatus
+ {
+ Code = 2,
+ Message = "test status message"
+ };
+
+ {
+ // step 1: test unary call
+ var request = new SimpleRequest { ResponseStatus = echoStatus };
+
+ var e = Assert.Throws<RpcException>(() => client.UnaryCall(request));
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+ Assert.AreEqual(echoStatus.Message, e.Status.Detail);
+ }
+
+ {
+ // step 2: test full duplex call
+ var request = new StreamingOutputCallRequest { ResponseStatus = echoStatus };
+
+ var call = client.FullDuplexCall();
+ await call.RequestStream.WriteAsync(request);
+ await call.RequestStream.CompleteAsync();
+
+ var e = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
+ Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode);
+ Assert.AreEqual(echoStatus.Message, e.Status.Detail);
+ }
+
+ Console.WriteLine("Passed!");
+ }
+
+ public static void RunUnimplementedMethod(UnimplementedService.IUnimplementedServiceClient client)
+ {
+ Console.WriteLine("running unimplemented_method");
+ var e = Assert.Throws<RpcException>(() => client.UnimplementedCall(new Empty()));
+
+ Assert.AreEqual(StatusCode.Unimplemented, e.Status.StatusCode);
+ Assert.AreEqual("", e.Status.Detail);
+ Console.WriteLine("Passed!");
}
private static Payload CreateZerosPayload(int size)
@@ -516,5 +606,14 @@ namespace Grpc.IntegrationTesting
Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
return email;
}
+
+ private static Metadata CreateTestMetadata()
+ {
+ return new Metadata
+ {
+ {"x-grpc-test-echo-initial", "test_initial_metadata_value"},
+ {"x-grpc-test-echo-trailing-bin", new byte[] {0xab, 0xab, 0xab}}
+ };
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 837ae74c45..18168f9970 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -128,9 +128,29 @@ namespace Grpc.IntegrationTesting
}
[Test]
- public async Task TimeoutOnSleepingServerAsync()
+ public async Task TimeoutOnSleepingServer()
{
await InteropClient.RunTimeoutOnSleepingServerAsync(client);
}
+
+ [Test]
+ public async Task CustomMetadata()
+ {
+ await InteropClient.RunCustomMetadataAsync(client);
+ }
+
+ [Test]
+ [Ignore("TODO: see #4427")]
+ public async Task StatusCodeAndMessage()
+ {
+ await InteropClient.RunStatusCodeAndMessageAsync(client);
+ }
+
+ [Test]
+ [Ignore("TODO: see #4427")]
+ public void UnimplementedMethod()
+ {
+ InteropClient.RunUnimplementedMethod(UnimplementedService.NewClient(channel));
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
index 3d56678b99..1c8bfed1f6 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -40,6 +40,7 @@ using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
+using Moq;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -50,37 +51,37 @@ namespace Grpc.IntegrationTesting
Server server;
Channel channel;
TestService.ITestServiceClient client;
+ List<ChannelOption> options;
+ Mock<TestService.ITestService> serviceMock;
+ AsyncAuthInterceptor asyncAuthInterceptor;
- [TestFixtureSetUp]
+ [SetUp]
public void Init()
{
- var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair(File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) });
+ serviceMock = new Mock<TestService.ITestService>();
+ 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(new TestServiceImpl()) },
- Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
+ Services = { TestService.BindService(serviceMock.Object) },
+ Ports = { { Host, ServerPort.PickUnused, TestCredentials.CreateSslServerCredentials() } }
};
server.Start();
- var options = new List<ChannelOption>
+ options = new List<ChannelOption>
{
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
};
- var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) =>
+ asyncAuthInterceptor = new AsyncAuthInterceptor(async (context, metadata) =>
{
- await Task.Delay(100); // make sure the operation is asynchronous.
+ await Task.Delay(100).ConfigureAwait(false); // make sure the operation is asynchronous.
metadata.Add("authorization", "SECRET_TOKEN");
});
-
- var clientCredentials = ChannelCredentials.Create(
- new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)),
- CallCredentials.FromInterceptor(asyncAuthInterceptor));
- channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
- client = TestService.NewClient(channel);
}
- [TestFixtureTearDown]
+ [TearDown]
public void Cleanup()
{
channel.ShutdownAsync().Wait();
@@ -90,8 +91,29 @@ namespace Grpc.IntegrationTesting
[Test]
public void MetadataCredentials()
{
- var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
- Assert.AreEqual(10, response.Payload.Body.Length);
+ var channelCredentials = ChannelCredentials.Create(TestCredentials.CreateSslCredentials(),
+ CallCredentials.FromInterceptor(asyncAuthInterceptor));
+ channel = new Channel(Host, server.Ports.Single().BoundPort, channelCredentials, options);
+ client = TestService.NewClient(channel);
+
+ client.UnaryCall(new SimpleRequest {});
+ }
+
+ [Test]
+ public void MetadataCredentials_PerCall()
+ {
+ channel = new Channel(Host, server.Ports.Single().BoundPort, TestCredentials.CreateSslCredentials(), options);
+ client = TestService.NewClient(channel);
+
+ var callCredentials = CallCredentials.FromInterceptor(asyncAuthInterceptor);
+ client.UnaryCall(new SimpleRequest { }, new CallOptions(credentials: callCredentials));
+ }
+
+ private Task<SimpleResponse> UnaryCallHandler(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/RunnerClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
index 2b51526c88..3dd91b7948 100644
--- a/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/RunnerClientServerTest.cs
@@ -75,9 +75,10 @@ namespace Grpc.IntegrationTesting
serverRunner.StopAsync().Wait();
}
- // Test attribute commented out to prevent running as part of the default test suite.
- //[Test]
- //[Category("Performance")]
+
+ [Test]
+ [Category("Performance")]
+ [Ignore("Prevent running on Jenkins")]
public async Task ClientServerRunner()
{
var config = new ClientConfig
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index c5bfcf08c0..5a1b4cf319 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Google.Protobuf;
@@ -51,14 +52,20 @@ namespace Grpc.Testing
return Task.FromResult(new Empty());
}
- public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
+ public async Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
+ await EnsureEchoMetadataAsync(context);
+ EnsureEchoStatus(request.ResponseStatus, context);
+
var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
- return Task.FromResult(response);
+ return response;
}
public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
+ await EnsureEchoMetadataAsync(context);
+ EnsureEchoStatus(request.ResponseStatus, context);
+
foreach (var responseParam in request.ResponseParameters)
{
var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) };
@@ -68,6 +75,8 @@ namespace Grpc.Testing
public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream, ServerCallContext context)
{
+ await EnsureEchoMetadataAsync(context);
+
int sum = 0;
await requestStream.ForEachAsync(async request =>
{
@@ -78,8 +87,11 @@ namespace Grpc.Testing
public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
+ await EnsureEchoMetadataAsync(context);
+
await requestStream.ForEachAsync(async request =>
{
+ EnsureEchoStatus(request.ResponseStatus, context);
foreach (var responseParam in request.ResponseParameters)
{
var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) };
@@ -97,5 +109,28 @@ namespace Grpc.Testing
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
+
+ private static async Task EnsureEchoMetadataAsync(ServerCallContext context)
+ {
+ var echoInitialList = context.RequestHeaders.Where((entry) => entry.Key == "x-grpc-test-echo-initial").ToList();
+ if (echoInitialList.Any()) {
+ var entry = echoInitialList.Single();
+ await context.WriteResponseHeadersAsync(new Metadata { entry });
+ }
+
+ var echoTrailingList = context.RequestHeaders.Where((entry) => entry.Key == "x-grpc-test-echo-trailing-bin").ToList();
+ if (echoTrailingList.Any()) {
+ context.ResponseTrailers.Add(echoTrailingList.Single());
+ }
+ }
+
+ private static void EnsureEchoStatus(EchoStatus responseStatus, ServerCallContext context)
+ {
+ if (responseStatus != null)
+ {
+ var statusCode = (StatusCode)responseStatus.Code;
+ context.Status = new Status(statusCode, responseStatus.Message);
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index bdb3dadf44..5c59af1b7d 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -11,6 +11,7 @@
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Moq" version="4.2.1510.2205" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index b8705c49d3..0ef9be33a6 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -927,7 +927,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
}
typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
- void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
+ void *state, const char *service_url, const char *method_name,
+ grpc_credentials_plugin_metadata_cb cb,
void *user_data, gpr_int32 is_destroy);
static void grpcsharp_get_metadata_handler(
@@ -935,13 +936,13 @@ static void grpcsharp_get_metadata_handler(
grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
- interceptor(state, context.service_url, cb, user_data, 0);
+ interceptor(state, context.service_url, context.method_name, cb, user_data, 0);
}
static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
- interceptor(state, NULL, NULL, NULL, 1);
+ interceptor(state, NULL, NULL, NULL, NULL, 1);
}
GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 92348d1394..4dbd9c3308 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -30,19 +30,19 @@
# Regenerates gRPC service stubs from proto files.
set +e
-cd $(dirname $0)
+cd $(dirname $0)/../..
-PROTOC=../../bins/opt/protobuf/protoc
-PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
-EXAMPLES_DIR=Grpc.Examples
-TESTING_DIR=Grpc.IntegrationTesting
-HEALTHCHECK_DIR=Grpc.HealthCheck
+PROTOC=bins/opt/protobuf/protoc
+PLUGIN=protoc-gen-grpc=bins/opt/grpc_csharp_plugin
+EXAMPLES_DIR=src/csharp/Grpc.Examples
+HEALTHCHECK_DIR=src/csharp/Grpc.HealthCheck
+TESTING_DIR=src/csharp/Grpc.IntegrationTesting
$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
- -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
-
-$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
- -I ../.. ../../test/proto/*.proto ../../test/proto/benchmarks/*.proto
+ -I src/proto/math src/proto/math/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
- -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
+ -I src/proto/grpc/health/v1alpha src/proto/grpc/health/v1alpha/health.proto
+
+$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
+ -I . test/proto/{empty,messages,test}.proto test/proto/benchmarks/*.proto
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
new file mode 100644
index 0000000000..4aa93668ad
--- /dev/null
+++ b/src/csharp/tests.json
@@ -0,0 +1,45 @@
+{
+ "assemblies": [
+ "Grpc.Core.Tests",
+ "Grpc.Examples.Tests",
+ "Grpc.HealthCheck.Tests",
+ "Grpc.IntegrationTesting"
+ ],
+ "tests": [
+ "Grpc.Core.Internal.Tests.AsyncCallTest",
+ "Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
+ "Grpc.Core.Internal.Tests.CompletionQueueEventTest",
+ "Grpc.Core.Internal.Tests.CompletionQueueSafeHandleTest",
+ "Grpc.Core.Internal.Tests.MetadataArraySafeHandleTest",
+ "Grpc.Core.Internal.Tests.TimespecTest",
+ "Grpc.Core.Tests.CallCredentialsTest",
+ "Grpc.Core.Tests.CallOptionsTest",
+ "Grpc.Core.Tests.ChannelCredentialsTest",
+ "Grpc.Core.Tests.ChannelOptionsTest",
+ "Grpc.Core.Tests.ChannelTest",
+ "Grpc.Core.Tests.ClientServerTest",
+ "Grpc.Core.Tests.CompressionTest",
+ "Grpc.Core.Tests.ContextPropagationTest",
+ "Grpc.Core.Tests.GrpcEnvironmentTest",
+ "Grpc.Core.Tests.MarshallingErrorsTest",
+ "Grpc.Core.Tests.MetadataTest",
+ "Grpc.Core.Tests.NUnitVersionTest",
+ "Grpc.Core.Tests.PerformanceTest",
+ "Grpc.Core.Tests.PInvokeTest",
+ "Grpc.Core.Tests.ResponseHeadersTest",
+ "Grpc.Core.Tests.SanityTest",
+ "Grpc.Core.Tests.ServerTest",
+ "Grpc.Core.Tests.ShutdownTest",
+ "Grpc.Core.Tests.TimeoutsTest",
+ "Grpc.Core.Tests.UserAgentStringTest",
+ "Math.Tests.MathClientServerTest",
+ "Grpc.HealthCheck.Tests.HealthClientServerTest",
+ "Grpc.HealthCheck.Tests.HealthServiceImplTest",
+ "Grpc.IntegrationTesting.HeaderInterceptorTest",
+ "Grpc.IntegrationTesting.HistogramTest",
+ "Grpc.IntegrationTesting.InteropClientServerTest",
+ "Grpc.IntegrationTesting.MetadataCredentialsTest",
+ "Grpc.IntegrationTesting.RunnerClientServerTest",
+ "Grpc.IntegrationTesting.SslCredentialsTest"
+ ]
+} \ No newline at end of file
diff --git a/src/node/ext/channel_credentials.cc b/src/node/ext/channel_credentials.cc
index b77ff80af2..059bc8a890 100644
--- a/src/node/ext/channel_credentials.cc
+++ b/src/node/ext/channel_credentials.cc
@@ -154,6 +154,12 @@ NAN_METHOD(ChannelCredentials::CreateSsl) {
return Nan::ThrowTypeError(
"createSSl's third argument must be a Buffer if provided");
}
+ if ((key_cert_pair.private_key == NULL) !=
+ (key_cert_pair.cert_chain == NULL)) {
+ return Nan::ThrowError(
+ "createSsl's second and third arguments must be"
+ " provided or omitted together");
+ }
grpc_channel_credentials *creds = grpc_ssl_credentials_create(
root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair,
NULL);
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index e6c55e263c..5285d53df4 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -167,30 +167,18 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
return Nan::ThrowTypeError("Key/cert pairs must be objects");
}
Local<Object> pair_obj = Nan::To<Object>(pair_val).ToLocalChecked();
- MaybeLocal<Value> maybe_key = Nan::Get(pair_obj, key_key);
- if (maybe_key.IsEmpty()) {
- delete key_cert_pairs;
- return Nan::ThrowTypeError(
- "Key/cert pairs must have a private_key and a cert_chain");
- }
- MaybeLocal<Value> maybe_cert = Nan::Get(pair_obj, cert_key);
- if (maybe_cert.IsEmpty()) {
- delete key_cert_pairs;
- return Nan::ThrowTypeError(
- "Key/cert pairs must have a private_key and a cert_chain");
- }
- if (!::node::Buffer::HasInstance(maybe_key.ToLocalChecked())) {
+ Local<Value> maybe_key = Nan::Get(pair_obj, key_key).ToLocalChecked();
+ Local<Value> maybe_cert = Nan::Get(pair_obj, cert_key).ToLocalChecked();
+ if (!::node::Buffer::HasInstance(maybe_key)) {
delete key_cert_pairs;
return Nan::ThrowTypeError("private_key must be a Buffer");
}
- if (!::node::Buffer::HasInstance(maybe_cert.ToLocalChecked())) {
+ if (!::node::Buffer::HasInstance(maybe_cert)) {
delete key_cert_pairs;
return Nan::ThrowTypeError("cert_chain must be a Buffer");
}
- key_cert_pairs[i].private_key = ::node::Buffer::Data(
- maybe_key.ToLocalChecked());
- key_cert_pairs[i].cert_chain = ::node::Buffer::Data(
- maybe_cert.ToLocalChecked());
+ key_cert_pairs[i].private_key = ::node::Buffer::Data(maybe_key);
+ key_cert_pairs[i].cert_chain = ::node::Buffer::Data(maybe_cert);
}
grpc_server_credentials *creds = grpc_ssl_server_credentials_create(
root_certs, key_cert_pairs, key_cert_pair_count, force_client_auth, NULL);
diff --git a/src/node/health_check/health.js b/src/node/health_check/health.js
index 84d7e0568e..1a2c036687 100644
--- a/src/node/health_check/health.js
+++ b/src/node/health_check/health.js
@@ -37,7 +37,8 @@ var grpc = require('../');
var _ = require('lodash');
-var health_proto = grpc.load(__dirname + '/health.proto');
+var health_proto = grpc.load(__dirname +
+ '/../../proto/grpc/health/v1alpha/health.proto');
var HealthClient = health_proto.grpc.health.v1alpha.Health;
diff --git a/src/node/health_check/health.proto b/src/node/health_check/health.proto
deleted file mode 100644
index 57f4aaa9c0..0000000000
--- a/src/node/health_check/health.proto
+++ /dev/null
@@ -1,49 +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.
-
-syntax = "proto3";
-
-package grpc.health.v1alpha;
-
-message HealthCheckRequest {
- string service = 1;
-}
-
-message HealthCheckResponse {
- enum ServingStatus {
- UNKNOWN = 0;
- SERVING = 1;
- NOT_SERVING = 2;
- }
- ServingStatus status = 1;
-}
-
-service Health {
- rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.c b/src/node/interop/async_delay_queue.js
index 8dedf5902b..2bd3ca4da3 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.c
+++ b/src/node/interop/async_delay_queue.js
@@ -31,31 +31,49 @@
*
*/
-#include "grpc/_adapter/_c/types.h"
+'use strict';
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
+var _ = require('lodash');
-int pygrpc_module_add_types(PyObject *module) {
- int i;
- PyTypeObject *types[] = {
- &pygrpc_CallCredentials_type,
- &pygrpc_ChannelCredentials_type,
- &pygrpc_ServerCredentials_type,
- &pygrpc_CompletionQueue_type,
- &pygrpc_Call_type,
- &pygrpc_Channel_type,
- &pygrpc_Server_type
- };
- for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
- if (PyType_Ready(types[i]) < 0) {
- return -1;
- }
+/**
+ * This class represents a queue of callbacks that must happen sequentially, each
+ * with a specific delay after the previous event.
+ */
+function AsyncDelayQueue() {
+ this.queue = [];
+
+ this.callback_pending = false;
+}
+
+/**
+ * Run the next callback after its corresponding delay, if there are any
+ * remaining.
+ */
+AsyncDelayQueue.prototype.runNext = function() {
+ var next = this.queue.shift();
+ var continueCallback = _.bind(this.runNext, this);
+ if (next) {
+ this.callback_pending = true;
+ setTimeout(function() {
+ next.callback(continueCallback);
+ }, next.delay);
+ } else {
+ this.callback_pending = false;
}
- for (i = 0; i < sizeof(types)/sizeof(PyTypeObject *); ++i) {
- Py_INCREF(types[i]);
- PyModule_AddObject(module, types[i]->tp_name, (PyObject *)types[i]);
+};
+
+/**
+ * Add a callback to be called with a specific delay after now or after the
+ * current last item in the queue or current pending callback, whichever is
+ * latest.
+ * @param {function(function())} callback The callback
+ * @param {Number} The delay to apply, in milliseconds
+ */
+AsyncDelayQueue.prototype.add = function(callback, delay) {
+ this.queue.push({callback: callback, delay: delay});
+ if (!this.callback_pending) {
+ this.runNext();
}
- return 0;
-}
+};
+
+module.exports = AsyncDelayQueue;
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 5321005c86..9526b5d183 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -36,6 +36,7 @@
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
+var AsyncDelayQueue = require('./async_delay_queue');
var grpc = require('..');
var testProto = grpc.load({
root: __dirname + '/../../..',
@@ -155,6 +156,7 @@ function handleStreamingInput(call, callback) {
*/
function handleStreamingOutput(call) {
echoHeader(call);
+ var delay_queue = new AsyncDelayQueue();
var req = call.request;
if (req.response_status) {
var status = req.response_status;
@@ -163,9 +165,15 @@ function handleStreamingOutput(call) {
return;
}
_.each(req.response_parameters, function(resp_param) {
- call.write({payload: getPayload(req.response_type, resp_param.size)});
+ delay_queue.add(function(next) {
+ call.write({payload: getPayload(req.response_type, resp_param.size)});
+ next();
+ }, resp_param.interval_us);
+ });
+ delay_queue.add(function(next) {
+ call.end(getEchoTrailer(call));
+ next();
});
- call.end(getEchoTrailer(call));
}
/**
@@ -175,6 +183,7 @@ function handleStreamingOutput(call) {
*/
function handleFullDuplex(call) {
echoHeader(call);
+ var delay_queue = new AsyncDelayQueue();
call.on('data', function(value) {
if (value.response_status) {
var status = value.response_status;
@@ -183,11 +192,17 @@ function handleFullDuplex(call) {
return;
}
_.each(value.response_parameters, function(resp_param) {
- call.write({payload: getPayload(value.response_type, resp_param.size)});
+ delay_queue.add(function(next) {
+ call.write({payload: getPayload(value.response_type, resp_param.size)});
+ next();
+ }, resp_param.interval_us);
});
});
call.on('end', function() {
- call.end(getEchoTrailer(call));
+ delay_queue.add(function(next) {
+ call.end(getEchoTrailer(call));
+ next();
+ });
});
}
diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js
new file mode 100644
index 0000000000..d97bdbbcaf
--- /dev/null
+++ b/src/node/performance/benchmark_client.js
@@ -0,0 +1,336 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Benchmark client module
+ * @module
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var EventEmitter = require('events');
+var _ = require('lodash');
+var PoissonProcess = require('poisson-process');
+var Histogram = require('./histogram');
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+ root: __dirname + '/../../..',
+ file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+/**
+ * Create a buffer filled with size zeroes
+ * @param {number} size The length of the buffer
+ * @return {Buffer} The new buffer
+ */
+function zeroBuffer(size) {
+ var zeros = new Buffer(size);
+ zeros.fill(0);
+ return zeros;
+}
+
+/**
+ * Convert a time difference, as returned by process.hrtime, to a number of
+ * nanoseconds.
+ * @param {Array.<number>} time_diff The time diff, represented as
+ * [seconds, nanoseconds]
+ * @return {number} The total number of nanoseconds
+ */
+function timeDiffToNanos(time_diff) {
+ return time_diff[0] * 1e9 + time_diff[1];
+}
+
+/**
+ * The BenchmarkClient class. Opens channels to servers and makes RPCs based on
+ * parameters from the driver, and records statistics about those RPCs.
+ * @param {Array.<string>} server_targets List of servers to connect to
+ * @param {number} channels The total number of channels to open
+ * @param {Object} histogram_params Options for setting up the histogram
+ * @param {Object=} security_params Options for TLS setup. If absent, don't use
+ * TLS
+ */
+function BenchmarkClient(server_targets, channels, histogram_params,
+ security_params) {
+ var options = {};
+ var creds;
+ if (security_params) {
+ var ca_path;
+ if (security_params.use_test_ca) {
+ ca_path = path.join(__dirname, '../test/data/ca.pem');
+ var ca_data = fs.readFileSync(ca_path);
+ creds = grpc.credentials.createSsl(ca_data);
+ } else {
+ creds = grpc.credentials.createSsl();
+ }
+ if (security_params.server_host_override) {
+ var host_override = security_params.server_host_override;
+ options['grpc.ssl_target_name_override'] = host_override;
+ options['grpc.default_authority'] = host_override;
+ }
+ } else {
+ creds = grpc.credentials.createInsecure();
+ }
+
+ this.clients = [];
+
+ for (var i = 0; i < channels; i++) {
+ this.clients[i] = new serviceProto.BenchmarkService(
+ server_targets[i % server_targets.length], creds, options);
+ }
+
+ this.histogram = new Histogram(histogram_params.resolution,
+ histogram_params.max_possible);
+
+ this.running = false;
+
+ this.pending_calls = 0;
+};
+
+util.inherits(BenchmarkClient, EventEmitter);
+
+/**
+ * Start a closed-loop test. For each channel, start
+ * outstanding_rpcs_per_channel RPCs. Then, whenever an RPC finishes, start
+ * another one.
+ * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
+ * channel
+ * @param {string} rpc_type Which method to call. Should be 'UNARY' or
+ * 'STREAMING'
+ * @param {number} req_size The size of the payload to send with each request
+ * @param {number} resp_size The size of payload to request be sent in responses
+ */
+BenchmarkClient.prototype.startClosedLoop = function(
+ outstanding_rpcs_per_channel, rpc_type, req_size, resp_size) {
+ var self = this;
+
+ self.running = true;
+
+ self.last_wall_time = process.hrtime();
+
+ var makeCall;
+
+ var argument = {
+ response_size: resp_size,
+ payload: {
+ body: zeroBuffer(req_size)
+ }
+ };
+
+ if (rpc_type == 'UNARY') {
+ makeCall = function(client) {
+ if (self.running) {
+ self.pending_calls++;
+ var start_time = process.hrtime();
+ client.unaryCall(argument, function(error, response) {
+ if (error) {
+ self.emit('error', new Error('Client error: ' + error.message));
+ self.running = false;
+ return;
+ }
+ var time_diff = process.hrtime(start_time);
+ self.histogram.add(timeDiffToNanos(time_diff));
+ makeCall(client);
+ self.pending_calls--;
+ if ((!self.running) && self.pending_calls == 0) {
+ self.emit('finished');
+ }
+ });
+ }
+ };
+ } else {
+ makeCall = function(client) {
+ if (self.running) {
+ self.pending_calls++;
+ var start_time = process.hrtime();
+ var call = client.streamingCall();
+ call.write(argument);
+ call.on('data', function() {
+ });
+ call.on('end', function() {
+ var time_diff = process.hrtime(start_time);
+ self.histogram.add(timeDiffToNanos(time_diff));
+ makeCall(client);
+ self.pending_calls--;
+ if ((!self.running) && self.pending_calls == 0) {
+ self.emit('finished');
+ }
+ });
+ call.on('error', function(error) {
+ self.emit('error', new Error('Client error: ' + error.message));
+ self.running = false;
+ });
+ }
+ };
+ }
+
+ _.each(self.clients, function(client) {
+ _.times(outstanding_rpcs_per_channel, function() {
+ makeCall(client);
+ });
+ });
+};
+
+/**
+ * Start a poisson test. For each channel, this initiates a number of Poisson
+ * processes equal to outstanding_rpcs_per_channel, where each Poisson process
+ * has the load parameter offered_load.
+ * @param {number} outstanding_rpcs_per_channel Number of RPCs to start per
+ * channel
+ * @param {string} rpc_type Which method to call. Should be 'UNARY' or
+ * 'STREAMING'
+ * @param {number} req_size The size of the payload to send with each request
+ * @param {number} resp_size The size of payload to request be sent in responses
+ * @param {number} offered_load The load parameter for the Poisson process
+ */
+BenchmarkClient.prototype.startPoisson = function(
+ outstanding_rpcs_per_channel, rpc_type, req_size, resp_size, offered_load) {
+ var self = this;
+
+ self.running = true;
+
+ self.last_wall_time = process.hrtime();
+
+ var makeCall;
+
+ var argument = {
+ response_size: resp_size,
+ payload: {
+ body: zeroBuffer(req_size)
+ }
+ };
+
+ if (rpc_type == 'UNARY') {
+ makeCall = function(client, poisson) {
+ if (self.running) {
+ self.pending_calls++;
+ var start_time = process.hrtime();
+ client.unaryCall(argument, function(error, response) {
+ if (error) {
+ self.emit('error', new Error('Client error: ' + error.message));
+ self.running = false;
+ return;
+ }
+ var time_diff = process.hrtime(start_time);
+ self.histogram.add(timeDiffToNanos(time_diff));
+ self.pending_calls--;
+ if ((!self.running) && self.pending_calls == 0) {
+ self.emit('finished');
+ }
+ });
+ } else {
+ poisson.stop();
+ }
+ };
+ } else {
+ makeCall = function(client, poisson) {
+ if (self.running) {
+ self.pending_calls++;
+ var start_time = process.hrtime();
+ var call = client.streamingCall();
+ call.write(argument);
+ call.on('data', function() {
+ });
+ call.on('end', function() {
+ var time_diff = process.hrtime(start_time);
+ self.histogram.add(timeDiffToNanos(time_diff));
+ self.pending_calls--;
+ if ((!self.running) && self.pending_calls == 0) {
+ self.emit('finished');
+ }
+ });
+ call.on('error', function(error) {
+ self.emit('error', new Error('Client error: ' + error.message));
+ self.running = false;
+ });
+ } else {
+ poisson.stop();
+ }
+ };
+ }
+
+ var averageIntervalMs = (1 / offered_load) * 1000;
+
+ _.each(self.clients, function(client) {
+ _.times(outstanding_rpcs_per_channel, function() {
+ var p = PoissonProcess.create(averageIntervalMs, function() {
+ makeCall(client, p);
+ });
+ p.start();
+ });
+ });
+};
+
+/**
+ * Return curent statistics for the client. If reset is set, restart
+ * statistic collection.
+ * @param {boolean} reset Indicates that statistics should be reset
+ * @return {object} Client statistics
+ */
+BenchmarkClient.prototype.mark = function(reset) {
+ var wall_time_diff = process.hrtime(this.last_wall_time);
+ var histogram = this.histogram;
+ if (reset) {
+ this.last_wall_time = process.hrtime();
+ this.histogram = new Histogram(histogram.resolution,
+ histogram.max_possible);
+ }
+
+ return {
+ latencies: {
+ bucket: histogram.getContents(),
+ min_seen: histogram.minimum(),
+ max_seen: histogram.maximum(),
+ sum: histogram.getSum(),
+ sum_of_squares: histogram.sumOfSquares(),
+ count: histogram.getCount()
+ },
+ time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
+ // Not sure how to measure these values
+ time_user: 0,
+ time_system: 0
+ };
+};
+
+/**
+ * Stop the clients.
+ * @param {function} callback Called when the clients have finished shutting
+ * down
+ */
+BenchmarkClient.prototype.stop = function(callback) {
+ this.running = false;
+ this.on('finished', callback);
+};
+
+module.exports = BenchmarkClient;
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
new file mode 100644
index 0000000000..ac96fc5edb
--- /dev/null
+++ b/src/node/performance/benchmark_server.js
@@ -0,0 +1,162 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Benchmark server module
+ * @module
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+ root: __dirname + '/../../..',
+ file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+/**
+ * Create a buffer filled with size zeroes
+ * @param {number} size The length of the buffer
+ * @return {Buffer} The new buffer
+ */
+function zeroBuffer(size) {
+ var zeros = new Buffer(size);
+ zeros.fill(0);
+ return zeros;
+}
+
+/**
+ * Handler for the unary benchmark method. Simply responds with a payload
+ * containing the requested number of zero bytes.
+ * @param {Call} call The call object to be handled
+ * @param {function} callback The callback to call with the response
+ */
+function unaryCall(call, callback) {
+ var req = call.request;
+ var payload = {body: zeroBuffer(req.response_size)};
+ callback(null, {payload: payload});
+}
+
+/**
+ * Handler for the streaming benchmark method. Simply responds to each request
+ * with a payload containing the requested number of zero bytes.
+ * @param {Call} call The call object to be handled
+ */
+function streamingCall(call) {
+ call.on('data', function(value) {
+ var payload = {body: zeroBuffer(value.repsonse_size)};
+ call.write({payload: payload});
+ });
+ call.on('end', function() {
+ call.end();
+ });
+}
+
+/**
+ * BenchmarkServer class. Constructed based on parameters from the driver and
+ * stores statistics.
+ * @param {string} host The host to serve on
+ * @param {number} port The port to listen to
+ * @param {tls} Indicates whether TLS should be used
+ */
+function BenchmarkServer(host, port, tls) {
+ var server_creds;
+ var host_override;
+ if (tls) {
+ var key_path = path.join(__dirname, '../test/data/server1.key');
+ var pem_path = path.join(__dirname, '../test/data/server1.pem');
+
+ var key_data = fs.readFileSync(key_path);
+ var pem_data = fs.readFileSync(pem_path);
+ server_creds = grpc.ServerCredentials.createSsl(null,
+ [{private_key: key_data,
+ cert_chain: pem_data}]);
+ } else {
+ server_creds = grpc.ServerCredentials.createInsecure();
+ }
+
+ var server = new grpc.Server();
+ this.port = server.bind(host + ':' + port, server_creds);
+ server.addProtoService(serviceProto.BenchmarkService.service, {
+ unaryCall: unaryCall,
+ streamingCall: streamingCall
+ });
+ this.server = server;
+}
+
+/**
+ * Start the benchmark server.
+ */
+BenchmarkServer.prototype.start = function() {
+ this.server.start();
+ this.last_wall_time = process.hrtime();
+};
+
+/**
+ * Return the port number that the server is bound to.
+ * @return {Number} The port number
+ */
+BenchmarkServer.prototype.getPort = function() {
+ return this.port;
+};
+
+/**
+ * Return current statistics for the server. If reset is set, restart
+ * statistic collection.
+ * @param {boolean} reset Indicates that statistics should be reset
+ * @return {object} Server statistics
+ */
+BenchmarkServer.prototype.mark = function(reset) {
+ var wall_time_diff = process.hrtime(this.last_wall_time);
+ if (reset) {
+ this.last_wall_time = process.hrtime();
+ }
+ return {
+ time_elapsed: wall_time_diff[0] + wall_time_diff[1] / 1e9,
+ // Not sure how to measure these values
+ time_user: 0,
+ time_system: 0
+ };
+};
+
+/**
+ * Stop the server.
+ * @param {function} callback Called when the server has finished shutting down
+ */
+BenchmarkServer.prototype.stop = function(callback) {
+ this.server.tryShutdown(callback);
+};
+
+module.exports = BenchmarkServer;
diff --git a/src/node/performance/histogram.js b/src/node/performance/histogram.js
new file mode 100644
index 0000000000..204d7d47da
--- /dev/null
+++ b/src/node/performance/histogram.js
@@ -0,0 +1,180 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Histogram module. Exports the Histogram class
+ * @module
+ */
+
+'use strict';
+
+/**
+ * Histogram class. Collects data and exposes a histogram and other statistics.
+ * This data structure is taken directly from src/core/support/histogram.c, but
+ * pared down to the statistics needed for client stats in
+ * test/proto/benchmarks/stats.proto.
+ * @constructor
+ * @param {number} resolution The histogram's bucket resolution. Must be positive
+ * @param {number} max_possible The maximum allowed value. Must be greater than 1
+ */
+function Histogram(resolution, max_possible) {
+ this.resolution = resolution;
+ this.max_possible = max_possible;
+
+ this.sum = 0;
+ this.sum_of_squares = 0;
+ this.multiplier = 1 + resolution;
+ this.count = 0;
+ this.min_seen = max_possible;
+ this.max_seen = 0;
+ this.buckets = [];
+ for (var i = 0; i < this.bucketFor(max_possible) + 1; i++) {
+ this.buckets[i] = 0;
+ }
+}
+
+/**
+ * Get the bucket index for a given value.
+ * @param {number} value The value to check
+ * @return {number} The bucket index
+ */
+Histogram.prototype.bucketFor = function(value) {
+ return Math.floor(Math.log(value) / Math.log(this.multiplier));
+};
+
+/**
+ * Get the minimum value for a given bucket index
+ * @param {number} The bucket index to check
+ * @return {number} The minimum value for that bucket
+ */
+Histogram.prototype.bucketStart = function(index) {
+ return Math.pow(this.multiplier, index);
+};
+
+/**
+ * Add a value to the histogram. This updates all statistics with the new
+ * value. Those statistics should not be modified except with this function
+ * @param {number} value The value to add
+ */
+Histogram.prototype.add = function(value) {
+ // Ensure value is a number
+ value = +value;
+ this.sum += value;
+ this.sum_of_squares += value * value;
+ this.count++;
+ if (value < this.min_seen) {
+ this.min_seen = value;
+ }
+ if (value > this.max_seen) {
+ this.max_seen = value;
+ }
+ this.buckets[this.bucketFor(value)]++;
+};
+
+/**
+ * Get the mean of all added values
+ * @return {number} The mean
+ */
+Histogram.prototype.mean = function() {
+ return this.sum / this.count;
+};
+
+/**
+ * Get the variance of all added values. Used to calulate the standard deviation
+ * @return {number} The variance
+ */
+Histogram.prototype.variance = function() {
+ if (this.count == 0) {
+ return 0;
+ }
+ return (this.sum_of_squares * this.count - this.sum * this.sum) /
+ (this.count * this.count);
+};
+
+/**
+ * Get the standard deviation of all added values
+ * @return {number} The standard deviation
+ */
+Histogram.prototype.stddev = function() {
+ return Math.sqrt(this.variance);
+};
+
+/**
+ * Get the maximum among all added values
+ * @return {number} The maximum
+ */
+Histogram.prototype.maximum = function() {
+ return this.max_seen;
+};
+
+/**
+ * Get the minimum among all added values
+ * @return {number} The minimum
+ */
+Histogram.prototype.minimum = function() {
+ return this.min_seen;
+};
+
+/**
+ * Get the number of all added values
+ * @return {number} The count
+ */
+Histogram.prototype.getCount = function() {
+ return this.count;
+};
+
+/**
+ * Get the sum of all added values
+ * @return {number} The sum
+ */
+Histogram.prototype.getSum = function() {
+ return this.sum;
+};
+
+/**
+ * Get the sum of squares of all added values
+ * @return {number} The sum of squares
+ */
+Histogram.prototype.sumOfSquares = function() {
+ return this.sum_of_squares;
+};
+
+/**
+ * Get the raw histogram as a list of bucket sizes
+ * @return {Array.<number>} The buckets
+ */
+Histogram.prototype.getContents = function() {
+ return this.buckets;
+};
+
+module.exports = Histogram;
diff --git a/src/node/performance/perf_test.js b/src/node/performance/perf_test.js
deleted file mode 100644
index fe51e4a603..0000000000
--- a/src/node/performance/perf_test.js
+++ /dev/null
@@ -1,119 +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.
- *
- */
-
-'use strict';
-
-var grpc = require('..');
-var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
-var _ = require('lodash');
-var interop_server = require('../interop/interop_server.js');
-
-function runTest(iterations, callback) {
- var testServer = interop_server.getServer(0, false);
- testServer.server.start();
- var client = new testProto.TestService('localhost:' + testServer.port,
- grpc.credentials.createInsecure());
-
- function runIterations(finish) {
- var start = process.hrtime();
- var intervals = [];
- function next(i) {
- if (i >= iterations) {
- testServer.server.shutdown();
- var totalDiff = process.hrtime(start);
- finish({
- total: totalDiff[0] * 1000000 + totalDiff[1] / 1000,
- intervals: intervals
- });
- } else{
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + 3);
- var startTime = process.hrtime();
- client.emptyCall({}, function(err, resp) {
- var timeDiff = process.hrtime(startTime);
- intervals[i] = timeDiff[0] * 1000000 + timeDiff[1] / 1000;
- next(i+1);
- }, {}, {deadline: deadline});
- }
- }
- next(0);
- }
-
- function warmUp(num) {
- var pending = num;
- function startCall() {
- client.emptyCall({}, function(err, resp) {
- pending--;
- if (pending === 0) {
- runIterations(callback);
- }
- });
- }
- for (var i = 0; i < num; i++) {
- startCall();
- }
- }
- warmUp(100);
-}
-
-function percentile(arr, pct) {
- if (pct > 99) {
- pct = 99;
- }
- if (pct < 0) {
- pct = 0;
- }
- var index = Math.floor(arr.length * pct / 100);
- return arr[index];
-}
-
-if (require.main === module) {
- var count;
- if (process.argv.length >= 3) {
- count = process.argv[2];
- } else {
- count = 100;
- }
- runTest(count, function(results) {
- var sorted_intervals = _.sortBy(results.intervals, _.identity);
- console.log('count:', count);
- console.log('total time:', results.total, 'us');
- console.log('median:', percentile(sorted_intervals, 50), 'us');
- console.log('90th percentile:', percentile(sorted_intervals, 90), 'us');
- console.log('95th percentile:', percentile(sorted_intervals, 95), 'us');
- console.log('99th percentile:', percentile(sorted_intervals, 99), 'us');
- console.log('QPS:', (count / results.total) * 1000000);
- });
-}
-
-module.exports = runTest;
diff --git a/src/node/performance/qps_test.js b/src/node/performance/qps_test.js
deleted file mode 100644
index 491f47364c..0000000000
--- a/src/node/performance/qps_test.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-/**
- * This script runs a QPS test. It sends requests for a specified length of time
- * with a specified number pending at any one time. It then outputs the measured
- * QPS. Usage:
- * node qps_test.js [--concurrent=count] [--time=seconds]
- * concurrent defaults to 100 and time defaults to 10
- */
-
-'use strict';
-
-var async = require('async');
-var parseArgs = require('minimist');
-
-var grpc = require('..');
-var testProto = grpc.load(__dirname + '/../interop/test.proto').grpc.testing;
-var interop_server = require('../interop/interop_server.js');
-
-/**
- * Runs the QPS test. Sends requests constantly for the given number of seconds,
- * and keeps concurrent_calls requests pending at all times. When the test ends,
- * the callback is called with the number of calls that completed within the
- * time limit.
- * @param {number} concurrent_calls The number of calls to have pending
- * simultaneously
- * @param {number} seconds The number of seconds to run the test for
- * @param {function(Error, number)} callback Callback for test completion
- */
-function runTest(concurrent_calls, seconds, callback) {
- var testServer = interop_server.getServer(0, false);
- testServer.server.start();
- var client = new testProto.TestService('localhost:' + testServer.port,
- grpc.credentials.createInsecure());
-
- var warmup_num = 100;
-
- /**
- * Warms up the client to avoid counting startup time in the test result
- * @param {function(Error)} callback Called when warmup is complete
- */
- function warmUp(callback) {
- var pending = warmup_num;
- function startCall() {
- client.emptyCall({}, function(err, resp) {
- if (err) {
- callback(err);
- return;
- }
- pending--;
- if (pending === 0) {
- callback(null);
- }
- });
- }
- for (var i = 0; i < warmup_num; i++) {
- startCall();
- }
- }
- /**
- * Run the QPS test. Starts concurrent_calls requests, then starts a new
- * request whenever one completes until time runs out.
- * @param {function(Error, number)} callback Called when the test is complete.
- * The second argument is the number of calls that finished within the
- * time limit
- */
- function run(callback) {
- var running = 0;
- var count = 0;
- var start = process.hrtime();
- function responseCallback(err, resp) {
- if (process.hrtime(start)[0] < seconds) {
- count += 1;
- client.emptyCall({}, responseCallback);
- } else {
- running -= 1;
- if (running <= 0) {
- callback(null, count);
- }
- }
- }
- for (var i = 0; i < concurrent_calls; i++) {
- running += 1;
- client.emptyCall({}, responseCallback);
- }
- }
- async.waterfall([warmUp, run], function(err, count) {
- testServer.server.shutdown();
- callback(err, count);
- });
-}
-
-if (require.main === module) {
- var argv = parseArgs(process.argv.slice(2), {
- default: {'concurrent': 100,
- 'time': 10}
- });
- runTest(argv.concurrent, argv.time, function(err, count) {
- if (err) {
- throw err;
- }
- console.log('Concurrent calls:', argv.concurrent);
- console.log('Time:', argv.time, 'seconds');
- console.log('QPS:', (count/argv.time));
- });
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/module.c b/src/node/performance/worker_server.js
index 9b93b051f6..43b86e5ecf 100644
--- a/src/python/grpcio/grpc/_adapter/_c/module.c
+++ b/src/node/performance/worker_server.js
@@ -31,37 +31,33 @@
*
*/
-#include <stdlib.h>
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-#include "grpc/_adapter/_c/types.h"
-
-static PyMethodDef c_methods[] = {
- {NULL}
-};
-
-PyMODINIT_FUNC init_c(void) {
- PyObject *module;
-
- module = Py_InitModule3("_c", c_methods,
- "Wrappings of C structures and functions.");
-
- if (pygrpc_module_add_types(module) < 0) {
- return;
- }
-
- if (PyModule_AddStringConstant(
- module, "PRIMARY_USER_AGENT_KEY",
- GRPC_ARG_PRIMARY_USER_AGENT_STRING) < 0) {
- return;
- }
+'use strict';
+
+var worker_service_impl = require('./worker_service_impl');
+
+var grpc = require('../../../');
+var serviceProto = grpc.load({
+ root: __dirname + '/../../..',
+ file: 'test/proto/benchmarks/services.proto'}).grpc.testing;
+
+function runServer(port) {
+ var server_creds = grpc.ServerCredentials.createInsecure();
+ var server = new grpc.Server();
+ server.addProtoService(serviceProto.WorkerService.service,
+ worker_service_impl);
+ var address = '0.0.0.0:' + port;
+ server.bind(address, server_creds);
+ server.start();
+ return server;
+}
- /* GRPC maintains an internal counter of how many times it has been
- initialized and handles multiple pairs of grpc_init()/grpc_shutdown()
- invocations accordingly. */
- grpc_init();
- atexit(&grpc_shutdown);
+if (require.main === module) {
+ Error.stackTraceLimit = Infinity;
+ var parseArgs = require('minimist');
+ var argv = parseArgs(process.argv, {
+ string: ['driver_port']
+ });
+ runServer(argv.driver_port);
}
+
+exports.runServer = runServer;
diff --git a/src/node/performance/worker_service_impl.js b/src/node/performance/worker_service_impl.js
new file mode 100644
index 0000000000..8841ae13c3
--- /dev/null
+++ b/src/node/performance/worker_service_impl.js
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+'use strict';
+
+var BenchmarkClient = require('./benchmark_client');
+var BenchmarkServer = require('./benchmark_server');
+
+exports.runClient = function runClient(call) {
+ var client;
+ call.on('data', function(request) {
+ var stats;
+ switch (request.argtype) {
+ case 'setup':
+ var setup = request.setup;
+ client = new BenchmarkClient(setup.server_targets,
+ setup.client_channels,
+ setup.histogram_params,
+ setup.security_params);
+ client.on('error', function(error) {
+ call.emit('error', error);
+ });
+ switch (setup.load_params.load) {
+ case 'closed_loop':
+ client.startClosedLoop(setup.outstanding_rpcs_per_channel,
+ setup.rpc_type,
+ setup.payload_config.simple_params.req_size,
+ setup.payload_config.simple_params.resp_size);
+ break;
+ case 'poisson':
+ client.startPoisson(setup.outstanding_rpcs_per_channel,
+ setup.rpc_type, setup.payload_config.req_size,
+ setup.payload_config.resp_size,
+ setup.load_params.poisson.offered_load);
+ break;
+ default:
+ call.emit('error', new Error('Unsupported LoadParams type' +
+ setup.load_params.load));
+ }
+ stats = client.mark();
+ call.write({
+ stats: stats
+ });
+ break;
+ case 'mark':
+ if (client) {
+ stats = client.mark(request.mark.reset);
+ call.write({
+ stats: stats
+ });
+ } else {
+ call.emit('error', new Error('Got Mark before ClientConfig'));
+ }
+ break;
+ default:
+ throw new Error('Nonexistent client argtype option: ' + request.argtype);
+ }
+ });
+ call.on('end', function() {
+ client.stop(function() {
+ call.end();
+ });
+ });
+};
+
+exports.runServer = function runServer(call) {
+ var server;
+ call.on('data', function(request) {
+ var stats;
+ switch (request.argtype) {
+ case 'setup':
+ server = new BenchmarkServer(request.setup.host, request.setup.port,
+ request.setup.security_params);
+ server.start();
+ stats = server.mark();
+ call.write({
+ stats: stats,
+ port: server.getPort()
+ });
+ break;
+ case 'mark':
+ if (server) {
+ stats = server.mark(request.mark.reset);
+ call.write({
+ stats: stats,
+ port: server.getPort(),
+ cores: 1
+ });
+ } else {
+ call.emit('error', new Error('Got Mark before ServerConfig'));
+ }
+ break;
+ default:
+ throw new Error('Nonexistent server argtype option');
+ }
+ });
+ call.on('end', function() {
+ server.stop(function() {
+ call.end();
+ });
+ });
+};
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index ff10a22e6a..dcbfac18f4 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -91,7 +91,7 @@ exports.createSsl = ChannelCredentials.createSsl;
*/
exports.createFromMetadataGenerator = function(metadata_generator) {
return CallCredentials.createFromPlugin(function(service_url, callback) {
- metadata_generator(service_url, function(error, metadata) {
+ metadata_generator({service_url: service_url}, function(error, metadata) {
var code = grpc.status.OK;
var message = '';
if (error) {
@@ -114,7 +114,8 @@ exports.createFromMetadataGenerator = function(metadata_generator) {
* @return {CallCredentials} The resulting credentials object
*/
exports.createFromGoogleCredential = function(google_credential) {
- return exports.createFromMetadataGenerator(function(service_url, callback) {
+ return exports.createFromMetadataGenerator(function(auth_context, callback) {
+ var service_url = auth_context.service_url;
google_credential.getRequestMetadata(service_url, function(err, header) {
if (err) {
callback(err);
diff --git a/src/node/src/server.js b/src/node/src/server.js
index d1fb627e6c..ceaa9f5d1f 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -101,28 +101,6 @@ function handleError(call, error) {
}
/**
- * Wait for the client to close, then emit a cancelled event if the client
- * cancelled.
- * @access private
- * @param {grpc.Call} call The call object to wait on
- * @param {EventEmitter} emitter The event emitter to emit the cancelled event
- * on
- */
-function waitForCancel(call, emitter) {
- var cancel_batch = {};
- cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
- call.startBatch(cancel_batch, function(err, result) {
- if (err) {
- emitter.emit('error', err);
- }
- if (result.cancelled) {
- emitter.cancelled = true;
- emitter.emit('cancelled');
- }
- });
-}
-
-/**
* Send a response to a unary or client streaming call.
* @access private
* @param {grpc.Call} call The call to respond on
@@ -258,6 +236,13 @@ function setUpReadable(stream, deserialize) {
});
}
+util.inherits(ServerUnaryCall, EventEmitter);
+
+function ServerUnaryCall(call) {
+ EventEmitter.call(this);
+ this.call = call;
+}
+
util.inherits(ServerWritableStream, Writable);
/**
@@ -311,33 +296,6 @@ function _write(chunk, encoding, callback) {
ServerWritableStream.prototype._write = _write;
-/**
- * Send the initial metadata for a writable stream.
- * @param {Metadata} responseMetadata Metadata to send
- */
-function sendMetadata(responseMetadata) {
- /* jshint validthis: true */
- var self = this;
- if (!this.call.metadataSent) {
- this.call.metadataSent = true;
- var batch = [];
- batch[grpc.opType.SEND_INITIAL_METADATA] =
- responseMetadata._getCoreRepresentation();
- this.call.startBatch(batch, function(err) {
- if (err) {
- self.emit('error', err);
- return;
- }
- });
- }
-}
-
-/**
- * @inheritdoc
- * @alias module:src/server~ServerWritableStream#sendMetadata
- */
-ServerWritableStream.prototype.sendMetadata = sendMetadata;
-
util.inherits(ServerReadableStream, Readable);
/**
@@ -427,6 +385,31 @@ function ServerDuplexStream(call, serialize, deserialize) {
ServerDuplexStream.prototype._read = _read;
ServerDuplexStream.prototype._write = _write;
+
+/**
+ * Send the initial metadata for a writable stream.
+ * @param {Metadata} responseMetadata Metadata to send
+ */
+function sendMetadata(responseMetadata) {
+ /* jshint validthis: true */
+ var self = this;
+ if (!this.call.metadataSent) {
+ this.call.metadataSent = true;
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ responseMetadata._getCoreRepresentation();
+ this.call.startBatch(batch, function(err) {
+ if (err) {
+ self.emit('error', err);
+ return;
+ }
+ });
+ }
+}
+
+ServerUnaryCall.prototype.sendMetadata = sendMetadata;
+ServerWritableStream.prototype.sendMetadata = sendMetadata;
+ServerReadableStream.prototype.sendMetadata = sendMetadata;
ServerDuplexStream.prototype.sendMetadata = sendMetadata;
/**
@@ -438,11 +421,37 @@ function getPeer() {
return this.call.getPeer();
}
+ServerUnaryCall.prototype.getPeer = getPeer;
ServerReadableStream.prototype.getPeer = getPeer;
ServerWritableStream.prototype.getPeer = getPeer;
ServerDuplexStream.prototype.getPeer = getPeer;
/**
+ * Wait for the client to close, then emit a cancelled event if the client
+ * cancelled.
+ */
+function waitForCancel() {
+ /* jshint validthis: true */
+ var self = this;
+ var cancel_batch = {};
+ cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ self.call.startBatch(cancel_batch, function(err, result) {
+ if (err) {
+ self.emit('error', err);
+ }
+ if (result.cancelled) {
+ self.cancelled = true;
+ self.emit('cancelled');
+ }
+ });
+}
+
+ServerUnaryCall.prototype.waitForCancel = waitForCancel;
+ServerReadableStream.prototype.waitForCancel = waitForCancel;
+ServerWritableStream.prototype.waitForCancel = waitForCancel;
+ServerDuplexStream.prototype.waitForCancel = waitForCancel;
+
+/**
* Fully handle a unary call
* @access private
* @param {grpc.Call} call The call to handle
@@ -450,25 +459,12 @@ ServerDuplexStream.prototype.getPeer = getPeer;
* @param {Metadata} metadata Metadata from the client
*/
function handleUnary(call, handler, metadata) {
- var emitter = new EventEmitter();
- emitter.sendMetadata = function(responseMetadata) {
- if (!call.metadataSent) {
- call.metadataSent = true;
- var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] =
- responseMetadata._getCoreRepresentation();
- call.startBatch(batch, function() {});
- }
- };
- emitter.getPeer = function() {
- return call.getPeer();
- };
+ var emitter = new ServerUnaryCall(call);
emitter.on('error', function(error) {
handleError(call, error);
});
emitter.metadata = metadata;
- waitForCancel(call, emitter);
- emitter.call = call;
+ emitter.waitForCancel();
var batch = {};
batch[grpc.opType.RECV_MESSAGE] = true;
call.startBatch(batch, function(err, result) {
@@ -508,7 +504,7 @@ function handleUnary(call, handler, metadata) {
*/
function handleServerStreaming(call, handler, metadata) {
var stream = new ServerWritableStream(call, handler.serialize);
- waitForCancel(call, stream);
+ stream.waitForCancel();
stream.metadata = metadata;
var batch = {};
batch[grpc.opType.RECV_MESSAGE] = true;
@@ -537,19 +533,10 @@ function handleServerStreaming(call, handler, metadata) {
*/
function handleClientStreaming(call, handler, metadata) {
var stream = new ServerReadableStream(call, handler.deserialize);
- stream.sendMetadata = function(responseMetadata) {
- if (!call.metadataSent) {
- call.metadataSent = true;
- var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] =
- responseMetadata._getCoreRepresentation();
- call.startBatch(batch, function() {});
- }
- };
stream.on('error', function(error) {
handleError(call, error);
});
- waitForCancel(call, stream);
+ stream.waitForCancel();
stream.metadata = metadata;
handler.func(stream, function(err, value, trailer, flags) {
stream.terminate();
@@ -574,7 +561,7 @@ function handleClientStreaming(call, handler, metadata) {
function handleBidiStreaming(call, handler, metadata) {
var stream = new ServerDuplexStream(call, handler.serialize,
handler.deserialize);
- waitForCancel(call, stream);
+ stream.waitForCancel();
stream.metadata = metadata;
handler.func(stream);
}
diff --git a/src/node/test/async_test.js b/src/node/test/async_test.js
index 0af63c379e..c46e745116 100644
--- a/src/node/test/async_test.js
+++ b/src/node/test/async_test.js
@@ -36,7 +36,7 @@
var assert = require('assert');
var grpc = require('..');
-var math = grpc.load(__dirname + '/math/math.proto').math;
+var math = grpc.load(__dirname + '/../../proto/math/math.proto').math;
/**
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 647f648ca9..294600c85a 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -76,6 +76,146 @@ var fakeFailingGoogleCredentials = {
}
};
+var key_data, pem_data, ca_data;
+
+before(function() {
+ var key_path = path.join(__dirname, './data/server1.key');
+ var pem_path = path.join(__dirname, './data/server1.pem');
+ var ca_path = path.join(__dirname, '../test/data/ca.pem');
+ key_data = fs.readFileSync(key_path);
+ pem_data = fs.readFileSync(pem_path);
+ ca_data = fs.readFileSync(ca_path);
+});
+
+describe('channel credentials', function() {
+ describe('#createSsl', function() {
+ it('works with no arguments', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.credentials.createSsl();
+ });
+ assert.notEqual(creds, null);
+ });
+ it('works with just one Buffer argument', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.credentials.createSsl(ca_data);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('works with 3 Buffer arguments', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.credentials.createSsl(ca_data, key_data, pem_data);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('works if the first argument is null', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.credentials.createSsl(null, key_data, pem_data);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('fails if the first argument is a non-Buffer value', function() {
+ assert.throws(function() {
+ grpc.credentials.createSsl('test');
+ }, TypeError);
+ });
+ it('fails if the second argument is a non-Buffer value', function() {
+ assert.throws(function() {
+ grpc.credentials.createSsl(null, 'test', pem_data);
+ }, TypeError);
+ });
+ it('fails if the third argument is a non-Buffer value', function() {
+ assert.throws(function() {
+ grpc.credentials.createSsl(null, key_data, 'test');
+ }, TypeError);
+ });
+ it('fails if only 1 of the last 2 arguments is provided', function() {
+ assert.throws(function() {
+ grpc.credentials.createSsl(null, key_data);
+ });
+ assert.throws(function() {
+ grpc.credentials.createSsl(null, null, pem_data);
+ });
+ });
+ });
+});
+
+describe('server credentials', function() {
+ describe('#createSsl', function() {
+ it('accepts a buffer and array as the first 2 arguments', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.ServerCredentials.createSsl(ca_data, []);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('accepts a boolean as the third argument', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.ServerCredentials.createSsl(ca_data, [], true);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('accepts an object with two buffers in the second argument', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.ServerCredentials.createSsl(null,
+ [{private_key: key_data,
+ cert_chain: pem_data}]);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('accepts multiple objects in the second argument', function() {
+ var creds;
+ assert.doesNotThrow(function() {
+ creds = grpc.ServerCredentials.createSsl(null,
+ [{private_key: key_data,
+ cert_chain: pem_data},
+ {private_key: key_data,
+ cert_chain: pem_data}]);
+ });
+ assert.notEqual(creds, null);
+ });
+ it('fails if the second argument is not an Array', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl(ca_data, 'test');
+ }, TypeError);
+ });
+ it('fails if the first argument is a non-Buffer value', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl('test', []);
+ }, TypeError);
+ });
+ it('fails if the third argument is a non-boolean value', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl(ca_data, [], 'test');
+ }, TypeError);
+ });
+ it('fails if the array elements are not objects', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl(ca_data, 'test');
+ }, TypeError);
+ });
+ it('fails if the object does not have a Buffer private_key', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl(null,
+ [{private_key: 'test',
+ cert_chain: pem_data}]);
+ }, TypeError);
+ });
+ it('fails if the object does not have a Buffer cert_chain', function() {
+ assert.throws(function() {
+ grpc.ServerCredentials.createSsl(null,
+ [{private_key: key_data,
+ cert_chain: 'test'}]);
+ }, TypeError);
+ });
+ });
+});
+
describe('client credentials', function() {
var Client;
var server;
@@ -109,20 +249,13 @@ describe('client credentials', function() {
});
}
});
- var key_path = path.join(__dirname, './data/server1.key');
- var pem_path = path.join(__dirname, './data/server1.pem');
- var key_data = fs.readFileSync(key_path);
- var pem_data = fs.readFileSync(pem_path);
var creds = grpc.ServerCredentials.createSsl(null,
[{private_key: key_data,
cert_chain: pem_data}]);
- //creds = grpc.ServerCredentials.createInsecure();
port = server.bind('localhost:0', creds);
server.start();
Client = proto.TestService;
- var ca_path = path.join(__dirname, '../test/data/ca.pem');
- var ca_data = fs.readFileSync(ca_path);
client_ssl_creds = grpc.credentials.createSsl(ca_data);
var host_override = 'foo.test.google.fr';
client_options['grpc.ssl_target_name_override'] = host_override;
diff --git a/src/node/test/math/math.proto b/src/node/test/math/math.proto
deleted file mode 100644
index 311e148c02..0000000000
--- a/src/node/test/math/math.proto
+++ /dev/null
@@ -1,80 +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.
-
-syntax = "proto3";
-
-package math;
-
-message DivArgs {
- int64 dividend = 1;
- int64 divisor = 2;
-}
-
-message DivReply {
- int64 quotient = 1;
- int64 remainder = 2;
-}
-
-message FibArgs {
- int64 limit = 1;
-}
-
-message Num {
- int64 num = 1;
-}
-
-message FibReply {
- int64 count = 1;
-}
-
-service Math {
- // Div divides args.dividend by args.divisor and returns the quotient and
- // remainder.
- rpc Div (DivArgs) returns (DivReply) {
- }
-
- // 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.
- rpc DivMany (stream DivArgs) returns (stream DivReply) {
- }
-
- // 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.
- rpc Fib (FibArgs) returns (stream Num) {
- }
-
- // Sum sums a stream of numbers, returning the final result once the stream
- // is closed.
- rpc Sum (stream Num) returns (Num) {
- }
-}
diff --git a/src/node/test/math/math_server.js b/src/node/test/math/math_server.js
index 9d06596f3d..9f67c52ab0 100644
--- a/src/node/test/math/math_server.js
+++ b/src/node/test/math/math_server.js
@@ -34,7 +34,8 @@
'use strict';
var grpc = require('../..');
-var math = grpc.load(__dirname + '/math.proto').math;
+var math = grpc.load(__dirname + '/../../../proto/math/math.proto').math;
+
/**
* Server function for division. Provides the /Math/DivMany and /Math/Div
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 6361d97857..3d44610536 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -36,7 +36,7 @@
var assert = require('assert');
var grpc = require('..');
-var math = grpc.load(__dirname + '/math/math.proto').math;
+var math = grpc.load(__dirname + '/../../proto/math/math.proto').math;
/**
* Client to use to make requests to a running server.
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 999a183b3c..592f47e145 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -45,9 +45,30 @@ describe('server', function() {
new grpc.Server();
});
});
- it('should work with an empty list argument', function() {
+ it('should work with an empty object argument', function() {
assert.doesNotThrow(function() {
- new grpc.Server([]);
+ new grpc.Server({});
+ });
+ });
+ it('should work without the new keyword', function() {
+ var server;
+ assert.doesNotThrow(function() {
+ server = grpc.Server();
+ });
+ assert(server instanceof grpc.Server);
+ });
+ it('should only accept objects with string or int values', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Server({'key' : 'value'});
+ });
+ assert.doesNotThrow(function() {
+ new grpc.Server({'key' : 5});
+ });
+ assert.throws(function() {
+ new grpc.Server({'key' : null});
+ });
+ assert.throws(function() {
+ new grpc.Server({'key' : new Date()});
});
});
});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 39673e4e05..fc765ed731 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -41,7 +41,8 @@ var ProtoBuf = require('protobufjs');
var grpc = require('..');
-var math_proto = ProtoBuf.loadProtoFile(__dirname + '/math/math.proto');
+var math_proto = ProtoBuf.loadProtoFile(__dirname +
+ '/../../proto/math/math.proto');
var mathService = math_proto.lookup('math.Math');
@@ -312,6 +313,54 @@ describe('Generic client and server', function() {
});
});
});
+describe('Server-side getPeer', function() {
+ function toString(val) {
+ return val.toString();
+ }
+ function toBuffer(str) {
+ return new Buffer(str);
+ }
+ var string_service_attrs = {
+ 'getPeer' : {
+ path: '/string/getPeer',
+ requestStream: false,
+ responseStream: false,
+ requestSerialize: toBuffer,
+ requestDeserialize: toString,
+ responseSerialize: toBuffer,
+ responseDeserialize: toString
+ }
+ };
+ var client;
+ var server;
+ before(function() {
+ server = new grpc.Server();
+ server.addService(string_service_attrs, {
+ getPeer: function(call, callback) {
+ try {
+ callback(null, call.getPeer());
+ } catch (e) {
+ call.emit('error', e);
+ }
+ }
+ });
+ var port = server.bind('localhost:0', server_insecure_creds);
+ server.start();
+ var Client = grpc.makeGenericClientConstructor(string_service_attrs);
+ client = new Client('localhost:' + port,
+ grpc.credentials.createInsecure());
+ });
+ after(function() {
+ server.forceShutdown();
+ });
+ it('should respond with a string representing the client', function(done) {
+ client.getPeer('', function(err, response) {
+ assert.ifError(err);
+ // We don't expect a specific value, just that it worked without error
+ done();
+ });
+ });
+});
describe('Echo metadata', function() {
var client;
var server;
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
new file mode 100644
index 0000000000..f5b738203d
--- /dev/null
+++ b/src/objective-c/BoringSSL.podspec
@@ -0,0 +1,1428 @@
+# BoringSSL CocoaPods podspec
+
+# 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.
+
+Pod::Spec.new do |s|
+ s.name = 'BoringSSL'
+ s.version = '1.0'
+ s.summary = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
+ # Adapted from the homepage:
+ s.description = <<-DESC
+ BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.
+
+ Although BoringSSL is an open source project, it is not intended for general use, as OpenSSL is.
+ We don’t recommend that third parties depend upon it. Doing so is likely to be frustrating
+ because there are no guarantees of API stability. Only the latest version of this pod is
+ supported, and every new version is a new major version.
+
+ We update Google libraries and programs that use BoringSSL as needed when deciding to make API
+ changes. This allows us to mostly avoid compromises in the name of compatibility. It works for
+ us, but it may not work for you.
+
+ As a Cocoapods pod, it has the advantage over OpenSSL's pods that the library doesn't need to
+ be precompiled. This eliminates the 10 - 20 minutes of wait the first time a user does "pod
+ install", lets it be used as a dynamic framework (pending solution of Cocoapods' issue #4605),
+ and works with bitcode automatically. It's also thought to be smaller than OpenSSL (which takes
+ 1MB - 2MB per ARM architecture), but we don't have specific numbers yet.
+
+ BoringSSL arose because Google used OpenSSL for many years in various ways and, over time, built
+ up a large number of patches that were maintained while tracking upstream OpenSSL. As Google’s
+ product portfolio became more complex, more copies of OpenSSL sprung up and the effort involved
+ in maintaining all these patches in multiple places was growing steadily.
+
+ Currently BoringSSL is the SSL library in Chrome/Chromium, Android (but it’s not part of the
+ NDK) and a number of other apps/programs.
+ DESC
+ s.homepage = 'https://boringssl.googlesource.com/boringssl/'
+ s.documentation_url = 'https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html'
+ s.license = { :type => 'Mixed', :file => 'LICENSE' }
+ # "The name and email addresses of the library maintainers, not the Podspec maintainer."
+ s.authors = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite'
+
+ s.source = { :git => 'https://boringssl.googlesource.com/boringssl',
+ :tag => 'version_for_cocoapods_1.0' }
+
+ s.source_files = 'ssl/*.{h,c}',
+ 'ssl/**/*.{h,c}',
+ '*.{h,c}',
+ 'crypto/*.{h,c}',
+ 'crypto/**/*.{h,c}',
+ 'include/openssl/*.h'
+
+ s.public_header_files = 'include/openssl/*.h'
+ s.header_mappings_dir = 'include'
+
+ s.exclude_files = "**/*_test.*"
+
+ # We don't need to inhibit all warnings; only -Wno-shorten-64-to-32. But Cocoapods' linter doesn't
+ # want that for some reason.
+ s.compiler_flags = '-DOPENSSL_NO_ASM', '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
+ s.requires_arc = false
+
+ s.prepare_command = <<-END_OF_COMMAND
+ # Replace "const BIGNUM *I" in rsa.h with a lowercase i, as the former fails when including
+ # OpenSSL in a Swift bridging header (complex.h defines "I", and it's as if the compiler
+ # included it in every bridged header).
+ sed -E -i '.back' 's/\\*I,/*i,/g' include/openssl/rsa.h
+
+ # This is a bit ridiculous, but requiring people to install Go in order to build is slightly
+ # more ridiculous IMO. To save you from scrolling, this is the last part of the podspec.
+ # TODO(jcanizales): Translate err_data_generate.go into a Bash or Ruby script.
+ cat > err_data.c <<EOF
+ /* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+ /* This file was generated by err_data_generate.go. */
+
+ #include <openssl/base.h>
+ #include <openssl/err.h>
+ #include <openssl/type_check.h>
+
+
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_NONE == 1, library_values_changed_1);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_SYS == 2, library_values_changed_2);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_BN == 3, library_values_changed_3);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_RSA == 4, library_values_changed_4);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_DH == 5, library_values_changed_5);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_EVP == 6, library_values_changed_6);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_BUF == 7, library_values_changed_7);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_OBJ == 8, library_values_changed_8);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_PEM == 9, library_values_changed_9);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_DSA == 10, library_values_changed_10);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_X509 == 11, library_values_changed_11);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_ASN1 == 12, library_values_changed_12);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_CONF == 13, library_values_changed_13);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_CRYPTO == 14, library_values_changed_14);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_EC == 15, library_values_changed_15);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_SSL == 16, library_values_changed_16);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_BIO == 17, library_values_changed_17);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS7 == 18, library_values_changed_18);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_PKCS8 == 19, library_values_changed_19);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_X509V3 == 20, library_values_changed_20);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_RAND == 21, library_values_changed_21);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_ENGINE == 22, library_values_changed_22);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_OCSP == 23, library_values_changed_23);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_UI == 24, library_values_changed_24);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_COMP == 25, library_values_changed_25);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDSA == 26, library_values_changed_26);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_ECDH == 27, library_values_changed_27);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_HMAC == 28, library_values_changed_28);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_DIGEST == 29, library_values_changed_29);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_CIPHER == 30, library_values_changed_30);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_HKDF == 31, library_values_changed_31);
+ OPENSSL_COMPILE_ASSERT(ERR_LIB_USER == 32, library_values_changed_32);
+ OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == 33, library_values_changed_num);
+
+ const uint32_t kOpenSSLReasonValues[] = {
+ 0xc3207ba,
+ 0xc3287d4,
+ 0xc3307e3,
+ 0xc3387f3,
+ 0xc340802,
+ 0xc34881b,
+ 0xc350827,
+ 0xc358844,
+ 0xc360856,
+ 0xc368864,
+ 0xc370874,
+ 0xc378881,
+ 0xc380891,
+ 0xc38889c,
+ 0xc3908b2,
+ 0xc3988c1,
+ 0xc3a08d5,
+ 0xc3a87c7,
+ 0xc3b00b0,
+ 0x10321478,
+ 0x10329484,
+ 0x1033149d,
+ 0x103394b0,
+ 0x10340de1,
+ 0x103494cf,
+ 0x103514e4,
+ 0x10359516,
+ 0x1036152f,
+ 0x10369544,
+ 0x10371562,
+ 0x10379571,
+ 0x1038158d,
+ 0x103895a8,
+ 0x103915b7,
+ 0x103995d3,
+ 0x103a15ee,
+ 0x103a9605,
+ 0x103b1616,
+ 0x103b962a,
+ 0x103c1649,
+ 0x103c9658,
+ 0x103d166f,
+ 0x103d9682,
+ 0x103e0b6c,
+ 0x103e96b3,
+ 0x103f16c6,
+ 0x103f96e0,
+ 0x104016f0,
+ 0x10409704,
+ 0x1041171a,
+ 0x10419732,
+ 0x10421747,
+ 0x1042975b,
+ 0x1043176d,
+ 0x104385d0,
+ 0x104408c1,
+ 0x10449782,
+ 0x10451799,
+ 0x104597ae,
+ 0x104617bc,
+ 0x10469695,
+ 0x104714f7,
+ 0x104787c7,
+ 0x104800b0,
+ 0x104894c3,
+ 0x14320b4f,
+ 0x14328b5d,
+ 0x14330b6c,
+ 0x14338b7e,
+ 0x18320083,
+ 0x18328e47,
+ 0x18340e75,
+ 0x18348e89,
+ 0x18358ec0,
+ 0x18368eed,
+ 0x18370f00,
+ 0x18378f14,
+ 0x18380f38,
+ 0x18388f46,
+ 0x18390f5c,
+ 0x18398f70,
+ 0x183a0f80,
+ 0x183b0f90,
+ 0x183b8fa5,
+ 0x183c8fd0,
+ 0x183d0fe4,
+ 0x183d8ff4,
+ 0x183e0b9b,
+ 0x183e9001,
+ 0x183f1013,
+ 0x183f901e,
+ 0x1840102e,
+ 0x1840903f,
+ 0x18411050,
+ 0x18419062,
+ 0x1842108b,
+ 0x184290bd,
+ 0x184310cc,
+ 0x18451135,
+ 0x1845914b,
+ 0x18461166,
+ 0x18468ed8,
+ 0x184709d9,
+ 0x18478094,
+ 0x18480fbc,
+ 0x18489101,
+ 0x18490e5d,
+ 0x18498e9e,
+ 0x184a119c,
+ 0x184a9119,
+ 0x184b10e0,
+ 0x184b8e37,
+ 0x184c10a4,
+ 0x184c866b,
+ 0x184d1181,
+ 0x203211c3,
+ 0x243211cf,
+ 0x24328907,
+ 0x243311e1,
+ 0x243391ee,
+ 0x243411fb,
+ 0x2434920d,
+ 0x2435121c,
+ 0x24359239,
+ 0x24361246,
+ 0x24369254,
+ 0x24371262,
+ 0x24379270,
+ 0x24381279,
+ 0x24389286,
+ 0x24391299,
+ 0x28320b8f,
+ 0x28328b9b,
+ 0x28330b6c,
+ 0x28338bae,
+ 0x2c322c0b,
+ 0x2c32ac19,
+ 0x2c332c2b,
+ 0x2c33ac3d,
+ 0x2c342c51,
+ 0x2c34ac63,
+ 0x2c352c7e,
+ 0x2c35ac90,
+ 0x2c362ca3,
+ 0x2c3682f3,
+ 0x2c372cb0,
+ 0x2c37acc2,
+ 0x2c382cd5,
+ 0x2c38ace3,
+ 0x2c392cf3,
+ 0x2c39ad05,
+ 0x2c3a2d19,
+ 0x2c3aad2a,
+ 0x2c3b1359,
+ 0x2c3bad3b,
+ 0x2c3c2d4f,
+ 0x2c3cad65,
+ 0x2c3d2d7e,
+ 0x2c3dadac,
+ 0x2c3e2dba,
+ 0x2c3eadd2,
+ 0x2c3f2dea,
+ 0x2c3fadf7,
+ 0x2c402e1a,
+ 0x2c40ae39,
+ 0x2c4111c3,
+ 0x2c41ae4a,
+ 0x2c422e5d,
+ 0x2c429135,
+ 0x2c432e6e,
+ 0x2c4386a2,
+ 0x2c442d9b,
+ 0x30320000,
+ 0x30328015,
+ 0x3033001f,
+ 0x30338038,
+ 0x3034004a,
+ 0x30348064,
+ 0x3035006b,
+ 0x30358083,
+ 0x30360094,
+ 0x303680a1,
+ 0x303700b0,
+ 0x303780bd,
+ 0x303800d0,
+ 0x303880eb,
+ 0x30390100,
+ 0x30398114,
+ 0x303a0128,
+ 0x303a8139,
+ 0x303b0152,
+ 0x303b816f,
+ 0x303c017d,
+ 0x303c8191,
+ 0x303d01a1,
+ 0x303d81ba,
+ 0x303e01ca,
+ 0x303e81dd,
+ 0x303f01ec,
+ 0x303f81f8,
+ 0x3040020d,
+ 0x3040821d,
+ 0x30410234,
+ 0x30418241,
+ 0x30420254,
+ 0x30428263,
+ 0x30430278,
+ 0x30438299,
+ 0x304402ac,
+ 0x304482bf,
+ 0x304502d8,
+ 0x304582f3,
+ 0x30460310,
+ 0x30468329,
+ 0x30470337,
+ 0x30478348,
+ 0x30480357,
+ 0x3048836f,
+ 0x30490381,
+ 0x30498395,
+ 0x304a03b4,
+ 0x304a83c7,
+ 0x304b03d2,
+ 0x304b83e1,
+ 0x304c03f2,
+ 0x304c83fe,
+ 0x304d0414,
+ 0x304d8422,
+ 0x304e0438,
+ 0x304e844a,
+ 0x304f045c,
+ 0x304f846f,
+ 0x30500482,
+ 0x30508493,
+ 0x305104a3,
+ 0x305184bb,
+ 0x305204d0,
+ 0x305284e8,
+ 0x305304fc,
+ 0x30538514,
+ 0x3054052d,
+ 0x30548546,
+ 0x30550563,
+ 0x3055856e,
+ 0x30560586,
+ 0x30568596,
+ 0x305705a7,
+ 0x305785ba,
+ 0x305805d0,
+ 0x305885d9,
+ 0x305905ee,
+ 0x30598601,
+ 0x305a0610,
+ 0x305a8630,
+ 0x305b063f,
+ 0x305b864b,
+ 0x305c066b,
+ 0x305c8687,
+ 0x305d0698,
+ 0x305d86a2,
+ 0x34320ac9,
+ 0x34328add,
+ 0x34330afa,
+ 0x34338b0d,
+ 0x34340b1c,
+ 0x34348b39,
+ 0x3c320083,
+ 0x3c328bd8,
+ 0x3c330bf1,
+ 0x3c338c0c,
+ 0x3c340c29,
+ 0x3c348c44,
+ 0x3c350c5f,
+ 0x3c358c74,
+ 0x3c360c8d,
+ 0x3c368ca5,
+ 0x3c370cb6,
+ 0x3c378cc4,
+ 0x3c380cd1,
+ 0x3c388ce5,
+ 0x3c390b9b,
+ 0x3c398cf9,
+ 0x3c3a0d0d,
+ 0x3c3a8881,
+ 0x3c3b0d1d,
+ 0x3c3b8d38,
+ 0x3c3c0d4a,
+ 0x3c3c8d60,
+ 0x3c3d0d6a,
+ 0x3c3d8d7e,
+ 0x3c3e0d8c,
+ 0x3c3e8db1,
+ 0x3c3f0bc4,
+ 0x3c3f8d9a,
+ 0x403217d3,
+ 0x403297e9,
+ 0x40331817,
+ 0x40339821,
+ 0x40341838,
+ 0x40349856,
+ 0x40351866,
+ 0x40359878,
+ 0x40361885,
+ 0x40369891,
+ 0x403718a6,
+ 0x403798bb,
+ 0x403818cd,
+ 0x403898d8,
+ 0x403918ea,
+ 0x40398de1,
+ 0x403a18fa,
+ 0x403a990d,
+ 0x403b192e,
+ 0x403b993f,
+ 0x403c194f,
+ 0x403c8064,
+ 0x403d195b,
+ 0x403d9977,
+ 0x403e198d,
+ 0x403e999c,
+ 0x403f19af,
+ 0x403f99c9,
+ 0x404019d7,
+ 0x404099ec,
+ 0x40411a00,
+ 0x40419a1d,
+ 0x40421a36,
+ 0x40429a51,
+ 0x40431a6a,
+ 0x40439a7d,
+ 0x40441a91,
+ 0x40449aa9,
+ 0x40451af4,
+ 0x40459b02,
+ 0x40461b20,
+ 0x40468094,
+ 0x40471b35,
+ 0x40479b47,
+ 0x40481b6b,
+ 0x40489b99,
+ 0x40491bad,
+ 0x40499bc2,
+ 0x404a1bdb,
+ 0x404a9c15,
+ 0x404b1c46,
+ 0x404b9c7c,
+ 0x404c1c97,
+ 0x404c9cb1,
+ 0x404d1cc8,
+ 0x404d9cf0,
+ 0x404e1d07,
+ 0x404e9d23,
+ 0x404f1d3f,
+ 0x404f9d60,
+ 0x40501d82,
+ 0x40509d9e,
+ 0x40511db2,
+ 0x40519dbf,
+ 0x40521dd6,
+ 0x40529de6,
+ 0x40531df6,
+ 0x40539e0a,
+ 0x40541e25,
+ 0x40549e35,
+ 0x40551e4c,
+ 0x40559e5b,
+ 0x40561e88,
+ 0x40569ea0,
+ 0x40571ebc,
+ 0x40579ed5,
+ 0x40581ee8,
+ 0x40589efd,
+ 0x40591f20,
+ 0x40599f4b,
+ 0x405a1f58,
+ 0x405a9f71,
+ 0x405b1f89,
+ 0x405b9f9c,
+ 0x405c1fb1,
+ 0x405c9fc3,
+ 0x405d1fd8,
+ 0x405d9fe8,
+ 0x405e2001,
+ 0x405ea015,
+ 0x405f2025,
+ 0x405fa03d,
+ 0x4060204e,
+ 0x4060a061,
+ 0x40612072,
+ 0x4061a090,
+ 0x406220a1,
+ 0x4062a0ae,
+ 0x406320c5,
+ 0x4063a106,
+ 0x4064211d,
+ 0x4064a12a,
+ 0x40652138,
+ 0x4065a15a,
+ 0x40662182,
+ 0x4066a197,
+ 0x406721ae,
+ 0x4067a1bf,
+ 0x406821d0,
+ 0x4068a1e1,
+ 0x406921f6,
+ 0x4069a20d,
+ 0x406a221e,
+ 0x406aa237,
+ 0x406b2252,
+ 0x406ba269,
+ 0x406c22d6,
+ 0x406ca2f7,
+ 0x406d230a,
+ 0x406da32b,
+ 0x406e2346,
+ 0x406ea38f,
+ 0x406f23b0,
+ 0x406fa3d6,
+ 0x407023f6,
+ 0x4070a412,
+ 0x4071259f,
+ 0x4071a5c2,
+ 0x407225d8,
+ 0x4072a5f7,
+ 0x4073260f,
+ 0x4073a62f,
+ 0x40742859,
+ 0x4074a87e,
+ 0x40752899,
+ 0x4075a8b8,
+ 0x407628e7,
+ 0x4076a90f,
+ 0x40772940,
+ 0x4077a95f,
+ 0x40782999,
+ 0x4078a9b0,
+ 0x407929c3,
+ 0x4079a9e0,
+ 0x407a0782,
+ 0x407aa9f2,
+ 0x407b2a05,
+ 0x407baa1e,
+ 0x407c2a36,
+ 0x407c90bd,
+ 0x407d2a4a,
+ 0x407daa64,
+ 0x407e2a75,
+ 0x407eaa89,
+ 0x407f2a97,
+ 0x407faab2,
+ 0x40801286,
+ 0x4080aad7,
+ 0x40812af9,
+ 0x4081ab14,
+ 0x40822b29,
+ 0x4082ab41,
+ 0x40832b59,
+ 0x4083ab70,
+ 0x40842b86,
+ 0x4084ab92,
+ 0x40852ba5,
+ 0x4085abba,
+ 0x40862bcc,
+ 0x4086abe1,
+ 0x40872bea,
+ 0x40879cde,
+ 0x40880083,
+ 0x4088a0e5,
+ 0x40890a17,
+ 0x4089a281,
+ 0x408a1bfe,
+ 0x408aa2ab,
+ 0x408b2928,
+ 0x408ba984,
+ 0x408c2361,
+ 0x408c9c2f,
+ 0x408d1c64,
+ 0x408d9e76,
+ 0x408e1ab9,
+ 0x408e9add,
+ 0x408f1f2e,
+ 0x408f9b8b,
+ 0x41f424ca,
+ 0x41f9255c,
+ 0x41fe244f,
+ 0x41fea680,
+ 0x41ff2771,
+ 0x420324e3,
+ 0x42082505,
+ 0x4208a541,
+ 0x42092433,
+ 0x4209a57b,
+ 0x420a248a,
+ 0x420aa46a,
+ 0x420b24aa,
+ 0x420ba523,
+ 0x420c278d,
+ 0x420ca64d,
+ 0x420d2667,
+ 0x420da69e,
+ 0x421226b8,
+ 0x42172754,
+ 0x4217a6fa,
+ 0x421c271c,
+ 0x421f26d7,
+ 0x422127a4,
+ 0x42262737,
+ 0x422b283d,
+ 0x422ba806,
+ 0x422c2825,
+ 0x422ca7e0,
+ 0x422d27bf,
+ 0x443206ad,
+ 0x443286bc,
+ 0x443306c8,
+ 0x443386d6,
+ 0x443406e9,
+ 0x443486fa,
+ 0x44350701,
+ 0x4435870b,
+ 0x4436071e,
+ 0x44368734,
+ 0x44370746,
+ 0x44378753,
+ 0x44380762,
+ 0x4438876a,
+ 0x44390782,
+ 0x44398790,
+ 0x443a07a3,
+ 0x4c3212b0,
+ 0x4c3292c0,
+ 0x4c3312d3,
+ 0x4c3392f3,
+ 0x4c340094,
+ 0x4c3480b0,
+ 0x4c3512ff,
+ 0x4c35930d,
+ 0x4c361329,
+ 0x4c36933c,
+ 0x4c37134b,
+ 0x4c379359,
+ 0x4c38136e,
+ 0x4c38937a,
+ 0x4c39139a,
+ 0x4c3993c4,
+ 0x4c3a13dd,
+ 0x4c3a93f6,
+ 0x4c3b05d0,
+ 0x4c3b940f,
+ 0x4c3c1421,
+ 0x4c3c9430,
+ 0x4c3d10bd,
+ 0x4c3d9449,
+ 0x4c3e1456,
+ 0x50322e80,
+ 0x5032ae8f,
+ 0x50332e9a,
+ 0x5033aeaa,
+ 0x50342ec3,
+ 0x5034aedd,
+ 0x50352eeb,
+ 0x5035af01,
+ 0x50362f13,
+ 0x5036af29,
+ 0x50372f42,
+ 0x5037af55,
+ 0x50382f6d,
+ 0x5038af7e,
+ 0x50392f93,
+ 0x5039afa7,
+ 0x503a2fc7,
+ 0x503aafdd,
+ 0x503b2ff5,
+ 0x503bb007,
+ 0x503c3023,
+ 0x503cb03a,
+ 0x503d3053,
+ 0x503db069,
+ 0x503e3076,
+ 0x503eb08c,
+ 0x503f309e,
+ 0x503f8348,
+ 0x504030b1,
+ 0x5040b0c1,
+ 0x504130db,
+ 0x5041b0ea,
+ 0x50423104,
+ 0x5042b121,
+ 0x50433131,
+ 0x5043b141,
+ 0x50443150,
+ 0x50448414,
+ 0x50453164,
+ 0x5045b182,
+ 0x50463195,
+ 0x5046b1ab,
+ 0x504731bd,
+ 0x5047b1d2,
+ 0x504831f8,
+ 0x5048b206,
+ 0x50493219,
+ 0x5049b22e,
+ 0x504a3244,
+ 0x504ab254,
+ 0x504b3274,
+ 0x504bb287,
+ 0x504c32aa,
+ 0x504cb2d8,
+ 0x504d32ea,
+ 0x504db307,
+ 0x504e3322,
+ 0x504eb33e,
+ 0x504f3350,
+ 0x504fb367,
+ 0x50503376,
+ 0x50508687,
+ 0x50513389,
+ 0x58320e1f,
+ 0x68320de1,
+ 0x68328b9b,
+ 0x68330bae,
+ 0x68338def,
+ 0x68340dff,
+ 0x683480b0,
+ 0x6c320dbd,
+ 0x6c328b7e,
+ 0x6c330dc8,
+ 0x7432098d,
+ 0x783208f2,
+ 0x78328907,
+ 0x78330913,
+ 0x78338083,
+ 0x78340922,
+ 0x78348937,
+ 0x78350956,
+ 0x78358978,
+ 0x7836098d,
+ 0x783689a3,
+ 0x783709b3,
+ 0x783789c6,
+ 0x783809d9,
+ 0x783889eb,
+ 0x783909f8,
+ 0x78398a17,
+ 0x783a0a2c,
+ 0x783a8a3a,
+ 0x783b0a44,
+ 0x783b8a58,
+ 0x783c0a6f,
+ 0x783c8a84,
+ 0x783d0a9b,
+ 0x783d8ab0,
+ 0x783e0a06,
+ 0x7c3211b2,
+ };
+
+ const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]);
+
+ const char kOpenSSLReasonStringData[] =
+ "ASN1_LENGTH_MISMATCH\\0"
+ "AUX_ERROR\\0"
+ "BAD_GET_ASN1_OBJECT_CALL\\0"
+ "BAD_OBJECT_HEADER\\0"
+ "BMPSTRING_IS_WRONG_LENGTH\\0"
+ "BN_LIB\\0"
+ "BOOLEAN_IS_WRONG_LENGTH\\0"
+ "BUFFER_TOO_SMALL\\0"
+ "DECODE_ERROR\\0"
+ "DEPTH_EXCEEDED\\0"
+ "ENCODE_ERROR\\0"
+ "ERROR_GETTING_TIME\\0"
+ "EXPECTING_AN_ASN1_SEQUENCE\\0"
+ "EXPECTING_AN_INTEGER\\0"
+ "EXPECTING_AN_OBJECT\\0"
+ "EXPECTING_A_BOOLEAN\\0"
+ "EXPECTING_A_TIME\\0"
+ "EXPLICIT_LENGTH_MISMATCH\\0"
+ "EXPLICIT_TAG_NOT_CONSTRUCTED\\0"
+ "FIELD_MISSING\\0"
+ "FIRST_NUM_TOO_LARGE\\0"
+ "HEADER_TOO_LONG\\0"
+ "ILLEGAL_BITSTRING_FORMAT\\0"
+ "ILLEGAL_BOOLEAN\\0"
+ "ILLEGAL_CHARACTERS\\0"
+ "ILLEGAL_FORMAT\\0"
+ "ILLEGAL_HEX\\0"
+ "ILLEGAL_IMPLICIT_TAG\\0"
+ "ILLEGAL_INTEGER\\0"
+ "ILLEGAL_NESTED_TAGGING\\0"
+ "ILLEGAL_NULL\\0"
+ "ILLEGAL_NULL_VALUE\\0"
+ "ILLEGAL_OBJECT\\0"
+ "ILLEGAL_OPTIONAL_ANY\\0"
+ "ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE\\0"
+ "ILLEGAL_TAGGED_ANY\\0"
+ "ILLEGAL_TIME_VALUE\\0"
+ "INTEGER_NOT_ASCII_FORMAT\\0"
+ "INTEGER_TOO_LARGE_FOR_LONG\\0"
+ "INVALID_BIT_STRING_BITS_LEFT\\0"
+ "INVALID_BMPSTRING_LENGTH\\0"
+ "INVALID_DIGIT\\0"
+ "INVALID_MODIFIER\\0"
+ "INVALID_NUMBER\\0"
+ "INVALID_OBJECT_ENCODING\\0"
+ "INVALID_SEPARATOR\\0"
+ "INVALID_TIME_FORMAT\\0"
+ "INVALID_UNIVERSALSTRING_LENGTH\\0"
+ "INVALID_UTF8STRING\\0"
+ "LIST_ERROR\\0"
+ "MALLOC_FAILURE\\0"
+ "MISSING_ASN1_EOS\\0"
+ "MISSING_EOC\\0"
+ "MISSING_SECOND_NUMBER\\0"
+ "MISSING_VALUE\\0"
+ "MSTRING_NOT_UNIVERSAL\\0"
+ "MSTRING_WRONG_TAG\\0"
+ "NESTED_ASN1_ERROR\\0"
+ "NESTED_ASN1_STRING\\0"
+ "NON_HEX_CHARACTERS\\0"
+ "NOT_ASCII_FORMAT\\0"
+ "NOT_ENOUGH_DATA\\0"
+ "NO_MATCHING_CHOICE_TYPE\\0"
+ "NULL_IS_WRONG_LENGTH\\0"
+ "OBJECT_NOT_ASCII_FORMAT\\0"
+ "ODD_NUMBER_OF_CHARS\\0"
+ "SECOND_NUMBER_TOO_LARGE\\0"
+ "SEQUENCE_LENGTH_MISMATCH\\0"
+ "SEQUENCE_NOT_CONSTRUCTED\\0"
+ "SEQUENCE_OR_SET_NEEDS_CONFIG\\0"
+ "SHORT_LINE\\0"
+ "STREAMING_NOT_SUPPORTED\\0"
+ "STRING_TOO_LONG\\0"
+ "STRING_TOO_SHORT\\0"
+ "TAG_VALUE_TOO_HIGH\\0"
+ "TIME_NOT_ASCII_FORMAT\\0"
+ "TOO_LONG\\0"
+ "TYPE_NOT_CONSTRUCTED\\0"
+ "TYPE_NOT_PRIMITIVE\\0"
+ "UNEXPECTED_EOC\\0"
+ "UNIVERSALSTRING_IS_WRONG_LENGTH\\0"
+ "UNKNOWN_FORMAT\\0"
+ "UNKNOWN_TAG\\0"
+ "UNSUPPORTED_ANY_DEFINED_BY_TYPE\\0"
+ "UNSUPPORTED_PUBLIC_KEY_TYPE\\0"
+ "UNSUPPORTED_TYPE\\0"
+ "WRONG_TAG\\0"
+ "WRONG_TYPE\\0"
+ "BAD_FOPEN_MODE\\0"
+ "BROKEN_PIPE\\0"
+ "CONNECT_ERROR\\0"
+ "ERROR_SETTING_NBIO\\0"
+ "INVALID_ARGUMENT\\0"
+ "IN_USE\\0"
+ "KEEPALIVE\\0"
+ "NBIO_CONNECT_ERROR\\0"
+ "NO_HOSTNAME_SPECIFIED\\0"
+ "NO_PORT_SPECIFIED\\0"
+ "NO_SUCH_FILE\\0"
+ "NULL_PARAMETER\\0"
+ "SYS_LIB\\0"
+ "UNABLE_TO_CREATE_SOCKET\\0"
+ "UNINITIALIZED\\0"
+ "UNSUPPORTED_METHOD\\0"
+ "WRITE_TO_READ_ONLY_BIO\\0"
+ "ARG2_LT_ARG3\\0"
+ "BAD_ENCODING\\0"
+ "BAD_RECIPROCAL\\0"
+ "BIGNUM_TOO_LONG\\0"
+ "BITS_TOO_SMALL\\0"
+ "CALLED_WITH_EVEN_MODULUS\\0"
+ "DIV_BY_ZERO\\0"
+ "EXPAND_ON_STATIC_BIGNUM_DATA\\0"
+ "INPUT_NOT_REDUCED\\0"
+ "INVALID_RANGE\\0"
+ "NEGATIVE_NUMBER\\0"
+ "NOT_A_SQUARE\\0"
+ "NOT_INITIALIZED\\0"
+ "NO_INVERSE\\0"
+ "PRIVATE_KEY_TOO_LARGE\\0"
+ "P_IS_NOT_PRIME\\0"
+ "TOO_MANY_ITERATIONS\\0"
+ "TOO_MANY_TEMPORARY_VARIABLES\\0"
+ "AES_KEY_SETUP_FAILED\\0"
+ "BAD_DECRYPT\\0"
+ "BAD_KEY_LENGTH\\0"
+ "CTRL_NOT_IMPLEMENTED\\0"
+ "CTRL_OPERATION_NOT_IMPLEMENTED\\0"
+ "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH\\0"
+ "INITIALIZATION_ERROR\\0"
+ "INPUT_NOT_INITIALIZED\\0"
+ "INVALID_AD_SIZE\\0"
+ "INVALID_KEY_LENGTH\\0"
+ "INVALID_NONCE_SIZE\\0"
+ "INVALID_OPERATION\\0"
+ "IV_TOO_LARGE\\0"
+ "NO_CIPHER_SET\\0"
+ "NO_DIRECTION_SET\\0"
+ "OUTPUT_ALIASES_INPUT\\0"
+ "TAG_TOO_LARGE\\0"
+ "TOO_LARGE\\0"
+ "UNSUPPORTED_AD_SIZE\\0"
+ "UNSUPPORTED_INPUT_SIZE\\0"
+ "UNSUPPORTED_KEY_SIZE\\0"
+ "UNSUPPORTED_NONCE_SIZE\\0"
+ "UNSUPPORTED_TAG_SIZE\\0"
+ "WRONG_FINAL_BLOCK_LENGTH\\0"
+ "LIST_CANNOT_BE_NULL\\0"
+ "MISSING_CLOSE_SQUARE_BRACKET\\0"
+ "MISSING_EQUAL_SIGN\\0"
+ "NO_CLOSE_BRACE\\0"
+ "UNABLE_TO_CREATE_NEW_SECTION\\0"
+ "VARIABLE_HAS_NO_VALUE\\0"
+ "BAD_GENERATOR\\0"
+ "INVALID_PUBKEY\\0"
+ "MODULUS_TOO_LARGE\\0"
+ "NO_PRIVATE_VALUE\\0"
+ "BAD_Q_VALUE\\0"
+ "MISSING_PARAMETERS\\0"
+ "NEED_NEW_SETUP_VALUES\\0"
+ "BIGNUM_OUT_OF_RANGE\\0"
+ "COORDINATES_OUT_OF_RANGE\\0"
+ "D2I_ECPKPARAMETERS_FAILURE\\0"
+ "EC_GROUP_NEW_BY_NAME_FAILURE\\0"
+ "GROUP2PKPARAMETERS_FAILURE\\0"
+ "I2D_ECPKPARAMETERS_FAILURE\\0"
+ "INCOMPATIBLE_OBJECTS\\0"
+ "INVALID_COMPRESSED_POINT\\0"
+ "INVALID_COMPRESSION_BIT\\0"
+ "INVALID_ENCODING\\0"
+ "INVALID_FIELD\\0"
+ "INVALID_FORM\\0"
+ "INVALID_GROUP_ORDER\\0"
+ "INVALID_PRIVATE_KEY\\0"
+ "MISSING_PRIVATE_KEY\\0"
+ "NON_NAMED_CURVE\\0"
+ "PKPARAMETERS2GROUP_FAILURE\\0"
+ "POINT_AT_INFINITY\\0"
+ "POINT_IS_NOT_ON_CURVE\\0"
+ "SLOT_FULL\\0"
+ "UNDEFINED_GENERATOR\\0"
+ "UNKNOWN_GROUP\\0"
+ "UNKNOWN_ORDER\\0"
+ "WRONG_CURVE_PARAMETERS\\0"
+ "WRONG_ORDER\\0"
+ "KDF_FAILED\\0"
+ "POINT_ARITHMETIC_FAILURE\\0"
+ "BAD_SIGNATURE\\0"
+ "NOT_IMPLEMENTED\\0"
+ "RANDOM_NUMBER_GENERATION_FAILED\\0"
+ "OPERATION_NOT_SUPPORTED\\0"
+ "BN_DECODE_ERROR\\0"
+ "COMMAND_NOT_SUPPORTED\\0"
+ "CONTEXT_NOT_INITIALISED\\0"
+ "DIFFERENT_KEY_TYPES\\0"
+ "DIFFERENT_PARAMETERS\\0"
+ "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED\\0"
+ "EXPECTING_AN_EC_KEY_KEY\\0"
+ "EXPECTING_AN_RSA_KEY\\0"
+ "EXPECTING_A_DH_KEY\\0"
+ "EXPECTING_A_DSA_KEY\\0"
+ "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE\\0"
+ "INVALID_CURVE\\0"
+ "INVALID_DIGEST_LENGTH\\0"
+ "INVALID_DIGEST_TYPE\\0"
+ "INVALID_KEYBITS\\0"
+ "INVALID_MGF1_MD\\0"
+ "INVALID_PADDING_MODE\\0"
+ "INVALID_PSS_PARAMETERS\\0"
+ "INVALID_PSS_SALTLEN\\0"
+ "INVALID_SALT_LENGTH\\0"
+ "INVALID_TRAILER\\0"
+ "KEYS_NOT_SET\\0"
+ "NO_DEFAULT_DIGEST\\0"
+ "NO_KEY_SET\\0"
+ "NO_MDC2_SUPPORT\\0"
+ "NO_NID_FOR_CURVE\\0"
+ "NO_OPERATION_SET\\0"
+ "NO_PARAMETERS_SET\\0"
+ "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE\\0"
+ "OPERATON_NOT_INITIALIZED\\0"
+ "PARAMETER_ENCODING_ERROR\\0"
+ "UNKNOWN_DIGEST\\0"
+ "UNKNOWN_MASK_DIGEST\\0"
+ "UNKNOWN_MESSAGE_DIGEST_ALGORITHM\\0"
+ "UNKNOWN_PUBLIC_KEY_TYPE\\0"
+ "UNKNOWN_SIGNATURE_ALGORITHM\\0"
+ "UNSUPPORTED_ALGORITHM\\0"
+ "UNSUPPORTED_MASK_ALGORITHM\\0"
+ "UNSUPPORTED_MASK_PARAMETER\\0"
+ "UNSUPPORTED_SIGNATURE_TYPE\\0"
+ "WRONG_PUBLIC_KEY_TYPE\\0"
+ "OUTPUT_TOO_LARGE\\0"
+ "UNKNOWN_NID\\0"
+ "BAD_BASE64_DECODE\\0"
+ "BAD_END_LINE\\0"
+ "BAD_IV_CHARS\\0"
+ "BAD_PASSWORD_READ\\0"
+ "CIPHER_IS_NULL\\0"
+ "ERROR_CONVERTING_PRIVATE_KEY\\0"
+ "NOT_DEK_INFO\\0"
+ "NOT_ENCRYPTED\\0"
+ "NOT_PROC_TYPE\\0"
+ "NO_START_LINE\\0"
+ "READ_KEY\\0"
+ "SHORT_HEADER\\0"
+ "UNSUPPORTED_CIPHER\\0"
+ "UNSUPPORTED_ENCRYPTION\\0"
+ "BAD_PKCS12_DATA\\0"
+ "BAD_PKCS12_VERSION\\0"
+ "CIPHER_HAS_NO_OBJECT_IDENTIFIER\\0"
+ "CRYPT_ERROR\\0"
+ "ENCRYPT_ERROR\\0"
+ "ERROR_SETTING_CIPHER_PARAMS\\0"
+ "INCORRECT_PASSWORD\\0"
+ "KEYGEN_FAILURE\\0"
+ "KEY_GEN_ERROR\\0"
+ "METHOD_NOT_SUPPORTED\\0"
+ "MISSING_MAC\\0"
+ "MULTIPLE_PRIVATE_KEYS_IN_PKCS12\\0"
+ "PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED\\0"
+ "PKCS12_TOO_DEEPLY_NESTED\\0"
+ "PRIVATE_KEY_DECODE_ERROR\\0"
+ "PRIVATE_KEY_ENCODE_ERROR\\0"
+ "UNKNOWN_ALGORITHM\\0"
+ "UNKNOWN_CIPHER\\0"
+ "UNKNOWN_CIPHER_ALGORITHM\\0"
+ "UNKNOWN_HASH\\0"
+ "UNSUPPORTED_PRIVATE_KEY_ALGORITHM\\0"
+ "BAD_E_VALUE\\0"
+ "BAD_FIXED_HEADER_DECRYPT\\0"
+ "BAD_PAD_BYTE_COUNT\\0"
+ "BAD_RSA_PARAMETERS\\0"
+ "BAD_VERSION\\0"
+ "BLOCK_TYPE_IS_NOT_01\\0"
+ "BN_NOT_INITIALIZED\\0"
+ "CANNOT_RECOVER_MULTI_PRIME_KEY\\0"
+ "CRT_PARAMS_ALREADY_GIVEN\\0"
+ "CRT_VALUES_INCORRECT\\0"
+ "DATA_LEN_NOT_EQUAL_TO_MOD_LEN\\0"
+ "DATA_TOO_LARGE\\0"
+ "DATA_TOO_LARGE_FOR_KEY_SIZE\\0"
+ "DATA_TOO_LARGE_FOR_MODULUS\\0"
+ "DATA_TOO_SMALL\\0"
+ "DATA_TOO_SMALL_FOR_KEY_SIZE\\0"
+ "DIGEST_TOO_BIG_FOR_RSA_KEY\\0"
+ "D_E_NOT_CONGRUENT_TO_1\\0"
+ "EMPTY_PUBLIC_KEY\\0"
+ "FIRST_OCTET_INVALID\\0"
+ "INCONSISTENT_SET_OF_CRT_VALUES\\0"
+ "INTERNAL_ERROR\\0"
+ "INVALID_MESSAGE_LENGTH\\0"
+ "KEY_SIZE_TOO_SMALL\\0"
+ "LAST_OCTET_INVALID\\0"
+ "MUST_HAVE_AT_LEAST_TWO_PRIMES\\0"
+ "NO_PUBLIC_EXPONENT\\0"
+ "NULL_BEFORE_BLOCK_MISSING\\0"
+ "N_NOT_EQUAL_P_Q\\0"
+ "OAEP_DECODING_ERROR\\0"
+ "ONLY_ONE_OF_P_Q_GIVEN\\0"
+ "OUTPUT_BUFFER_TOO_SMALL\\0"
+ "PADDING_CHECK_FAILED\\0"
+ "PKCS_DECODING_ERROR\\0"
+ "SLEN_CHECK_FAILED\\0"
+ "SLEN_RECOVERY_FAILED\\0"
+ "UNKNOWN_ALGORITHM_TYPE\\0"
+ "UNKNOWN_PADDING_TYPE\\0"
+ "VALUE_MISSING\\0"
+ "WRONG_SIGNATURE_LENGTH\\0"
+ "APP_DATA_IN_HANDSHAKE\\0"
+ "ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT\\0"
+ "BAD_ALERT\\0"
+ "BAD_CHANGE_CIPHER_SPEC\\0"
+ "BAD_DATA_RETURNED_BY_CALLBACK\\0"
+ "BAD_DH_P_LENGTH\\0"
+ "BAD_DIGEST_LENGTH\\0"
+ "BAD_ECC_CERT\\0"
+ "BAD_ECPOINT\\0"
+ "BAD_HANDSHAKE_LENGTH\\0"
+ "BAD_HANDSHAKE_RECORD\\0"
+ "BAD_HELLO_REQUEST\\0"
+ "BAD_LENGTH\\0"
+ "BAD_PACKET_LENGTH\\0"
+ "BAD_RSA_ENCRYPT\\0"
+ "BAD_SRTP_MKI_VALUE\\0"
+ "BAD_SRTP_PROTECTION_PROFILE_LIST\\0"
+ "BAD_SSL_FILETYPE\\0"
+ "BAD_WRITE_RETRY\\0"
+ "BIO_NOT_SET\\0"
+ "CANNOT_SERIALIZE_PUBLIC_KEY\\0"
+ "CA_DN_LENGTH_MISMATCH\\0"
+ "CA_DN_TOO_LONG\\0"
+ "CCS_RECEIVED_EARLY\\0"
+ "CERTIFICATE_VERIFY_FAILED\\0"
+ "CERT_CB_ERROR\\0"
+ "CERT_LENGTH_MISMATCH\\0"
+ "CHANNEL_ID_NOT_P256\\0"
+ "CHANNEL_ID_SIGNATURE_INVALID\\0"
+ "CIPHER_CODE_WRONG_LENGTH\\0"
+ "CIPHER_OR_HASH_UNAVAILABLE\\0"
+ "CLIENTHELLO_PARSE_FAILED\\0"
+ "CLIENTHELLO_TLSEXT\\0"
+ "CONNECTION_REJECTED\\0"
+ "CONNECTION_TYPE_NOT_SET\\0"
+ "COOKIE_MISMATCH\\0"
+ "CUSTOM_EXTENSION_CONTENTS_TOO_LARGE\\0"
+ "CUSTOM_EXTENSION_ERROR\\0"
+ "D2I_ECDSA_SIG\\0"
+ "DATA_BETWEEN_CCS_AND_FINISHED\\0"
+ "DATA_LENGTH_TOO_LONG\\0"
+ "DECRYPTION_FAILED\\0"
+ "DECRYPTION_FAILED_OR_BAD_RECORD_MAC\\0"
+ "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\\0"
+ "DH_P_TOO_LONG\\0"
+ "DIGEST_CHECK_FAILED\\0"
+ "DTLS_MESSAGE_TOO_BIG\\0"
+ "ECC_CERT_NOT_FOR_SIGNING\\0"
+ "EMPTY_SRTP_PROTECTION_PROFILE_LIST\\0"
+ "EMS_STATE_INCONSISTENT\\0"
+ "ENCRYPTED_LENGTH_TOO_LONG\\0"
+ "ERROR_ADDING_EXTENSION\\0"
+ "ERROR_IN_RECEIVED_CIPHER_LIST\\0"
+ "ERROR_PARSING_EXTENSION\\0"
+ "EVP_DIGESTSIGNFINAL_FAILED\\0"
+ "EVP_DIGESTSIGNINIT_FAILED\\0"
+ "EXCESSIVE_MESSAGE_SIZE\\0"
+ "EXTRA_DATA_IN_MESSAGE\\0"
+ "FRAGMENT_MISMATCH\\0"
+ "GOT_A_FIN_BEFORE_A_CCS\\0"
+ "GOT_CHANNEL_ID_BEFORE_A_CCS\\0"
+ "GOT_NEXT_PROTO_BEFORE_A_CCS\\0"
+ "GOT_NEXT_PROTO_WITHOUT_EXTENSION\\0"
+ "HANDSHAKE_FAILURE_ON_CLIENT_HELLO\\0"
+ "HANDSHAKE_RECORD_BEFORE_CCS\\0"
+ "HTTPS_PROXY_REQUEST\\0"
+ "HTTP_REQUEST\\0"
+ "INAPPROPRIATE_FALLBACK\\0"
+ "INVALID_COMMAND\\0"
+ "INVALID_MESSAGE\\0"
+ "INVALID_SSL_SESSION\\0"
+ "INVALID_TICKET_KEYS_LENGTH\\0"
+ "LENGTH_MISMATCH\\0"
+ "LIBRARY_HAS_NO_CIPHERS\\0"
+ "MISSING_DH_KEY\\0"
+ "MISSING_ECDSA_SIGNING_CERT\\0"
+ "MISSING_EXTENSION\\0"
+ "MISSING_RSA_CERTIFICATE\\0"
+ "MISSING_RSA_ENCRYPTING_CERT\\0"
+ "MISSING_RSA_SIGNING_CERT\\0"
+ "MISSING_TMP_DH_KEY\\0"
+ "MISSING_TMP_ECDH_KEY\\0"
+ "MIXED_SPECIAL_OPERATOR_WITH_GROUPS\\0"
+ "MTU_TOO_SMALL\\0"
+ "NEGOTIATED_BOTH_NPN_AND_ALPN\\0"
+ "NESTED_GROUP\\0"
+ "NO_CERTIFICATES_RETURNED\\0"
+ "NO_CERTIFICATE_ASSIGNED\\0"
+ "NO_CERTIFICATE_SET\\0"
+ "NO_CIPHERS_AVAILABLE\\0"
+ "NO_CIPHERS_PASSED\\0"
+ "NO_CIPHERS_SPECIFIED\\0"
+ "NO_CIPHER_MATCH\\0"
+ "NO_COMPRESSION_SPECIFIED\\0"
+ "NO_METHOD_SPECIFIED\\0"
+ "NO_P256_SUPPORT\\0"
+ "NO_PRIVATE_KEY_ASSIGNED\\0"
+ "NO_RENEGOTIATION\\0"
+ "NO_REQUIRED_DIGEST\\0"
+ "NO_SHARED_CIPHER\\0"
+ "NO_SHARED_SIGATURE_ALGORITHMS\\0"
+ "NO_SRTP_PROFILES\\0"
+ "NULL_SSL_CTX\\0"
+ "NULL_SSL_METHOD_PASSED\\0"
+ "OLD_SESSION_CIPHER_NOT_RETURNED\\0"
+ "OLD_SESSION_VERSION_NOT_RETURNED\\0"
+ "PACKET_LENGTH_TOO_LONG\\0"
+ "PARSE_TLSEXT\\0"
+ "PATH_TOO_LONG\\0"
+ "PEER_DID_NOT_RETURN_A_CERTIFICATE\\0"
+ "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\\0"
+ "PROTOCOL_IS_SHUTDOWN\\0"
+ "PSK_IDENTITY_NOT_FOUND\\0"
+ "PSK_NO_CLIENT_CB\\0"
+ "PSK_NO_SERVER_CB\\0"
+ "READ_BIO_NOT_SET\\0"
+ "READ_TIMEOUT_EXPIRED\\0"
+ "RECORD_LENGTH_MISMATCH\\0"
+ "RECORD_TOO_LARGE\\0"
+ "RENEGOTIATE_EXT_TOO_LONG\\0"
+ "RENEGOTIATION_ENCODING_ERR\\0"
+ "RENEGOTIATION_MISMATCH\\0"
+ "REQUIRED_CIPHER_MISSING\\0"
+ "RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION\\0"
+ "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\\0"
+ "SCSV_RECEIVED_WHEN_RENEGOTIATING\\0"
+ "SERVERHELLO_TLSEXT\\0"
+ "SESSION_ID_CONTEXT_UNINITIALIZED\\0"
+ "SESSION_MAY_NOT_BE_CREATED\\0"
+ "SIGNATURE_ALGORITHMS_ERROR\\0"
+ "SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER\\0"
+ "SRTP_COULD_NOT_ALLOCATE_PROFILES\\0"
+ "SRTP_PROTECTION_PROFILE_LIST_TOO_LONG\\0"
+ "SRTP_UNKNOWN_PROTECTION_PROFILE\\0"
+ "SSL3_EXT_INVALID_SERVERNAME\\0"
+ "SSL3_EXT_INVALID_SERVERNAME_TYPE\\0"
+ "SSLV3_ALERT_BAD_CERTIFICATE\\0"
+ "SSLV3_ALERT_BAD_RECORD_MAC\\0"
+ "SSLV3_ALERT_CERTIFICATE_EXPIRED\\0"
+ "SSLV3_ALERT_CERTIFICATE_REVOKED\\0"
+ "SSLV3_ALERT_CERTIFICATE_UNKNOWN\\0"
+ "SSLV3_ALERT_CLOSE_NOTIFY\\0"
+ "SSLV3_ALERT_DECOMPRESSION_FAILURE\\0"
+ "SSLV3_ALERT_HANDSHAKE_FAILURE\\0"
+ "SSLV3_ALERT_ILLEGAL_PARAMETER\\0"
+ "SSLV3_ALERT_NO_CERTIFICATE\\0"
+ "SSLV3_ALERT_UNEXPECTED_MESSAGE\\0"
+ "SSLV3_ALERT_UNSUPPORTED_CERTIFICATE\\0"
+ "SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION\\0"
+ "SSL_HANDSHAKE_FAILURE\\0"
+ "SSL_SESSION_ID_CALLBACK_FAILED\\0"
+ "SSL_SESSION_ID_CONFLICT\\0"
+ "SSL_SESSION_ID_CONTEXT_TOO_LONG\\0"
+ "SSL_SESSION_ID_HAS_BAD_LENGTH\\0"
+ "TLSV1_ALERT_ACCESS_DENIED\\0"
+ "TLSV1_ALERT_DECODE_ERROR\\0"
+ "TLSV1_ALERT_DECRYPTION_FAILED\\0"
+ "TLSV1_ALERT_DECRYPT_ERROR\\0"
+ "TLSV1_ALERT_EXPORT_RESTRICTION\\0"
+ "TLSV1_ALERT_INAPPROPRIATE_FALLBACK\\0"
+ "TLSV1_ALERT_INSUFFICIENT_SECURITY\\0"
+ "TLSV1_ALERT_INTERNAL_ERROR\\0"
+ "TLSV1_ALERT_NO_RENEGOTIATION\\0"
+ "TLSV1_ALERT_PROTOCOL_VERSION\\0"
+ "TLSV1_ALERT_RECORD_OVERFLOW\\0"
+ "TLSV1_ALERT_UNKNOWN_CA\\0"
+ "TLSV1_ALERT_USER_CANCELLED\\0"
+ "TLSV1_BAD_CERTIFICATE_HASH_VALUE\\0"
+ "TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE\\0"
+ "TLSV1_CERTIFICATE_UNOBTAINABLE\\0"
+ "TLSV1_UNRECOGNIZED_NAME\\0"
+ "TLSV1_UNSUPPORTED_EXTENSION\\0"
+ "TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER\\0"
+ "TLS_ILLEGAL_EXPORTER_LABEL\\0"
+ "TLS_INVALID_ECPOINTFORMAT_LIST\\0"
+ "TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST\\0"
+ "TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG\\0"
+ "TOO_MANY_EMPTY_FRAGMENTS\\0"
+ "TOO_MANY_WARNING_ALERTS\\0"
+ "UNABLE_TO_FIND_ECDH_PARAMETERS\\0"
+ "UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS\\0"
+ "UNEXPECTED_EXTENSION\\0"
+ "UNEXPECTED_GROUP_CLOSE\\0"
+ "UNEXPECTED_MESSAGE\\0"
+ "UNEXPECTED_OPERATOR_IN_GROUP\\0"
+ "UNEXPECTED_RECORD\\0"
+ "UNKNOWN_ALERT_TYPE\\0"
+ "UNKNOWN_CERTIFICATE_TYPE\\0"
+ "UNKNOWN_CIPHER_RETURNED\\0"
+ "UNKNOWN_CIPHER_TYPE\\0"
+ "UNKNOWN_KEY_EXCHANGE_TYPE\\0"
+ "UNKNOWN_PROTOCOL\\0"
+ "UNKNOWN_SSL_VERSION\\0"
+ "UNKNOWN_STATE\\0"
+ "UNPROCESSED_HANDSHAKE_DATA\\0"
+ "UNSAFE_LEGACY_RENEGOTIATION_DISABLED\\0"
+ "UNSUPPORTED_COMPRESSION_ALGORITHM\\0"
+ "UNSUPPORTED_ELLIPTIC_CURVE\\0"
+ "UNSUPPORTED_PROTOCOL\\0"
+ "UNSUPPORTED_SSL_VERSION\\0"
+ "USE_SRTP_NOT_NEGOTIATED\\0"
+ "WRONG_CERTIFICATE_TYPE\\0"
+ "WRONG_CIPHER_RETURNED\\0"
+ "WRONG_CURVE\\0"
+ "WRONG_MESSAGE_TYPE\\0"
+ "WRONG_SIGNATURE_TYPE\\0"
+ "WRONG_SSL_VERSION\\0"
+ "WRONG_VERSION_NUMBER\\0"
+ "X509_LIB\\0"
+ "X509_VERIFICATION_SETUP_PROBLEMS\\0"
+ "AKID_MISMATCH\\0"
+ "BAD_PKCS7_VERSION\\0"
+ "BAD_X509_FILETYPE\\0"
+ "BASE64_DECODE_ERROR\\0"
+ "CANT_CHECK_DH_KEY\\0"
+ "CERT_ALREADY_IN_HASH_TABLE\\0"
+ "CRL_ALREADY_DELTA\\0"
+ "CRL_VERIFY_FAILURE\\0"
+ "IDP_MISMATCH\\0"
+ "INVALID_DIRECTORY\\0"
+ "INVALID_FIELD_NAME\\0"
+ "INVALID_TRUST\\0"
+ "ISSUER_MISMATCH\\0"
+ "KEY_TYPE_MISMATCH\\0"
+ "KEY_VALUES_MISMATCH\\0"
+ "LOADING_CERT_DIR\\0"
+ "LOADING_DEFAULTS\\0"
+ "NEWER_CRL_NOT_NEWER\\0"
+ "NOT_PKCS7_SIGNED_DATA\\0"
+ "NO_CERTIFICATES_INCLUDED\\0"
+ "NO_CERT_SET_FOR_US_TO_VERIFY\\0"
+ "NO_CRLS_INCLUDED\\0"
+ "NO_CRL_NUMBER\\0"
+ "PUBLIC_KEY_DECODE_ERROR\\0"
+ "PUBLIC_KEY_ENCODE_ERROR\\0"
+ "SHOULD_RETRY\\0"
+ "UNABLE_TO_FIND_PARAMETERS_IN_CHAIN\\0"
+ "UNABLE_TO_GET_CERTS_PUBLIC_KEY\\0"
+ "UNKNOWN_KEY_TYPE\\0"
+ "UNKNOWN_PURPOSE_ID\\0"
+ "UNKNOWN_TRUST_ID\\0"
+ "WRONG_LOOKUP_TYPE\\0"
+ "BAD_IP_ADDRESS\\0"
+ "BAD_OBJECT\\0"
+ "BN_DEC2BN_ERROR\\0"
+ "BN_TO_ASN1_INTEGER_ERROR\\0"
+ "CANNOT_FIND_FREE_FUNCTION\\0"
+ "DIRNAME_ERROR\\0"
+ "DISTPOINT_ALREADY_SET\\0"
+ "DUPLICATE_ZONE_ID\\0"
+ "ERROR_CONVERTING_ZONE\\0"
+ "ERROR_CREATING_EXTENSION\\0"
+ "ERROR_IN_EXTENSION\\0"
+ "EXPECTED_A_SECTION_NAME\\0"
+ "EXTENSION_EXISTS\\0"
+ "EXTENSION_NAME_ERROR\\0"
+ "EXTENSION_NOT_FOUND\\0"
+ "EXTENSION_SETTING_NOT_SUPPORTED\\0"
+ "EXTENSION_VALUE_ERROR\\0"
+ "ILLEGAL_EMPTY_EXTENSION\\0"
+ "ILLEGAL_HEX_DIGIT\\0"
+ "INCORRECT_POLICY_SYNTAX_TAG\\0"
+ "INVALID_BOOLEAN_STRING\\0"
+ "INVALID_EXTENSION_STRING\\0"
+ "INVALID_MULTIPLE_RDNS\\0"
+ "INVALID_NAME\\0"
+ "INVALID_NULL_ARGUMENT\\0"
+ "INVALID_NULL_NAME\\0"
+ "INVALID_NULL_VALUE\\0"
+ "INVALID_NUMBERS\\0"
+ "INVALID_OBJECT_IDENTIFIER\\0"
+ "INVALID_OPTION\\0"
+ "INVALID_POLICY_IDENTIFIER\\0"
+ "INVALID_PROXY_POLICY_SETTING\\0"
+ "INVALID_PURPOSE\\0"
+ "INVALID_SECTION\\0"
+ "INVALID_SYNTAX\\0"
+ "ISSUER_DECODE_ERROR\\0"
+ "NEED_ORGANIZATION_AND_NUMBERS\\0"
+ "NO_CONFIG_DATABASE\\0"
+ "NO_ISSUER_CERTIFICATE\\0"
+ "NO_ISSUER_DETAILS\\0"
+ "NO_POLICY_IDENTIFIER\\0"
+ "NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED\\0"
+ "NO_PUBLIC_KEY\\0"
+ "NO_SUBJECT_DETAILS\\0"
+ "ODD_NUMBER_OF_DIGITS\\0"
+ "OPERATION_NOT_DEFINED\\0"
+ "OTHERNAME_ERROR\\0"
+ "POLICY_LANGUAGE_ALREADY_DEFINED\\0"
+ "POLICY_PATH_LENGTH\\0"
+ "POLICY_PATH_LENGTH_ALREADY_DEFINED\\0"
+ "POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY\\0"
+ "SECTION_NOT_FOUND\\0"
+ "UNABLE_TO_GET_ISSUER_DETAILS\\0"
+ "UNABLE_TO_GET_ISSUER_KEYID\\0"
+ "UNKNOWN_BIT_STRING_ARGUMENT\\0"
+ "UNKNOWN_EXTENSION\\0"
+ "UNKNOWN_EXTENSION_NAME\\0"
+ "UNKNOWN_OPTION\\0"
+ "UNSUPPORTED_OPTION\\0"
+ "USER_TOO_LONG\\0"
+ "";
+ EOF
+ END_OF_COMMAND
+end
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 5918f8857a..c9fda42855 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -50,6 +50,8 @@
#import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h>
+#include <AvailabilityMacros.h>
+
#pragma mark gRPC errors
/** Domain of NSError objects produced by gRPC. */
@@ -161,6 +163,9 @@ extern id const kGRPCTrailersKey;
#pragma mark GRPCCall
+/** Represents a single gRPC remote call. */
+@interface GRPCCall : GRXWriter
+
/**
* The container of the request headers of an RPC conforms to this protocol, which is a subset of
* NSMutableDictionary's interface. It will become a NSMutableDictionary later on.
@@ -170,21 +175,6 @@ extern id const kGRPCTrailersKey;
* A header value is a NSString object (with only ASCII characters), unless the header name has the
* suffix "-bin", in which case the value has to be a NSData object.
*/
-@protocol GRPCRequestHeaders <NSObject>
-
-@property(nonatomic, readonly) NSUInteger count;
-
-- (id)objectForKeyedSubscript:(NSString *)key;
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
-
-- (void)removeAllObjects;
-- (void)removeObjectForKey:(NSString *)key;
-
-@end
-
-/** Represents a single gRPC remote call. */
-@interface GRPCCall : GRXWriter
-
/**
* These HTTP headers will be passed to the server as part of this call. Each HTTP header is a
* name-value pair with string names and either string or binary values.
@@ -200,7 +190,7 @@ extern id const kGRPCTrailersKey;
*
* The property is initialized to an empty NSMutableDictionary.
*/
-@property(atomic, readonly) id<GRPCRequestHeaders> requestHeaders;
+@property(atomic, readonly) NSMutableDictionary *requestHeaders;
/**
* This dictionary is populated with the HTTP headers received from the server. This happens before
@@ -243,3 +233,24 @@ extern id const kGRPCTrailersKey;
// TODO(jcanizales): Let specify a deadline. As a category of GRXWriter?
@end
+
+#pragma mark Backwards compatibiity
+
+/** This protocol is kept for backwards compatibility with existing code. */
+DEPRECATED_MSG_ATTRIBUTE("Use NSDictionary or NSMutableDictionary instead.")
+@protocol GRPCRequestHeaders <NSObject>
+@property(nonatomic, readonly) NSUInteger count;
+
+- (id)objectForKeyedSubscript:(NSString *)key;
+- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
+
+- (void)removeAllObjects;
+- (void)removeObjectForKey:(NSString *)key;
+@end
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated"
+/** This is only needed for backwards-compatibility. */
+@interface NSMutableDictionary (GRPCRequestHeaders) <GRPCRequestHeaders>
+@end
+#pragma clang diagnostic pop
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index b6986bf59c..f79b7d0bc0 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -221,7 +221,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
#pragma mark Send headers
-- (void)sendHeaders:(id<GRPCRequestHeaders>)headers {
+- (void)sendHeaders:(NSDictionary *)headers {
// TODO(jcanizales): Add error handlers for async failures
[_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc] initWithMetadata:headers
handler:nil]]];
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
index cf5a1be9d6..b580f19406 100644
--- a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
@@ -32,21 +32,14 @@
*/
#import <Foundation/Foundation.h>
-#include <grpc/grpc.h>
#import "../GRPCCall.h"
-@interface GRPCRequestHeaders : NSObject<GRPCRequestHeaders>
-
-@property(nonatomic, readonly) NSUInteger count;
-@property(nonatomic, readonly) grpc_metadata *grpc_metadataArray;
+@interface GRPCRequestHeaders : NSMutableDictionary
- (instancetype)initWithCall:(GRPCCall *)call;
-- (id)objectForKeyedSubscript:(NSString *)key;
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
-
-- (void)removeAllObjects;
-- (void)removeObjectForKey:(NSString *)key;
+- (instancetype)initWithCall:(GRPCCall *)call
+ storage:(NSMutableDictionary *)storage NS_DESIGNATED_INITIALIZER;
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
index d23f21c0f9..c6a03c145e 100644
--- a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
@@ -68,17 +68,44 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
@implementation GRPCRequestHeaders {
__weak GRPCCall *_call;
+ // The NSMutableDictionary superclass doesn't hold any storage (so that people can implement their
+ // own in subclasses). As that's not the reason we're subclassing, we just delegate storage to the
+ // default NSMutableDictionary subclass returned by the cluster (e.g. __NSDictionaryM on iOS 9).
NSMutableDictionary *_delegate;
}
+- (instancetype)init {
+ return [self initWithCall:nil];
+}
+
+- (instancetype)initWithCapacity:(NSUInteger)numItems {
+ return [self init];
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+ return [self init];
+}
+
- (instancetype)initWithCall:(GRPCCall *)call {
+ return [self initWithCall:call storage:[NSMutableDictionary dictionary]];
+}
+
+// Designated initializer
+- (instancetype)initWithCall:(GRPCCall *)call storage:(NSMutableDictionary *)storage {
+ // TODO(jcanizales): Throw if call or storage are nil.
if ((self = [super init])) {
_call = call;
- _delegate = [NSMutableDictionary dictionary];
+ _delegate = storage;
}
return self;
}
+- (instancetype)initWithObjects:(const id _Nonnull __unsafe_unretained *)objects
+ forKeys:(const id<NSCopying> _Nonnull __unsafe_unretained *)keys
+ count:(NSUInteger)cnt {
+ return [self init];
+}
+
- (void)checkCallIsNotStarted {
if (_call.state != GRXWriterStateNotStarted) {
[NSException raise:@"Invalid modification"
@@ -86,11 +113,11 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
}
}
-- (id)objectForKeyedSubscript:(NSString *)key {
+- (id)objectForKey:(NSString *)key {
return _delegate[key.lowercaseString];
}
-- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key {
+- (void)setObject:(id)obj forKey:(NSString *)key {
[self checkCallIsNotStarted];
CheckIsNonNilASCII(@"Header name", key);
key = key.lowercaseString;
@@ -103,16 +130,12 @@ static void CheckKeyValuePairIsValid(NSString *key, id value) {
[_delegate removeObjectForKey:key.lowercaseString];
}
-- (void)removeAllObjects {
- [self checkCallIsNotStarted];
- [_delegate removeAllObjects];
-}
-
- (NSUInteger)count {
return _delegate.count;
}
-- (grpc_metadata *)grpc_metadataArray {
- return _delegate.grpc_metadataArray;
+- (NSEnumerator * _Nonnull)keyEnumerator {
+ return [_delegate keyEnumerator];
}
+
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 7747aa53ef..71e7e0e54e 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -45,7 +45,7 @@
@interface GRPCOpSendMetadata : GRPCOperation
-- (instancetype)initWithMetadata:(GRPCRequestHeaders *)metadata
+- (instancetype)initWithMetadata:(NSDictionary *)metadata
handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index cea7c479e0..fe3d51da53 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -65,7 +65,7 @@
return [self initWithMetadata:nil handler:nil];
}
-- (instancetype)initWithMetadata:(GRPCRequestHeaders *)metadata handler:(void (^)())handler {
+- (instancetype)initWithMetadata:(NSDictionary *)metadata handler:(void (^)())handler {
if (self = [super init]) {
_op.op = GRPC_OP_SEND_INITIAL_METADATA;
_op.data.send_initial_metadata.count = metadata.count;
diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile
index 3b2f412569..93859fb734 100644
--- a/src/objective-c/examples/Sample/Podfile
+++ b/src/objective-c/examples/Sample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
pod 'Protobuf', :path => "../../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../.."
pod 'gRPC', :path => "../../../.."
pod 'RemoteTest', :path => "../RemoteTestClient"
diff --git a/src/objective-c/examples/SwiftSample/Podfile b/src/objective-c/examples/SwiftSample/Podfile
index 3611b00863..f2df4a34a3 100644
--- a/src/objective-c/examples/SwiftSample/Podfile
+++ b/src/objective-c/examples/SwiftSample/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
pod 'Protobuf', :path => "../../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => "../.."
pod 'gRPC', :path => "../../../.."
pod 'RemoteTest', :path => "../RemoteTestClient"
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index cab608d37f..7ec7a25898 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
pod 'Protobuf', :path => "../../../third_party/protobuf"
+pod 'BoringSSL', :podspec => ".."
pod 'gRPC', :path => "../../.."
pod 'RemoteTest', :path => "RemoteTestClient"
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
index 2a7335e20a..235d161ca7 100755
--- a/src/php/bin/run_tests.sh
+++ b/src/php/bin/run_tests.sh
@@ -30,7 +30,7 @@
# Loads the local shared library, and runs all of the test cases in tests/
# against it
-set -e
+set -ex
cd $(dirname $0)/../../..
root=$(pwd)
cd src/php/bin
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 3b99de7538..7ba14a38d8 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -42,13 +42,13 @@
#include <ext/standard/info.h>
#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
+#include "call_credentials.h"
#include <zend_exceptions.h>
#include <zend_hash.h>
#include <stdbool.h>
-#include <grpc/support/log.h>
#include <grpc/support/alloc.h>
#include <grpc/grpc.h>
@@ -515,11 +515,41 @@ PHP_METHOD(Call, cancel) {
grpc_call_cancel(call->wrapped, NULL);
}
+/**
+ * Set the CallCredentials for this call.
+ * @param CallCredentials creds_obj The CallCredentials object
+ * @param int The error code
+ */
+PHP_METHOD(Call, setCredentials) {
+ zval *creds_obj;
+
+ /* "O" == 1 Object */
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &creds_obj,
+ grpc_ce_call_credentials) == FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "setCredentials expects 1 CallCredentials",
+ 1 TSRMLS_CC);
+ return;
+ }
+
+ wrapped_grpc_call_credentials *creds =
+ (wrapped_grpc_call_credentials *)zend_object_store_get_object(
+ creds_obj TSRMLS_CC);
+
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ grpc_call_error error = GRPC_CALL_ERROR;
+ error = grpc_call_set_credentials(call->wrapped, creds->wrapped);
+ RETURN_LONG(error);
+}
+
static zend_function_entry call_methods[] = {
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, getPeer, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, setCredentials, NULL, ZEND_ACC_PUBLIC)
PHP_FE_END};
void grpc_init_call(TSRMLS_D) {
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index f3ef89dc97..73efadae35 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -66,4 +66,8 @@ zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned);
* call metadata */
zval *grpc_parse_metadata_array(grpc_metadata_array *metadata_array);
+/* Populates a grpc_metadata_array with the data in a PHP array object.
+ Returns true on success and false on failure */
+bool create_metadata_array(zval *array, grpc_metadata_array *metadata);
+
#endif /* NET_GRPC_PHP_GRPC_CHANNEL_H_ */
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 17f167befb..285c4e7c85 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -43,6 +43,7 @@
#include <ext/standard/info.h>
#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
+#include "call.h"
#include <zend_exceptions.h>
#include <zend_hash.h>
@@ -103,7 +104,7 @@ PHP_METHOD(CallCredentials, createComposite) {
zval *cred1_obj;
zval *cred2_obj;
- /* "OO" == 3 Objects */
+ /* "OO" == 2 Objects */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
grpc_ce_call_credentials, &cred2_obj,
grpc_ce_call_credentials) == FAILURE) {
@@ -125,9 +126,107 @@ PHP_METHOD(CallCredentials, createComposite) {
RETURN_DESTROY_ZVAL(creds_object);
}
+/**
+ * Create a call credentials object from the plugin API
+ * @param function callback The callback function
+ * @return CallCredentials The new call credentials object
+ */
+PHP_METHOD(CallCredentials, createFromPlugin) {
+ zend_fcall_info *fci;
+ zend_fcall_info_cache *fci_cache;
+
+ fci = (zend_fcall_info *)emalloc(sizeof(zend_fcall_info));
+ fci_cache = (zend_fcall_info_cache *)emalloc(sizeof(zend_fcall_info_cache));
+ memset(fci, 0, sizeof(zend_fcall_info));
+ memset(fci_cache, 0, sizeof(zend_fcall_info_cache));
+
+ /* "f" == 1 function */
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "f", fci,
+ fci_cache,
+ fci->params,
+ fci->param_count) == FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "createFromPlugin expects 1 callback",
+ 1 TSRMLS_CC);
+ return;
+ }
+
+ plugin_state *state;
+ state = (plugin_state *)emalloc(sizeof(plugin_state));
+ memset(state, 0, sizeof(plugin_state));
+
+ /* save the user provided PHP callback function */
+ state->fci = fci;
+ state->fci_cache = fci_cache;
+
+ grpc_metadata_credentials_plugin plugin;
+ plugin.get_metadata = plugin_get_metadata;
+ plugin.destroy = plugin_destroy_state;
+ plugin.state = (void *)state;
+ plugin.type = "";
+
+ grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
+ plugin, NULL);
+ zval *creds_object = grpc_php_wrap_call_credentials(creds);
+ RETURN_DESTROY_ZVAL(creds_object);
+}
+
+/* Callback function for plugin creds API */
+void plugin_get_metadata(void *ptr, grpc_auth_metadata_context context,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data) {
+ plugin_state *state = (plugin_state *)ptr;
+
+ /* prepare to call the user callback function with info from the
+ * grpc_auth_metadata_context */
+ zval **params[1];
+ zval *arg;
+ zval *retval;
+ MAKE_STD_ZVAL(arg);
+ object_init(arg);
+ add_property_string(arg, "service_url", context.service_url, true);
+ add_property_string(arg, "method_name", context.method_name, true);
+ params[0] = &arg;
+ state->fci->param_count = 1;
+ state->fci->params = params;
+ state->fci->retval_ptr_ptr = &retval;
+
+ /* call the user callback function */
+ zend_call_function(state->fci, state->fci_cache);
+
+ if (Z_TYPE_P(retval) != IS_ARRAY) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "plugin callback must return metadata array",
+ 1 TSRMLS_CC);
+ }
+
+ grpc_metadata_array metadata;
+ if (!create_metadata_array(retval, &metadata)) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "invalid metadata", 1 TSRMLS_CC);
+ grpc_metadata_array_destroy(&metadata);
+ }
+
+ /* TODO: handle error */
+ grpc_status_code code = GRPC_STATUS_OK;
+
+ /* Pass control back to core */
+ cb(user_data, metadata.metadata, metadata.count, code, NULL);
+}
+
+/* Cleanup function for plugin creds API */
+void plugin_destroy_state(void *ptr) {
+ plugin_state *state = (plugin_state *)ptr;
+ efree(state->fci);
+ efree(state->fci_cache);
+ efree(state);
+}
+
static zend_function_entry call_credentials_methods[] = {
PHP_ME(CallCredentials, createComposite, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(CallCredentials, createFromPlugin, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END};
void grpc_init_call_credentials(TSRMLS_D) {
diff --git a/src/php/ext/grpc/call_credentials.h b/src/php/ext/grpc/call_credentials.h
index 8f35ac68bc..d2f6a92449 100755
--- a/src/php/ext/grpc/call_credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -57,6 +57,20 @@ typedef struct wrapped_grpc_call_credentials {
grpc_call_credentials *wrapped;
} wrapped_grpc_call_credentials;
+/* Struct to hold callback function for plugin creds API */
+typedef struct plugin_state {
+ zend_fcall_info *fci;
+ zend_fcall_info_cache *fci_cache;
+} plugin_state;
+
+/* Callback function for plugin creds API */
+void plugin_get_metadata(void *state, grpc_auth_metadata_context context,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data);
+
+/* Cleanup function for plugin creds API */
+void plugin_destroy_state(void *ptr);
+
/* Initializes the CallCredentials PHP class */
void grpc_init_call_credentials(TSRMLS_D);
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index f8c4f0423f..60c94412dc 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -154,16 +154,20 @@ PHP_METHOD(Channel, __construct) {
array_hash = Z_ARRVAL_P(args_array);
if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
(void **)&creds_obj) == SUCCESS) {
- if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
+ if (Z_TYPE_P(*creds_obj) == IS_NULL) {
+ creds = NULL;
+ zend_hash_del(array_hash, "credentials", 12);
+ } else if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
grpc_ce_channel_credentials) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"credentials must be a ChannelCredentials object",
1 TSRMLS_CC);
return;
+ } else {
+ creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
+ *creds_obj TSRMLS_CC);
+ zend_hash_del(array_hash, "credentials", 12);
}
- creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
- *creds_obj TSRMLS_CC);
- zend_hash_del(array_hash, "credentials", 12);
}
php_grpc_read_args_array(args_array, &args);
if (creds == NULL) {
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index df4a5d5162..ae9a9897fc 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -169,6 +169,14 @@ PHP_METHOD(ChannelCredentials, createComposite) {
RETURN_DESTROY_ZVAL(creds_object);
}
+/**
+ * Create insecure channel credentials
+ * @return null
+ */
+PHP_METHOD(ChannelCredentials, createInsecure) {
+ RETURN_NULL();
+}
+
static zend_function_entry channel_credentials_methods[] = {
PHP_ME(ChannelCredentials, createDefault, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
@@ -176,6 +184,8 @@ static zend_function_entry channel_credentials_methods[] = {
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(ChannelCredentials, createComposite, NULL,
ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(ChannelCredentials, createInsecure, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END};
void grpc_init_channel_credentials(TSRMLS_D) {
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index a2e3e2826a..9c98f82540 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,11 +10,11 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2015-10-21</date>
- <time>17:04:32</time>
+ <date>2015-12-16</date>
+ <time>12:56:11</time>
<version>
- <release>0.6.1</release>
- <api>0.6.0</api>
+ <release>0.7.0</release>
+ <api>0.7.0</api>
</version>
<stability>
<release>beta</release>
@@ -22,19 +22,22 @@
</stability>
<license>BSD</license>
<notes>
-- fixed undefined constant fatal error when run with apache/nginx #2275
+- Breaking change to Credentials class (removed) #3765
+- Replaced by ChannelCredentials and CallCredentials class #3765
+- New plugin based metadata auth API #4394
+- Explicit ChannelCredentials::createInsecure() call
</notes>
<contents>
<dir baseinstalldir="/" name="/">
<file baseinstalldir="/" md5sum="6f19828fb869b7b8a590cbb76b4f996d" name="byte_buffer.c" role="src" />
<file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" />
- <file baseinstalldir="/" md5sum="d64c9005993de02abac55664b0b9e0b2" name="call.c" role="src" />
- <file baseinstalldir="/" md5sum="26acbf04c30162c2d2aca4688bb2aec8" name="call.h" role="src" />
- <file baseinstalldir="/" md5sum="6fa13d260dfde216f795225644f04e7a" name="call_credentials.c" role="src" />
- <file baseinstalldir="/" md5sum="e45269975f9a30fd349a90daf6b31aa2" name="call_credentials.h" role="src" />
- <file baseinstalldir="/" md5sum="0779db3b196c98081b2260ceec22cd4d" name="channel.c" role="src" />
+ <file baseinstalldir="/" md5sum="ee7eb7757f9e6f0e36f8f616b6bd0af5" name="call.c" role="src" />
+ <file baseinstalldir="/" md5sum="44c56bd9912d2538cbd6059e3e0452b6" name="call.h" role="src" />
+ <file baseinstalldir="/" md5sum="ff90f6c03ed44b5f4170bf3259a6704e" name="call_credentials.c" role="src" />
+ <file baseinstalldir="/" md5sum="3c3860e1d84f43cb6b2fbaa8d2ae1ab7" name="call_credentials.h" role="src" />
+ <file baseinstalldir="/" md5sum="aee9b63f790522aec2c682055240cc61" name="channel.c" role="src" />
<file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
- <file baseinstalldir="/" md5sum="1b40f50fa6184ad7d24a961ac76151ff" name="channel_credentials.c" role="src" />
+ <file baseinstalldir="/" md5sum="1a51c76d0b7b7d3ab570ed7d60c2ea46" name="channel_credentials.c" role="src" />
<file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" />
<file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
<file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
@@ -130,5 +133,23 @@ Update to wrap gRPC C Core version 0.10.0
- fixed undefined constant fatal error when run with apache/nginx #2275
</notes>
</release>
+ <release>
+ <version>
+ <release>0.7.0</release>
+ <api>0.7.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2015-12-16</date>
+ <license>BSD</license>
+ <notes>
+- Breaking change to Credentials class (removed) #3765
+- Replaced by ChannelCredentials and CallCredentials class #3765
+- New plugin based metadata auth API #4394
+- Explicit ChannelCredentials::createInsecure() call
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index 53849d51fc..712af91eb2 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -43,19 +43,20 @@ abstract class AbstractCall
/**
* Create a new Call wrapper object.
*
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the
- * remote server
- * @param callback $deserialize A callback function to deserialize
- * the response
- * @param (optional) long $timeout Timeout in microseconds
+ * @param Channel $channel The channel to communicate on
+ * @param string $method The method to call on the
+ * remote server
+ * @param callback $deserialize A callback function to deserialize
+ * the response
+ * @param array $options Call options (optional)
*/
public function __construct(Channel $channel,
$method,
$deserialize,
- $timeout = false)
+ $options = [])
{
- if ($timeout) {
+ if (isset($options['timeout']) &&
+ is_numeric($timeout = $options['timeout'])) {
$now = Timeval::now();
$delta = new Timeval($timeout);
$deadline = $now->add($delta);
@@ -65,6 +66,13 @@ abstract class AbstractCall
$this->call = new Call($channel, $method, $deadline);
$this->deserialize = $deserialize;
$this->metadata = null;
+ if (isset($options['call_credentials_callback']) &&
+ is_callable($call_credentials_callback =
+ $options['call_credentials_callback'])) {
+ $call_credentials = CallCredentials::createFromPlugin(
+ $call_credentials_callback);
+ $this->call->setCredentials($call_credentials);
+ }
}
/**
@@ -106,4 +114,15 @@ abstract class AbstractCall
return call_user_func($this->deserialize, $value);
}
+
+ /**
+ * Set the CallCredentials for the underlying Call.
+ *
+ * @param CallCredentials $call_credentials The CallCredentials
+ * object
+ */
+ public function setCallCredentials($call_credentials)
+ {
+ $this->call->setCredentials($call_credentials);
+ }
}
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 7b2627f516..2de1b337e5 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -72,6 +72,11 @@ class BaseStub
}
$opts['grpc.primary_user_agent'] .=
'grpc-php/'.$package_config['version'];
+ if (!array_key_exists('credentials', $opts)) {
+ throw new \Exception("The opts['credentials'] key is now ".
+ 'required. Please see one of the '.
+ 'ChannelCredentials::create methods');
+ }
$this->channel = new Channel($hostname, $opts);
}
@@ -159,25 +164,6 @@ class BaseStub
}
/**
- * extract $timeout from $metadata.
- *
- * @param $metadata The metadata map
- *
- * @return list($metadata_copy, $timeout)
- */
- private function _extract_timeout_from_metadata($metadata)
- {
- $timeout = false;
- $metadata_copy = $metadata;
- if (isset($metadata['timeout'])) {
- $timeout = $metadata['timeout'];
- unset($metadata_copy['timeout']);
- }
-
- return [$metadata_copy, $timeout];
- }
-
- /**
* validate and normalize the metadata array.
*
* @param $metadata The metadata map
@@ -220,21 +206,19 @@ class BaseStub
$metadata = [],
$options = [])
{
- list($actual_metadata, $timeout) =
- $this->_extract_timeout_from_metadata($metadata);
$call = new UnaryCall($this->channel,
$method,
$deserialize,
- $timeout);
+ $options);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
if (is_callable($this->update_metadata)) {
- $actual_metadata = call_user_func($this->update_metadata,
- $actual_metadata,
+ $metadata = call_user_func($this->update_metadata,
+ $metadata,
$jwt_aud_uri);
}
- $actual_metadata = $this->_validate_and_normalize_metadata(
- $actual_metadata);
- $call->start($argument, $actual_metadata, $options);
+ $metadata = $this->_validate_and_normalize_metadata(
+ $metadata);
+ $call->start($argument, $metadata, $options);
return $call;
}
@@ -253,23 +237,22 @@ class BaseStub
*/
public function _clientStreamRequest($method,
callable $deserialize,
- $metadata = [])
+ $metadata = [],
+ $options = [])
{
- list($actual_metadata, $timeout) =
- $this->_extract_timeout_from_metadata($metadata);
$call = new ClientStreamingCall($this->channel,
$method,
$deserialize,
- $timeout);
+ $options);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
if (is_callable($this->update_metadata)) {
- $actual_metadata = call_user_func($this->update_metadata,
- $actual_metadata,
+ $metadata = call_user_func($this->update_metadata,
+ $metadata,
$jwt_aud_uri);
}
- $actual_metadata = $this->_validate_and_normalize_metadata(
- $actual_metadata);
- $call->start($actual_metadata);
+ $metadata = $this->_validate_and_normalize_metadata(
+ $metadata);
+ $call->start($metadata);
return $call;
}
@@ -291,21 +274,19 @@ class BaseStub
$metadata = [],
$options = [])
{
- list($actual_metadata, $timeout) =
- $this->_extract_timeout_from_metadata($metadata);
$call = new ServerStreamingCall($this->channel,
$method,
$deserialize,
- $timeout);
+ $options);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
if (is_callable($this->update_metadata)) {
- $actual_metadata = call_user_func($this->update_metadata,
- $actual_metadata,
+ $metadata = call_user_func($this->update_metadata,
+ $metadata,
$jwt_aud_uri);
}
- $actual_metadata = $this->_validate_and_normalize_metadata(
- $actual_metadata);
- $call->start($argument, $actual_metadata, $options);
+ $metadata = $this->_validate_and_normalize_metadata(
+ $metadata);
+ $call->start($argument, $metadata, $options);
return $call;
}
@@ -321,23 +302,22 @@ class BaseStub
*/
public function _bidiRequest($method,
callable $deserialize,
- $metadata = [])
+ $metadata = [],
+ $options = [])
{
- list($actual_metadata, $timeout) =
- $this->_extract_timeout_from_metadata($metadata);
$call = new BidiStreamingCall($this->channel,
$method,
$deserialize,
- $timeout);
+ $options);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
if (is_callable($this->update_metadata)) {
- $actual_metadata = call_user_func($this->update_metadata,
- $actual_metadata,
+ $metadata = call_user_func($this->update_metadata,
+ $metadata,
$jwt_aud_uri);
}
- $actual_metadata = $this->_validate_and_normalize_metadata(
- $actual_metadata);
- $call->start($actual_metadata);
+ $metadata = $this->_validate_and_normalize_metadata(
+ $metadata);
+ $call->start($metadata);
return $call;
}
diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
index 4a0bd6a1f1..1fe81b9d54 100644
--- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -41,7 +41,6 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase
* running on $GRPC_TEST_HOST.
*/
protected static $client;
- protected static $timeout;
public function testWaitForNotReady()
{
@@ -93,7 +92,7 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase
public function testTimeout()
{
$div_arg = new math\DivArgs();
- $call = self::$client->Div($div_arg, ['timeout' => 100]);
+ $call = self::$client->Div($div_arg, [], ['timeout' => 100]);
list($response, $status) = $call->wait();
$this->assertSame(\Grpc\STATUS_DEADLINE_EXCEEDED, $status->code);
}
@@ -112,7 +111,9 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase
*/
public function testInvalidMethodName()
{
- $invalid_client = new DummyInvalidClient('host', []);
+ $invalid_client = new DummyInvalidClient('host', [
+ 'credentials' => Grpc\ChannelCredentials::createInsecure(),
+ ]);
$div_arg = new math\DivArgs();
$invalid_client->InvalidUnaryCall($div_arg);
}
diff --git a/src/php/tests/generated_code/GeneratedCodeTest.php b/src/php/tests/generated_code/GeneratedCodeTest.php
index 7043e8e1d1..0cdce6cf92 100755
--- a/src/php/tests/generated_code/GeneratedCodeTest.php
+++ b/src/php/tests/generated_code/GeneratedCodeTest.php
@@ -38,10 +38,12 @@ class GeneratedCodeTest extends AbstractGeneratedCodeTest
public function setUp()
{
self::$client = new math\MathClient(
- getenv('GRPC_TEST_HOST'), []);
+ getenv('GRPC_TEST_HOST'), [
+ 'credentials' => Grpc\ChannelCredentials::createInsecure(),
+ ]);
}
- public static function tearDownAfterClass()
+ public function tearDown()
{
self::$client->close();
}
diff --git a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php
index 5a20e684c7..6bb1955ccb 100644
--- a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php
+++ b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php
@@ -39,7 +39,8 @@ class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest
{
self::$client = new math\MathClient(
getenv('GRPC_TEST_HOST'),
- ['update_metadata' => function ($a_hash,
+ ['credentials' => Grpc\ChannelCredentials::createInsecure(),
+ 'update_metadata' => function ($a_hash,
$client = []) {
$a_copy = $a_hash;
$a_copy['foo'] = ['bar'];
@@ -48,7 +49,7 @@ class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest
}]);
}
- public static function tearDownAfterClass()
+ public function tearDown()
{
self::$client->close();
}
diff --git a/src/php/tests/generated_code/math.proto b/src/php/tests/generated_code/math.proto
index 1de7d0b8de..c872ee6e0b 100644
--- a/src/php/tests/generated_code/math.proto
+++ b/src/php/tests/generated_code/math.proto
@@ -28,6 +28,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// TODO: start using src/proto/math/math.proto and remove this file once
+// PHP supports proto3.
+
syntax = "proto2";
package math;
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 9aab5c966c..aebf80f6bf 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -84,7 +84,7 @@ function largeUnary($stub)
* @param $fillOauthScope boolean whether to fill result with oauth scope
*/
function performLargeUnary($stub, $fillUsername = false, $fillOauthScope = false,
- $metadata = [])
+ $callback = false)
{
$request_len = 271828;
$response_len = 314159;
@@ -99,7 +99,12 @@ function performLargeUnary($stub, $fillUsername = false, $fillOauthScope = false
$request->setFillUsername($fillUsername);
$request->setFillOauthScope($fillOauthScope);
- list($result, $status) = $stub->UnaryCall($request, $metadata)->wait();
+ $options = false;
+ if ($callback) {
+ $options['call_credentials_callback'] = $callback;
+ }
+
+ list($result, $status) = $stub->UnaryCall($request, [], $options)->wait();
hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result !== null, 'Call returned a null response');
$payload = $result->getPayload();
@@ -186,6 +191,15 @@ function oauth2AuthToken($stub, $args)
'invalid email returned');
}
+function updateAuthMetadataCallback($context)
+{
+ $authUri = $context->service_url;
+ $methodName = $context->method_name;
+ $auth_credentials = ApplicationDefaultCredentials::getCredentials();
+
+ return $auth_credentials->updateMetadata($metadata = [], $authUri);
+}
+
/**
* Run the per_rpc_creds auth test.
*
@@ -197,15 +211,9 @@ function perRpcCreds($stub, $args)
$jsonKey = json_decode(
file_get_contents(getenv(CredentialsLoader::ENV_VAR)),
true);
- $auth_credentials = ApplicationDefaultCredentials::getCredentials(
- $args['oauth_scope']
- );
- $token = $auth_credentials->fetchAuthToken();
- $metadata = [CredentialsLoader::AUTH_METADATA_KEY => [sprintf('%s %s',
- $token['token_type'],
- $token['access_token'])]];
+
$result = performLargeUnary($stub, $fillUsername = true, $fillOauthScope = true,
- $metadata);
+ 'updateAuthMetadataCallback');
hardAssert($result->getUsername() == $jsonKey['client_email'],
'invalid email returned');
}
@@ -363,7 +371,7 @@ function cancelAfterFirstResponse($stub)
function timeoutOnSleepingServer($stub)
{
- $call = $stub->FullDuplexCall(['timeout' => 1000]);
+ $call = $stub->FullDuplexCall([], ['timeout' => 1000]);
$request = new grpc\testing\StreamingOutputCallRequest();
$request->setResponseType(grpc\testing\PayloadType::COMPRESSABLE);
$response_parameters = new grpc\testing\ResponseParameters();
@@ -430,6 +438,8 @@ if ($use_tls) {
}
$opts['credentials'] = $ssl_credentials;
$opts['grpc.ssl_target_name_override'] = $host_override;
+} else {
+ $opts['credentials'] = Grpc\ChannelCredentials::createInsecure();
}
if (in_array($test_case, ['service_account_creds',
diff --git a/src/php/tests/unit_tests/CallCredentialsTest.php b/src/php/tests/unit_tests/CallCredentialsTest.php
new file mode 100644
index 0000000000..0918412781
--- /dev/null
+++ b/src/php/tests/unit_tests/CallCredentialsTest.php
@@ -0,0 +1,137 @@
+<?php
+/*
+ *
+ * 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.
+ *
+ */
+
+class CallCredentialsTest extends PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ $credentials = Grpc\ChannelCredentials::createSsl(
+ file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
+ $call_credentials = Grpc\CallCredentials::createFromPlugin(
+ array($this, 'callbackFunc'));
+ $credentials = Grpc\ChannelCredentials::createComposite(
+ $credentials,
+ $call_credentials
+ );
+ $server_credentials = Grpc\ServerCredentials::createSsl(
+ null,
+ file_get_contents(dirname(__FILE__).'/../data/server1.key'),
+ file_get_contents(dirname(__FILE__).'/../data/server1.pem'));
+ $this->server = new Grpc\Server();
+ $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0',
+ $server_credentials);
+ $this->server->start();
+ $this->host_override = 'foo.test.google.fr';
+ $this->channel = new Grpc\Channel(
+ 'localhost:'.$this->port,
+ [
+ 'grpc.ssl_target_name_override' => $this->host_override,
+ 'grpc.default_authority' => $this->host_override,
+ 'credentials' => $credentials,
+ ]
+ );
+ }
+
+ public function tearDown()
+ {
+ unset($this->channel);
+ unset($this->server);
+ }
+
+ public function callbackFunc($context)
+ {
+ $this->assertTrue(is_string($context->service_url));
+ $this->assertTrue(is_string($context->method_name));
+
+ return ['k1' => ['v1'], 'k2' => ['v2']];
+ }
+
+ public function testCreateFromPlugin()
+ {
+ $deadline = Grpc\Timeval::infFuture();
+ $status_text = 'xyz';
+ $call = new Grpc\Call($this->channel,
+ '/abc/dummy_method',
+ $deadline,
+ $this->host_override);
+
+ $event = $call->startBatch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+
+ $event = $this->server->requestCall();
+
+ $this->assertTrue(is_array($event->metadata));
+ $metadata = $event->metadata;
+ $this->assertTrue(array_key_exists('k1', $metadata));
+ $this->assertTrue(array_key_exists('k2', $metadata));
+ $this->assertSame($metadata['k1'], ['v1']);
+ $this->assertSame($metadata['k2'], ['v2']);
+
+ $this->assertSame('/abc/dummy_method', $event->method);
+ $server_call = $event->call;
+
+ $event = $server_call->startBatch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_STATUS_FROM_SERVER => [
+ 'metadata' => [],
+ 'code' => Grpc\STATUS_OK,
+ 'details' => $status_text,
+ ],
+ Grpc\OP_RECV_CLOSE_ON_SERVER => true,
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_status);
+ $this->assertFalse($event->cancelled);
+
+ $event = $call->startBatch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+ ]);
+
+ $this->assertSame([], $event->metadata);
+ $status = $event->status;
+ $this->assertSame([], $status->metadata);
+ $this->assertSame(Grpc\STATUS_OK, $status->code);
+ $this->assertSame($status_text, $status->details);
+
+ unset($call);
+ unset($server_call);
+ }
+}
diff --git a/src/ruby/pb/grpc/health/v1alpha/health.proto b/src/proto/grpc/health/v1alpha/health.proto
index d31df1e0a7..28786c4427 100644
--- a/src/ruby/pb/grpc/health/v1alpha/health.proto
+++ b/src/proto/grpc/health/v1alpha/health.proto
@@ -30,6 +30,7 @@
syntax = "proto3";
package grpc.health.v1alpha;
+option csharp_namespace = "Grpc.Health.V1Alpha";
message HealthCheckRequest {
string host = 1;
diff --git a/src/csharp/Grpc.Examples/proto/math.proto b/src/proto/math/math.proto
index 311e148c02..311e148c02 100644
--- a/src/csharp/Grpc.Examples/proto/math.proto
+++ b/src/proto/math/math.proto
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore
index 4c02b8d14d..95b96f7c1e 100644
--- a/src/python/grpcio/.gitignore
+++ b/src/python/grpcio/.gitignore
@@ -5,5 +5,12 @@ dist/
*.egg
*.egg/
*.eggs/
+*_pb2.py
+.coverage
+.coverage.*
+.cache/
+.tox/
+nosetests.xml
doc/
_grpcio_metadata.py
+htmlcov/
diff --git a/src/python/grpcio/MANIFEST.in b/src/python/grpcio/MANIFEST.in
index 9583dc7768..407eeabc17 100644
--- a/src/python/grpcio/MANIFEST.in
+++ b/src/python/grpcio/MANIFEST.in
@@ -1,3 +1,4 @@
graft grpc
+graft tests
include commands.py
include requirements.txt
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 8a2f2d6283..d9fd023b21 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -29,14 +29,18 @@
"""Provides distutils command classes for the GRPC Python setup process."""
+import distutils
import os
import os.path
+import re
+import subprocess
import sys
import setuptools
from setuptools.command import build_py
+from setuptools.command import test
-_CONF_PY_ADDENDUM = """
+CONF_PY_ADDENDUM = """
extensions.append('sphinx.ext.napoleon')
napoleon_google_docstring = True
napoleon_numpy_docstring = True
@@ -48,7 +52,7 @@ html_theme = 'sphinx_rtd_theme'
class SphinxDocumentation(setuptools.Command):
"""Command to generate documentation via sphinx."""
- description = ''
+ description = 'generate sphinx documentation'
user_options = []
def initialize_options(self):
@@ -72,14 +76,61 @@ class SphinxDocumentation(setuptools.Command):
'-o', os.path.join('doc', 'src'), src_dir])
conf_filepath = os.path.join('doc', 'src', 'conf.py')
with open(conf_filepath, 'a') as conf_file:
- conf_file.write(_CONF_PY_ADDENDUM)
+ conf_file.write(CONF_PY_ADDENDUM)
sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])
+class BuildProtoModules(setuptools.Command):
+ """Command to generate project *_pb2.py modules from proto files."""
+
+ description = 'build protobuf modules'
+ user_options = [
+ ('include=', None, 'path patterns to include in protobuf generation'),
+ ('exclude=', None, 'path patterns to exclude from protobuf generation')
+ ]
+
+ def initialize_options(self):
+ self.exclude = None
+ self.include = r'.*\.proto$'
+ self.protoc_command = None
+ self.grpc_python_plugin_command = None
+
+ def finalize_options(self):
+ self.protoc_command = distutils.spawn.find_executable('protoc')
+ self.grpc_python_plugin_command = distutils.spawn.find_executable(
+ 'grpc_python_plugin')
+
+ def run(self):
+ include_regex = re.compile(self.include)
+ exclude_regex = re.compile(self.exclude) if self.exclude else None
+ paths = []
+ root_directory = os.getcwd()
+ for walk_root, directories, filenames in os.walk(root_directory):
+ for filename in filenames:
+ path = os.path.join(walk_root, filename)
+ if include_regex.match(path) and not (
+ exclude_regex and exclude_regex.match(path)):
+ paths.append(path)
+ command = [
+ self.protoc_command,
+ '--plugin=protoc-gen-python-grpc={}'.format(
+ self.grpc_python_plugin_command),
+ '-I {}'.format(root_directory),
+ '--python_out={}'.format(root_directory),
+ '--python-grpc_out={}'.format(root_directory),
+ ] + paths
+ try:
+ subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
+ stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ raise Exception('Command:\n{}\nMessage:\n{}\nOutput:\n{}'.format(
+ command, e.message, e.output))
+
+
class BuildProjectMetadata(setuptools.Command):
"""Command to generate project metadata in a module."""
- description = ''
+ description = 'build grpcio project metadata files'
user_options = []
def initialize_options(self):
@@ -98,5 +149,73 @@ class BuildPy(build_py.build_py):
"""Custom project build command."""
def run(self):
+ self.run_command('build_proto_modules')
self.run_command('build_project_metadata')
build_py.build_py.run(self)
+
+
+class Gather(setuptools.Command):
+ """Command to gather project dependencies."""
+
+ description = 'gather dependencies for grpcio'
+ user_options = [
+ ('test', 't', 'flag indicating to gather test dependencies'),
+ ('install', 'i', 'flag indicating to gather install dependencies')
+ ]
+
+ def initialize_options(self):
+ self.test = False
+ self.install = False
+
+ def finalize_options(self):
+ # distutils requires this override.
+ pass
+
+ def run(self):
+ if self.install and self.distribution.install_requires:
+ self.distribution.fetch_build_eggs(self.distribution.install_requires)
+ if self.test and self.distribution.tests_require:
+ self.distribution.fetch_build_eggs(self.distribution.tests_require)
+
+
+class RunInterop(test.test):
+
+ description = 'run interop test client/server'
+ user_options = [
+ ('args=', 'a', 'pass-thru arguments for the client/server'),
+ ('client', 'c', 'flag indicating to run the client'),
+ ('server', 's', 'flag indicating to run the server')
+ ]
+
+ def initialize_options(self):
+ self.args = ''
+ self.client = False
+ self.server = False
+
+ def finalize_options(self):
+ if self.client and self.server:
+ raise DistutilsOptionError('you may only specify one of client or server')
+
+ def run(self):
+ if self.distribution.install_requires:
+ self.distribution.fetch_build_eggs(self.distribution.install_requires)
+ if self.distribution.tests_require:
+ self.distribution.fetch_build_eggs(self.distribution.tests_require)
+ if self.client:
+ self.run_client()
+ elif self.server:
+ self.run_server()
+
+ def run_server(self):
+ # We import here to ensure that our setuptools parent has had a chance to
+ # edit the Python system path.
+ from tests.interop import server
+ sys.argv[1:] = self.args.split()
+ server.serve()
+
+ def run_client(self):
+ # We import here to ensure that our setuptools parent has had a chance to
+ # edit the Python system path.
+ from tests.interop import client
+ sys.argv[1:] = self.args.split()
+ client.test_interoperability()
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h
deleted file mode 100644
index 9ab415d216..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types.h
+++ /dev/null
@@ -1,286 +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.
- *
- */
-
-#ifndef GRPC__ADAPTER__C_TYPES_H_
-#define GRPC__ADAPTER__C_TYPES_H_
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-/*=========================*/
-/* Client-side credentials */
-/*=========================*/
-
-typedef struct ChannelCredentials {
- PyObject_HEAD
- grpc_channel_credentials *c_creds;
-} ChannelCredentials;
-void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self);
-ChannelCredentials *pygrpc_ChannelCredentials_google_default(
- PyTypeObject *type, PyObject *ignored);
-ChannelCredentials *pygrpc_ChannelCredentials_ssl(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ChannelCredentials *pygrpc_ChannelCredentials_composite(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ChannelCredentials_type;
-
-typedef struct CallCredentials {
- PyObject_HEAD
- grpc_call_credentials *c_creds;
-} CallCredentials;
-void pygrpc_CallCredentials_dealloc(CallCredentials *self);
-CallCredentials *pygrpc_CallCredentials_composite(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_compute_engine(
- PyTypeObject *type, PyObject *ignored);
-CallCredentials *pygrpc_CallCredentials_jwt(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_refresh_token(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-CallCredentials *pygrpc_CallCredentials_iam(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_CallCredentials_type;
-
-/*=========================*/
-/* Server-side credentials */
-/*=========================*/
-
-typedef struct ServerCredentials {
- PyObject_HEAD
- grpc_server_credentials *c_creds;
-} ServerCredentials;
-void pygrpc_ServerCredentials_dealloc(ServerCredentials *self);
-ServerCredentials *pygrpc_ServerCredentials_ssl(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ServerCredentials_type;
-
-
-/*==================*/
-/* Completion queue */
-/*==================*/
-
-typedef struct CompletionQueue {
- PyObject_HEAD
- grpc_completion_queue *c_cq;
-} CompletionQueue;
-CompletionQueue *pygrpc_CompletionQueue_new(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_CompletionQueue_dealloc(CompletionQueue *self);
-PyObject *pygrpc_CompletionQueue_next(
- CompletionQueue *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_CompletionQueue_shutdown(
- CompletionQueue *self, PyObject *ignored);
-extern PyTypeObject pygrpc_CompletionQueue_type;
-
-
-/*======*/
-/* Call */
-/*======*/
-
-typedef struct Call {
- PyObject_HEAD
- grpc_call *c_call;
- CompletionQueue *cq;
-} Call;
-Call *pygrpc_Call_new_empty(CompletionQueue *cq);
-void pygrpc_Call_dealloc(Call *self);
-PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Call_peer(Call *self);
-PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
- PyObject *kwargs);
-extern PyTypeObject pygrpc_Call_type;
-
-
-/*=========*/
-/* Channel */
-/*=========*/
-
-typedef struct Channel {
- PyObject_HEAD
- grpc_channel *c_chan;
-} Channel;
-Channel *pygrpc_Channel_new(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_Channel_dealloc(Channel *self);
-Call *pygrpc_Channel_create_call(
- Channel *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Channel_check_connectivity_state(Channel *self, PyObject *args,
- PyObject *kwargs);
-PyObject *pygrpc_Channel_watch_connectivity_state(Channel *self, PyObject *args,
- PyObject *kwargs);
-PyObject *pygrpc_Channel_target(Channel *self);
-extern PyTypeObject pygrpc_Channel_type;
-
-
-/*========*/
-/* Server */
-/*========*/
-
-typedef struct Server {
- PyObject_HEAD
- grpc_server *c_serv;
- CompletionQueue *cq;
- int shutdown_called;
-} Server;
-Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
-void pygrpc_Server_dealloc(Server *self);
-PyObject *pygrpc_Server_request_call(
- Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_add_http2_port(
- Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_start(Server *self, PyObject *ignored);
-PyObject *pygrpc_Server_shutdown(
- Server *self, PyObject *args, PyObject *kwargs);
-PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused);
-extern PyTypeObject pygrpc_Server_type;
-
-/*=========*/
-/* Utility */
-/*=========*/
-
-/* Every tag that passes from Python GRPC to GRPC core is of this type. */
-typedef struct pygrpc_tag {
- PyObject *user_tag;
- Call *call;
- grpc_call_details request_call_details;
- grpc_metadata_array request_metadata;
- grpc_op *ops;
- size_t nops;
- int is_new_call;
-} pygrpc_tag;
-
-/* Construct a tag associated with a batch call. Does not take ownership of the
- resources in the elements of ops. */
-pygrpc_tag *pygrpc_produce_batch_tag(PyObject *user_tag, Call *call,
- grpc_op *ops, size_t nops);
-
-
-/* Construct a tag associated with a server request. The calling code should
- use the appropriate fields of the produced tag in the invocation of
- grpc_server_request_call. */
-pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call);
-
-/* Construct a tag associated with a server shutdown. */
-pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag);
-
-/* Construct a tag associated with a channel state change. */
-pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag);
-
-/* Frees all resources owned by the tag and the tag itself. */
-void pygrpc_discard_tag(pygrpc_tag *tag);
-
-/* Consumes an event and its associated tag, providing a Python tuple of the
- form `(type, tag, call, call_details, results)` (where type is an integer
- corresponding to a grpc_completion_type, tag is an arbitrary PyObject, call
- is the call object associated with the event [if any], call_details is a
- tuple of form `(method, host, deadline)` [if such details are available],
- and resultd is a list of tuples of form `(type, metadata, message, status,
- cancelled)` [where type corresponds to a grpc_op_type, metadata is a
- sequence of 2-sequences of strings, message is a byte string, and status is
- a 2-tuple of an integer corresponding to grpc_status_code and a string of
- status details]).
-
- Frees all resources associated with the event tag. */
-PyObject *pygrpc_consume_event(grpc_event event);
-
-/* Transliterate the Python tuple of form `(type, metadata, message,
- status)` (where type is an integer corresponding to a grpc_op_type, metadata
- is a sequence of 2-sequences of strings, message is a byte string, and
- status is 2-tuple of an integer corresponding to grpc_status_code and a
- string of status details) to a grpc_op suitable for use in a
- grpc_call_start_batch invocation. The grpc_op is a 'directory' of resources
- that must be freed after GRPC core is done with them.
-
- Calls gpr_malloc (or the appropriate type-specific grpc_*_create function)
- to populate the appropriate union-discriminated members of the op.
-
- Returns true on success, false on failure. */
-int pygrpc_produce_op(PyObject *op, grpc_op *result);
-
-/* Discards all resources associated with the passed in op that was produced by
- pygrpc_produce_op. */
-void pygrpc_discard_op(grpc_op op);
-
-/* Transliterate the grpc_ops (which have been sent through a
- grpc_call_start_batch invocation and whose corresponding event has appeared
- on a completion queue) to a Python tuple of form `(type, metadata, message,
- status, cancelled)` (where type is an integer corresponding to a
- grpc_op_type, metadata is a sequence of 2-sequences of strings, message is a
- byte string, and status is 2-tuple of an integer corresponding to
- grpc_status_code and a string of status details).
-
- Calls gpr_free (or the appropriate type-specific grpc_*_destroy function) on
- the appropriate union-discriminated populated members of the ops. */
-PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops);
-
-/* Transliterate from a gpr_timespec to a double (in units of seconds, either
- from the epoch if interpreted absolutely or as a delta otherwise). */
-double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec);
-
-/* Transliterate from a double (in units of seconds from the epoch if
- interpreted absolutely or as a delta otherwise) to a gpr_timespec. */
-gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds);
-
-/* Returns true on success, false on failure. */
-int pygrpc_cast_pyseq_to_send_metadata(
- PyObject *pyseq, grpc_metadata **metadata, size_t *count);
-/* Returns a metadata array as a Python object on success, else NULL. */
-PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata);
-
-/* Transliterate from a list of python channel arguments (2-tuples of string
- and string|integer|None) to a grpc_channel_args object. The strings placed
- in the grpc_channel_args object's grpc_arg elements are views of the Python
- object. The Python object must live long enough for the grpc_channel_args
- to be used. Arguments set to None are silently ignored. Returns true on
- success, false on failure. */
-int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args);
-void pygrpc_discard_channel_args(grpc_channel_args args);
-
-/* Read the bytes from grpc_byte_buffer to a gpr_malloc'd array of bytes;
- output to result and result_size. */
-void pygrpc_byte_buffer_to_bytes(
- grpc_byte_buffer *buffer, char **result, size_t *result_size);
-
-
-/*========*/
-/* Module */
-/*========*/
-
-/* Returns 0 on success, -1 on failure. */
-int pygrpc_module_add_types(PyObject *module);
-
-#endif /* GRPC__ADAPTER__C_TYPES_H_ */
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
deleted file mode 100644
index 04ec871880..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ /dev/null
@@ -1,186 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_Call_methods[] = {
- {"start_batch", (PyCFunction)pygrpc_Call_start_batch, METH_KEYWORDS, ""},
- {"cancel", (PyCFunction)pygrpc_Call_cancel, METH_KEYWORDS, ""},
- {"peer", (PyCFunction)pygrpc_Call_peer, METH_NOARGS, ""},
- {"set_credentials", (PyCFunction)pygrpc_Call_set_credentials, METH_KEYWORDS,
- ""},
- {NULL}
-};
-const char pygrpc_Call_doc[] = "See grpc._adapter._types.Call.";
-PyTypeObject pygrpc_Call_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "Call", /* tp_name */
- sizeof(Call), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_Call_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_Call_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_Call_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0 /* tp_new */
-};
-
-Call *pygrpc_Call_new_empty(CompletionQueue *cq) {
- Call *call = (Call *)pygrpc_Call_type.tp_alloc(&pygrpc_Call_type, 0);
- call->c_call = NULL;
- call->cq = cq;
- Py_XINCREF(call->cq);
- return call;
-}
-void pygrpc_Call_dealloc(Call *self) {
- if (self->c_call) {
- grpc_call_destroy(self->c_call);
- }
- Py_XDECREF(self->cq);
- self->ob_type->tp_free((PyObject *)self);
-}
-PyObject *pygrpc_Call_start_batch(Call *self, PyObject *args, PyObject *kwargs) {
- PyObject *op_list;
- PyObject *user_tag;
- grpc_op *ops;
- size_t nops;
- size_t i;
- size_t j;
- pygrpc_tag *tag;
- grpc_call_error errcode;
- static char *keywords[] = {"ops", "tag", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO:start_batch", keywords,
- &op_list, &user_tag)) {
- return NULL;
- }
- if (!PyList_Check(op_list)) {
- PyErr_SetString(PyExc_TypeError, "expected a list of OpArgs");
- return NULL;
- }
- nops = PyList_Size(op_list);
- ops = gpr_malloc(sizeof(grpc_op) * nops);
- for (i = 0; i < nops; ++i) {
- PyObject *item = PyList_GET_ITEM(op_list, i);
- if (!pygrpc_produce_op(item, &ops[i])) {
- for (j = 0; j < i; ++j) {
- pygrpc_discard_op(ops[j]);
- }
- return NULL;
- }
- }
- tag = pygrpc_produce_batch_tag(user_tag, self, ops, nops);
- errcode = grpc_call_start_batch(self->c_call, tag->ops, tag->nops, tag, NULL);
- gpr_free(ops);
- return PyInt_FromLong(errcode);
-}
-PyObject *pygrpc_Call_cancel(Call *self, PyObject *args, PyObject *kwargs) {
- PyObject *py_code = NULL;
- grpc_call_error errcode;
- int code;
- char *details = NULL;
- static char *keywords[] = {"code", "details", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:start_batch", keywords,
- &py_code, &details)) {
- return NULL;
- }
- if (py_code != NULL && details != NULL) {
- if (!PyInt_Check(py_code)) {
- PyErr_SetString(PyExc_TypeError, "expected integer code");
- return NULL;
- }
- code = PyInt_AsLong(py_code);
- errcode = grpc_call_cancel_with_status(self->c_call, code, details, NULL);
- } else if (py_code != NULL || details != NULL) {
- PyErr_SetString(PyExc_ValueError,
- "if `code` is specified, so must `details`");
- return NULL;
- } else {
- errcode = grpc_call_cancel(self->c_call, NULL);
- }
- return PyInt_FromLong(errcode);
-}
-
-PyObject *pygrpc_Call_peer(Call *self) {
- char *peer = grpc_call_get_peer(self->c_call);
- PyObject *py_peer = PyString_FromString(peer);
- gpr_free(peer);
- return py_peer;
-}
-PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
- PyObject *kwargs) {
- CallCredentials *creds;
- grpc_call_error errcode;
- static char *keywords[] = {"creds", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, "O!:set_credentials", keywords,
- &pygrpc_CallCredentials_type, &creds)) {
- return NULL;
- }
- errcode = grpc_call_set_credentials(self->c_call, creds->c_creds);
- return PyInt_FromLong(errcode);
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
deleted file mode 100644
index 5a15a6e17d..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
+++ /dev/null
@@ -1,203 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-PyMethodDef pygrpc_CallCredentials_methods[] = {
- {"composite", (PyCFunction)pygrpc_CallCredentials_composite,
- METH_CLASS|METH_KEYWORDS, ""},
- {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine,
- METH_CLASS|METH_NOARGS, ""},
- {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt,
- METH_CLASS|METH_KEYWORDS, ""},
- {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token,
- METH_CLASS|METH_KEYWORDS, ""},
- {"iam", (PyCFunction)pygrpc_CallCredentials_iam,
- METH_CLASS|METH_KEYWORDS, ""},
- {NULL}
-};
-
-const char pygrpc_CallCredentials_doc[] = "";
-PyTypeObject pygrpc_CallCredentials_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "CallCredentials", /* tp_name */
- sizeof(CallCredentials), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_CallCredentials_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_CallCredentials_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_CallCredentials_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0 /* tp_new */
-};
-
-void pygrpc_CallCredentials_dealloc(CallCredentials *self) {
- grpc_call_credentials_release(self->c_creds);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-CallCredentials *pygrpc_CallCredentials_composite(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- CallCredentials *self;
- CallCredentials *creds1;
- CallCredentials *creds2;
- static char *keywords[] = {"creds1", "creds2", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
- &pygrpc_CallCredentials_type, &creds1,
- &pygrpc_CallCredentials_type, &creds2)) {
- return NULL;
- }
- self = (CallCredentials *)type->tp_alloc(type, 0);
- self->c_creds =
- grpc_composite_call_credentials_create(
- creds1->c_creds, creds2->c_creds, NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials");
- return NULL;
- }
- return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_compute_engine(
- PyTypeObject *type, PyObject *ignored) {
- CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_google_compute_engine_credentials_create(NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError,
- "couldn't create compute engine credentials");
- return NULL;
- }
- return self;
-}
-
-/* TODO: Rename this credentials to something like service_account_jwt_access */
-CallCredentials *pygrpc_CallCredentials_jwt(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- CallCredentials *self;
- const char *json_key;
- double lifetime;
- static char *keywords[] = {"json_key", "token_lifetime", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sd:jwt", keywords,
- &json_key, &lifetime)) {
- return NULL;
- }
- self = (CallCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_service_account_jwt_access_credentials_create(
- json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials");
- return NULL;
- }
- return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_refresh_token(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- CallCredentials *self;
- const char *json_refresh_token;
- static char *keywords[] = {"json_refresh_token", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords,
- &json_refresh_token)) {
- return NULL;
- }
- self = (CallCredentials *)type->tp_alloc(type, 0);
- self->c_creds =
- grpc_google_refresh_token_credentials_create(json_refresh_token, NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError,
- "couldn't create credentials from refresh token");
- return NULL;
- }
- return self;
-}
-
-CallCredentials *pygrpc_CallCredentials_iam(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- CallCredentials *self;
- const char *authorization_token;
- const char *authority_selector;
- static char *keywords[] = {"authorization_token", "authority_selector", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss:iam", keywords,
- &authorization_token, &authority_selector)) {
- return NULL;
- }
- self = (CallCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_google_iam_credentials_create(authorization_token,
- authority_selector, NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials");
- return NULL;
- }
- return self;
-}
-
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
deleted file mode 100644
index c4db2a0dfd..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ /dev/null
@@ -1,187 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_Channel_methods[] = {
- {"create_call", (PyCFunction)pygrpc_Channel_create_call, METH_KEYWORDS, ""},
- {"check_connectivity_state", (PyCFunction)pygrpc_Channel_check_connectivity_state, METH_KEYWORDS, ""},
- {"watch_connectivity_state", (PyCFunction)pygrpc_Channel_watch_connectivity_state, METH_KEYWORDS, ""},
- {"target", (PyCFunction)pygrpc_Channel_target, METH_NOARGS, ""},
- {NULL}
-};
-const char pygrpc_Channel_doc[] = "See grpc._adapter._types.Channel.";
-PyTypeObject pygrpc_Channel_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "Channel", /* tp_name */
- sizeof(Channel), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_Channel_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_Channel_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_Channel_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- (newfunc)pygrpc_Channel_new /* tp_new */
-};
-
-Channel *pygrpc_Channel_new(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- Channel *self;
- const char *target;
- PyObject *py_args;
- ChannelCredentials *creds = NULL;
- grpc_channel_args c_args;
- char *keywords[] = {"target", "args", "creds", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords,
- &target, &py_args, &pygrpc_ChannelCredentials_type, &creds)) {
- return NULL;
- }
- if (!pygrpc_produce_channel_args(py_args, &c_args)) {
- return NULL;
- }
- self = (Channel *)type->tp_alloc(type, 0);
- if (creds) {
- self->c_chan =
- grpc_secure_channel_create(creds->c_creds, target, &c_args, NULL);
- } else {
- self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL);
- }
- pygrpc_discard_channel_args(c_args);
- return self;
-}
-void pygrpc_Channel_dealloc(Channel *self) {
- grpc_channel_destroy(self->c_chan);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-Call *pygrpc_Channel_create_call(
- Channel *self, PyObject *args, PyObject *kwargs) {
- Call *call;
- CompletionQueue *cq;
- const char *method;
- const char *host;
- double deadline;
- char *keywords[] = {"cq", "method", "host", "deadline", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!szd:create_call", keywords,
- &pygrpc_CompletionQueue_type, &cq, &method, &host, &deadline)) {
- return NULL;
- }
- call = pygrpc_Call_new_empty(cq);
- call->c_call = grpc_channel_create_call(
- self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
- pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
- return call;
-}
-
-PyObject *pygrpc_Channel_check_connectivity_state(
- Channel *self, PyObject *args, PyObject *kwargs) {
- PyObject *py_try_to_connect;
- int try_to_connect;
- char *keywords[] = {"try_to_connect", NULL};
- grpc_connectivity_state state;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:connectivity_state", keywords,
- &py_try_to_connect)) {
- return NULL;
- }
- if (!PyBool_Check(py_try_to_connect)) {
- Py_XDECREF(py_try_to_connect);
- return NULL;
- }
- try_to_connect = Py_True == py_try_to_connect;
- Py_DECREF(py_try_to_connect);
- state = grpc_channel_check_connectivity_state(self->c_chan, try_to_connect);
- return PyInt_FromLong(state);
-}
-
-PyObject *pygrpc_Channel_watch_connectivity_state(
- Channel *self, PyObject *args, PyObject *kwargs) {
- PyObject *tag;
- double deadline;
- int last_observed_state;
- CompletionQueue *completion_queue;
- char *keywords[] = {"last_observed_state", "deadline",
- "completion_queue", "tag", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, "idO!O:watch_connectivity_state", keywords,
- &last_observed_state, &deadline, &pygrpc_CompletionQueue_type,
- &completion_queue, &tag)) {
- return NULL;
- }
- grpc_channel_watch_connectivity_state(
- self->c_chan, (grpc_connectivity_state)last_observed_state,
- pygrpc_cast_double_to_gpr_timespec(deadline), completion_queue->c_cq,
- pygrpc_produce_channel_state_change_tag(tag));
- Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Channel_target(Channel *self) {
- char *target = grpc_channel_get_target(self->c_chan);
- PyObject *py_target = PyString_FromString(target);
- gpr_free(target);
- return py_target;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
deleted file mode 100644
index 83b1fc0406..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
+++ /dev/null
@@ -1,165 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-
-PyMethodDef pygrpc_ChannelCredentials_methods[] = {
- {"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default,
- METH_CLASS|METH_NOARGS, ""},
- {"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl,
- METH_CLASS|METH_KEYWORDS, ""},
- {"composite", (PyCFunction)pygrpc_ChannelCredentials_composite,
- METH_CLASS|METH_KEYWORDS, ""},
- {NULL}
-};
-
-const char pygrpc_ChannelCredentials_doc[] = "";
-PyTypeObject pygrpc_ChannelCredentials_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "ChannelCredentials", /* tp_name */
- sizeof(ChannelCredentials), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_ChannelCredentials_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_ChannelCredentials_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_ChannelCredentials_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0 /* tp_new */
-};
-
-void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self) {
- grpc_channel_credentials_release(self->c_creds);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_google_default(
- PyTypeObject *type, PyObject *ignored) {
- ChannelCredentials *self = (ChannelCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_google_default_credentials_create();
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError,
- "couldn't create Google default credentials");
- return NULL;
- }
- return self;
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_ssl(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- ChannelCredentials *self;
- const char *root_certs;
- const char *private_key = NULL;
- const char *cert_chain = NULL;
- grpc_ssl_pem_key_cert_pair key_cert_pair;
- static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords,
- &root_certs, &private_key, &cert_chain)) {
- return NULL;
- }
- self = (ChannelCredentials *)type->tp_alloc(type, 0);
- if (private_key && cert_chain) {
- key_cert_pair.private_key = private_key;
- key_cert_pair.cert_chain = cert_chain;
- self->c_creds =
- grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL);
- } else {
- self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
- }
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
- return NULL;
- }
- return self;
-}
-
-ChannelCredentials *pygrpc_ChannelCredentials_composite(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- ChannelCredentials *self;
- ChannelCredentials *creds1;
- CallCredentials *creds2;
- static char *keywords[] = {"creds1", "creds2", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
- &pygrpc_ChannelCredentials_type, &creds1,
- &pygrpc_CallCredentials_type, &creds2)) {
- return NULL;
- }
- self = (ChannelCredentials *)type->tp_alloc(type, 0);
- self->c_creds =
- grpc_composite_channel_credentials_create(
- creds1->c_creds, creds2->c_creds, NULL);
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(
- PyExc_RuntimeError, "couldn't create composite credentials");
- return NULL;
- }
- return self;
-}
-
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c b/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
deleted file mode 100644
index d8bb89ca4b..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/completion_queue.c
+++ /dev/null
@@ -1,124 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-
-PyMethodDef pygrpc_CompletionQueue_methods[] = {
- {"next", (PyCFunction)pygrpc_CompletionQueue_next, METH_KEYWORDS, ""},
- {"shutdown", (PyCFunction)pygrpc_CompletionQueue_shutdown, METH_NOARGS, ""},
- {NULL}
-};
-const char pygrpc_CompletionQueue_doc[] =
- "See grpc._adapter._types.CompletionQueue.";
-PyTypeObject pygrpc_CompletionQueue_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "CompletionQueue", /* tp_name */
- sizeof(CompletionQueue), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_CompletionQueue_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_CompletionQueue_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_CompletionQueue_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- (newfunc)pygrpc_CompletionQueue_new /* tp_new */
-};
-
-CompletionQueue *pygrpc_CompletionQueue_new(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- CompletionQueue *self = (CompletionQueue *)type->tp_alloc(type, 0);
- self->c_cq = grpc_completion_queue_create(NULL);
- return self;
-}
-
-void pygrpc_CompletionQueue_dealloc(CompletionQueue *self) {
- grpc_completion_queue_destroy(self->c_cq);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-PyObject *pygrpc_CompletionQueue_next(
- CompletionQueue *self, PyObject *args, PyObject *kwargs) {
- double deadline;
- grpc_event event;
- PyObject *transliterated_event;
- static char *keywords[] = {"deadline", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:next", keywords,
- &deadline)) {
- return NULL;
- }
- Py_BEGIN_ALLOW_THREADS;
- event = grpc_completion_queue_next(
- self->c_cq, pygrpc_cast_double_to_gpr_timespec(deadline), NULL);
- Py_END_ALLOW_THREADS;
- transliterated_event = pygrpc_consume_event(event);
- return transliterated_event;
-}
-
-PyObject *pygrpc_CompletionQueue_shutdown(
- CompletionQueue *self, PyObject *ignored) {
- grpc_completion_queue_shutdown(self->c_cq);
- Py_RETURN_NONE;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server.c b/src/python/grpcio/grpc/_adapter/_c/types/server.c
deleted file mode 100644
index 8feab8aab1..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/server.c
+++ /dev/null
@@ -1,196 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-
-
-PyMethodDef pygrpc_Server_methods[] = {
- {"request_call", (PyCFunction)pygrpc_Server_request_call,
- METH_KEYWORDS, ""},
- {"add_http2_port", (PyCFunction)pygrpc_Server_add_http2_port,
- METH_KEYWORDS, ""},
- {"start", (PyCFunction)pygrpc_Server_start, METH_NOARGS, ""},
- {"shutdown", (PyCFunction)pygrpc_Server_shutdown, METH_KEYWORDS, ""},
- {"cancel_all_calls", (PyCFunction)pygrpc_Server_cancel_all_calls,
- METH_NOARGS, ""},
- {NULL}
-};
-const char pygrpc_Server_doc[] = "See grpc._adapter._types.Server.";
-PyTypeObject pygrpc_Server_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "Server", /* tp_name */
- sizeof(Server), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_Server_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_Server_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_Server_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- (newfunc)pygrpc_Server_new /* tp_new */
-};
-
-Server *pygrpc_Server_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- Server *self;
- CompletionQueue *cq;
- PyObject *py_args;
- grpc_channel_args c_args;
- char *keywords[] = {"cq", "args", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Server", keywords,
- &pygrpc_CompletionQueue_type, &cq, &py_args)) {
- return NULL;
- }
- if (!pygrpc_produce_channel_args(py_args, &c_args)) {
- return NULL;
- }
- self = (Server *)type->tp_alloc(type, 0);
- self->c_serv = grpc_server_create(&c_args, NULL);
- grpc_server_register_completion_queue(self->c_serv, cq->c_cq, NULL);
- pygrpc_discard_channel_args(c_args);
- self->cq = cq;
- Py_INCREF(self->cq);
- self->shutdown_called = 0;
- return self;
-}
-
-void pygrpc_Server_dealloc(Server *self) {
- grpc_server_destroy(self->c_serv);
- Py_XDECREF(self->cq);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-PyObject *pygrpc_Server_request_call(
- Server *self, PyObject *args, PyObject *kwargs) {
- CompletionQueue *cq;
- PyObject *user_tag;
- pygrpc_tag *tag;
- Call *empty_call;
- grpc_call_error errcode;
- static char *keywords[] = {"cq", "tag", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, "O!O", keywords,
- &pygrpc_CompletionQueue_type, &cq, &user_tag)) {
- return NULL;
- }
- empty_call = pygrpc_Call_new_empty(cq);
- tag = pygrpc_produce_request_tag(user_tag, empty_call);
- errcode = grpc_server_request_call(
- self->c_serv, &tag->call->c_call, &tag->request_call_details,
- &tag->request_metadata, tag->call->cq->c_cq, self->cq->c_cq, tag);
- Py_DECREF(empty_call);
- return PyInt_FromLong(errcode);
-}
-
-PyObject *pygrpc_Server_add_http2_port(
- Server *self, PyObject *args, PyObject *kwargs) {
- const char *addr;
- ServerCredentials *creds = NULL;
- int port;
- static char *keywords[] = {"addr", "creds", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, "s|O!:add_http2_port", keywords,
- &addr, &pygrpc_ServerCredentials_type, &creds)) {
- return NULL;
- }
- if (creds) {
- port = grpc_server_add_secure_http2_port(
- self->c_serv, addr, creds->c_creds);
- } else {
- port = grpc_server_add_insecure_http2_port(self->c_serv, addr);
- }
- return PyInt_FromLong(port);
-
-}
-
-PyObject *pygrpc_Server_start(Server *self, PyObject *ignored) {
- grpc_server_start(self->c_serv);
- self->shutdown_called = 0;
- Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Server_shutdown(
- Server *self, PyObject *args, PyObject *kwargs) {
- PyObject *user_tag;
- pygrpc_tag *tag;
- static char *keywords[] = {"tag", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &user_tag)) {
- return NULL;
- }
- tag = pygrpc_produce_server_shutdown_tag(user_tag);
- grpc_server_shutdown_and_notify(self->c_serv, self->cq->c_cq, tag);
- self->shutdown_called = 1;
- Py_RETURN_NONE;
-}
-
-PyObject *pygrpc_Server_cancel_all_calls(Server *self, PyObject *unused) {
- if (!self->shutdown_called) {
- PyErr_SetString(
- PyExc_RuntimeError,
- "shutdown must have been called prior to calling cancel_all_calls!");
- return NULL;
- }
- grpc_server_cancel_all_calls(self->c_serv);
- Py_RETURN_NONE;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
deleted file mode 100644
index df51a99b6a..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
+++ /dev/null
@@ -1,137 +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 "grpc/_adapter/_c/types.h"
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-#include <grpc/support/alloc.h>
-
-
-PyMethodDef pygrpc_ServerCredentials_methods[] = {
- {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl,
- METH_CLASS|METH_KEYWORDS, ""},
- {NULL}
-};
-const char pygrpc_ServerCredentials_doc[] = "";
-PyTypeObject pygrpc_ServerCredentials_type = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "ServerCredentials", /* tp_name */
- sizeof(ServerCredentials), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)pygrpc_ServerCredentials_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- pygrpc_ServerCredentials_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- pygrpc_ServerCredentials_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0 /* tp_new */
-};
-
-void pygrpc_ServerCredentials_dealloc(ServerCredentials *self) {
- grpc_server_credentials_release(self->c_creds);
- self->ob_type->tp_free((PyObject *)self);
-}
-
-ServerCredentials *pygrpc_ServerCredentials_ssl(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- ServerCredentials *self;
- const char *root_certs;
- PyObject *py_key_cert_pairs;
- grpc_ssl_pem_key_cert_pair *key_cert_pairs;
- int force_client_auth;
- size_t num_key_cert_pairs;
- size_t i;
- static char *keywords[] = {
- "root_certs", "key_cert_pairs", "force_client_auth", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords,
- &root_certs, &py_key_cert_pairs, &force_client_auth)) {
- return NULL;
- }
- if (!PyList_Check(py_key_cert_pairs)) {
- PyErr_SetString(PyExc_TypeError, "expected a list of 2-tuples of strings");
- return NULL;
- }
- num_key_cert_pairs = PyList_Size(py_key_cert_pairs);
- key_cert_pairs =
- gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
- for (i = 0; i < num_key_cert_pairs; ++i) {
- PyObject *item = PyList_GET_ITEM(py_key_cert_pairs, i);
- const char *key;
- const char *cert;
- if (!PyArg_ParseTuple(item, "zz", &key, &cert)) {
- gpr_free(key_cert_pairs);
- PyErr_SetString(PyExc_TypeError,
- "expected a list of 2-tuples of strings");
- return NULL;
- }
- key_cert_pairs[i].private_key = key;
- key_cert_pairs[i].cert_chain = cert;
- }
-
- self = (ServerCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_ssl_server_credentials_create(
- root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL);
- gpr_free(key_cert_pairs);
- return self;
-}
diff --git a/src/python/grpcio/grpc/_adapter/_c/utility.c b/src/python/grpcio/grpc/_adapter/_c/utility.c
deleted file mode 100644
index 590f7e013a..0000000000
--- a/src/python/grpcio/grpc/_adapter/_c/utility.c
+++ /dev/null
@@ -1,524 +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 <math.h>
-#include <string.h>
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#include <grpc/grpc.h>
-#include <grpc/byte_buffer_reader.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/slice.h>
-#include <grpc/support/time.h>
-#include <grpc/support/string_util.h>
-
-#include "grpc/_adapter/_c/types.h"
-
-pygrpc_tag *pygrpc_produce_batch_tag(
- PyObject *user_tag, Call *call, grpc_op *ops, size_t nops) {
- pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
- tag->user_tag = user_tag;
- Py_XINCREF(tag->user_tag);
- tag->call = call;
- Py_XINCREF(tag->call);
- tag->ops = gpr_malloc(sizeof(grpc_op)*nops);
- memcpy(tag->ops, ops, sizeof(grpc_op)*nops);
- tag->nops = nops;
- grpc_call_details_init(&tag->request_call_details);
- grpc_metadata_array_init(&tag->request_metadata);
- tag->is_new_call = 0;
- return tag;
-}
-
-pygrpc_tag *pygrpc_produce_request_tag(PyObject *user_tag, Call *empty_call) {
- pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
- tag->user_tag = user_tag;
- Py_XINCREF(tag->user_tag);
- tag->call = empty_call;
- Py_XINCREF(tag->call);
- tag->ops = NULL;
- tag->nops = 0;
- grpc_call_details_init(&tag->request_call_details);
- grpc_metadata_array_init(&tag->request_metadata);
- tag->is_new_call = 1;
- return tag;
-}
-
-pygrpc_tag *pygrpc_produce_server_shutdown_tag(PyObject *user_tag) {
- pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
- tag->user_tag = user_tag;
- Py_XINCREF(tag->user_tag);
- tag->call = NULL;
- tag->ops = NULL;
- tag->nops = 0;
- grpc_call_details_init(&tag->request_call_details);
- grpc_metadata_array_init(&tag->request_metadata);
- tag->is_new_call = 0;
- return tag;
-}
-
-pygrpc_tag *pygrpc_produce_channel_state_change_tag(PyObject *user_tag) {
- pygrpc_tag *tag = gpr_malloc(sizeof(pygrpc_tag));
- tag->user_tag = user_tag;
- Py_XINCREF(tag->user_tag);
- tag->call = NULL;
- tag->ops = NULL;
- tag->nops = 0;
- grpc_call_details_init(&tag->request_call_details);
- grpc_metadata_array_init(&tag->request_metadata);
- tag->is_new_call = 0;
- return tag;
-}
-
-void pygrpc_discard_tag(pygrpc_tag *tag) {
- if (!tag) {
- return;
- }
- Py_XDECREF(tag->user_tag);
- Py_XDECREF(tag->call);
- gpr_free(tag->ops);
- grpc_call_details_destroy(&tag->request_call_details);
- grpc_metadata_array_destroy(&tag->request_metadata);
- gpr_free(tag);
-}
-
-PyObject *pygrpc_consume_event(grpc_event event) {
- pygrpc_tag *tag;
- PyObject *result;
- if (event.type == GRPC_QUEUE_TIMEOUT) {
- Py_RETURN_NONE;
- }
- tag = event.tag;
- switch (event.type) {
- case GRPC_QUEUE_SHUTDOWN:
- result = Py_BuildValue("iOOOOO", GRPC_QUEUE_SHUTDOWN,
- Py_None, Py_None, Py_None, Py_None, Py_True);
- break;
- case GRPC_OP_COMPLETE:
- if (tag->is_new_call) {
- result = Py_BuildValue(
- "iOO(ssd)[(iNOOOO)]O", GRPC_OP_COMPLETE, tag->user_tag, tag->call,
- tag->request_call_details.method, tag->request_call_details.host,
- pygrpc_cast_gpr_timespec_to_double(tag->request_call_details.deadline),
- GRPC_OP_RECV_INITIAL_METADATA,
- pygrpc_cast_metadata_array_to_pyseq(tag->request_metadata), Py_None,
- Py_None, Py_None, Py_None,
- event.success ? Py_True : Py_False);
- } else {
- result = Py_BuildValue("iOOONO", GRPC_OP_COMPLETE, tag->user_tag,
- tag->call ? (PyObject*)tag->call : Py_None, Py_None,
- pygrpc_consume_ops(tag->ops, tag->nops),
- event.success ? Py_True : Py_False);
- }
- break;
- default:
- PyErr_SetString(PyExc_ValueError,
- "unknown completion type; could not translate event");
- return NULL;
- }
- pygrpc_discard_tag(tag);
- return result;
-}
-
-int pygrpc_produce_op(PyObject *op, grpc_op *result) {
- static const int OP_TUPLE_SIZE = 6;
- static const int STATUS_TUPLE_SIZE = 2;
- static const int TYPE_INDEX = 0;
- static const int INITIAL_METADATA_INDEX = 1;
- static const int TRAILING_METADATA_INDEX = 2;
- static const int MESSAGE_INDEX = 3;
- static const int STATUS_INDEX = 4;
- static const int STATUS_CODE_INDEX = 0;
- static const int STATUS_DETAILS_INDEX = 1;
- static const int WRITE_FLAGS_INDEX = 5;
- int type;
- Py_ssize_t message_size;
- char *message;
- char *status_details;
- gpr_slice message_slice;
- grpc_op c_op;
- if (!PyTuple_Check(op)) {
- PyErr_SetString(PyExc_TypeError, "expected tuple op");
- return 0;
- }
- if (PyTuple_Size(op) != OP_TUPLE_SIZE) {
- char *buf;
- gpr_asprintf(&buf, "expected tuple op of length %d", OP_TUPLE_SIZE);
- PyErr_SetString(PyExc_ValueError, buf);
- gpr_free(buf);
- return 0;
- }
- type = PyInt_AsLong(PyTuple_GET_ITEM(op, TYPE_INDEX));
- if (PyErr_Occurred()) {
- return 0;
- }
- c_op.op = type;
- c_op.reserved = NULL;
- c_op.flags = PyInt_AsLong(PyTuple_GET_ITEM(op, WRITE_FLAGS_INDEX));
- if (PyErr_Occurred()) {
- return 0;
- }
- switch (type) {
- case GRPC_OP_SEND_INITIAL_METADATA:
- if (!pygrpc_cast_pyseq_to_send_metadata(
- PyTuple_GetItem(op, INITIAL_METADATA_INDEX),
- &c_op.data.send_initial_metadata.metadata,
- &c_op.data.send_initial_metadata.count)) {
- return 0;
- }
- break;
- case GRPC_OP_SEND_MESSAGE:
- PyString_AsStringAndSize(
- PyTuple_GET_ITEM(op, MESSAGE_INDEX), &message, &message_size);
- message_slice = gpr_slice_from_copied_buffer(message, message_size);
- c_op.data.send_message = grpc_raw_byte_buffer_create(&message_slice, 1);
- gpr_slice_unref(message_slice);
- break;
- case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
- /* Don't need to fill in any other fields. */
- break;
- case GRPC_OP_SEND_STATUS_FROM_SERVER:
- if (!pygrpc_cast_pyseq_to_send_metadata(
- PyTuple_GetItem(op, TRAILING_METADATA_INDEX),
- &c_op.data.send_status_from_server.trailing_metadata,
- &c_op.data.send_status_from_server.trailing_metadata_count)) {
- return 0;
- }
- if (!PyTuple_Check(PyTuple_GET_ITEM(op, STATUS_INDEX))) {
- char *buf;
- gpr_asprintf(&buf, "expected tuple status in op of length %d",
- STATUS_TUPLE_SIZE);
- PyErr_SetString(PyExc_ValueError, buf);
- gpr_free(buf);
- return 0;
- }
- c_op.data.send_status_from_server.status = PyInt_AsLong(
- PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_CODE_INDEX));
- status_details = PyString_AsString(
- PyTuple_GET_ITEM(PyTuple_GET_ITEM(op, STATUS_INDEX), STATUS_DETAILS_INDEX));
- if (PyErr_Occurred()) {
- return 0;
- }
- c_op.data.send_status_from_server.status_details =
- gpr_malloc(strlen(status_details) + 1);
- strcpy((char *)c_op.data.send_status_from_server.status_details,
- status_details);
- break;
- case GRPC_OP_RECV_INITIAL_METADATA:
- c_op.data.recv_initial_metadata = gpr_malloc(sizeof(grpc_metadata_array));
- grpc_metadata_array_init(c_op.data.recv_initial_metadata);
- break;
- case GRPC_OP_RECV_MESSAGE:
- c_op.data.recv_message = gpr_malloc(sizeof(grpc_byte_buffer *));
- break;
- case GRPC_OP_RECV_STATUS_ON_CLIENT:
- c_op.data.recv_status_on_client.trailing_metadata =
- gpr_malloc(sizeof(grpc_metadata_array));
- grpc_metadata_array_init(c_op.data.recv_status_on_client.trailing_metadata);
- c_op.data.recv_status_on_client.status =
- gpr_malloc(sizeof(grpc_status_code *));
- c_op.data.recv_status_on_client.status_details =
- gpr_malloc(sizeof(char *));
- *c_op.data.recv_status_on_client.status_details = NULL;
- c_op.data.recv_status_on_client.status_details_capacity =
- gpr_malloc(sizeof(size_t));
- *c_op.data.recv_status_on_client.status_details_capacity = 0;
- break;
- case GRPC_OP_RECV_CLOSE_ON_SERVER:
- c_op.data.recv_close_on_server.cancelled = gpr_malloc(sizeof(int));
- break;
- default:
- return 0;
- }
- *result = c_op;
- return 1;
-}
-
-void pygrpc_discard_op(grpc_op op) {
- size_t i;
- switch(op.op) {
- case GRPC_OP_SEND_INITIAL_METADATA:
- /* Whenever we produce send-metadata, we allocate new strings (to handle
- arbitrary sequence input as opposed to just lists or just tuples). We
- thus must free those elements. */
- for (i = 0; i < op.data.send_initial_metadata.count; ++i) {
- gpr_free((void *)op.data.send_initial_metadata.metadata[i].key);
- gpr_free((void *)op.data.send_initial_metadata.metadata[i].value);
- }
- gpr_free(op.data.send_initial_metadata.metadata);
- break;
- case GRPC_OP_SEND_MESSAGE:
- grpc_byte_buffer_destroy(op.data.send_message);
- break;
- case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
- /* Don't need to free any fields. */
- break;
- case GRPC_OP_SEND_STATUS_FROM_SERVER:
- /* Whenever we produce send-metadata, we allocate new strings (to handle
- arbitrary sequence input as opposed to just lists or just tuples). We
- thus must free those elements. */
- for (i = 0; i < op.data.send_status_from_server.trailing_metadata_count;
- ++i) {
- gpr_free(
- (void *)op.data.send_status_from_server.trailing_metadata[i].key);
- gpr_free(
- (void *)op.data.send_status_from_server.trailing_metadata[i].value);
- }
- gpr_free(op.data.send_status_from_server.trailing_metadata);
- gpr_free((char *)op.data.send_status_from_server.status_details);
- break;
- case GRPC_OP_RECV_INITIAL_METADATA:
- grpc_metadata_array_destroy(op.data.recv_initial_metadata);
- gpr_free(op.data.recv_initial_metadata);
- break;
- case GRPC_OP_RECV_MESSAGE:
- grpc_byte_buffer_destroy(*op.data.recv_message);
- gpr_free(op.data.recv_message);
- break;
- case GRPC_OP_RECV_STATUS_ON_CLIENT:
- grpc_metadata_array_destroy(op.data.recv_status_on_client.trailing_metadata);
- gpr_free(op.data.recv_status_on_client.trailing_metadata);
- gpr_free(op.data.recv_status_on_client.status);
- gpr_free(*op.data.recv_status_on_client.status_details);
- gpr_free(op.data.recv_status_on_client.status_details);
- gpr_free(op.data.recv_status_on_client.status_details_capacity);
- break;
- case GRPC_OP_RECV_CLOSE_ON_SERVER:
- gpr_free(op.data.recv_close_on_server.cancelled);
- break;
- }
-}
-
-PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) {
- static const int TYPE_INDEX = 0;
- static const int INITIAL_METADATA_INDEX = 1;
- static const int TRAILING_METADATA_INDEX = 2;
- static const int MESSAGE_INDEX = 3;
- static const int STATUS_INDEX = 4;
- static const int CANCELLED_INDEX = 5;
- static const int OPRESULT_LENGTH = 6;
- PyObject *list;
- size_t i;
- size_t j;
- char *bytes;
- size_t bytes_size;
- PyObject *results = PyList_New(nops);
- if (!results) {
- return NULL;
- }
- for (i = 0; i < nops; ++i) {
- PyObject *result = PyTuple_Pack(OPRESULT_LENGTH, Py_None, Py_None, Py_None,
- Py_None, Py_None, Py_None);
- PyTuple_SetItem(result, TYPE_INDEX, PyInt_FromLong(op[i].op));
- switch(op[i].op) {
- case GRPC_OP_RECV_INITIAL_METADATA:
- PyTuple_SetItem(result, INITIAL_METADATA_INDEX,
- list=PyList_New(op[i].data.recv_initial_metadata->count));
- for (j = 0; j < op[i].data.recv_initial_metadata->count; ++j) {
- grpc_metadata md = op[i].data.recv_initial_metadata->metadata[j];
- PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
- (Py_ssize_t)md.value_length));
- }
- break;
- case GRPC_OP_RECV_MESSAGE:
- if (*op[i].data.recv_message) {
- pygrpc_byte_buffer_to_bytes(
- *op[i].data.recv_message, &bytes, &bytes_size);
- PyTuple_SetItem(result, MESSAGE_INDEX,
- PyString_FromStringAndSize(bytes, bytes_size));
- gpr_free(bytes);
- } else {
- PyTuple_SetItem(result, MESSAGE_INDEX, Py_BuildValue(""));
- }
- break;
- case GRPC_OP_RECV_STATUS_ON_CLIENT:
- PyTuple_SetItem(
- result, TRAILING_METADATA_INDEX,
- list = PyList_New(op[i].data.recv_status_on_client.trailing_metadata->count));
- for (j = 0; j < op[i].data.recv_status_on_client.trailing_metadata->count; ++j) {
- grpc_metadata md =
- op[i].data.recv_status_on_client.trailing_metadata->metadata[j];
- PyList_SetItem(list, j, Py_BuildValue("ss#", md.key, md.value,
- (Py_ssize_t)md.value_length));
- }
- PyTuple_SetItem(
- result, STATUS_INDEX, Py_BuildValue(
- "is", *op[i].data.recv_status_on_client.status,
- *op[i].data.recv_status_on_client.status_details));
- break;
- case GRPC_OP_RECV_CLOSE_ON_SERVER:
- PyTuple_SetItem(
- result, CANCELLED_INDEX,
- PyBool_FromLong(*op[i].data.recv_close_on_server.cancelled));
- break;
- default:
- break;
- }
- pygrpc_discard_op(op[i]);
- PyList_SetItem(results, i, result);
- }
- return results;
-}
-
-double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) {
- timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME);
- return timespec.tv_sec + 1e-9*timespec.tv_nsec;
-}
-
-/* Because C89 doesn't have a way to check for infinity... */
-static int pygrpc_isinf(double x) {
- return x * 0 != 0;
-}
-
-gpr_timespec pygrpc_cast_double_to_gpr_timespec(double seconds) {
- gpr_timespec result;
- if (pygrpc_isinf(seconds)) {
- result = seconds > 0.0 ? gpr_inf_future(GPR_CLOCK_REALTIME)
- : gpr_inf_past(GPR_CLOCK_REALTIME);
- } else {
- result.tv_sec = (time_t)seconds;
- result.tv_nsec = ((seconds - result.tv_sec) * 1e9);
- result.clock_type = GPR_CLOCK_REALTIME;
- }
- return result;
-}
-
-int pygrpc_produce_channel_args(PyObject *py_args, grpc_channel_args *c_args) {
- size_t num_args = PyList_Size(py_args);
- size_t i;
- grpc_channel_args args;
- args.num_args = num_args;
- args.args = gpr_malloc(sizeof(grpc_arg) * num_args);
- for (i = 0; i < args.num_args; ++i) {
- char *key;
- PyObject *value;
- if (!PyArg_ParseTuple(PyList_GetItem(py_args, i), "zO", &key, &value)) {
- gpr_free(args.args);
- args.num_args = 0;
- args.args = NULL;
- PyErr_SetString(PyExc_TypeError,
- "expected a list of 2-tuple of str and str|int|None");
- return 0;
- }
- args.args[i].key = key;
- if (PyInt_Check(value)) {
- args.args[i].type = GRPC_ARG_INTEGER;
- args.args[i].value.integer = PyInt_AsLong(value);
- } else if (PyString_Check(value)) {
- args.args[i].type = GRPC_ARG_STRING;
- args.args[i].value.string = PyString_AsString(value);
- } else if (value == Py_None) {
- --args.num_args;
- --i;
- continue;
- } else {
- gpr_free(args.args);
- args.num_args = 0;
- args.args = NULL;
- PyErr_SetString(PyExc_TypeError,
- "expected a list of 2-tuple of str and str|int|None");
- return 0;
- }
- }
- *c_args = args;
- return 1;
-}
-
-void pygrpc_discard_channel_args(grpc_channel_args args) {
- gpr_free(args.args);
-}
-
-int pygrpc_cast_pyseq_to_send_metadata(
- PyObject *pyseq, grpc_metadata **metadata, size_t *count) {
- size_t i;
- Py_ssize_t value_length;
- char *key;
- char *value;
- if (!PySequence_Check(pyseq)) {
- return 0;
- }
- *count = PySequence_Size(pyseq);
- *metadata = gpr_malloc(sizeof(grpc_metadata) * *count);
- for (i = 0; i < *count; ++i) {
- PyObject *item = PySequence_GetItem(pyseq, i);
- if (!PyArg_ParseTuple(item, "ss#", &key, &value, &value_length)) {
- Py_DECREF(item);
- gpr_free(*metadata);
- *count = 0;
- *metadata = NULL;
- return 0;
- } else {
- (*metadata)[i].key = gpr_strdup(key);
- (*metadata)[i].value = gpr_malloc(value_length);
- memcpy((void *)(*metadata)[i].value, value, value_length);
- Py_DECREF(item);
- }
- (*metadata)[i].value_length = value_length;
- }
- return 1;
-}
-
-PyObject *pygrpc_cast_metadata_array_to_pyseq(grpc_metadata_array metadata) {
- PyObject *result = PyTuple_New(metadata.count);
- size_t i;
- for (i = 0; i < metadata.count; ++i) {
- PyTuple_SetItem(
- result, i, Py_BuildValue(
- "ss#", metadata.metadata[i].key, metadata.metadata[i].value,
- (Py_ssize_t)metadata.metadata[i].value_length));
- if (PyErr_Occurred()) {
- Py_DECREF(result);
- return NULL;
- }
- }
- return result;
-}
-
-void pygrpc_byte_buffer_to_bytes(
- grpc_byte_buffer *buffer, char **result, size_t *result_size) {
- grpc_byte_buffer_reader reader;
- gpr_slice slice;
- char *read_result = NULL;
- size_t size = 0;
- grpc_byte_buffer_reader_init(&reader, buffer);
- while (grpc_byte_buffer_reader_next(&reader, &slice)) {
- read_result = gpr_realloc(read_result, size + GPR_SLICE_LENGTH(slice));
- memcpy(read_result + size, GPR_SLICE_START_PTR(slice),
- GPR_SLICE_LENGTH(slice));
- size = size + GPR_SLICE_LENGTH(slice);
- gpr_slice_unref(slice);
- }
- *result_size = size;
- *result = read_result;
-}
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py b/src/python/grpcio/grpc/_adapter/_implementations.py
index fe020e2a9c..b85f228bf6 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_c_test.py
+++ b/src/python/grpcio/grpc/_adapter/_implementations.py
@@ -27,29 +27,22 @@
# (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 time
-import unittest
+import collections
-from grpc._adapter import _c
-from grpc._adapter import _types
+from grpc.beta import interfaces
+class AuthMetadataContext(collections.namedtuple(
+ 'AuthMetadataContext', [
+ 'service_url',
+ 'method_name'
+ ]), interfaces.GRPCAuthMetadataContext):
+ pass
-class CTypeSmokeTest(unittest.TestCase):
- def testCompletionQueueUpDown(self):
- completion_queue = _c.CompletionQueue()
- del completion_queue
+class AuthMetadataPluginCallback(interfaces.GRPCAuthMetadataContext):
- def testServerUpDown(self):
- completion_queue = _c.CompletionQueue()
- serv = _c.Server(completion_queue, [])
- del serv
- del completion_queue
+ def __init__(self, callback):
+ self._callback = callback
- def testChannelUpDown(self):
- channel = _c.Channel('[::]:0', [])
- del channel
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
+ def __call__(self, metadata, error):
+ self._callback(metadata, error)
diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
index 5634c2024d..9698ffeabf 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -115,16 +115,20 @@ class Call(object):
return call
def invoke(self, completion_queue, metadata_tag, finish_tag):
- err0 = self._internal.start_batch([
+ err = self._internal.start_batch([
_types.OpArgs.send_initial_metadata(self._metadata)
], _IGNORE_ME_TAG)
- err1 = self._internal.start_batch([
+ if err != _types.CallError.OK:
+ return err
+ err = self._internal.start_batch([
_types.OpArgs.recv_initial_metadata()
], _TagAdapter(metadata_tag, Event.Kind.METADATA_ACCEPTED))
- err2 = self._internal.start_batch([
+ if err != _types.CallError.OK:
+ return err
+ err = self._internal.start_batch([
_types.OpArgs.recv_status_on_client()
], _TagAdapter(finish_tag, Event.Kind.FINISH))
- return err0 if err0 != _types.CallError.OK else err1 if err1 != _types.CallError.OK else err2 if err2 != _types.CallError.OK else _types.CallError.OK
+ return err
def write(self, message, tag, flags):
return self._internal.start_batch([
@@ -158,7 +162,8 @@ class Call(object):
def status(self, status, tag):
return self._internal.start_batch([
- _types.OpArgs.send_status_from_server(self._metadata, status.code, status.details)
+ _types.OpArgs.send_status_from_server(
+ self._metadata, status.code, status.details)
], _TagAdapter(tag, Event.Kind.COMPLETE_ACCEPTED))
def cancel(self):
@@ -168,20 +173,17 @@ class Call(object):
return self._internal.peer()
def set_credentials(self, creds):
- return self._internal.set_credentials(creds._internal)
+ return self._internal.set_credentials(creds)
class Channel(object):
"""Adapter from old _low.Channel interface to new _low.Channel."""
- def __init__(self, hostport, client_credentials, server_host_override=None):
+ def __init__(self, hostport, channel_credentials, server_host_override=None):
args = []
if server_host_override:
args.append((_types.GrpcChannelArgumentKeys.SSL_TARGET_NAME_OVERRIDE.value, server_host_override))
- creds = None
- if client_credentials:
- creds = client_credentials._internal
- self._internal = _low.Channel(hostport, args, creds)
+ self._internal = _low.Channel(hostport, args, channel_credentials)
class CompletionQueue(object):
@@ -192,7 +194,7 @@ class CompletionQueue(object):
def get(self, deadline=None):
if deadline is None:
- ev = self._internal.next()
+ ev = self._internal.next(float('+inf'))
else:
ev = self._internal.next(deadline)
if ev is None:
@@ -240,7 +242,7 @@ class Server(object):
if server_credentials is None:
return self._internal.add_http2_port(addr, None)
else:
- return self._internal.add_http2_port(addr, server_credentials._internal)
+ return self._internal.add_http2_port(addr, server_credentials)
def start(self):
return self._internal.start()
@@ -248,20 +250,9 @@ class Server(object):
def service(self, tag):
return self._internal.request_call(self._internal_cq, _TagAdapter(tag, Event.Kind.SERVICE_ACCEPTED))
+ def cancel_all_calls(self):
+ self._internal.cancel_all_calls()
+
def stop(self):
return self._internal.shutdown(_TagAdapter(None, Event.Kind.STOP))
-
-class ClientCredentials(object):
- """Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials."""
-
- def __init__(self, root_certificates, private_key, certificate_chain):
- self._internal = _low.ChannelCredentials.ssl(root_certificates, private_key, certificate_chain)
-
-
-class ServerCredentials(object):
- """Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials."""
-
- def __init__(self, root_credentials, pair_sequence, force_client_auth):
- self._internal = _low.ServerCredentials.ssl(
- root_credentials, list(pair_sequence), force_client_auth)
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index 57146aaefe..b13d8dd9dd 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -27,36 +27,157 @@
# (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
+
from grpc import _grpcio_metadata
-from grpc._adapter import _c
+from grpc._cython import cygrpc
+from grpc._adapter import _implementations
from grpc._adapter import _types
_USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
-ChannelCredentials = _c.ChannelCredentials
-CallCredentials = _c.CallCredentials
-ServerCredentials = _c.ServerCredentials
+ChannelCredentials = cygrpc.ChannelCredentials
+CallCredentials = cygrpc.CallCredentials
+ServerCredentials = cygrpc.ServerCredentials
+
+channel_credentials_composite = cygrpc.channel_credentials_composite
+call_credentials_composite = cygrpc.call_credentials_composite
+
+def server_credentials_ssl(root_credentials, pair_sequence, force_client_auth):
+ return cygrpc.server_credentials_ssl(
+ root_credentials,
+ [cygrpc.SslPemKeyCertPair(key, pem) for key, pem in pair_sequence],
+ force_client_auth)
+
+def channel_credentials_ssl(
+ root_certificates, private_key, certificate_chain):
+ pair = None
+ if private_key is not None or certificate_chain is not None:
+ pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain)
+ 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))
class CompletionQueue(_types.CompletionQueue):
def __init__(self):
- self.completion_queue = _c.CompletionQueue()
+ self.completion_queue = cygrpc.CompletionQueue()
def next(self, deadline=float('+inf')):
- raw_event = self.completion_queue.next(deadline)
- if raw_event is None:
+ raw_event = self.completion_queue.poll(cygrpc.Timespec(deadline))
+ if raw_event.type == cygrpc.CompletionType.queue_timeout:
return None
- event = _types.Event(*raw_event)
- if event.call is not None:
- event = event._replace(call=Call(event.call))
- if event.call_details is not None:
- event = event._replace(call_details=_types.CallDetails(*event.call_details))
- if event.results is not None:
- new_results = [_types.OpResult(*r) for r in event.results]
- new_results = [r if r.status is None else r._replace(status=_types.Status(_types.StatusCode(r.status[0]), r.status[1])) for r in new_results]
- event = event._replace(results=new_results)
- return event
+ event_type = raw_event.type
+ event_tag = raw_event.tag
+ event_call = Call(raw_event.operation_call)
+ if raw_event.request_call_details:
+ event_call_details = _types.CallDetails(
+ raw_event.request_call_details.method,
+ raw_event.request_call_details.host,
+ float(raw_event.request_call_details.deadline))
+ else:
+ event_call_details = None
+ event_success = raw_event.success
+ event_results = []
+ if raw_event.is_new_request:
+ event_results.append(_types.OpResult(
+ _types.OpType.RECV_INITIAL_METADATA, raw_event.request_metadata,
+ None, None, None, None))
+ else:
+ if raw_event.batch_operations:
+ for operation in raw_event.batch_operations:
+ result_type = operation.type
+ result_initial_metadata = operation.received_metadata_or_none
+ result_trailing_metadata = operation.received_metadata_or_none
+ result_message = operation.received_message_or_none
+ if result_message is not None:
+ result_message = result_message.bytes()
+ result_cancelled = operation.received_cancelled_or_none
+ if operation.has_status:
+ result_status = _types.Status(
+ operation.received_status_code_or_none,
+ operation.received_status_details_or_none)
+ else:
+ result_status = None
+ event_results.append(
+ _types.OpResult(result_type, result_initial_metadata,
+ result_trailing_metadata, result_message,
+ result_status, result_cancelled))
+ return _types.Event(event_type, event_tag, event_call, event_call_details,
+ event_results, event_success)
def shutdown(self):
self.completion_queue.shutdown()
@@ -68,7 +189,36 @@ class Call(_types.Call):
self.call = call
def start_batch(self, ops, tag):
- return self.call.start_batch(ops, tag)
+ translated_ops = []
+ for op in ops:
+ if op.type == _types.OpType.SEND_INITIAL_METADATA:
+ translated_op = cygrpc.operation_send_initial_metadata(
+ cygrpc.Metadata(
+ cygrpc.Metadatum(key, value)
+ for key, value in op.initial_metadata))
+ elif op.type == _types.OpType.SEND_MESSAGE:
+ translated_op = cygrpc.operation_send_message(op.message)
+ elif op.type == _types.OpType.SEND_CLOSE_FROM_CLIENT:
+ translated_op = cygrpc.operation_send_close_from_client()
+ elif op.type == _types.OpType.SEND_STATUS_FROM_SERVER:
+ translated_op = cygrpc.operation_send_status_from_server(
+ cygrpc.Metadata(
+ cygrpc.Metadatum(key, value)
+ for key, value in op.trailing_metadata),
+ op.status.code,
+ op.status.details)
+ elif op.type == _types.OpType.RECV_INITIAL_METADATA:
+ translated_op = cygrpc.operation_receive_initial_metadata()
+ elif op.type == _types.OpType.RECV_MESSAGE:
+ translated_op = cygrpc.operation_receive_message()
+ elif op.type == _types.OpType.RECV_STATUS_ON_CLIENT:
+ translated_op = cygrpc.operation_receive_status_on_client()
+ elif op.type == _types.OpType.RECV_CLOSE_ON_SERVER:
+ translated_op = cygrpc.operation_receive_close_on_server()
+ else:
+ raise ValueError('unexpected operation type {}'.format(op.type))
+ translated_ops.append(translated_op)
+ return self.call.start_batch(cygrpc.Operations(translated_ops), tag)
def cancel(self, code=None, details=None):
if code is None and details is None:
@@ -86,14 +236,20 @@ class Call(_types.Call):
class Channel(_types.Channel):
def __init__(self, target, args, creds=None):
- args = list(args) + [(_c.PRIMARY_USER_AGENT_KEY, _USER_AGENT)]
+ args = list(args) + [
+ (cygrpc.ChannelArgKey.primary_user_agent_string, _USER_AGENT)]
+ args = cygrpc.ChannelArgs(
+ cygrpc.ChannelArg(key, value) for key, value in args)
if creds is None:
- self.channel = _c.Channel(target, args)
+ self.channel = cygrpc.Channel(target, args)
else:
- self.channel = _c.Channel(target, args, creds)
+ self.channel = cygrpc.Channel(target, args, creds)
def create_call(self, completion_queue, method, host, deadline=None):
- return Call(self.channel.create_call(completion_queue.completion_queue, method, host, deadline))
+ internal_call = self.channel.create_call(
+ None, 0, completion_queue.completion_queue, method, host,
+ cygrpc.Timespec(deadline))
+ return Call(internal_call)
def check_connectivity_state(self, try_to_connect):
return self.channel.check_connectivity_state(try_to_connect)
@@ -101,7 +257,8 @@ class Channel(_types.Channel):
def watch_connectivity_state(self, last_observed_state, deadline,
completion_queue, tag):
self.channel.watch_connectivity_state(
- last_observed_state, deadline, completion_queue.completion_queue, tag)
+ last_observed_state, cygrpc.Timespec(deadline),
+ completion_queue.completion_queue, tag)
def target(self):
return self.channel.target()
@@ -112,7 +269,11 @@ _NO_TAG = object()
class Server(_types.Server):
def __init__(self, completion_queue, args):
- self.server = _c.Server(completion_queue.completion_queue, args)
+ args = cygrpc.ChannelArgs(
+ cygrpc.ChannelArg(key, value) for key, value in args)
+ self.server = cygrpc.Server(args)
+ self.server.register_completion_queue(completion_queue.completion_queue)
+ self.server_queue = completion_queue
def add_http2_port(self, addr, creds=None):
if creds is None:
@@ -124,10 +285,11 @@ class Server(_types.Server):
return self.server.start()
def shutdown(self, tag=None):
- return self.server.shutdown(tag)
+ return self.server.shutdown(self.server_queue.completion_queue, tag)
def request_call(self, completion_queue, tag):
- return self.server.request_call(completion_queue.completion_queue, tag)
+ return self.server.request_call(completion_queue.completion_queue,
+ self.server_queue.completion_queue, tag)
def cancel_all_calls(self):
return self.server.cancel_all_calls()
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index ca0fa066bc..3d5ab33d00 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -31,6 +31,8 @@ import abc
import collections
import enum
+from grpc._cython import cygrpc
+
class GrpcChannelArgumentKeys(enum.Enum):
"""Mirrors keys used in grpc_channel_args for GRPC-specific arguments."""
@@ -40,77 +42,77 @@ class GrpcChannelArgumentKeys(enum.Enum):
@enum.unique
class CallError(enum.IntEnum):
"""Mirrors grpc_call_error in the C core."""
- OK = 0
- ERROR = 1
- ERROR_NOT_ON_SERVER = 2
- ERROR_NOT_ON_CLIENT = 3
- ERROR_ALREADY_ACCEPTED = 4
- ERROR_ALREADY_INVOKED = 5
- ERROR_NOT_INVOKED = 6
- ERROR_ALREADY_FINISHED = 7
- ERROR_TOO_MANY_OPERATIONS = 8
- ERROR_INVALID_FLAGS = 9
- ERROR_INVALID_METADATA = 10
+ OK = cygrpc.CallError.ok
+ ERROR = cygrpc.CallError.error
+ ERROR_NOT_ON_SERVER = cygrpc.CallError.not_on_server
+ ERROR_NOT_ON_CLIENT = cygrpc.CallError.not_on_client
+ ERROR_ALREADY_ACCEPTED = cygrpc.CallError.already_accepted
+ ERROR_ALREADY_INVOKED = cygrpc.CallError.already_invoked
+ ERROR_NOT_INVOKED = cygrpc.CallError.not_invoked
+ ERROR_ALREADY_FINISHED = cygrpc.CallError.already_finished
+ ERROR_TOO_MANY_OPERATIONS = cygrpc.CallError.too_many_operations
+ ERROR_INVALID_FLAGS = cygrpc.CallError.invalid_flags
+ ERROR_INVALID_METADATA = cygrpc.CallError.invalid_metadata
@enum.unique
class StatusCode(enum.IntEnum):
"""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
+ OK = cygrpc.StatusCode.ok
+ CANCELLED = cygrpc.StatusCode.cancelled
+ UNKNOWN = cygrpc.StatusCode.unknown
+ INVALID_ARGUMENT = cygrpc.StatusCode.invalid_argument
+ DEADLINE_EXCEEDED = cygrpc.StatusCode.deadline_exceeded
+ NOT_FOUND = cygrpc.StatusCode.not_found
+ ALREADY_EXISTS = cygrpc.StatusCode.already_exists
+ PERMISSION_DENIED = cygrpc.StatusCode.permission_denied
+ RESOURCE_EXHAUSTED = cygrpc.StatusCode.resource_exhausted
+ FAILED_PRECONDITION = cygrpc.StatusCode.failed_precondition
+ ABORTED = cygrpc.StatusCode.aborted
+ OUT_OF_RANGE = cygrpc.StatusCode.out_of_range
+ UNIMPLEMENTED = cygrpc.StatusCode.unimplemented
+ INTERNAL = cygrpc.StatusCode.internal
+ UNAVAILABLE = cygrpc.StatusCode.unavailable
+ DATA_LOSS = cygrpc.StatusCode.data_loss
+ UNAUTHENTICATED = cygrpc.StatusCode.unauthenticated
@enum.unique
class OpWriteFlags(enum.IntEnum):
"""Mirrors defined write-flag constants in the C core."""
- WRITE_BUFFER_HINT = 1
- WRITE_NO_COMPRESS = 2
+ WRITE_BUFFER_HINT = cygrpc.WriteFlag.buffer_hint
+ WRITE_NO_COMPRESS = cygrpc.WriteFlag.no_compress
@enum.unique
class OpType(enum.IntEnum):
"""Mirrors grpc_op_type in the C core."""
- SEND_INITIAL_METADATA = 0
- SEND_MESSAGE = 1
- SEND_CLOSE_FROM_CLIENT = 2
- SEND_STATUS_FROM_SERVER = 3
- RECV_INITIAL_METADATA = 4
- RECV_MESSAGE = 5
- RECV_STATUS_ON_CLIENT = 6
- RECV_CLOSE_ON_SERVER = 7
+ SEND_INITIAL_METADATA = cygrpc.OperationType.send_initial_metadata
+ SEND_MESSAGE = cygrpc.OperationType.send_message
+ SEND_CLOSE_FROM_CLIENT = cygrpc.OperationType.send_close_from_client
+ SEND_STATUS_FROM_SERVER = cygrpc.OperationType.send_status_from_server
+ RECV_INITIAL_METADATA = cygrpc.OperationType.receive_initial_metadata
+ RECV_MESSAGE = cygrpc.OperationType.receive_message
+ RECV_STATUS_ON_CLIENT = cygrpc.OperationType.receive_status_on_client
+ RECV_CLOSE_ON_SERVER = cygrpc.OperationType.receive_close_on_server
@enum.unique
class EventType(enum.IntEnum):
"""Mirrors grpc_completion_type in the C core."""
- QUEUE_SHUTDOWN = 0
- QUEUE_TIMEOUT = 1 # if seen on the Python side, something went horridly wrong
- OP_COMPLETE = 2
+ QUEUE_SHUTDOWN = cygrpc.CompletionType.queue_shutdown
+ QUEUE_TIMEOUT = cygrpc.CompletionType.queue_timeout
+ OP_COMPLETE = cygrpc.CompletionType.operation_complete
@enum.unique
class ConnectivityState(enum.IntEnum):
"""Mirrors grpc_connectivity_state in the C core."""
- IDLE = 0
- CONNECTING = 1
- READY = 2
- TRANSIENT_FAILURE = 3
- FATAL_FAILURE = 4
+ IDLE = cygrpc.ConnectivityState.idle
+ CONNECTING = cygrpc.ConnectivityState.connecting
+ READY = cygrpc.ConnectivityState.ready
+ TRANSIENT_FAILURE = cygrpc.ConnectivityState.transient_failure
+ FATAL_FAILURE = cygrpc.ConnectivityState.fatal_failure
class Status(collections.namedtuple(
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
index 51c4668138..1c07f9f4f4 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
@@ -53,24 +53,24 @@ cdef class Call:
self.c_call, cy_operations.c_ops, cy_operations.c_nops,
<cpython.PyObject *>operation_tag, NULL)
- def cancel(self,
- grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
- details=None):
+ def cancel(
+ self, grpc.grpc_status_code error_code=grpc.GRPC_STATUS__DO_NOT_USE,
+ details=None):
if not self.is_valid:
raise ValueError("invalid call object cannot be used from Python")
if (details is None) != (error_code == grpc.GRPC_STATUS__DO_NOT_USE):
raise ValueError("if error_code is specified, so must details "
"(and vice-versa)")
- if isinstance(details, bytes):
- pass
- elif isinstance(details, basestring):
- details = details.encode()
- else:
- raise TypeError("expected details to be str or bytes")
if error_code != grpc.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)
- return grpc.grpc_call_cancel_with_status(self.c_call, error_code, details,
- NULL)
+ return grpc.grpc_call_cancel_with_status(
+ self.c_call, error_code, details, NULL)
else:
return grpc.grpc_call_cancel(self.c_call, NULL)
@@ -79,6 +79,12 @@ cdef class Call:
return grpc.grpc_call_set_credentials(
self.c_call, call_credentials.c_credentials)
+ def peer(self):
+ cdef char *peer = grpc.grpc_call_get_peer(self.c_call)
+ result = <bytes>peer
+ grpc.gpr_free(peer)
+ return result
+
def __dealloc__(self):
if self.c_call != NULL:
grpc.grpc_call_destroy(self.c_call)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
index e25db3e2a4..a944a83576 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
@@ -27,6 +27,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.
+cimport cpython
+
from grpc._cython._cygrpc cimport call
from grpc._cython._cygrpc cimport completion_queue
from grpc._cython._cygrpc cimport credentials
@@ -70,12 +72,16 @@ cdef class Channel:
method = method.encode()
else:
raise TypeError("expected method to be str or bytes")
- if isinstance(host, bytes):
+ cdef char *host_c_string = NULL
+ if host is None:
pass
+ elif isinstance(host, bytes):
+ host_c_string = host
elif isinstance(host, basestring):
host = host.encode()
+ host_c_string = host
else:
- raise TypeError("expected host to be str or bytes")
+ raise TypeError("expected host to be str, bytes, or None")
cdef call.Call operation_call = call.Call()
operation_call.references = [self, method, host, queue]
cdef grpc.grpc_call *parent_call = NULL
@@ -83,10 +89,29 @@ cdef class Channel:
parent_call = parent.c_call
operation_call.c_call = grpc.grpc_channel_create_call(
self.c_channel, parent_call, flags,
- queue.c_completion_queue, method, host, deadline.c_time,
+ queue.c_completion_queue, method, host_c_string, deadline.c_time,
NULL)
return operation_call
+ def check_connectivity_state(self, bint try_to_connect):
+ return grpc.grpc_channel_check_connectivity_state(self.c_channel,
+ try_to_connect)
+
+ def watch_connectivity_state(
+ self, last_observed_state, records.Timespec deadline not None,
+ completion_queue.CompletionQueue queue not None, tag):
+ cdef records.OperationTag operation_tag = records.OperationTag(tag)
+ cpython.Py_INCREF(operation_tag)
+ grpc.grpc_channel_watch_connectivity_state(
+ self.c_channel, last_observed_state, deadline.c_time,
+ queue.c_completion_queue, <cpython.PyObject *>operation_tag)
+
+ def target(self):
+ cdef char * target = grpc.grpc_channel_get_target(self.c_channel)
+ result = <bytes>target
+ grpc.gpr_free(target)
+ return result
+
def __dealloc__(self):
if self.c_channel != NULL:
grpc.grpc_channel_destroy(self.c_channel)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
index a7a265eab7..2cf49707b4 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx
@@ -62,6 +62,8 @@ cdef class CompletionQueue:
cdef grpc.grpc_event event
# Poll within a critical section
+ # TODO consider making queue polling contention a hard error to enable
+ # easier bug discovery
with self.poll_condition:
while self.is_polling:
self.poll_condition.wait(float(deadline) - time.time())
@@ -74,10 +76,12 @@ cdef class CompletionQueue:
self.poll_condition.notify()
if event.type == grpc.GRPC_QUEUE_TIMEOUT:
- return records.Event(event.type, False, None, None, None, None, None)
+ return records.Event(
+ event.type, False, None, None, None, None, False, None)
elif event.type == grpc.GRPC_QUEUE_SHUTDOWN:
self.is_shutdown = True
- return records.Event(event.type, True, None, None, None, None, None)
+ return records.Event(
+ event.type, True, None, None, None, None, False, None)
else:
if event.tag != NULL:
tag = <records.OperationTag>event.tag
@@ -97,7 +101,8 @@ cdef class CompletionQueue:
operation_call.references.extend(tag.references)
return records.Event(
event.type, event.success, user_tag, operation_call,
- request_call_details, request_metadata, batch_operations)
+ request_call_details, request_metadata, tag.is_new_request,
+ batch_operations)
def shutdown(self):
grpc.grpc_completion_queue_shutdown(self.c_completion_queue)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
index 7a9fa7b76d..db9f8ddec9 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
@@ -27,7 +27,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+cimport cpython
+
from grpc._cython._cygrpc cimport grpc
+from grpc._cython._cygrpc cimport records
cdef class ChannelCredentials:
@@ -49,3 +52,23 @@ cdef class ServerCredentials:
cdef grpc.grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
cdef size_t c_ssl_pem_key_cert_pairs_count
cdef list references
+
+
+cdef class CredentialsMetadataPlugin:
+
+ cdef object plugin_callback
+ cdef str plugin_name
+
+ cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self)
+
+
+cdef class AuthMetadataContext:
+
+ cdef grpc.grpc_auth_metadata_context context
+
+
+cdef void plugin_get_metadata(
+ void *state, grpc.grpc_auth_metadata_context context,
+ grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil
+
+cdef void plugin_destroy_c_plugin_state(void *state)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
index e9836fec2c..a968894967 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
@@ -27,6 +27,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.
+cimport cpython
+
from grpc._cython._cygrpc cimport grpc
from grpc._cython._cygrpc cimport records
@@ -71,19 +73,80 @@ cdef class ServerCredentials:
def __cinit__(self):
self.c_credentials = NULL
+ self.references = []
def __dealloc__(self):
if self.c_credentials != NULL:
grpc.grpc_server_credentials_release(self.c_credentials)
+cdef class CredentialsMetadataPlugin:
+
+ def __cinit__(self, object plugin_callback, str name):
+ """
+ Args:
+ plugin_callback (callable): Callback accepting a service URL (str/bytes)
+ and callback object (accepting a records.Metadata,
+ grpc.grpc_status_code, and a str/bytes error message). This argument
+ when called should be non-blocking and eventually call the callback
+ object with the appropriate status code/details and metadata (if
+ successful).
+ name (str): Plugin name.
+ """
+ if not callable(plugin_callback):
+ raise ValueError('expected callable plugin_callback')
+ self.plugin_callback = plugin_callback
+ self.plugin_name = name
+
+ @staticmethod
+ cdef grpc.grpc_metadata_credentials_plugin make_c_plugin(self):
+ cdef grpc.grpc_metadata_credentials_plugin result
+ result.get_metadata = plugin_get_metadata
+ result.destroy = plugin_destroy_c_plugin_state
+ result.state = <void *>self
+ result.type = self.plugin_name
+ cpython.Py_INCREF(self)
+ return result
+
+
+cdef class AuthMetadataContext:
+
+ def __cinit__(self):
+ self.context.service_url = NULL
+ self.context.method_name = NULL
+
+ @property
+ def service_url(self):
+ return self.context.service_url
+
+ @property
+ def method_name(self):
+ return self.context.method_name
+
+
+cdef void plugin_get_metadata(
+ void *state, grpc.grpc_auth_metadata_context context,
+ grpc.grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil:
+ def python_callback(
+ records.Metadata metadata, grpc.grpc_status_code status,
+ const char *error_details):
+ cb(user_data, metadata.c_metadata_array.metadata,
+ metadata.c_metadata_array.count, status, error_details)
+ cdef CredentialsMetadataPlugin self = <CredentialsMetadataPlugin>state
+ cdef AuthMetadataContext cy_context = AuthMetadataContext()
+ cy_context.context = context
+ self.plugin_callback(cy_context, python_callback)
+
+cdef void plugin_destroy_c_plugin_state(void *state):
+ cpython.Py_DECREF(<CredentialsMetadataPlugin>state)
+
def channel_credentials_google_default():
cdef ChannelCredentials credentials = ChannelCredentials();
credentials.c_credentials = grpc.grpc_google_default_credentials_create()
return credentials
def channel_credentials_ssl(pem_root_certificates,
- records.SslPemKeyCertPair ssl_pem_key_cert_pair):
+ records.SslPemKeyCertPair ssl_pem_key_cert_pair):
if pem_root_certificates is None:
pass
elif isinstance(pem_root_certificates, bytes):
@@ -104,6 +167,7 @@ def channel_credentials_ssl(pem_root_certificates,
else:
credentials.c_credentials = grpc.grpc_ssl_credentials_create(
c_pem_root_certificates, NULL, NULL)
+ return credentials
def channel_credentials_composite(
ChannelCredentials credentials_1 not None,
@@ -135,7 +199,6 @@ def call_credentials_google_compute_engine():
grpc.grpc_google_compute_engine_credentials_create(NULL))
return credentials
-#TODO rename to something like client_credentials_service_account_jwt_access.
def call_credentials_service_account_jwt_access(
json_key, records.Timespec token_lifetime not None):
if isinstance(json_key, bytes):
@@ -184,14 +247,25 @@ def call_credentials_google_iam(authorization_token, authority_selector):
credentials.references.append(authority_selector)
return credentials
+def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin):
+ cdef CallCredentials credentials = CallCredentials()
+ credentials.c_credentials = (
+ grpc.grpc_metadata_credentials_create_from_plugin(plugin.make_c_plugin(),
+ NULL))
+ # TODO(atash): the following held reference is *probably* never necessary
+ credentials.references.append(plugin)
+ return credentials
+
def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
bint force_client_auth):
+ cdef char *c_pem_root_certs = NULL
if pem_root_certs is None:
pass
elif isinstance(pem_root_certs, bytes):
- pass
+ c_pem_root_certs = pem_root_certs
elif isinstance(pem_root_certs, basestring):
pem_root_certs = pem_root_certs.encode()
+ 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)
@@ -212,7 +286,7 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
credentials.c_ssl_pem_key_cert_pairs[i] = (
(<records.SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
credentials.c_credentials = grpc.grpc_ssl_server_credentials_create(
- pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
+ c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL)
return credentials
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index 36aea81a6c..643cdc9e3d 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -60,6 +60,8 @@ cdef extern from "grpc/support/port_platform.h":
# type exactly; just close enough that the operations will be supported in the
# underlying C layers.
ctypedef unsigned int gpr_uint32
+ ctypedef int gpr_int32
+ ctypedef long int gpr_int64
cdef extern from "grpc/support/time.h":
@@ -71,8 +73,8 @@ cdef extern from "grpc/support/time.h":
GPR_TIMESPAN
ctypedef struct gpr_timespec:
- libc.time.time_t seconds "tv_sec"
- int nanoseconds "tv_nsec"
+ gpr_int64 seconds "tv_sec"
+ gpr_int32 nanoseconds "tv_nsec"
gpr_clock_type clock_type
gpr_timespec gpr_time_0(gpr_clock_type type)
@@ -132,6 +134,20 @@ cdef extern from "grpc/byte_buffer.h":
cdef extern from "grpc/grpc.h":
+ const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
+ const char *GRPC_ARG_ENABLE_CENSUS
+ const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
+ const char *GRPC_ARG_MAX_MESSAGE_LENGTH
+ const char *GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+ const char *GRPC_ARG_DEFAULT_AUTHORITY
+ const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
+ const char *GRPC_ARG_SECONDARY_USER_AGENT_STRING
+ const char *GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+
+ const int GRPC_WRITE_BUFFER_HINT
+ const int GRPC_WRITE_NO_COMPRESS
+ const int GRPC_WRITE_USED_MASK
+
ctypedef struct grpc_completion_queue:
# We don't care about the internals (and in fact don't know them)
pass
@@ -149,9 +165,9 @@ cdef extern from "grpc/grpc.h":
pass
ctypedef enum grpc_arg_type:
- grpc_arg_string "GRPC_ARG_STRING"
- grpc_arg_integer "GRPC_ARG_INTEGER"
- grpc_arg_pointer "GRPC_ARG_POINTER"
+ GRPC_ARG_STRING
+ GRPC_ARG_INTEGER
+ GRPC_ARG_POINTER
ctypedef struct grpc_arg_value_pointer:
void *address "p"
@@ -185,6 +201,13 @@ cdef extern from "grpc/grpc.h":
GRPC_CALL_ERROR_INVALID_FLAGS
GRPC_CALL_ERROR_INVALID_METADATA
+ ctypedef enum grpc_connectivity_state:
+ GRPC_CHANNEL_IDLE
+ GRPC_CHANNEL_CONNECTING
+ GRPC_CHANNEL_READY
+ GRPC_CHANNEL_TRANSIENT_FAILURE
+ GRPC_CHANNEL_FATAL_FAILURE
+
ctypedef struct grpc_metadata:
const char *key
const char *value
@@ -279,9 +302,9 @@ cdef extern from "grpc/grpc.h":
grpc_status_code status,
const char *description,
void *reserved)
+ char *grpc_call_get_peer(grpc_call *call)
void grpc_call_destroy(grpc_call *call)
-
grpc_channel *grpc_insecure_channel_create(const char *target,
const grpc_channel_args *args,
void *reserved)
@@ -291,6 +314,12 @@ cdef extern from "grpc/grpc.h":
grpc_completion_queue *completion_queue,
const char *method, const char *host,
gpr_timespec deadline, void *reserved)
+ grpc_connectivity_state grpc_channel_check_connectivity_state(
+ grpc_channel *channel, int try_to_connect)
+ void grpc_channel_watch_connectivity_state(
+ grpc_channel *channel, grpc_connectivity_state last_observed_state,
+ gpr_timespec deadline, grpc_completion_queue *cq, void *tag)
+ char *grpc_channel_get_target(grpc_channel *channel)
void grpc_channel_destroy(grpc_channel *channel)
grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved)
@@ -367,3 +396,27 @@ cdef extern from "grpc/grpc_security.h":
grpc_call_error grpc_call_set_credentials(grpc_call *call,
grpc_call_credentials *creds)
+
+ ctypedef struct grpc_auth_context:
+ # We don't care about the internals (and in fact don't know them)
+ pass
+
+ ctypedef struct grpc_auth_metadata_context:
+ const char *service_url
+ const char *method_name
+ const grpc_auth_context *channel_auth_context
+
+ ctypedef void (*grpc_credentials_plugin_metadata_cb)(
+ void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
+ grpc_status_code status, const char *error_details)
+
+ ctypedef struct grpc_metadata_credentials_plugin:
+ void (*get_metadata)(
+ void *state, grpc_auth_metadata_context context,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data)
+ void (*destroy)(void *state)
+ void *state
+ const char *type
+
+ grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
+ grpc_metadata_credentials_plugin plugin, void *reserved)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
index 9ee487882a..4c844e4cb6 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pxd
@@ -66,6 +66,7 @@ cdef class Event:
cdef readonly call.Call operation_call
# For Server.request_call
+ cdef readonly bint is_new_request
cdef readonly CallDetails request_call_details
cdef readonly Metadata request_metadata
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
index 8edee09c2d..79a7f8f563 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx
@@ -32,6 +32,30 @@ from grpc._cython._cygrpc cimport call
from grpc._cython._cygrpc cimport server
+class ConnectivityState:
+ idle = grpc.GRPC_CHANNEL_IDLE
+ connecting = grpc.GRPC_CHANNEL_CONNECTING
+ ready = grpc.GRPC_CHANNEL_READY
+ transient_failure = grpc.GRPC_CHANNEL_TRANSIENT_FAILURE
+ fatal_failure = grpc.GRPC_CHANNEL_FATAL_FAILURE
+
+
+class ChannelArgKey:
+ enable_census = grpc.GRPC_ARG_ENABLE_CENSUS
+ max_concurrent_streams = grpc.GRPC_ARG_MAX_CONCURRENT_STREAMS
+ max_message_length = grpc.GRPC_ARG_MAX_MESSAGE_LENGTH
+ http2_initial_sequence_number = grpc.GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER
+ default_authority = grpc.GRPC_ARG_DEFAULT_AUTHORITY
+ primary_user_agent_string = grpc.GRPC_ARG_PRIMARY_USER_AGENT_STRING
+ secondary_user_agent_string = grpc.GRPC_ARG_SECONDARY_USER_AGENT_STRING
+ ssl_target_name_override = grpc.GRPC_SSL_TARGET_NAME_OVERRIDE_ARG
+
+
+class WriteFlag:
+ buffer_hint = grpc.GRPC_WRITE_BUFFER_HINT
+ no_compress = grpc.GRPC_WRITE_NO_COMPRESS
+
+
class StatusCode:
ok = grpc.GRPC_STATUS_OK
cancelled = grpc.GRPC_STATUS_CANCELLED
@@ -88,7 +112,10 @@ cdef class Timespec:
def __cinit__(self, time):
if time is None:
self.c_time = grpc.gpr_now(grpc.GPR_CLOCK_REALTIME)
- elif isinstance(time, float):
+ return
+ if isinstance(time, int):
+ time = float(time)
+ if isinstance(time, float):
if time == float("+inf"):
self.c_time = grpc.gpr_inf_future(grpc.GPR_CLOCK_REALTIME)
elif time == float("-inf"):
@@ -97,8 +124,11 @@ cdef class Timespec:
self.c_time.seconds = time
self.c_time.nanoseconds = (time - float(self.c_time.seconds)) * 1e9
self.c_time.clock_type = grpc.GPR_CLOCK_REALTIME
+ elif isinstance(time, Timespec):
+ self.c_time = (<Timespec>time).c_time
else:
- raise TypeError("expected time to be float")
+ raise TypeError("expected time to be float, int, or Timespec, not {}"
+ .format(type(time)))
@property
def seconds(self):
@@ -166,6 +196,7 @@ cdef class Event:
object tag, call.Call operation_call,
CallDetails request_call_details,
Metadata request_metadata,
+ bint is_new_request,
Operations batch_operations):
self.type = type
self.success = success
@@ -174,6 +205,7 @@ cdef class Event:
self.request_call_details = request_call_details
self.request_metadata = request_metadata
self.batch_operations = batch_operations
+ self.is_new_request = is_new_request
cdef class ByteBuffer:
@@ -186,8 +218,14 @@ cdef class ByteBuffer:
pass
elif isinstance(data, basestring):
data = data.encode()
+ elif 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 or bytes")
+ raise TypeError("expected value to be of type str, bytes, or "
+ "ByteBuffer, not {}".format(type(data)))
cdef char *c_data = data
data_slice = grpc.gpr_slice_from_copied_buffer(c_data, len(data))
@@ -410,12 +448,22 @@ cdef class Operation:
return self.c_op.type
@property
+ def has_status(self):
+ return self.c_op.type == grpc.GRPC_OP_RECV_STATUS_ON_CLIENT
+
+ @property
def received_message(self):
if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
raise TypeError("self must be an operation receiving a message")
return self._received_message
@property
+ def received_message_or_none(self):
+ if self.c_op.type != grpc.GRPC_OP_RECV_MESSAGE:
+ return None
+ return self._received_message
+
+ @property
def received_metadata(self):
if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
@@ -423,12 +471,25 @@ cdef class Operation:
return self._received_metadata
@property
+ def received_metadata_or_none(self):
+ if (self.c_op.type != grpc.GRPC_OP_RECV_INITIAL_METADATA and
+ self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT):
+ return None
+ return self._received_metadata
+
+ @property
def received_status_code(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
raise TypeError("self must be an operation receiving a status code")
return self._received_status_code
@property
+ def received_status_code_or_none(self):
+ if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+ return None
+ return self._received_status_code
+
+ @property
def received_status_details(self):
if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
raise TypeError("self must be an operation receiving status details")
@@ -438,12 +499,27 @@ cdef class Operation:
return None
@property
+ def received_status_details_or_none(self):
+ if self.c_op.type != grpc.GRPC_OP_RECV_STATUS_ON_CLIENT:
+ return None
+ if self._received_status_details:
+ return self._received_status_details
+ else:
+ return None
+
+ @property
def received_cancelled(self):
if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
raise TypeError("self must be an operation receiving cancellation "
"information")
return False if self._received_cancelled == 0 else True
+ @property
+ def received_cancelled_or_none(self):
+ if self.c_op.type != grpc.GRPC_OP_RECV_CLOSE_ON_SERVER:
+ return None
+ return False if self._received_cancelled == 0 else True
+
def __dealloc__(self):
# We *almost* don't need to do anything; most of the objects are handled by
# Python. The remaining one(s) are primitive fields filled in by GRPC core.
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
index 6d20d2910c..46df8bf77f 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx
@@ -132,7 +132,7 @@ cdef class Server:
def cancel_all_calls(self):
if not self.is_shutting_down:
- raise ValueError("the server must be shutting down to cancel all calls")
+ raise RuntimeError("the server must be shutting down to cancel all calls")
elif self.is_shutdown:
return
else:
diff --git a/src/python/grpcio/grpc/_cython/adapter_low.py b/src/python/grpcio/grpc/_cython/adapter_low.py
deleted file mode 100644
index 4f24da330f..0000000000
--- a/src/python/grpcio/grpc/_cython/adapter_low.py
+++ /dev/null
@@ -1,102 +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.
-
-
-# Adapter from grpc._cython.types to the surface expected by
-# grpc._adapter._intermediary_low.
-#
-# TODO(atash): Once this is plugged into grpc._adapter._intermediary_low, remove
-# both grpc._adapter._intermediary_low and this file. The fore and rear links in
-# grpc._adapter should be able to use grpc._cython.types directly.
-
-from grpc._adapter import _types as type_interfaces
-from grpc._cython import cygrpc
-
-
-class ClientCredentials(object):
- def __init__(self):
- raise NotImplementedError()
-
- @staticmethod
- def google_default():
- raise NotImplementedError()
-
- @staticmethod
- def ssl():
- raise NotImplementedError()
-
- @staticmethod
- def composite():
- raise NotImplementedError()
-
- @staticmethod
- def compute_engine():
- raise NotImplementedError()
-
- @staticmethod
- def jwt():
- raise NotImplementedError()
-
- @staticmethod
- def refresh_token():
- raise NotImplementedError()
-
- @staticmethod
- def iam():
- raise NotImplementedError()
-
-
-class ServerCredentials(object):
- def __init__(self):
- raise NotImplementedError()
-
- @staticmethod
- def ssl():
- raise NotImplementedError()
-
-
-class CompletionQueue(type_interfaces.CompletionQueue):
- def __init__(self):
- raise NotImplementedError()
-
-
-class Call(type_interfaces.Call):
- def __init__(self):
- raise NotImplementedError()
-
-
-class Channel(type_interfaces.Channel):
- def __init__(self):
- raise NotImplementedError()
-
-
-class Server(type_interfaces.Server):
- def __init__(self):
- raise NotImplementedError()
-
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index b20dda8a95..16ec12dac0 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -44,6 +44,9 @@ from grpc._cython._cygrpc import completion_queue
from grpc._cython._cygrpc import records
from grpc._cython._cygrpc import server
+ConnectivityState = records.ConnectivityState
+ChannelArgKey = records.ChannelArgKey
+WriteFlag = records.WriteFlag
StatusCode = records.StatusCode
CallError = records.CallError
CompletionType = records.CompletionType
@@ -73,6 +76,8 @@ Operations = records.Operations
CallCredentials = credentials.CallCredentials
ChannelCredentials = credentials.ChannelCredentials
ServerCredentials = credentials.ServerCredentials
+CredentialsMetadataPlugin = credentials.CredentialsMetadataPlugin
+AuthMetadataContext = credentials.AuthMetadataContext
channel_credentials_google_default = (
credentials.channel_credentials_google_default)
@@ -88,6 +93,7 @@ call_credentials_jwt_access = (
call_credentials_refresh_token = (
credentials.call_credentials_google_refresh_token)
call_credentials_google_iam = credentials.call_credentials_google_iam
+call_credentials_metadata_plugin = credentials.call_credentials_metadata_plugin
server_credentials_ssl = credentials.server_credentials_ssl
CompletionQueue = completion_queue.CompletionQueue
diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py
index 67ef86a176..5ca0a0ee60 100644
--- a/src/python/grpcio/grpc/_links/invocation.py
+++ b/src/python/grpcio/grpc/_links/invocation.py
@@ -182,15 +182,15 @@ class _Kernel(object):
def _on_finish_event(self, operation_id, event, rpc_state):
_no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states)
- if event.status.code is _intermediary_low.Code.OK:
+ if event.status.code == _intermediary_low.Code.OK:
termination = links.Ticket.Termination.COMPLETION
- elif event.status.code is _intermediary_low.Code.CANCELLED:
+ elif event.status.code == _intermediary_low.Code.CANCELLED:
termination = links.Ticket.Termination.CANCELLATION
- elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+ elif event.status.code == _intermediary_low.Code.DEADLINE_EXCEEDED:
termination = links.Ticket.Termination.EXPIRATION
- elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED:
+ elif event.status.code == _intermediary_low.Code.UNIMPLEMENTED:
termination = links.Ticket.Termination.REMOTE_FAILURE
- elif event.status.code is _intermediary_low.Code.UNKNOWN:
+ elif event.status.code == _intermediary_low.Code.UNKNOWN:
termination = links.Ticket.Termination.LOCAL_FAILURE
else:
termination = links.Ticket.Termination.TRANSMISSION_FAILURE
@@ -262,7 +262,7 @@ class _Kernel(object):
self._channel, self._completion_queue, '/%s/%s' % (group, method),
self._host, time.time() + timeout)
if options is not None and options.credentials is not None:
- call.set_credentials(options.credentials._intermediary_low_credentials)
+ call.set_credentials(options.credentials._low_credentials)
if transformed_initial_metadata is not None:
for metadata_key, metadata_value in transformed_initial_metadata:
call.add_metadata(metadata_key, metadata_value)
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index f56df84007..01edee6896 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -254,12 +254,12 @@ class _Kernel(object):
rpc_state = self._rpc_states[call]
_no_longer_due(_FINISH, rpc_state, call, self._rpc_states)
code = event.status.code
- if code is _intermediary_low.Code.OK:
+ if code == _intermediary_low.Code.OK:
return
- if code is _intermediary_low.Code.CANCELLED:
+ if code == _intermediary_low.Code.CANCELLED:
termination = links.Ticket.Termination.CANCELLATION
- elif code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+ elif code == _intermediary_low.Code.DEADLINE_EXCEEDED:
termination = links.Ticket.Termination.EXPIRATION
else:
termination = links.Ticket.Termination.TRANSMISSION_FAILURE
diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py
index 05b954d186..2b520cc7e5 100644
--- a/src/python/grpcio/grpc/beta/_server.py
+++ b/src/python/grpcio/grpc/beta/_server.py
@@ -44,6 +44,12 @@ _DEFAULT_TIMEOUT = 300
_MAXIMUM_TIMEOUT = 24 * 60 * 60
+def _set_event():
+ event = threading.Event()
+ event.set()
+ return event
+
+
class _GRPCServicer(base.Servicer):
def __init__(self, delegate):
@@ -61,86 +67,143 @@ class _GRPCServicer(base.Servicer):
raise
-def _disassemble(grpc_link, end_link, pool, event, grace):
- grpc_link.begin_stop()
- end_link.stop(grace).wait()
- grpc_link.end_stop()
- grpc_link.join_link(utilities.NULL_LINK)
- end_link.join_link(utilities.NULL_LINK)
- if pool is not None:
- pool.shutdown(wait=True)
- event.set()
+class _Server(interfaces.Server):
+ def __init__(
+ self, implementations, multi_implementation, pool, pool_size,
+ default_timeout, maximum_timeout, grpc_link):
+ self._lock = threading.Lock()
+ self._implementations = implementations
+ self._multi_implementation = multi_implementation
+ self._customer_pool = pool
+ self._pool_size = pool_size
+ self._default_timeout = default_timeout
+ self._maximum_timeout = maximum_timeout
+ self._grpc_link = grpc_link
-class Server(interfaces.Server):
+ self._end_link = None
+ self._stop_events = None
+ self._pool = None
- def __init__(self, grpc_link, end_link, pool):
- self._grpc_link = grpc_link
- self._end_link = end_link
- self._pool = pool
+ def _start(self):
+ with self._lock:
+ if self._end_link is not None:
+ raise ValueError('Cannot start already-started server!')
+
+ if self._customer_pool is None:
+ self._pool = logging_pool.pool(self._pool_size)
+ assembly_pool = self._pool
+ else:
+ assembly_pool = self._customer_pool
+
+ servicer = _GRPCServicer(
+ _crust_implementations.servicer(
+ self._implementations, self._multi_implementation, assembly_pool))
+
+ self._end_link = _core_implementations.service_end_link(
+ servicer, self._default_timeout, self._maximum_timeout)
+
+ self._grpc_link.join_link(self._end_link)
+ self._end_link.join_link(self._grpc_link)
+ self._grpc_link.start()
+ self._end_link.start()
+
+ def _dissociate_links_and_shut_down_pool(self):
+ self._grpc_link.end_stop()
+ self._grpc_link.join_link(utilities.NULL_LINK)
+ self._end_link.join_link(utilities.NULL_LINK)
+ self._end_link = None
+ if self._pool is not None:
+ self._pool.shutdown(wait=True)
+ self._pool = None
+
+ def _stop_stopping(self):
+ self._dissociate_links_and_shut_down_pool()
+ for stop_event in self._stop_events:
+ stop_event.set()
+ self._stop_events = None
+
+ def _stop_started(self):
+ self._grpc_link.begin_stop()
+ self._end_link.stop(0).wait()
+ self._dissociate_links_and_shut_down_pool()
+
+ def _foreign_thread_stop(self, end_stop_event, stop_events):
+ end_stop_event.wait()
+ with self._lock:
+ if self._stop_events is stop_events:
+ self._stop_stopping()
+
+ def _schedule_stop(self, grace):
+ with self._lock:
+ if self._end_link is None:
+ return _set_event()
+ server_stop_event = threading.Event()
+ if self._stop_events is None:
+ self._stop_events = [server_stop_event]
+ self._grpc_link.begin_stop()
+ else:
+ self._stop_events.append(server_stop_event)
+ end_stop_event = self._end_link.stop(grace)
+ end_stop_thread = threading.Thread(
+ target=self._foreign_thread_stop,
+ args=(end_stop_event, self._stop_events))
+ end_stop_thread.start()
+ return server_stop_event
+
+ def _stop_now(self):
+ with self._lock:
+ if self._end_link is not None:
+ if self._stop_events is None:
+ self._stop_started()
+ else:
+ self._stop_stopping()
def add_insecure_port(self, address):
- return self._grpc_link.add_port(address, None)
+ with self._lock:
+ if self._end_link is None:
+ return self._grpc_link.add_port(address, None)
+ else:
+ raise ValueError('Can\'t add port to serving server!')
def add_secure_port(self, address, server_credentials):
- return self._grpc_link.add_port(
- address, server_credentials._intermediary_low_credentials) # pylint: disable=protected-access
-
- def _start(self):
- self._grpc_link.join_link(self._end_link)
- self._end_link.join_link(self._grpc_link)
- self._grpc_link.start()
- self._end_link.start()
-
- def _stop(self, grace):
- stop_event = threading.Event()
- if 0 < grace:
- disassembly_thread = threading.Thread(
- target=_disassemble,
- args=(
- self._grpc_link, self._end_link, self._pool, stop_event, grace,))
- disassembly_thread.start()
- return stop_event
- else:
- _disassemble(self._grpc_link, self._end_link, self._pool, stop_event, 0)
- return stop_event
+ with self._lock:
+ if self._end_link is None:
+ return self._grpc_link.add_port(
+ address, server_credentials._low_credentials) # pylint: disable=protected-access
+ else:
+ raise ValueError('Can\'t add port to serving server!')
def start(self):
self._start()
def stop(self, grace):
- return self._stop(grace)
+ if 0 < grace:
+ return self._schedule_stop(grace)
+ else:
+ self._stop_now()
+ return _set_event()
def __enter__(self):
self._start()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
- self._stop(0).wait()
+ self._stop_now()
return False
+ def __del__(self):
+ self._stop_now()
+
def server(
implementations, multi_implementation, request_deserializers,
response_serializers, thread_pool, thread_pool_size, default_timeout,
maximum_timeout):
- if thread_pool is None:
- service_thread_pool = logging_pool.pool(
- _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
- assembly_thread_pool = service_thread_pool
- else:
- service_thread_pool = thread_pool
- assembly_thread_pool = None
-
- servicer = _GRPCServicer(
- _crust_implementations.servicer(
- implementations, multi_implementation, service_thread_pool))
-
grpc_link = service.service_link(request_deserializers, response_serializers)
-
- end_link = _core_implementations.service_end_link(
- servicer,
+ return _Server(
+ implementations, multi_implementation, thread_pool,
+ _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size,
_DEFAULT_TIMEOUT if default_timeout is None else default_timeout,
- _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout)
-
- return Server(grpc_link, end_link, assembly_thread_pool)
+ _MAXIMUM_TIMEOUT if maximum_timeout is None else maximum_timeout,
+ grpc_link)
diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py
index 11dab889cd..2af019309a 100644
--- a/src/python/grpcio/grpc/beta/_stub.py
+++ b/src/python/grpcio/grpc/beta/_stub.py
@@ -42,76 +42,114 @@ _DEFAULT_POOL_SIZE = 6
class _AutoIntermediary(object):
- def __init__(self, delegate, on_deletion):
+ def __init__(self, up, down, delegate):
+ self._lock = threading.Lock()
+ self._up = up
+ self._down = down
+ self._in_context = False
self._delegate = delegate
- self._on_deletion = on_deletion
def __getattr__(self, attr):
- return getattr(self._delegate, attr)
+ with self._lock:
+ if self._delegate is None:
+ raise AttributeError('No useful attributes out of context!')
+ else:
+ return getattr(self._delegate, attr)
def __enter__(self):
- return self
+ with self._lock:
+ if self._in_context:
+ raise ValueError('Already in context!')
+ elif self._delegate is None:
+ self._delegate = self._up()
+ self._in_context = True
+ return self
def __exit__(self, exc_type, exc_val, exc_tb):
- return False
+ with self._lock:
+ if not self._in_context:
+ raise ValueError('Not in context!')
+ self._down()
+ self._in_context = False
+ self._delegate = None
+ return False
def __del__(self):
- self._on_deletion()
+ with self._lock:
+ if self._delegate is not None:
+ self._down()
+ self._delegate = None
+
+
+class _StubAssemblyManager(object):
+
+ def __init__(
+ self, thread_pool, thread_pool_size, end_link, grpc_link, stub_creator):
+ self._thread_pool = thread_pool
+ self._pool_size = thread_pool_size
+ self._end_link = end_link
+ self._grpc_link = grpc_link
+ self._stub_creator = stub_creator
+ self._own_pool = None
+
+ def up(self):
+ if self._thread_pool is None:
+ self._own_pool = logging_pool.pool(
+ _DEFAULT_POOL_SIZE if self._pool_size is None else self._pool_size)
+ assembly_pool = self._own_pool
+ else:
+ assembly_pool = self._thread_pool
+ self._end_link.join_link(self._grpc_link)
+ self._grpc_link.join_link(self._end_link)
+ self._end_link.start()
+ self._grpc_link.start()
+ return self._stub_creator(self._end_link, assembly_pool)
+
+ def down(self):
+ self._end_link.stop(0).wait()
+ self._grpc_link.stop()
+ self._end_link.join_link(utilities.NULL_LINK)
+ self._grpc_link.join_link(utilities.NULL_LINK)
+ if self._own_pool is not None:
+ self._own_pool.shutdown(wait=True)
+ self._own_pool = None
def _assemble(
channel, host, metadata_transformer, request_serializers,
- response_deserializers, thread_pool, thread_pool_size):
+ response_deserializers, thread_pool, thread_pool_size, stub_creator):
end_link = _core_implementations.invocation_end_link()
grpc_link = invocation.invocation_link(
channel, host, metadata_transformer, request_serializers,
response_deserializers)
- if thread_pool is None:
- invocation_pool = logging_pool.pool(
- _DEFAULT_POOL_SIZE if thread_pool_size is None else thread_pool_size)
- assembly_pool = invocation_pool
- else:
- invocation_pool = thread_pool
- assembly_pool = None
- end_link.join_link(grpc_link)
- grpc_link.join_link(end_link)
- end_link.start()
- grpc_link.start()
- return end_link, grpc_link, invocation_pool, assembly_pool
-
-
-def _disassemble(end_link, grpc_link, pool):
- end_link.stop(24 * 60 * 60).wait()
- grpc_link.stop()
- end_link.join_link(utilities.NULL_LINK)
- grpc_link.join_link(utilities.NULL_LINK)
- if pool is not None:
- pool.shutdown(wait=True)
-
-
-def _wrap_assembly(stub, end_link, grpc_link, assembly_pool):
- disassembly_thread = threading.Thread(
- target=_disassemble, args=(end_link, grpc_link, assembly_pool))
- return _AutoIntermediary(stub, disassembly_thread.start)
+ stub_assembly_manager = _StubAssemblyManager(
+ thread_pool, thread_pool_size, end_link, grpc_link, stub_creator)
+ stub = stub_assembly_manager.up()
+ return _AutoIntermediary(
+ stub_assembly_manager.up, stub_assembly_manager.down, stub)
+
+
+def _dynamic_stub_creator(service, cardinalities):
+ def create_dynamic_stub(end_link, invocation_pool):
+ return _crust_implementations.dynamic_stub(
+ end_link, service, cardinalities, invocation_pool)
+ return create_dynamic_stub
def generic_stub(
channel, host, metadata_transformer, request_serializers,
response_deserializers, thread_pool, thread_pool_size):
- end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+ return _assemble(
channel, host, metadata_transformer, request_serializers,
- response_deserializers, thread_pool, thread_pool_size)
- stub = _crust_implementations.generic_stub(end_link, invocation_pool)
- return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
+ response_deserializers, thread_pool, thread_pool_size,
+ _crust_implementations.generic_stub)
def dynamic_stub(
channel, host, service, cardinalities, metadata_transformer,
request_serializers, response_deserializers, thread_pool,
thread_pool_size):
- end_link, grpc_link, invocation_pool, assembly_pool = _assemble(
+ return _assemble(
channel, host, metadata_transformer, request_serializers,
- response_deserializers, thread_pool, thread_pool_size)
- stub = _crust_implementations.dynamic_stub(
- end_link, service, cardinalities, invocation_pool)
- return _wrap_assembly(stub, end_link, grpc_link, assembly_pool)
+ response_deserializers, thread_pool, thread_pool_size,
+ _dynamic_stub_creator(service, cardinalities))
diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py
index c9d64ad35a..a0ca330d2c 100644
--- a/src/python/grpcio/grpc/beta/implementations.py
+++ b/src/python/grpcio/grpc/beta/implementations.py
@@ -36,6 +36,7 @@ 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
from grpc._adapter import _types
from grpc.beta import _connectivity_channel
from grpc.beta import _server
@@ -48,7 +49,7 @@ _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
'Exception calling channel subscription callback!')
-class ClientCredentials(object):
+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
@@ -56,13 +57,12 @@ class ClientCredentials(object):
functions.
"""
- def __init__(self, low_credentials, intermediary_low_credentials):
+ def __init__(self, low_credentials):
self._low_credentials = low_credentials
- self._intermediary_low_credentials = intermediary_low_credentials
-def ssl_client_credentials(root_certificates, private_key, certificate_chain):
- """Creates a ClientCredentials for use with an SSL-enabled Channel.
+def ssl_channel_credentials(root_certificates, private_key, certificate_chain):
+ """Creates a ChannelCredentials for use with an SSL-enabled Channel.
Args:
root_certificates: The PEM-encoded root certificates or None to ask for
@@ -73,12 +73,73 @@ def ssl_client_credentials(root_certificates, private_key, certificate_chain):
certificate chain should be used.
Returns:
- A ClientCredentials for use with an SSL-enabled Channel.
+ A ChannelCredentials for use with an SSL-enabled Channel.
"""
- intermediary_low_credentials = _intermediary_low.ClientCredentials(
- root_certificates, private_key, certificate_chain)
- return ClientCredentials(
- intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access
+ 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:
+ name = metadata_plugin.__name__
+ return CallCredentials(
+ _low.call_credentials_metadata_plugin(metadata_plugin, name))
+
+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))
class Channel(object):
@@ -135,19 +196,19 @@ def insecure_channel(host, port):
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
-def secure_channel(host, port, client_credentials):
+def secure_channel(host, port, channel_credentials):
"""Creates a secure Channel to a remote host.
Args:
host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect.
- client_credentials: A ClientCredentials.
+ channel_credentials: A ChannelCredentials.
Returns:
A secure Channel to the remote host through which RPCs may be conducted.
"""
intermediary_low_channel = _intermediary_low.Channel(
- '%s:%d' % (host, port), client_credentials._intermediary_low_credentials)
+ '%s:%d' % (host, port), channel_credentials._low_credentials)
return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
@@ -251,9 +312,8 @@ class ServerCredentials(object):
functions.
"""
- def __init__(self, low_credentials, intermediary_low_credentials):
+ def __init__(self, low_credentials):
self._low_credentials = low_credentials
- self._intermediary_low_credentials = intermediary_low_credentials
def ssl_server_credentials(
@@ -282,11 +342,9 @@ def ssl_server_credentials(
raise ValueError(
'Illegal to require client auth without providing root certificates!')
else:
- intermediary_low_credentials = _intermediary_low.ServerCredentials(
+ return ServerCredentials(_low.server_credentials_ssl(
root_certificates, private_key_certificate_chain_pairs,
- require_client_auth)
- return ServerCredentials(
- intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access
+ require_client_auth))
class ServerOptions(object):
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
index d4ca56500f..0663119163 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -100,14 +100,55 @@ def grpc_call_options(disable_compression=False, credentials=None):
disable_compression: A boolean indicating whether or not compression should
be disabled for the request object of the RPC. Only valid for
request-unary RPCs.
- credentials: Reserved for gRPC per-call credentials. The type for this does
- not exist yet at the Python level.
+ credentials: A CallCredentials object to use for the invoked RPC.
"""
- if credentials is not None:
- raise ValueError('`credentials` is a reserved argument')
return GRPCCallOptions(disable_compression, None, credentials)
+class GRPCAuthMetadataContext(object):
+ """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.
+ """
+ __metaclass__ = abc.ABCMeta
+
+
+class GRPCAuthMetadataPluginCallback(object):
+ """Callback object received by a metadata plugin."""
+ __metaclass__ = abc.ABCMeta
+
+ 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(object):
+ """
+ """
+ __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()
+
+
class GRPCServicerContext(object):
"""Exposes gRPC-specific options and behaviors to code servicing RPCs."""
__metaclass__ = abc.ABCMeta
diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py
index 8e07d9061e..9c615672aa 100644
--- a/src/python/grpcio/grpc/framework/core/_end.py
+++ b/src/python/grpcio/grpc/framework/core/_end.py
@@ -85,35 +85,6 @@ def _future_shutdown(lock, cycle, event):
return in_future
-def _termination_action(lock, stats, operation_id, cycle):
- """Constructs the termination action for a single operation.
-
- Args:
- lock: A lock to hold during the termination action.
- stats: A mapping from base.Outcome.Kind values to integers to increment
- with the outcome kind given to the termination action.
- operation_id: The operation ID for the termination action.
- cycle: A _Cycle value to be updated during the termination action.
-
- Returns:
- A callable that takes an operation outcome kind as its sole parameter and
- that should be used as the termination action for the operation
- associated with the given operation ID.
- """
- def termination_action(outcome_kind):
- with lock:
- stats[outcome_kind] += 1
- cycle.operations.pop(operation_id, None)
- if not cycle.operations:
- for action in cycle.idle_actions:
- cycle.pool.submit(action)
- cycle.idle_actions = []
- if cycle.grace:
- _cancel_futures(cycle.futures)
- cycle.pool.shutdown(wait=False)
- return termination_action
-
-
class _End(End):
"""An End implementation."""
@@ -133,6 +104,31 @@ class _End(End):
self._cycle = None
+ def _termination_action(self, operation_id):
+ """Constructs the termination action for a single operation.
+
+ Args:
+ operation_id: The operation ID for the termination action.
+
+ Returns:
+ A callable that takes an operation outcome kind as its sole parameter and
+ that should be used as the termination action for the operation
+ associated with the given operation ID.
+ """
+ def termination_action(outcome_kind):
+ with self._lock:
+ self._stats[outcome_kind] += 1
+ self._cycle.operations.pop(operation_id, None)
+ if not self._cycle.operations:
+ for action in self._cycle.idle_actions:
+ self._cycle.pool.submit(action)
+ self._cycle.idle_actions = []
+ if self._cycle.grace:
+ _cancel_futures(self._cycle.futures)
+ self._cycle.pool.shutdown(wait=False)
+ self._cycle = None
+ return termination_action
+
def start(self):
"""See base.End.start for specification."""
with self._lock:
@@ -174,8 +170,7 @@ class _End(End):
with self._lock:
if self._cycle is None or self._cycle.grace:
raise ValueError('Can\'t operate on stopped or stopping End!')
- termination_action = _termination_action(
- self._lock, self._stats, operation_id, self._cycle)
+ termination_action = self._termination_action(operation_id)
operation = _operation.invocation_operate(
operation_id, group, method, subscription, timeout, protocol_options,
initial_metadata, payload, completion, self._mate.accept_ticket,
@@ -208,8 +203,7 @@ class _End(End):
if operation is not None:
operation.handle_ticket(ticket)
elif self._servicer_package is not None and not self._cycle.grace:
- termination_action = _termination_action(
- self._lock, self._stats, ticket.operation_id, self._cycle)
+ termination_action = self._termination_action(ticket.operation_id)
operation = _operation.service_operate(
self._servicer_package, ticket, self._mate.accept_ticket,
termination_action, self._cycle.pool)
diff --git a/src/python/grpcio/requirements.txt b/src/python/grpcio/requirements.txt
index ee8568120b..06516ee0d7 100644
--- a/src/python/grpcio/requirements.txt
+++ b/src/python/grpcio/requirements.txt
@@ -1,3 +1,4 @@
enum34>=1.0.4
futures>=2.2.0
cython>=0.23
+coverage>=4.0
diff --git a/src/python/grpcio/setup.cfg b/src/python/grpcio/setup.cfg
index 8f69613632..52b6b50900 100644
--- a/src/python/grpcio/setup.cfg
+++ b/src/python/grpcio/setup.cfg
@@ -1,2 +1,8 @@
+[coverage:run]
+plugins = Cython.Coverage
+
[build_ext]
inplace=1
+
+[build_proto_modules]
+exclude=.*protoc_plugin/protoc_plugin_test\.proto$
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index ec68eb6755..b8a98c3d85 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -43,27 +43,23 @@ os.chdir(os.path.dirname(os.path.abspath(__file__)))
# Break import-style to ensure we can actually find our commands module.
import commands
-# Use environment variables to determine whether or not the Cython extension
-# should *use* Cython or use the generated C files. Note that this requires the
-# C files to have been generated by building first *with* Cython support.
-_BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
-
-_C_EXTENSION_SOURCES = (
- 'grpc/_adapter/_c/module.c',
- 'grpc/_adapter/_c/types.c',
- 'grpc/_adapter/_c/utility.c',
- 'grpc/_adapter/_c/types/call_credentials.c',
- 'grpc/_adapter/_c/types/channel_credentials.c',
- 'grpc/_adapter/_c/types/server_credentials.c',
- 'grpc/_adapter/_c/types/completion_queue.c',
- 'grpc/_adapter/_c/types/call.c',
- 'grpc/_adapter/_c/types/channel.c',
- 'grpc/_adapter/_c/types/server.c',
-)
+# Environment variable to determine whether or not the Cython extension should
+# *use* Cython or use the generated C files. Note that this requires the C files
+# to have been generated by building first *with* Cython support.
+BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+
+# Environment variable to determine whether or not to enable coverage analysis
+# in Cython modules.
+ENABLE_CYTHON_TRACING = os.environ.get(
+ 'GRPC_PYTHON_ENABLE_CYTHON_TRACING', False)
+
+# Environment variable to determine whether or not to include the test files in
+# the installation.
+INSTALL_TESTS = os.environ.get('GRPC_PYTHON_INSTALL_TESTS', False)
-_CYTHON_EXTENSION_PACKAGE_NAMES = ()
+CYTHON_EXTENSION_PACKAGE_NAMES = ()
-_CYTHON_EXTENSION_MODULE_NAMES = (
+CYTHON_EXTENSION_MODULE_NAMES = (
'grpc._cython.cygrpc',
'grpc._cython._cygrpc.call',
'grpc._cython._cygrpc.channel',
@@ -73,24 +69,16 @@ _CYTHON_EXTENSION_MODULE_NAMES = (
'grpc._cython._cygrpc.server',
)
-_EXTENSION_INCLUDE_DIRECTORIES = (
+EXTENSION_INCLUDE_DIRECTORIES = (
'.',
)
-_EXTENSION_LIBRARIES = (
+EXTENSION_LIBRARIES = (
'grpc',
'gpr',
)
if not "darwin" in sys.platform:
- _EXTENSION_LIBRARIES += ('rt',)
-
-
-_C_EXTENSION_MODULE = _core.Extension(
- 'grpc._adapter._c', sources=list(_C_EXTENSION_SOURCES),
- include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES),
- libraries=list(_EXTENSION_LIBRARIES),
-)
-_EXTENSION_MODULES = [_C_EXTENSION_MODULE]
+ EXTENSION_LIBRARIES += ('rt',)
def cython_extensions(package_names, module_names, include_dirs, libraries,
@@ -101,48 +89,89 @@ def cython_extensions(package_names, module_names, include_dirs, libraries,
extensions = [
_extension.Extension(
name=module_name, sources=[module_file],
- include_dirs=include_dirs, libraries=libraries
+ include_dirs=include_dirs, libraries=libraries,
+ define_macros=[('CYTHON_TRACE_NOGIL', 1)] if ENABLE_CYTHON_TRACING else []
) for (module_name, module_file) in zip(module_names, module_files)
]
if build_with_cython:
import Cython.Build
- return Cython.Build.cythonize(extensions)
+ return Cython.Build.cythonize(
+ extensions,
+ compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)})
else:
return extensions
-_CYTHON_EXTENSION_MODULES = cython_extensions(
- list(_CYTHON_EXTENSION_PACKAGE_NAMES), list(_CYTHON_EXTENSION_MODULE_NAMES),
- list(_EXTENSION_INCLUDE_DIRECTORIES), list(_EXTENSION_LIBRARIES),
- bool(_BUILD_WITH_CYTHON))
+CYTHON_EXTENSION_MODULES = cython_extensions(
+ list(CYTHON_EXTENSION_PACKAGE_NAMES), list(CYTHON_EXTENSION_MODULE_NAMES),
+ list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES),
+ bool(BUILD_WITH_CYTHON))
-_PACKAGES = setuptools.find_packages('.')
-
-_PACKAGE_DIRECTORIES = {
+PACKAGE_DIRECTORIES = {
'': '.',
}
-_INSTALL_REQUIRES = (
+INSTALL_REQUIRES = (
'enum34>=1.0.4',
'futures>=2.2.0',
)
-_SETUP_REQUIRES = (
+SETUP_REQUIRES = (
'sphinx>=1.3',
-) + _INSTALL_REQUIRES
+) + INSTALL_REQUIRES
-_COMMAND_CLASS = {
+COMMAND_CLASS = {
'doc': commands.SphinxDocumentation,
+ 'build_proto_modules': commands.BuildProtoModules,
'build_project_metadata': commands.BuildProjectMetadata,
'build_py': commands.BuildPy,
+ 'gather': commands.Gather,
+ 'run_interop': commands.RunInterop,
+}
+
+TEST_PACKAGE_DATA = {
+ 'tests.interop': [
+ 'credentials/ca.pem',
+ 'credentials/server1.key',
+ 'credentials/server1.pem',
+ ],
+ 'tests.protoc_plugin': [
+ 'protoc_plugin_test.proto',
+ ],
+ 'tests.unit': [
+ 'credentials/ca.pem',
+ 'credentials/server1.key',
+ 'credentials/server1.pem',
+ ],
}
+TESTS_REQUIRE = (
+ 'oauth2client>=1.4.7',
+ 'protobuf==3.0.0a3',
+ 'coverage>=4.0',
+) + INSTALL_REQUIRES
+
+TEST_SUITE = 'tests'
+TEST_LOADER = 'tests:Loader'
+TEST_RUNNER = 'tests:Runner'
+
+PACKAGE_DATA = {}
+if INSTALL_TESTS:
+ PACKAGE_DATA = dict(PACKAGE_DATA, **TEST_PACKAGE_DATA)
+ PACKAGES = setuptools.find_packages('.')
+else:
+ PACKAGES = setuptools.find_packages('.', exclude=['tests', 'tests.*'])
+
setuptools.setup(
name='grpcio',
- version='0.11.0b1',
- ext_modules=_EXTENSION_MODULES + _CYTHON_EXTENSION_MODULES,
- packages=list(_PACKAGES),
- package_dir=_PACKAGE_DIRECTORIES,
- install_requires=_INSTALL_REQUIRES,
- setup_requires=_SETUP_REQUIRES,
- cmdclass=_COMMAND_CLASS
+ version='0.12.0b0',
+ ext_modules=CYTHON_EXTENSION_MODULES,
+ packages=list(PACKAGES),
+ package_dir=PACKAGE_DIRECTORIES,
+ install_requires=INSTALL_REQUIRES,
+ setup_requires=SETUP_REQUIRES,
+ cmdclass=COMMAND_CLASS,
+ tests_require=TESTS_REQUIRE,
+ test_suite=TEST_SUITE,
+ test_loader=TEST_LOADER,
+ test_runner=TEST_RUNNER,
)
diff --git a/src/python/grpcio/tests/__init__.py b/src/python/grpcio/tests/__init__.py
new file mode 100644
index 0000000000..b76b3985a1
--- /dev/null
+++ b/src/python/grpcio/tests/__init__.py
@@ -0,0 +1,34 @@
+# 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.
+
+from tests import _loader
+from tests import _runner
+
+Loader = _loader.Loader
+Runner = _runner.Runner
diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py
new file mode 100644
index 0000000000..6992029b5e
--- /dev/null
+++ b/src/python/grpcio/tests/_loader.py
@@ -0,0 +1,119 @@
+# 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 importlib
+import pkgutil
+import re
+import unittest
+
+import coverage
+
+TEST_MODULE_REGEX = r'^.*_test$'
+
+
+class Loader(object):
+ """Test loader for setuptools test suite support.
+
+ Attributes:
+ suite (unittest.TestSuite): All tests collected by the loader.
+ loader (unittest.TestLoader): Standard Python unittest loader to be ran per
+ module discovered.
+ module_matcher (re.RegexObject): A regular expression object to match
+ against module names and determine whether or not the discovered module
+ contributes to the test suite.
+ """
+
+ def __init__(self):
+ self.suite = unittest.TestSuite()
+ self.loader = unittest.TestLoader()
+ self.module_matcher = re.compile(TEST_MODULE_REGEX)
+
+ def loadTestsFromNames(self, names, module=None):
+ """Function mirroring TestLoader::loadTestsFromNames, as expected by
+ setuptools.setup argument `test_loader`."""
+ # ensure that we capture decorators and definitions (else our coverage
+ # measure unnecessarily suffers)
+ coverage_context = coverage.Coverage(data_suffix=True)
+ coverage_context.start()
+ modules = [importlib.import_module(name) for name in names]
+ for module in modules:
+ self.visit_module(module)
+ for module in modules:
+ try:
+ package_paths = module.__path__
+ except:
+ continue
+ self.walk_packages(package_paths)
+ coverage_context.stop()
+ coverage_context.save()
+ return self.suite
+
+ def walk_packages(self, package_paths):
+ """Walks over the packages, dispatching `visit_module` calls.
+
+ Args:
+ package_paths (list): A list of paths over which to walk through modules
+ along.
+ """
+ for importer, module_name, is_package in (
+ pkgutil.iter_modules(package_paths)):
+ module = importer.find_module(module_name).load_module(module_name)
+ self.visit_module(module)
+ if is_package:
+ self.walk_packages(module.__path__)
+
+ def visit_module(self, module):
+ """Visits the module, adding discovered tests to the test suite.
+
+ Args:
+ module (module): Module to match against self.module_matcher; if matched
+ it has its tests loaded via self.loader into self.suite.
+ """
+ if self.module_matcher.match(module.__name__):
+ module_suite = self.loader.loadTestsFromModule(module)
+ self.suite.addTest(module_suite)
+
+
+def iterate_suite_cases(suite):
+ """Generator over all unittest.TestCases in a unittest.TestSuite.
+
+ Args:
+ suite (unittest.TestSuite): Suite to iterate over in the generator.
+
+ Returns:
+ generator: A generator over all unittest.TestCases in `suite`.
+ """
+ for item in suite:
+ if isinstance(item, unittest.TestSuite):
+ for child_item in iterate_suite_cases(item):
+ yield child_item
+ elif isinstance(item, unittest.TestCase):
+ yield item
+ else:
+ raise ValueError('unexpected suite item of type {}'.format(type(item)))
diff --git a/src/python/grpcio/tests/_result.py b/src/python/grpcio/tests/_result.py
new file mode 100644
index 0000000000..5a570f4279
--- /dev/null
+++ b/src/python/grpcio/tests/_result.py
@@ -0,0 +1,451 @@
+# 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 cStringIO as StringIO
+import collections
+import itertools
+import traceback
+import unittest
+from xml.etree import ElementTree
+
+import coverage
+
+from tests import _loader
+
+
+class CaseResult(collections.namedtuple('CaseResult', [
+ 'id', 'name', 'kind', 'stdout', 'stderr', 'skip_reason', 'traceback'])):
+ """A serializable result of a single test case.
+
+ Attributes:
+ id (object): Any serializable object used to denote the identity of this
+ test case.
+ name (str or None): A human-readable name of the test case.
+ kind (CaseResult.Kind): The kind of test result.
+ stdout (object or None): Output on stdout, or None if nothing was captured.
+ stderr (object or None): Output on stderr, or None if nothing was captured.
+ skip_reason (object or None): The reason the test was skipped. Must be
+ something if self.kind is CaseResult.Kind.SKIP, else None.
+ traceback (object or None): The traceback of the test. Must be something if
+ self.kind is CaseResult.Kind.{ERROR, FAILURE, EXPECTED_FAILURE}, else
+ None.
+ """
+
+ class Kind:
+ UNTESTED = 'untested'
+ RUNNING = 'running'
+ ERROR = 'error'
+ FAILURE = 'failure'
+ SUCCESS = 'success'
+ SKIP = 'skip'
+ EXPECTED_FAILURE = 'expected failure'
+ UNEXPECTED_SUCCESS = 'unexpected success'
+
+ def __new__(cls, id=None, name=None, kind=None, stdout=None, stderr=None,
+ skip_reason=None, traceback=None):
+ """Helper keyword constructor for the namedtuple.
+
+ See this class' attributes for information on the arguments."""
+ assert id is not None
+ assert name is None or isinstance(name, str)
+ if kind is CaseResult.Kind.UNTESTED:
+ pass
+ elif kind is CaseResult.Kind.RUNNING:
+ pass
+ elif kind is CaseResult.Kind.ERROR:
+ assert traceback is not None
+ elif kind is CaseResult.Kind.FAILURE:
+ assert traceback is not None
+ elif kind is CaseResult.Kind.SUCCESS:
+ pass
+ elif kind is CaseResult.Kind.SKIP:
+ assert skip_reason is not None
+ elif kind is CaseResult.Kind.EXPECTED_FAILURE:
+ assert traceback is not None
+ elif kind is CaseResult.Kind.UNEXPECTED_SUCCESS:
+ pass
+ else:
+ assert False
+ return super(cls, CaseResult).__new__(
+ cls, id, name, kind, stdout, stderr, skip_reason, traceback)
+
+ def updated(self, name=None, kind=None, stdout=None, stderr=None,
+ skip_reason=None, traceback=None):
+ """Get a new validated CaseResult with the fields updated.
+
+ See this class' attributes for information on the arguments."""
+ name = self.name if name is None else name
+ kind = self.kind if kind is None else kind
+ stdout = self.stdout if stdout is None else stdout
+ stderr = self.stderr if stderr is None else stderr
+ skip_reason = self.skip_reason if skip_reason is None else skip_reason
+ traceback = self.traceback if traceback is None else traceback
+ return CaseResult(id=self.id, name=name, kind=kind, stdout=stdout,
+ stderr=stderr, skip_reason=skip_reason,
+ traceback=traceback)
+
+
+class AugmentedResult(unittest.TestResult):
+ """unittest.Result that keeps track of additional information.
+
+ Uses CaseResult objects to store test-case results, providing additional
+ information beyond that of the standard Python unittest library, such as
+ standard output.
+
+ Attributes:
+ id_map (callable): A unary callable mapping unittest.TestCase objects to
+ unique identifiers.
+ cases (dict): A dictionary mapping from the identifiers returned by id_map
+ to CaseResult objects corresponding to those IDs.
+ """
+
+ def __init__(self, id_map):
+ """Initialize the object with an identifier mapping.
+
+ Arguments:
+ id_map (callable): Corresponds to the attribute `id_map`."""
+ super(AugmentedResult, self).__init__()
+ self.id_map = id_map
+ self.cases = None
+
+ def startTestRun(self):
+ """See unittest.TestResult.startTestRun."""
+ super(AugmentedResult, self).startTestRun()
+ self.cases = dict()
+
+ def stopTestRun(self):
+ """See unittest.TestResult.stopTestRun."""
+ super(AugmentedResult, self).stopTestRun()
+
+ def startTest(self, test):
+ """See unittest.TestResult.startTest."""
+ super(AugmentedResult, self).startTest(test)
+ case_id = self.id_map(test)
+ self.cases[case_id] = CaseResult(
+ id=case_id, name=test.id(), kind=CaseResult.Kind.RUNNING)
+
+ def addError(self, test, error):
+ """See unittest.TestResult.addError."""
+ super(AugmentedResult, self).addError(test, error)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.ERROR, traceback=error)
+
+ def addFailure(self, test, error):
+ """See unittest.TestResult.addFailure."""
+ super(AugmentedResult, self).addFailure(test, error)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.FAILURE, traceback=error)
+
+ def addSuccess(self, test):
+ """See unittest.TestResult.addSuccess."""
+ super(AugmentedResult, self).addSuccess(test)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.SUCCESS)
+
+ def addSkip(self, test, reason):
+ """See unittest.TestResult.addSkip."""
+ super(AugmentedResult, self).addSkip(test, reason)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.SKIP, skip_reason=reason)
+
+ def addExpectedFailure(self, test, error):
+ """See unittest.TestResult.addExpectedFailure."""
+ super(AugmentedResult, self).addExpectedFailure(test, error)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.EXPECTED_FAILURE, traceback=error)
+
+ def addUnexpectedSuccess(self, test):
+ """See unittest.TestResult.addUnexpectedSuccess."""
+ super(AugmentedResult, self).addUnexpectedSuccess(test)
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ kind=CaseResult.Kind.UNEXPECTED_SUCCESS)
+
+ def set_output(self, test, stdout, stderr):
+ """Set the output attributes for the CaseResult corresponding to a test.
+
+ Args:
+ test (unittest.TestCase): The TestCase to set the outputs of.
+ stdout (str): Output from stdout to assign to self.id_map(test).
+ stderr (str): Output from stderr to assign to self.id_map(test).
+ """
+ case_id = self.id_map(test)
+ self.cases[case_id] = self.cases[case_id].updated(
+ stdout=stdout, stderr=stderr)
+
+ def augmented_results(self, filter):
+ """Convenience method to retrieve filtered case results.
+
+ Args:
+ filter (callable): A unary predicate to filter over CaseResult objects.
+ """
+ return (self.cases[case_id] for case_id in self.cases
+ if filter(self.cases[case_id]))
+
+
+class CoverageResult(AugmentedResult):
+ """Extension to AugmentedResult adding coverage.py support per test.\
+
+ Attributes:
+ coverage_context (coverage.Coverage): coverage.py management object.
+ """
+
+ def __init__(self, id_map):
+ """See AugmentedResult.__init__."""
+ super(CoverageResult, self).__init__(id_map=id_map)
+ self.coverage_context = None
+
+ def startTest(self, test):
+ """See unittest.TestResult.startTest.
+
+ Additionally initializes and begins code coverage tracking."""
+ super(CoverageResult, self).startTest(test)
+ self.coverage_context = coverage.Coverage(data_suffix=True)
+ self.coverage_context.start()
+
+ def stopTest(self, test):
+ """See unittest.TestResult.stopTest.
+
+ Additionally stops and deinitializes code coverage tracking."""
+ super(CoverageResult, self).stopTest(test)
+ self.coverage_context.stop()
+ self.coverage_context.save()
+ self.coverage_context = None
+
+ def stopTestRun(self):
+ """See unittest.TestResult.stopTestRun."""
+ super(CoverageResult, self).stopTestRun()
+ # TODO(atash): Dig deeper into why the following line fails to properly
+ # combine coverage data from the Cython plugin.
+ #coverage.Coverage().combine()
+
+
+class _Colors:
+ """Namespaced constants for terminal color magic numbers."""
+ HEADER = '\033[95m'
+ INFO = '\033[94m'
+ OK = '\033[92m'
+ WARN = '\033[93m'
+ FAIL = '\033[91m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+ END = '\033[0m'
+
+
+class TerminalResult(CoverageResult):
+ """Extension to CoverageResult adding basic terminal reporting."""
+
+ def __init__(self, out, id_map):
+ """Initialize the result object.
+
+ Args:
+ out (file-like): Output file to which terminal-colored live results will
+ be written.
+ id_map (callable): See AugmentedResult.__init__.
+ """
+ super(TerminalResult, self).__init__(id_map=id_map)
+ self.out = out
+
+ def startTestRun(self):
+ """See unittest.TestResult.startTestRun."""
+ super(TerminalResult, self).startTestRun()
+ self.out.write(
+ _Colors.HEADER +
+ 'Testing gRPC Python...\n' +
+ _Colors.END)
+
+ def stopTestRun(self):
+ """See unittest.TestResult.stopTestRun."""
+ super(TerminalResult, self).stopTestRun()
+ self.out.write(summary(self))
+ self.out.flush()
+
+ def addError(self, test, error):
+ """See unittest.TestResult.addError."""
+ super(TerminalResult, self).addError(test, error)
+ self.out.write(
+ _Colors.FAIL +
+ 'ERROR {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+ def addFailure(self, test, error):
+ """See unittest.TestResult.addFailure."""
+ super(TerminalResult, self).addFailure(test, error)
+ self.out.write(
+ _Colors.FAIL +
+ 'FAILURE {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+ def addSuccess(self, test):
+ """See unittest.TestResult.addSuccess."""
+ super(TerminalResult, self).addSuccess(test)
+ self.out.write(
+ _Colors.OK +
+ 'SUCCESS {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+ def addSkip(self, test, reason):
+ """See unittest.TestResult.addSkip."""
+ super(TerminalResult, self).addSkip(test, reason)
+ self.out.write(
+ _Colors.INFO +
+ 'SKIP {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+ def addExpectedFailure(self, test, error):
+ """See unittest.TestResult.addExpectedFailure."""
+ super(TerminalResult, self).addExpectedFailure(test, error)
+ self.out.write(
+ _Colors.INFO +
+ 'FAILURE_OK {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+ def addUnexpectedSuccess(self, test):
+ """See unittest.TestResult.addUnexpectedSuccess."""
+ super(TerminalResult, self).addUnexpectedSuccess(test)
+ self.out.write(
+ _Colors.INFO +
+ 'UNEXPECTED_OK {}\n'.format(test.id()) +
+ _Colors.END)
+ self.out.flush()
+
+def _traceback_string(type, value, trace):
+ """Generate a descriptive string of a Python exception traceback.
+
+ Args:
+ type (class): The type of the exception.
+ value (Exception): The value of the exception.
+ trace (traceback): Traceback of the exception.
+
+ Returns:
+ str: Formatted exception descriptive string.
+ """
+ buffer = StringIO.StringIO()
+ traceback.print_exception(type, value, trace, file=buffer)
+ return buffer.getvalue()
+
+def summary(result):
+ """A summary string of a result object.
+
+ Args:
+ result (AugmentedResult): The result object to get the summary of.
+
+ Returns:
+ str: The summary string.
+ """
+ assert isinstance(result, AugmentedResult)
+ untested = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.UNTESTED))
+ running = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.RUNNING))
+ failures = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.FAILURE))
+ errors = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.ERROR))
+ successes = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.SUCCESS))
+ skips = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.SKIP))
+ expected_failures = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.EXPECTED_FAILURE))
+ unexpected_successes = list(result.augmented_results(
+ lambda case_result: case_result.kind is CaseResult.Kind.UNEXPECTED_SUCCESS))
+ running_names = [case.name for case in running]
+ finished_count = (len(failures) + len(errors) + len(successes) +
+ len(expected_failures) + len(unexpected_successes))
+ statistics = (
+ '{finished} tests finished:\n'
+ '\t{successful} successful\n'
+ '\t{unsuccessful} unsuccessful\n'
+ '\t{skipped} skipped\n'
+ '\t{expected_fail} expected failures\n'
+ '\t{unexpected_successful} unexpected successes\n'
+ 'Interrupted Tests:\n'
+ '\t{interrupted}\n'
+ .format(finished=finished_count,
+ successful=len(successes),
+ unsuccessful=(len(failures)+len(errors)),
+ skipped=len(skips),
+ expected_fail=len(expected_failures),
+ unexpected_successful=len(unexpected_successes),
+ interrupted=str(running_names)))
+ tracebacks = '\n\n'.join([
+ (_Colors.FAIL + '{test_name}' + _Colors.END + + '\n' +
+ _Colors.BOLD + 'traceback:' + _Colors.END + '\n' +
+ '{traceback}\n' +
+ _Colors.BOLD + 'stdout:' + _Colors.END + '\n' +
+ '{stdout}\n' +
+ _Colors.BOLD + 'stderr:' + _Colors.END + '\n' +
+ '{stderr}\n').format(
+ test_name=result.name,
+ traceback=_traceback_string(*result.traceback),
+ stdout=result.stdout, stderr=result.stderr)
+ for result in itertools.chain(failures, errors)
+ ])
+ notes = 'Unexpected successes: {}\n'.format([
+ result.name for result in unexpected_successes])
+ return statistics + '\nErrors/Failures: \n' + tracebacks + '\n' + notes
+
+
+def jenkins_junit_xml(result):
+ """An XML tree object that when written is recognizable by Jenkins.
+
+ Args:
+ result (AugmentedResult): The result object to get the junit xml output of.
+
+ Returns:
+ ElementTree.ElementTree: The XML tree.
+ """
+ assert isinstance(result, AugmentedResult)
+ root = ElementTree.Element('testsuites')
+ suite = ElementTree.SubElement(root, 'testsuite', {
+ 'name': 'Python gRPC tests',
+ })
+ for case in result.cases.values():
+ if case.kind is CaseResult.Kind.SUCCESS:
+ ElementTree.SubElement(suite, 'testcase', {
+ 'name': case.name,
+ })
+ elif case.kind in (CaseResult.Kind.ERROR, CaseResult.Kind.FAILURE):
+ case_xml = ElementTree.SubElement(suite, 'testcase', {
+ 'name': case.name,
+ })
+ error_xml = ElementTree.SubElement(case_xml, 'error', {})
+ error_xml.text = ''.format(case.stderr, case.traceback)
+ return ElementTree.ElementTree(element=root)
diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py
new file mode 100644
index 0000000000..4f1ddb57fc
--- /dev/null
+++ b/src/python/grpcio/tests/_runner.py
@@ -0,0 +1,224 @@
+# 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 cStringIO as StringIO
+import collections
+import fcntl
+import multiprocessing
+import os
+import select
+import signal
+import sys
+import threading
+import time
+import unittest
+import uuid
+
+from tests import _loader
+from tests import _result
+
+
+class CapturePipe(object):
+ """A context-manager pipe to redirect output to a byte array.
+
+ Attributes:
+ _redirect_fd (int): File descriptor of file to redirect writes from.
+ _saved_fd (int): A copy of the original value of the redirected file
+ descriptor.
+ _read_thread (threading.Thread or None): Thread upon which reads through the
+ pipe are performed. Only non-None when self is started.
+ _read_fd (int or None): File descriptor of the read end of the redirect
+ pipe. Only non-None when self is started.
+ _write_fd (int or None): File descriptor of the write end of the redirect
+ pipe. Only non-None when self is started.
+ output (bytearray or None): Redirected output from writes to the redirected
+ file descriptor. Only valid during and after self has started.
+ """
+
+ def __init__(self, fd):
+ self._redirect_fd = fd
+ self._saved_fd = os.dup(self._redirect_fd)
+ self._read_thread = None
+ self._read_fd = None
+ self._write_fd = None
+ self.output = None
+
+ def start(self):
+ """Start redirection of writes to the file descriptor."""
+ self._read_fd, self._write_fd = os.pipe()
+ os.dup2(self._write_fd, self._redirect_fd)
+ flags = fcntl.fcntl(self._read_fd, fcntl.F_GETFL)
+ fcntl.fcntl(self._read_fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+ self._read_thread = threading.Thread(target=self._read)
+ self._read_thread.start()
+
+ def stop(self):
+ """Stop redirection of writes to the file descriptor."""
+ os.close(self._write_fd)
+ os.dup2(self._saved_fd, self._redirect_fd) # auto-close self._redirect_fd
+ self._read_thread.join()
+ self._read_thread = None
+ # we waited for the read thread to finish, so _read_fd has been read and we
+ # can close it.
+ os.close(self._read_fd)
+
+ def _read(self):
+ """Read-thread target for self."""
+ self.output = bytearray()
+ while True:
+ select.select([self._read_fd], [], [])
+ read_bytes = os.read(self._read_fd, 1024)
+ if read_bytes:
+ self.output.extend(read_bytes)
+ else:
+ break
+
+ def write_bypass(self, value):
+ """Bypass the redirection and write directly to the original file.
+
+ Arguments:
+ value (str): What to write to the original file.
+ """
+ if self._saved_fd is None:
+ os.write(self._redirect_fd, value)
+ else:
+ os.write(self._saved_fd, value)
+
+ def __enter__(self):
+ self.start()
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.stop()
+
+ def close(self):
+ """Close any resources used by self not closed by stop()."""
+ os.close(self._saved_fd)
+
+
+class AugmentedCase(collections.namedtuple('AugmentedCase', [
+ 'case', 'id'])):
+ """A test case with a guaranteed unique externally specified identifier.
+
+ Attributes:
+ case (unittest.TestCase): TestCase we're decorating with an additional
+ identifier.
+ id (object): Any identifier that may be considered 'unique' for testing
+ purposes.
+ """
+
+ def __new__(cls, case, id=None):
+ if id is None:
+ id = uuid.uuid4()
+ return super(cls, AugmentedCase).__new__(cls, case, id)
+
+
+class Runner(object):
+
+ def run(self, suite):
+ """See setuptools' test_runner setup argument for information."""
+ # Ensure that every test case has no collision with any other test case in
+ # the augmented results.
+ augmented_cases = [AugmentedCase(case, uuid.uuid4())
+ for case in _loader.iterate_suite_cases(suite)]
+ case_id_by_case = dict((augmented_case.case, augmented_case.id)
+ for augmented_case in augmented_cases)
+ result_out = StringIO.StringIO()
+ result = _result.TerminalResult(
+ result_out, id_map=lambda case: case_id_by_case[case])
+ stdout_pipe = CapturePipe(sys.stdout.fileno())
+ stderr_pipe = CapturePipe(sys.stderr.fileno())
+ kill_flag = [False]
+
+ def sigint_handler(signal_number, frame):
+ if signal_number == signal.SIGINT:
+ kill_flag[0] = True # Python 2.7 not having 'local'... :-(
+ signal.signal(signal_number, signal.SIG_DFL)
+
+ def fault_handler(signal_number, frame):
+ stdout_pipe.write_bypass(
+ 'Received fault signal {}\nstdout:\n{}\n\nstderr:{}\n'
+ .format(signal_number, stdout_pipe.output, stderr_pipe.output))
+ os._exit(1)
+
+ def check_kill_self():
+ if kill_flag[0]:
+ stdout_pipe.write_bypass('Stopping tests short...')
+ result.stopTestRun()
+ stdout_pipe.write_bypass(result_out.getvalue())
+ stdout_pipe.write_bypass(
+ '\ninterrupted stdout:\n{}\n'.format(stdout_pipe.output))
+ stderr_pipe.write_bypass(
+ '\ninterrupted stderr:\n{}\n'.format(stderr_pipe.output))
+ os._exit(1)
+ signal.signal(signal.SIGINT, sigint_handler)
+ signal.signal(signal.SIGSEGV, fault_handler)
+ signal.signal(signal.SIGBUS, fault_handler)
+ signal.signal(signal.SIGABRT, fault_handler)
+ signal.signal(signal.SIGFPE, fault_handler)
+ signal.signal(signal.SIGILL, fault_handler)
+ # Sometimes output will lag after a test has successfully finished; we
+ # ignore such writes to our pipes.
+ signal.signal(signal.SIGPIPE, signal.SIG_IGN)
+
+ # Run the tests
+ result.startTestRun()
+ for augmented_case in augmented_cases:
+ sys.stdout.write('Running {}\n'.format(augmented_case.case.id()))
+ sys.stdout.flush()
+ case_thread = threading.Thread(
+ target=augmented_case.case.run, args=(result,))
+ try:
+ with stdout_pipe, stderr_pipe:
+ case_thread.start()
+ while case_thread.is_alive():
+ check_kill_self()
+ time.sleep(0)
+ case_thread.join()
+ except:
+ # re-raise the exception after forcing the with-block to end
+ raise
+ result.set_output(
+ augmented_case.case, stdout_pipe.output, stderr_pipe.output)
+ sys.stdout.write(result_out.getvalue())
+ sys.stdout.flush()
+ result_out.truncate(0)
+ check_kill_self()
+ result.stopTestRun()
+ stdout_pipe.close()
+ stderr_pipe.close()
+
+ # Report results
+ sys.stdout.write(result_out.getvalue())
+ sys.stdout.flush()
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+ with open('report.xml', 'w') as report_xml_file:
+ _result.jenkins_junit_xml(result).write(report_xml_file)
+ return result
+
diff --git a/src/python/grpcio_test/grpc_interop/__init__.py b/src/python/grpcio/tests/interop/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_interop/__init__.py
+++ b/src/python/grpcio/tests/interop/__init__.py
diff --git a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py b/src/python/grpcio/tests/interop/_insecure_interop_test.py
index 5007be28ff..00b49aba37 100644
--- a/src/python/grpcio_test/grpc_interop/_insecure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_insecure_interop_test.py
@@ -33,10 +33,10 @@ import unittest
from grpc.beta import implementations
-from grpc_interop import _interop_test_case
-from grpc_interop import methods
-from grpc_interop import server
-from grpc_interop import test_pb2
+from tests.interop import _interop_test_case
+from tests.interop import methods
+from tests.interop import server
+from tests.interop import test_pb2
class InsecureInteropTest(
diff --git a/src/python/grpcio_test/grpc_interop/_interop_test_case.py b/src/python/grpcio/tests/interop/_interop_test_case.py
index b6d06b300d..ccea17a66d 100644
--- a/src/python/grpcio_test/grpc_interop/_interop_test_case.py
+++ b/src/python/grpcio/tests/interop/_interop_test_case.py
@@ -29,7 +29,7 @@
"""Common code for unit tests of the interoperability test code."""
-from grpc_interop import methods
+from tests.interop import methods
class InteropTestCase(object):
diff --git a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py b/src/python/grpcio/tests/interop/_secure_interop_test.py
index 108e15b0f9..7e3061133f 100644
--- a/src/python/grpcio_test/grpc_interop/_secure_interop_test.py
+++ b/src/python/grpcio/tests/interop/_secure_interop_test.py
@@ -33,12 +33,12 @@ import unittest
from grpc.beta import implementations
-from grpc_test.beta import test_utilities
+from tests.interop import _interop_test_case
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
-from grpc_interop import _interop_test_case
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.unit.beta import test_utilities
_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
@@ -55,7 +55,7 @@ class SecureInteropTest(
self.server.start()
self.stub = test_pb2.beta_create_TestService_stub(
test_utilities.not_really_secure_channel(
- '[::]', port, implementations.ssl_client_credentials(
+ '[::]', port, implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None),
_SERVER_HOST_OVERRIDE))
diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio/tests/interop/client.py
index b8d5047ca5..573ec2bd71 100644
--- a/src/python/grpcio_test/grpc_interop/client.py
+++ b/src/python/grpcio/tests/interop/client.py
@@ -34,11 +34,10 @@ from oauth2client import client as oauth2client_client
from grpc.beta import implementations
-from grpc_test.beta import test_utilities
-
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
+from tests.unit.beta import test_utilities
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
@@ -91,11 +90,11 @@ def _stub(args):
if args.use_test_ca:
root_certificates = resources.test_root_certificates()
else:
- root_certificates = resources.prod_root_certificates()
+ root_certificates = None # will load default roots.
channel = test_utilities.not_really_secure_channel(
args.server_host, args.server_port,
- implementations.ssl_client_credentials(root_certificates, None, None),
+ implementations.ssl_channel_credentials(root_certificates, None, None),
args.server_host_override)
stub = test_pb2.beta_create_TestService_stub(
channel, metadata_transformer=metadata_transformer)
@@ -114,7 +113,7 @@ def _test_case_from_arg(test_case_arg):
raise ValueError('No test case "%s"!' % test_case_arg)
-def _test_interoperability():
+def test_interoperability():
args = _args()
stub = _stub(args)
test_case = _test_case_from_arg(args.test_case)
@@ -122,4 +121,4 @@ def _test_interoperability():
if __name__ == '__main__':
- _test_interoperability()
+ test_interoperability()
diff --git a/src/python/grpcio_test/grpc_interop/credentials/README b/src/python/grpcio/tests/interop/credentials/README
index cb20dcb49f..cb20dcb49f 100644
--- a/src/python/grpcio_test/grpc_interop/credentials/README
+++ b/src/python/grpcio/tests/interop/credentials/README
diff --git a/src/python/grpcio_test/grpc_interop/credentials/ca.pem b/src/python/grpcio/tests/interop/credentials/ca.pem
index 6c8511a73c..6c8511a73c 100755
--- a/src/python/grpcio_test/grpc_interop/credentials/ca.pem
+++ b/src/python/grpcio/tests/interop/credentials/ca.pem
diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.key b/src/python/grpcio/tests/interop/credentials/server1.key
index 143a5b8765..143a5b8765 100755
--- a/src/python/grpcio_test/grpc_interop/credentials/server1.key
+++ b/src/python/grpcio/tests/interop/credentials/server1.key
diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.pem b/src/python/grpcio/tests/interop/credentials/server1.pem
index f3d43fcc5b..f3d43fcc5b 100755
--- a/src/python/grpcio_test/grpc_interop/credentials/server1.pem
+++ b/src/python/grpcio/tests/interop/credentials/server1.pem
diff --git a/src/python/grpcio_test/grpc_interop/empty.proto b/src/python/grpcio/tests/interop/empty.proto
index 6d0eb937d6..6d0eb937d6 100644
--- a/src/python/grpcio_test/grpc_interop/empty.proto
+++ b/src/python/grpcio/tests/interop/empty.proto
diff --git a/src/python/grpcio_test/grpc_interop/messages.proto b/src/python/grpcio/tests/interop/messages.proto
index 193b6c4171..193b6c4171 100644
--- a/src/python/grpcio_test/grpc_interop/messages.proto
+++ b/src/python/grpcio/tests/interop/messages.proto
diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio/tests/interop/methods.py
index 3ef8545355..b3591aef7b 100644
--- a/src/python/grpcio_test/grpc_interop/methods.py
+++ b/src/python/grpcio/tests/interop/methods.py
@@ -40,9 +40,9 @@ from oauth2client import client as oauth2client_client
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import face
-from grpc_interop import empty_pb2
-from grpc_interop import messages_pb2
-from grpc_interop import test_pb2
+from tests.interop import empty_pb2
+from tests.interop import messages_pb2
+from tests.interop import test_pb2
_TIMEOUT = 7
diff --git a/src/python/grpcio_test/grpc_interop/resources.py b/src/python/grpcio/tests/interop/resources.py
index 1122499418..c424385cf6 100644
--- a/src/python/grpcio_test/grpc_interop/resources.py
+++ b/src/python/grpcio/tests/interop/resources.py
@@ -44,10 +44,6 @@ def test_root_certificates():
__name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
-def prod_root_certificates():
- return open(os.environ['SSL_CERT_FILE'], mode='rb').read()
-
-
def private_key():
return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH)
diff --git a/src/python/grpcio_test/grpc_interop/server.py b/src/python/grpcio/tests/interop/server.py
index b541087663..6dd55f008c 100644
--- a/src/python/grpcio_test/grpc_interop/server.py
+++ b/src/python/grpcio/tests/interop/server.py
@@ -35,9 +35,9 @@ import time
from grpc.beta import implementations
-from grpc_interop import methods
-from grpc_interop import resources
-from grpc_interop import test_pb2
+from tests.interop import methods
+from tests.interop import resources
+from tests.interop import test_pb2
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
@@ -68,7 +68,7 @@ def serve():
time.sleep(_ONE_DAY_IN_SECONDS)
except BaseException as e:
logging.info('Caught exception "%s"; stopping server...', e)
- server.stop()
+ server.stop(0)
logging.info('Server stopped; exiting.')
if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_interop/test.proto b/src/python/grpcio/tests/interop/test.proto
index b499813e56..9feecc0278 100644
--- a/src/python/grpcio_test/grpc_interop/test.proto
+++ b/src/python/grpcio/tests/interop/test.proto
@@ -33,8 +33,8 @@
syntax = "proto3";
-import "grpc_interop/empty.proto";
-import "grpc_interop/messages.proto";
+import "tests/interop/empty.proto";
+import "tests/interop/messages.proto";
package grpc.testing;
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py b/src/python/grpcio/tests/protoc_plugin/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_protoc_plugin/__init__.py
+++ b/src/python/grpcio/tests/protoc_plugin/__init__.py
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
index 259b978de2..ba5b219a88 100644
--- a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
@@ -45,7 +45,7 @@ import unittest
from grpc.beta import implementations
from grpc.framework.foundation import future
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
# Identifiers of entities we expect to find in the generated module.
SERVICER_IDENTIFIER = 'BetaTestServiceServicer'
@@ -218,7 +218,7 @@ class PythonPluginTest(unittest.TestCase):
protoc_plugin_filename = distutils.spawn.find_executable(
'grpc_python_plugin')
test_proto_filename = pkg_resources.resource_filename(
- 'grpc_protoc_plugin', 'test.proto')
+ 'tests.protoc_plugin', 'protoc_plugin_test.proto')
if not os.path.isfile(protoc_command):
# Assume that if we haven't built protoc that it's on the system.
protoc_command = 'protoc'
@@ -237,7 +237,7 @@ class PythonPluginTest(unittest.TestCase):
]
subprocess.check_call(' '.join(cmd), shell=True, env=os.environ,
cwd=os.path.dirname(test_proto_filename))
- sys.path.append(self.outdir)
+ sys.path.insert(0, self.outdir)
def tearDown(self):
try:
@@ -245,22 +245,26 @@ class PythonPluginTest(unittest.TestCase):
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.
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None))
self.assertIsNotNone(getattr(test_pb2, STUB_IDENTIFIER, None))
self.assertIsNotNone(getattr(test_pb2, SERVER_FACTORY_IDENTIFIER, None))
self.assertIsNotNone(getattr(test_pb2, STUB_FACTORY_IDENTIFIER, None))
def testUpDown(self):
- import test_pb2
+ import protoc_plugin_test_pb2 as test_pb2
+ reload(test_pb2)
with _CreateService(test_pb2) as (servicer, stub):
request = test_pb2.SimpleRequest(response_size=13)
def testUnaryCall(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
request = test_pb2.SimpleRequest(response_size=13)
response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
@@ -268,7 +272,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testUnaryCallFuture(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2) as (methods, stub):
# Check that the call does not block waiting for the server to respond.
@@ -280,7 +285,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testUnaryCallFutureExpired(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
request = test_pb2.SimpleRequest(response_size=13)
with methods.pause():
@@ -290,7 +296,8 @@ class PythonPluginTest(unittest.TestCase):
response_future.result()
def testUnaryCallFutureCancelled(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
@@ -299,7 +306,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertTrue(response_future.cancelled())
def testUnaryCallFutureFailed(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = test_pb2.SimpleRequest(response_size=13)
with _CreateService(test_pb2) as (methods, stub):
with methods.fail():
@@ -308,7 +316,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertIsNotNone(response_future.exception())
def testStreamingOutputCall(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
responses = stub.StreamingOutputCall(
@@ -320,7 +329,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testStreamingOutputCallExpired(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
@@ -330,7 +340,8 @@ class PythonPluginTest(unittest.TestCase):
list(responses)
def testStreamingOutputCallCancelled(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2) as (unused_methods, stub):
responses = stub.StreamingOutputCall(
@@ -341,7 +352,8 @@ class PythonPluginTest(unittest.TestCase):
next(responses)
def testStreamingOutputCallFailed(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request = _streaming_output_request(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.fail():
@@ -351,7 +363,8 @@ class PythonPluginTest(unittest.TestCase):
next(responses)
def testStreamingInputCall(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
response = stub.StreamingInputCall(
_streaming_input_request_iterator(test_pb2),
@@ -361,7 +374,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testStreamingInputCallFuture(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
response_future = stub.StreamingInputCall.future(
@@ -373,7 +387,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testStreamingInputCallFutureExpired(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
response_future = stub.StreamingInputCall.future(
@@ -385,7 +400,8 @@ class PythonPluginTest(unittest.TestCase):
response_future.exception(), face.ExpirationError)
def testStreamingInputCallFutureCancelled(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
response_future = stub.StreamingInputCall.future(
@@ -397,7 +413,8 @@ class PythonPluginTest(unittest.TestCase):
response_future.result()
def testStreamingInputCallFutureFailed(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.fail():
response_future = stub.StreamingInputCall.future(
@@ -406,7 +423,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertIsNotNone(response_future.exception())
def testFullDuplexCall(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
responses = stub.FullDuplexCall(
_full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT)
@@ -417,7 +435,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testFullDuplexCallExpired(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request_iterator = _full_duplex_request_iterator(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.pause():
@@ -427,7 +446,8 @@ class PythonPluginTest(unittest.TestCase):
list(responses)
def testFullDuplexCallCancelled(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
request_iterator = _full_duplex_request_iterator(test_pb2)
responses = stub.FullDuplexCall(
@@ -438,7 +458,8 @@ class PythonPluginTest(unittest.TestCase):
next(responses)
def testFullDuplexCallFailed(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
request_iterator = _full_duplex_request_iterator(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
with methods.fail():
@@ -449,7 +470,8 @@ class PythonPluginTest(unittest.TestCase):
next(responses)
def testHalfDuplexCall(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
with _CreateService(test_pb2) as (methods, stub):
def half_duplex_request_iterator():
request = test_pb2.StreamingOutputCallRequest()
@@ -468,7 +490,8 @@ class PythonPluginTest(unittest.TestCase):
self.assertEqual(expected_response, response)
def testHalfDuplexCallWedged(self):
- import test_pb2 # pylint: disable=g-import-not-at-top
+ import protoc_plugin_test_pb2 as test_pb2 # pylint: disable=g-import-not-at-top
+ reload(test_pb2)
condition = threading.Condition()
wait_cell = [False]
@contextlib.contextmanager
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/test.proto b/src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto
index 6762a8e7f3..6762a8e7f3 100644
--- a/src/python/grpcio_test/grpc_protoc_plugin/test.proto
+++ b/src/python/grpcio/tests/protoc_plugin/protoc_plugin_test.proto
diff --git a/src/python/grpcio_test/grpc_test/__init__.py b/src/python/grpcio/tests/unit/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/__init__.py
+++ b/src/python/grpcio/tests/unit/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_adapter/.gitignore b/src/python/grpcio/tests/unit/_adapter/.gitignore
index a6f96cd6db..a6f96cd6db 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/.gitignore
+++ b/src/python/grpcio/tests/unit/_adapter/.gitignore
diff --git a/src/python/grpcio_test/grpc_test/_adapter/__init__.py b/src/python/grpcio/tests/unit/_adapter/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/__init__.py
+++ b/src/python/grpcio/tests/unit/_adapter/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
index 90ad0b9bcb..a6fd82388c 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
+++ b/src/python/grpcio/tests/unit/_adapter/_intermediary_low_test.py
@@ -115,6 +115,7 @@ class EchoTest(unittest.TestCase):
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()
@@ -286,11 +287,6 @@ class EchoTest(unittest.TestCase):
set((server_trailing_metadata_key,
server_trailing_binary_metadata_key,)))
- server_timeout_none_event = self.server_completion_queue.get(0)
- self.assertIsNone(server_timeout_none_event)
- client_timeout_none_event = self.client_completion_queue.get(0)
- self.assertIsNone(client_timeout_none_event)
-
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
@@ -335,6 +331,7 @@ class CancellationTest(unittest.TestCase):
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()
@@ -410,14 +407,9 @@ class CancellationTest(unittest.TestCase):
finish_event = self.client_events.get()
self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
- self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
+ self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
finish_event.status)
- server_timeout_none_event = self.server_completion_queue.get(0)
- self.assertIsNone(server_timeout_none_event)
- client_timeout_none_event = self.client_completion_queue.get(0)
- self.assertIsNone(client_timeout_none_event)
-
self.assertSequenceEqual(test_data, server_data)
self.assertSequenceEqual(test_data, client_data)
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py b/src/python/grpcio/tests/unit/_adapter/_low_test.py
index 8115cd0e83..ec46617996 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_low_test.py
+++ b/src/python/grpcio/tests/unit/_adapter/_low_test.py
@@ -34,7 +34,7 @@ import unittest
from grpc import _grpcio_metadata
from grpc._adapter import _types
from grpc._adapter import _low
-from grpc_test import test_common
+from tests.unit import test_common
def wait_for_events(completion_queues, deadline):
@@ -80,11 +80,11 @@ class InsecureServerInsecureClient(unittest.TestCase):
del self.client_channel
self.client_completion_queue.shutdown()
- while (self.client_completion_queue.next().type !=
+ 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().type !=
+ while (self.server_completion_queue.next(float('+inf')).type !=
_types.EventType.QUEUE_SHUTDOWN):
pass
@@ -294,8 +294,12 @@ class HangingServerShutdown(unittest.TestCase):
# 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()
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
index b3d6ec8607..f55a7a23ea 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_adapter/_proto_scenarios.py
@@ -32,7 +32,7 @@
import abc
import threading
-from grpc_test._junkdrawer import math_pb2
+from tests.unit._junkdrawer import math_pb2
class ProtoScenario(object):
diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
index cafb6b6eae..efc990421a 100644
--- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
+++ b/src/python/grpcio/tests/unit/_core_over_links_base_interface_test.py
@@ -41,10 +41,10 @@ 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 grpc_test import test_common as grpc_test_common
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import test_cases
-from grpc_test.framework.interfaces.base import test_interfaces
+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(
diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
index a4d4dee38c..4faaaadc2b 100644
--- a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/_crust_over_core_over_links_face_interface_test.py
@@ -40,10 +40,10 @@ 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 grpc_test import test_common as grpc_test_common
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
+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(
diff --git a/src/python/grpcio_test/grpc_test/_cython/.gitignore b/src/python/grpcio/tests/unit/_cython/.gitignore
index c315029288..c315029288 100644
--- a/src/python/grpcio_test/grpc_test/_cython/.gitignore
+++ b/src/python/grpcio/tests/unit/_cython/.gitignore
diff --git a/src/python/grpcio_test/grpc_test/_cython/__init__.py b/src/python/grpcio/tests/unit/_cython/__init__.py
index b89398809f..b89398809f 100644
--- a/src/python/grpcio_test/grpc_test/_cython/__init__.py
+++ b/src/python/grpcio/tests/unit/_cython/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
index 1307a30ca0..876da88de9 100644
--- a/src/python/grpcio_test/grpc_test/_cython/cygrpc_test.py
+++ b/src/python/grpcio/tests/unit/_cython/cygrpc_test.py
@@ -28,11 +28,24 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
+import threading
import unittest
from grpc._cython import cygrpc
-from grpc_test._cython import test_utilities
-from grpc_test import test_common
+from tests.unit._cython import test_utilities
+from tests.unit import test_common
+from tests.unit import resources
+
+
+_SSL_HOST_OVERRIDE = 'foo.test.google.fr'
+_CALL_CREDENTIALS_METADATA_KEY = 'call-creds-key'
+_CALL_CREDENTIALS_METADATA_VALUE = 'call-creds-value'
+
+def _metadata_plugin_callback(context, callback):
+ callback(cygrpc.Metadata(
+ [cygrpc.Metadatum(_CALL_CREDENTIALS_METADATA_KEY,
+ _CALL_CREDENTIALS_METADATA_VALUE)]),
+ cygrpc.StatusCode.ok, '')
class TypeSmokeTest(unittest.TestCase):
@@ -89,7 +102,17 @@ class TypeSmokeTest(unittest.TestCase):
channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([]))
del channel
- @unittest.skip('TODO(atash): undo skip after #2229 is merged')
+ def testCredentialsMetadataPluginUpDown(self):
+ plugin = cygrpc.CredentialsMetadataPlugin(
+ lambda ignored_a, ignored_b: None, '')
+ del plugin
+
+ def testCallCredentialsFromPluginUpDown(self):
+ plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
+ call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
+ del plugin
+ del call_credentials
+
def testServerStartNoExplicitShutdown(self):
server = cygrpc.Server()
completion_queue = cygrpc.CompletionQueue()
@@ -99,7 +122,6 @@ class TypeSmokeTest(unittest.TestCase):
server.start()
del server
- @unittest.skip('TODO(atash): undo skip after #2229 is merged')
def testServerStartShutdown(self):
completion_queue = cygrpc.CompletionQueue()
server = cygrpc.Server()
@@ -262,5 +284,169 @@ class InsecureServerInsecureClient(unittest.TestCase):
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):
+ 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
+
+ cygrpc_deadline = cygrpc.Timespec(DEADLINE)
+
+ server_request_tag = object()
+ request_call_result = self.server.request_call(
+ self.server_completion_queue, self.server_completion_queue,
+ server_request_tag)
+
+ self.assertEqual(cygrpc.CallError.ok, request_call_result)
+
+ plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, '')
+ call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
+
+ 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),
+ cygrpc.operation_send_message(REQUEST),
+ cygrpc.operation_send_close_from_client(),
+ cygrpc.operation_receive_initial_metadata(),
+ cygrpc.operation_receive_message(),
+ cygrpc.operation_receive_status_on_client()
+ ]), client_call_tag)
+ self.assertEqual(cygrpc.CallError.ok, client_start_batch_result)
+ client_event_future = test_utilities.CompletionQueuePollFuture(
+ self.client_completion_queue, cygrpc_deadline)
+
+ 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),
+ cygrpc.operation_receive_message(),
+ cygrpc.operation_send_message(RESPONSE),
+ cygrpc.operation_receive_close_on_server(),
+ cygrpc.operation_send_status_from_server(
+ server_trailing_metadata, SERVER_STATUS_CODE, SERVER_STATUS_DETAILS)
+ ], 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)
+
+ 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)
+
+ 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)
+
+ del client_call
+ del server_call
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/_cython/test_utilities.py b/src/python/grpcio/tests/unit/_cython/test_utilities.py
index 21ea3075b4..21ea3075b4 100644
--- a/src/python/grpcio_test/grpc_test/_cython/test_utilities.py
+++ b/src/python/grpcio/tests/unit/_cython/test_utilities.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py b/src/python/grpcio/tests/unit/_junkdrawer/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/_junkdrawer/__init__.py
+++ b/src/python/grpcio/tests/unit/_junkdrawer/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py
index 20165955b4..20165955b4 100644
--- a/src/python/grpcio_test/grpc_test/_junkdrawer/math_pb2.py
+++ b/src/python/grpcio/tests/unit/_junkdrawer/math_pb2.py
diff --git a/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py b/src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py
index eef18f82d6..eef18f82d6 100644
--- a/src/python/grpcio_test/grpc_test/_junkdrawer/stock_pb2.py
+++ b/src/python/grpcio/tests/unit/_junkdrawer/stock_pb2.py
diff --git a/src/python/grpcio_test/grpc_test/_links/__init__.py b/src/python/grpcio/tests/unit/_links/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/_links/__init__.py
+++ b/src/python/grpcio/tests/unit/_links/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
index 8e12e8cc22..890755f81c 100644
--- a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
+++ b/src/python/grpcio/tests/unit/_links/_lonely_invocation_link_test.py
@@ -34,9 +34,9 @@ import unittest
from grpc._adapter import _intermediary_low
from grpc._links import invocation
from grpc.framework.interfaces.links import links
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_cases
-from grpc_test.framework.interfaces.links import test_utilities
+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
diff --git a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
index 0d74d66297..f69ff51b16 100644
--- a/src/python/grpcio_test/grpc_test/_links/_proto_scenarios.py
+++ b/src/python/grpcio/tests/unit/_links/_proto_scenarios.py
@@ -32,8 +32,8 @@
import abc
import threading
-from grpc_test._junkdrawer import math_pb2
-from grpc_test.framework.common import test_constants
+from tests.unit._junkdrawer import math_pb2
+from tests.unit.framework.common import test_constants
class ProtoScenario(object):
diff --git a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py b/src/python/grpcio/tests/unit/_links/_transmission_test.py
index 77e83d5561..888684d197 100644
--- a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py
+++ b/src/python/grpcio/tests/unit/_links/_transmission_test.py
@@ -36,11 +36,11 @@ 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 grpc_test import test_common
-from grpc_test._links import _proto_scenarios
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_cases
-from grpc_test.framework.interfaces.links import test_utilities
+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
diff --git a/src/python/grpcio_test/grpc_test/beta/__init__.py b/src/python/grpcio/tests/unit/beta/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/beta/__init__.py
+++ b/src/python/grpcio/tests/unit/beta/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
index 5916a9e3ea..ea44177b49 100644
--- a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
+++ b/src/python/grpcio/tests/unit/beta/_beta_features_test.py
@@ -36,12 +36,15 @@ from grpc.beta import implementations
from grpc.beta import interfaces
from grpc.framework.common import cardinality
from grpc.framework.interfaces.face import utilities
-from grpc_test import resources
-from grpc_test.beta import test_utilities
-from grpc_test.framework.common import test_constants
+from tests.unit import resources
+from tests.unit.beta import test_utilities
+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'
+
_GROUP = 'group'
_UNARY_UNARY = 'unary-unary'
_UNARY_STREAM = 'unary-stream'
@@ -63,6 +66,7 @@ class _Servicer(object):
with self._condition:
self._request = request
self._peer = context.protocol_context().peer()
+ self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression()
self._serviced = True
self._condition.notify_all()
@@ -72,6 +76,7 @@ class _Servicer(object):
with self._condition:
self._request = request
self._peer = context.protocol_context().peer()
+ self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression()
self._serviced = True
self._condition.notify_all()
@@ -83,6 +88,7 @@ class _Servicer(object):
self._request = request
with self._condition:
self._peer = context.protocol_context().peer()
+ self._invocation_metadata = context.invocation_metadata()
context.protocol_context().disable_next_response_compression()
self._serviced = True
self._condition.notify_all()
@@ -95,6 +101,7 @@ class _Servicer(object):
context.protocol_context().disable_next_response_compression()
yield _RESPONSE
with self._condition:
+ self._invocation_metadata = context.invocation_metadata()
self._serviced = True
self._condition.notify_all()
@@ -137,6 +144,11 @@ class _BlockingIterator(object):
self._condition.notify_all()
+def _metadata_plugin(context, callback):
+ callback([(_PER_RPC_CREDENTIALS_METADATA_KEY,
+ _PER_RPC_CREDENTIALS_METADATA_VALUE)], None)
+
+
class BetaFeaturesTest(unittest.TestCase):
def setUp(self):
@@ -167,10 +179,12 @@ class BetaFeaturesTest(unittest.TestCase):
[(resources.private_key(), resources.certificate_chain(),),])
port = self._server.add_secure_port('[::]:0', server_credentials)
self._server.start()
- self._client_credentials = implementations.ssl_client_credentials(
+ self._channel_credentials = implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None)
+ self._call_credentials = implementations.metadata_call_credentials(
+ _metadata_plugin)
channel = test_utilities.not_really_secure_channel(
- 'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE)
+ 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
stub_options = implementations.stub_options(
thread_pool_size=test_constants.POOL_SIZE)
self._dynamic_stub = implementations.dynamic_stub(
@@ -181,21 +195,36 @@ class BetaFeaturesTest(unittest.TestCase):
self._server.stop(test_constants.SHORT_TIMEOUT).wait()
def test_unary_unary(self):
- call_options = interfaces.grpc_call_options(disable_compression=True)
+ call_options = interfaces.grpc_call_options(
+ disable_compression=True, credentials=self._call_credentials)
response = getattr(self._dynamic_stub, _UNARY_UNARY)(
_REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
self.assertEqual(_RESPONSE, response)
self.assertIsNotNone(self._servicer.peer())
+ invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+ self._servicer._invocation_metadata]
+ self.assertIn(
+ (_PER_RPC_CREDENTIALS_METADATA_KEY,
+ _PER_RPC_CREDENTIALS_METADATA_VALUE),
+ invocation_metadata)
def test_unary_stream(self):
- call_options = interfaces.grpc_call_options(disable_compression=True)
+ call_options = interfaces.grpc_call_options(
+ disable_compression=True, credentials=self._call_credentials)
response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)(
_REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer())
+ invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+ self._servicer._invocation_metadata]
+ self.assertIn(
+ (_PER_RPC_CREDENTIALS_METADATA_KEY,
+ _PER_RPC_CREDENTIALS_METADATA_VALUE),
+ invocation_metadata)
def test_stream_unary(self):
- call_options = interfaces.grpc_call_options()
+ call_options = interfaces.grpc_call_options(
+ credentials=self._call_credentials)
request_iterator = _BlockingIterator(iter((_REQUEST,)))
response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future(
request_iterator, test_constants.LONG_TIMEOUT,
@@ -207,9 +236,16 @@ class BetaFeaturesTest(unittest.TestCase):
self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer())
self.assertEqual(_RESPONSE, response_future.result())
+ invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+ self._servicer._invocation_metadata]
+ self.assertIn(
+ (_PER_RPC_CREDENTIALS_METADATA_KEY,
+ _PER_RPC_CREDENTIALS_METADATA_VALUE),
+ invocation_metadata)
def test_stream_stream(self):
- call_options = interfaces.grpc_call_options()
+ call_options = interfaces.grpc_call_options(
+ credentials=self._call_credentials)
request_iterator = _BlockingIterator(iter((_REQUEST,)))
response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)(
request_iterator, test_constants.SHORT_TIMEOUT,
@@ -222,6 +258,85 @@ class BetaFeaturesTest(unittest.TestCase):
self._servicer.block_until_serviced()
self.assertIsNotNone(self._servicer.peer())
self.assertEqual(_RESPONSE, response)
+ invocation_metadata = [(metadatum.key, metadatum.value) for metadatum in
+ self._servicer._invocation_metadata]
+ self.assertIn(
+ (_PER_RPC_CREDENTIALS_METADATA_KEY,
+ _PER_RPC_CREDENTIALS_METADATA_VALUE),
+ invocation_metadata)
+
+
+class ContextManagementAndLifecycleTest(unittest.TestCase):
+
+ def setUp(self):
+ self._servicer = _Servicer()
+ self._method_implementations = {
+ (_GROUP, _UNARY_UNARY):
+ utilities.unary_unary_inline(self._servicer.unary_unary),
+ (_GROUP, _UNARY_STREAM):
+ utilities.unary_stream_inline(self._servicer.unary_stream),
+ (_GROUP, _STREAM_UNARY):
+ utilities.stream_unary_inline(self._servicer.stream_unary),
+ (_GROUP, _STREAM_STREAM):
+ utilities.stream_stream_inline(self._servicer.stream_stream),
+ }
+
+ self._cardinalities = {
+ _UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY,
+ _UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM,
+ _STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY,
+ _STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM,
+ }
+
+ self._server_options = implementations.server_options(
+ thread_pool_size=test_constants.POOL_SIZE)
+ self._server_credentials = implementations.ssl_server_credentials(
+ [(resources.private_key(), resources.certificate_chain(),),])
+ self._channel_credentials = implementations.ssl_channel_credentials(
+ resources.test_root_certificates(), None, None)
+ self._stub_options = implementations.stub_options(
+ thread_pool_size=test_constants.POOL_SIZE)
+
+ def test_stub_context(self):
+ server = implementations.server(
+ self._method_implementations, options=self._server_options)
+ port = server.add_secure_port('[::]:0', self._server_credentials)
+ server.start()
+
+ channel = test_utilities.not_really_secure_channel(
+ 'localhost', port, self._channel_credentials, _SERVER_HOST_OVERRIDE)
+ dynamic_stub = implementations.dynamic_stub(
+ channel, _GROUP, self._cardinalities, options=self._stub_options)
+ for _ in range(100):
+ with dynamic_stub:
+ pass
+ for _ in range(10):
+ with dynamic_stub:
+ call_options = interfaces.grpc_call_options(
+ disable_compression=True)
+ response = getattr(dynamic_stub, _UNARY_UNARY)(
+ _REQUEST, test_constants.LONG_TIMEOUT,
+ protocol_options=call_options)
+ self.assertEqual(_RESPONSE, response)
+ self.assertIsNotNone(self._servicer.peer())
+
+ server.stop(test_constants.SHORT_TIMEOUT).wait()
+
+ def test_server_lifecycle(self):
+ for _ in range(100):
+ server = implementations.server(
+ self._method_implementations, options=self._server_options)
+ port = server.add_secure_port('[::]:0', self._server_credentials)
+ server.start()
+ server.stop(test_constants.SHORT_TIMEOUT).wait()
+ for _ in range(100):
+ server = implementations.server(
+ self._method_implementations, options=self._server_options)
+ server.add_secure_port('[::]:0', self._server_credentials)
+ server.add_insecure_port('[::]:0')
+ with server:
+ server.stop(test_constants.SHORT_TIMEOUT)
+ server.stop(test_constants.SHORT_TIMEOUT)
if __name__ == '__main__':
diff --git a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
index b3c05bdb0c..5dc8720639 100644
--- a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
+++ b/src/python/grpcio/tests/unit/beta/_connectivity_channel_test.py
@@ -37,7 +37,7 @@ from grpc._adapter import _low
from grpc._adapter import _types
from grpc.beta import _connectivity_channel
from grpc.beta import interfaces
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
def _drive_completion_queue(completion_queue):
diff --git a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
index aa33e1e6f8..1c21dfd03d 100644
--- a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/beta/_face_interface_test.py
@@ -34,12 +34,12 @@ import unittest
from grpc.beta import implementations
from grpc.beta import interfaces
-from grpc_test import resources
-from grpc_test import test_common as grpc_test_common
-from grpc_test.beta import test_utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
+from tests.unit import resources
+from tests.unit import test_common as grpc_test_common
+from tests.unit.beta import test_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
_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
@@ -91,10 +91,10 @@ class _Implementation(test_interfaces.Implementation):
[(resources.private_key(), resources.certificate_chain(),),])
port = server.add_secure_port('[::]:0', server_credentials)
server.start()
- client_credentials = implementations.ssl_client_credentials(
+ channel_credentials = implementations.ssl_channel_credentials(
resources.test_root_certificates(), None, None)
channel = test_utilities.not_really_secure_channel(
- 'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE)
+ 'localhost', port, channel_credentials, _SERVER_HOST_OVERRIDE)
stub_options = implementations.stub_options(
request_serializers=serialization_behaviors.request_serializers,
response_deserializers=serialization_behaviors.response_deserializers,
diff --git a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py b/src/python/grpcio/tests/unit/beta/_not_found_test.py
index 5feb997fef..44fcd1e13c 100644
--- a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py
+++ b/src/python/grpcio/tests/unit/beta/_not_found_test.py
@@ -34,7 +34,7 @@ import unittest
from grpc.beta import implementations
from grpc.beta import interfaces
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
class NotFoundTest(unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py b/src/python/grpcio/tests/unit/beta/_utilities_test.py
index 996cea9118..08ce98e751 100644
--- a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py
+++ b/src/python/grpcio/tests/unit/beta/_utilities_test.py
@@ -38,7 +38,7 @@ from grpc._adapter import _types
from grpc.beta import implementations
from grpc.beta import utilities
from grpc.framework.foundation import future
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
def _drive_completion_queue(completion_queue):
diff --git a/src/python/grpcio_test/grpc_test/beta/test_utilities.py b/src/python/grpcio/tests/unit/beta/test_utilities.py
index 24a8600e12..0313e06a93 100644
--- a/src/python/grpcio_test/grpc_test/beta/test_utilities.py
+++ b/src/python/grpcio/tests/unit/beta/test_utilities.py
@@ -34,13 +34,13 @@ from grpc.beta import implementations
def not_really_secure_channel(
- host, port, client_credentials, server_host_override):
+ host, port, channel_credentials, server_host_override):
"""Creates an insecure Channel to a remote host.
Args:
host: The name of the remote host to which to connect.
port: The port of the remote host to which to connect.
- client_credentials: The implementations.ClientCredentials with which to
+ channel_credentials: The implementations.ChannelCredentials with which to
connect.
server_host_override: The target name used for SSL host name checking.
@@ -50,7 +50,7 @@ def not_really_secure_channel(
"""
hostport = '%s:%d' % (host, port)
intermediary_low_channel = _intermediary_low.Channel(
- hostport, client_credentials._intermediary_low_credentials,
+ hostport, channel_credentials._low_credentials,
server_host_override=server_host_override)
return implementations.Channel(
intermediary_low_channel._internal, intermediary_low_channel)
diff --git a/src/python/grpcio_test/grpc_test/credentials/README b/src/python/grpcio/tests/unit/credentials/README
index cb20dcb49f..cb20dcb49f 100644
--- a/src/python/grpcio_test/grpc_test/credentials/README
+++ b/src/python/grpcio/tests/unit/credentials/README
diff --git a/src/python/grpcio_test/grpc_test/credentials/ca.pem b/src/python/grpcio/tests/unit/credentials/ca.pem
index 6c8511a73c..6c8511a73c 100755
--- a/src/python/grpcio_test/grpc_test/credentials/ca.pem
+++ b/src/python/grpcio/tests/unit/credentials/ca.pem
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.key b/src/python/grpcio/tests/unit/credentials/server1.key
index 143a5b8765..143a5b8765 100755
--- a/src/python/grpcio_test/grpc_test/credentials/server1.key
+++ b/src/python/grpcio/tests/unit/credentials/server1.key
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio/tests/unit/credentials/server1.pem
index f3d43fcc5b..f3d43fcc5b 100755
--- a/src/python/grpcio_test/grpc_test/credentials/server1.pem
+++ b/src/python/grpcio/tests/unit/credentials/server1.pem
diff --git a/src/python/grpcio_test/grpc_test/framework/__init__.py b/src/python/grpcio/tests/unit/framework/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
index 30bb85f6c3..360ecc95d5 100644
--- a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
+++ b/src/python/grpcio/tests/unit/framework/_crust_over_core_face_interface_test.py
@@ -36,10 +36,10 @@ 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 grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import test_cases
-from grpc_test.framework.interfaces.face import test_interfaces
-from grpc_test.framework.interfaces.links import test_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):
diff --git a/src/python/grpcio_test/grpc_test/framework/common/__init__.py b/src/python/grpcio/tests/unit/framework/common/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/common/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/common/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py b/src/python/grpcio/tests/unit/framework/common/test_constants.py
index e1d3c2709d..e1d3c2709d 100644
--- a/src/python/grpcio_test/grpc_test/framework/common/test_constants.py
+++ b/src/python/grpcio/tests/unit/framework/common/test_constants.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_control.py b/src/python/grpcio/tests/unit/framework/common/test_control.py
index 8d6eba5c2c..8d6eba5c2c 100644
--- a/src/python/grpcio_test/grpc_test/framework/common/test_control.py
+++ b/src/python/grpcio/tests/unit/framework/common/test_control.py
diff --git a/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py b/src/python/grpcio/tests/unit/framework/common/test_coverage.py
index a7ed3582c4..a7ed3582c4 100644
--- a/src/python/grpcio_test/grpc_test/framework/common/test_coverage.py
+++ b/src/python/grpcio/tests/unit/framework/common/test_coverage.py
diff --git a/src/python/grpcio_test/grpc_test/framework/core/__init__.py b/src/python/grpcio/tests/unit/framework/core/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/core/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/core/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
index 8d72f131d5..1310292306 100644
--- a/src/python/grpcio_test/grpc_test/framework/core/_base_interface_test.py
+++ b/src/python/grpcio/tests/unit/framework/core/_base_interface_test.py
@@ -36,9 +36,9 @@ import unittest
from grpc.framework.core import implementations
from grpc.framework.interfaces.base import utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import test_cases
-from grpc_test.framework.interfaces.base import test_interfaces
+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):
diff --git a/src/python/grpcio_test/grpc_test/framework/face/__init__.py b/src/python/grpcio/tests/unit/framework/face/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/face/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
index 1df1529b27..1df1529b27 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/base_util.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
index 251e1eb68e..0613516421 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
@@ -34,12 +34,12 @@ import abc
import unittest # pylint: disable=unused-import
from grpc.framework.face import exceptions
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
class BlockingInvocationInlineServiceTestCase(
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py b/src/python/grpcio/tests/unit/framework/face/testing/callback.py
index d0e63c8c56..d0e63c8c56 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/callback.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/callback.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py
index 3960c4e649..3960c4e649 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/control.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/control.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
index f3aca113fe..f3aca113fe 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/coverage.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
index 54ff21779a..39f28b9657 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/digest.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
@@ -40,9 +40,9 @@ from grpc.framework.face import exceptions
from grpc.framework.face import interfaces as face_interfaces
from grpc.framework.foundation import stream
from grpc.framework.foundation import stream_util
-from grpc_test.framework.face.testing import control as testing_control # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import
-from grpc_test.framework.face.testing import service as testing_service # pylint: disable=unused-import
+from tests.unit.framework.face.testing import control as testing_control # pylint: disable=unused-import
+from tests.unit.framework.face.testing import interfaces # pylint: disable=unused-import
+from tests.unit.framework.face.testing import service as testing_service # pylint: disable=unused-import
_IDENTITY = lambda x: x
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
index 9df77678eb..179f3a2f67 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
@@ -33,13 +33,13 @@ import abc
import unittest
from grpc.framework.face import interfaces
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import callback as testing_callback
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import callback as testing_callback
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
class EventInvocationSynchronousEventServiceTestCase(
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
index 70d86a0422..485524a356 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
@@ -37,12 +37,12 @@ import unittest
from grpc.framework.face import exceptions
from grpc.framework.foundation import future
from grpc.framework.foundation import logging_pool
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.face.testing import control
-from grpc_test.framework.face.testing import coverage
-from grpc_test.framework.face.testing import digest
-from grpc_test.framework.face.testing import stock_service
-from grpc_test.framework.face.testing import test_case
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.face.testing import control
+from tests.unit.framework.face.testing import coverage
+from tests.unit.framework.face.testing import digest
+from tests.unit.framework.face.testing import stock_service
+from tests.unit.framework.face.testing import test_case
_MAXIMUM_POOL_SIZE = 10
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
index 5932dabf1e..5932dabf1e 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py
index ee9d6a3da3..ac0b89b6ee 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/service.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/service.py
@@ -33,7 +33,7 @@ import abc
# interfaces is referenced from specification in this module.
from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces
+from tests.unit.framework.face.testing import interfaces
class UnaryUnaryTestMethodImplementation(interfaces.Method):
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
index 0f83ca4db1..117c723f79 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/stock_service.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
@@ -33,8 +33,8 @@ from grpc.framework.common import cardinality
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import stream
from grpc.framework.foundation import stream_util
-from grpc_test.framework.face.testing import service
-from grpc_test._junkdrawer import stock_pb2
+from tests.unit.framework.face.testing import service
+from tests.unit._junkdrawer import stock_pb2
SYMBOL_FORMAT = 'test symbol:%03d'
STREAM_LENGTH = 400
diff --git a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
index 858d5cf7fd..23d4d919c2 100644
--- a/src/python/grpcio_test/grpc_test/framework/face/testing/test_case.py
+++ b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
@@ -33,7 +33,7 @@ import abc
# face_interfaces and interfaces are referenced in specification in this module.
from grpc.framework.face import interfaces as face_interfaces # pylint: disable=unused-import
-from grpc_test.framework.face.testing import interfaces # pylint: disable=unused-import
+from tests.unit.framework.face.testing import interfaces # pylint: disable=unused-import
class FaceTestCase(object):
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py b/src/python/grpcio/tests/unit/framework/foundation/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/foundation/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/foundation/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
index 6c2459e185..6c2459e185 100644
--- a/src/python/grpcio_test/grpc_test/framework/foundation/_later_test.py
+++ b/src/python/grpcio/tests/unit/framework/foundation/_later_test.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
index 452802da6a..452802da6a 100644
--- a/src/python/grpcio_test/grpc_test/framework/foundation/_logging_pool_test.py
+++ b/src/python/grpcio/tests/unit/framework/foundation/_logging_pool_test.py
diff --git a/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py b/src/python/grpcio/tests/unit/framework/foundation/stream_testing.py
index 098a53d5e7..098a53d5e7 100644
--- a/src/python/grpcio_test/grpc_test/framework/foundation/stream_testing.py
+++ b/src/python/grpcio/tests/unit/framework/foundation/stream_testing.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
index 46a01876d8..38102b198a 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_control.py
@@ -37,10 +37,10 @@ import threading
import time
from grpc.framework.interfaces.base import base
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import _sequence
-from grpc_test.framework.interfaces.base import _state
-from grpc_test.framework.interfaces.base import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import _sequence
+from tests.unit.framework.interfaces.base import _state
+from tests.unit.framework.interfaces.base import test_interfaces # pylint: disable=unused-import
_GROUP = 'base test cases test group'
_METHOD = 'base test cases test method'
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py
index f547d91681..571d0e1e63 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_sequence.py
@@ -33,7 +33,7 @@ import collections
import enum
from grpc.framework.interfaces.base import base
-from grpc_test.framework.common import test_constants
+from tests.unit.framework.common import test_constants
class Invocation(
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py b/src/python/grpcio/tests/unit/framework/interfaces/base/_state.py
index 21cf33aeb6..21cf33aeb6 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_state.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/_state.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
index ddda1018c3..4f8e26c9a2 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_cases.py
@@ -38,9 +38,9 @@ import unittest
from grpc.framework.foundation import logging_pool
from grpc.framework.interfaces.base import base
from grpc.framework.interfaces.base import utilities
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.base import _control
-from grpc_test.framework.interfaces.base import test_interfaces
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.base import _control
+from tests.unit.framework.interfaces.base import test_interfaces
_SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True))
@@ -271,6 +271,7 @@ def test_cases(implementation):
'_randomness': randomness,
'_synchronicity_variation': synchronicity_variation[1],
'_controller_creator': controller_creator,
+ '__module__': implementation.__module__,
}))
return test_case_classes
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
index 02426ab846..84afd24d47 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/base/test_interfaces.py
@@ -131,7 +131,7 @@ class Implementation(object):
@abc.abstractmethod
def service_initial_metadata(self):
- """Provices an operation's service-side initial metadata.
+ """Provides an operation's service-side initial metadata.
Returns:
A value to use for an operation's service-side initial metadata, or
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py
index 363d9ce8f1..1ea356c0bf 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_3069_test_constant.py
@@ -30,7 +30,7 @@
"""A test constant working around issue 3069."""
# test_constants is referenced from specification in this module.
-from grpc_test.framework.common import test_constants # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants # pylint: disable=unused-import
# TODO(issue 3069): Replace uses of this constant with
# test_constants.SHORT_TIMEOUT.
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
index 2d2a081955..3bcefa601d 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -34,13 +34,13 @@ import unittest
# test_interfaces is referenced from specification in this module.
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
class TestCase(test_coverage.Coverage, unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
index da56ed7b27..9304b6b1db 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_digest.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_digest.py
@@ -39,9 +39,9 @@ from grpc.framework.common import style
from grpc.framework.foundation import stream
from grpc.framework.foundation import stream_util
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_control # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import _service # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.common import test_control # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import _service # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
_IDENTITY = lambda x: x
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
index 7cb273bf78..34db6c3e55 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
@@ -34,14 +34,14 @@ import unittest
# test_interfaces is referenced from specification in this module.
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _receiver
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _receiver
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
class TestCase(test_coverage.Coverage, unittest.TestCase):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index 3032736975..c178f2f108 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -37,13 +37,13 @@ import unittest
# test_interfaces is referenced from specification in this module.
from grpc.framework.foundation import logging_pool
from grpc.framework.interfaces.face import face
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.common import test_control
-from grpc_test.framework.common import test_coverage
-from grpc_test.framework.interfaces.face import _3069_test_constant
-from grpc_test.framework.interfaces.face import _digest
-from grpc_test.framework.interfaces.face import _stock_service
-from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+from tests.unit.framework.common import test_coverage
+from tests.unit.framework.interfaces.face import _3069_test_constant
+from tests.unit.framework.interfaces.face import _digest
+from tests.unit.framework.interfaces.face import _stock_service
+from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
class _PauseableIterator(object):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
index 448e845a08..448e845a08 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_invocation.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_invocation.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
index 2e444ff09d..2e444ff09d 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_receiver.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_receiver.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
index e25b8a038c..28941e2ad0 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_service.py
@@ -33,7 +33,7 @@ import abc
# face is referenced from specification in this module.
from grpc.framework.interfaces.face import face # pylint: disable=unused-import
-from grpc_test.framework.interfaces.face import test_interfaces
+from tests.unit.framework.interfaces.face import test_interfaces
class UnaryUnaryTestMethodImplementation(test_interfaces.Method):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py
index 808e2c4e36..5299655bb3 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/_stock_service.py
@@ -32,9 +32,9 @@
from grpc.framework.common import cardinality
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import stream
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.face import _service
-from grpc_test._junkdrawer import stock_pb2
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.face import _service
+from tests.unit._junkdrawer import stock_pb2
_STOCK_GROUP_NAME = 'Stock'
_SYMBOL_FORMAT = 'test symbol:%03d'
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
index ca623662f7..462829b660 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
@@ -33,11 +33,11 @@
import unittest # pylint: disable=unused-import
# test_interfaces is referenced from specification in this module.
-from grpc_test.framework.interfaces.face import _blocking_invocation_inline_service
-from grpc_test.framework.interfaces.face import _event_invocation_synchronous_event_service
-from grpc_test.framework.interfaces.face import _future_invocation_asynchronous_event_service
-from grpc_test.framework.interfaces.face import _invocation
-from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
+from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service
+from tests.unit.framework.interfaces.face import _event_invocation_synchronous_event_service
+from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service
+from tests.unit.framework.interfaces.face import _invocation
+from tests.unit.framework.interfaces.face import test_interfaces # pylint: disable=unused-import
_TEST_CASE_SUPERCLASSES = (
_blocking_invocation_inline_service.TestCase,
@@ -63,5 +63,7 @@ def test_cases(implementation):
test_case_classes.append(
type(invoker_constructor.name() + super_class.NAME, (super_class,),
{'implementation': implementation,
- 'invoker_constructor': invoker_constructor}))
+ 'invoker_constructor': invoker_constructor,
+ '__module__': implementation.__module__,
+ }))
return test_case_classes
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
index b2b5c10fa6..b2b5c10fa6 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/test_interfaces.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_interfaces.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py b/src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py
index 7086519106..7086519106 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/__init__.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/links/__init__.py
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
index ecf49d9cdb..dace6c23f3 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_cases.py
@@ -34,8 +34,8 @@ import abc
import unittest # pylint: disable=unused-import
from grpc.framework.interfaces.links import links
-from grpc_test.framework.common import test_constants
-from grpc_test.framework.interfaces.links import test_utilities
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.interfaces.links import test_utilities
def at_least_n_payloads_received_predicate(n):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py b/src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py
index 39c7f2fc63..39c7f2fc63 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/links/test_utilities.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/links/test_utilities.py
diff --git a/src/python/grpcio_test/grpc_test/resources.py b/src/python/grpcio/tests/unit/resources.py
index 2c3045313d..023cdb155f 100644
--- a/src/python/grpcio_test/grpc_test/resources.py
+++ b/src/python/grpcio/tests/unit/resources.py
@@ -43,10 +43,6 @@ def test_root_certificates():
__name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
-def prod_root_certificates():
- return open(os.environ['SSL_CERT_FILE'], mode='rb').read()
-
-
def private_key():
return pkg_resources.resource_string(__name__, _PRIVATE_KEY_RESOURCE_PATH)
diff --git a/src/python/grpcio_test/grpc_test/test_common.py b/src/python/grpcio/tests/unit/test_common.py
index 29431bfb9d..29431bfb9d 100644
--- a/src/python/grpcio_test/grpc_test/test_common.py
+++ b/src/python/grpcio/tests/unit/test_common.py
diff --git a/src/python/grpcio/tox.ini b/src/python/grpcio/tox.ini
new file mode 100644
index 0000000000..bfb1ca0cfa
--- /dev/null
+++ b/src/python/grpcio/tox.ini
@@ -0,0 +1,19 @@
+# Tox (http://tox.testrun.org/) is a tool for running tests
+# in multiple virtualenvs. This configuration file will run the
+# test suite on all supported python versions. To use it, "pip install tox"
+# and then run "tox" from this directory.
+
+[tox]
+skipsdist = true
+envlist = py27
+
+[testenv]
+commands =
+ {envpython} setup.py build_py
+ {envpython} setup.py test
+ coverage combine
+ coverage html --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
+ coverage report --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py'
+deps =
+ -rrequirements.txt
+passenv = *
diff --git a/src/python/grpcio_test/.gitignore b/src/python/grpcio_test/.gitignore
deleted file mode 100644
index 6158313bde..0000000000
--- a/src/python/grpcio_test/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-MANIFEST
-*.egg-info/
-build/
-dist/
-*.egg
-*.egg/
-*.eggs/
-*_pb2.py
-.coverage
-.coverage.*
-.cache/
-nosetests.xml
diff --git a/src/python/grpcio_test/MANIFEST.in b/src/python/grpcio_test/MANIFEST.in
deleted file mode 100644
index c9327307dc..0000000000
--- a/src/python/grpcio_test/MANIFEST.in
+++ /dev/null
@@ -1,4 +0,0 @@
-graft grpc_interop
-graft grpc_test
-include commands.py
-include requirements.txt
diff --git a/src/python/grpcio_test/commands.py b/src/python/grpcio_test/commands.py
deleted file mode 100644
index edaa2aa72d..0000000000
--- a/src/python/grpcio_test/commands.py
+++ /dev/null
@@ -1,106 +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.
-
-"""Provides distutils command classes for the GRPC Python test setup process."""
-
-import distutils
-import os
-import os.path
-import subprocess
-import sys
-
-import setuptools
-from setuptools.command import build_py
-
-
-class RunTests(setuptools.Command):
- """Command to run all tests via py.test."""
-
- description = ''
- user_options = [('pytest-args=', 'a', 'arguments to pass to py.test')]
-
- def initialize_options(self):
- self.pytest_args = []
-
- def finalize_options(self):
- pass
-
- def run(self):
- # We import here to ensure that setup.py has had a chance to install the
- # relevant package eggs first.
- import pytest
-
- self.run_command('build_proto_modules')
- result = pytest.main(self.pytest_args)
- if result != 0:
- raise SystemExit(result)
-
-
-class BuildProtoModules(setuptools.Command):
- """Command to generate project *_pb2.py modules from proto files."""
-
- description = ''
- user_options = []
-
- def initialize_options(self):
- pass
-
- def finalize_options(self):
- self.protoc_command = distutils.spawn.find_executable('protoc')
- self.grpc_python_plugin_command = distutils.spawn.find_executable(
- 'grpc_python_plugin')
-
- def run(self):
- paths = []
- root_directory = os.getcwd()
- for walk_root, directories, filenames in os.walk(root_directory):
- for filename in filenames:
- if filename.endswith('.proto'):
- paths.append(os.path.join(walk_root, filename))
- command = [
- self.protoc_command,
- '--plugin=protoc-gen-python-grpc={}'.format(
- self.grpc_python_plugin_command),
- '-I {}'.format(root_directory),
- '--python_out={}'.format(root_directory),
- '--python-grpc_out={}'.format(root_directory),
- ] + paths
- try:
- subprocess.check_output(' '.join(command), cwd=root_directory, shell=True,
- stderr=subprocess.STDOUT)
- except subprocess.CalledProcessError as e:
- raise Exception('{}\nOutput:\n{}'.format(e.message, e.output))
-
-
-class BuildPy(build_py.build_py):
- """Custom project build command."""
-
- def run(self):
- self.run_command('build_proto_modules')
- build_py.build_py.run(self)
diff --git a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py b/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py
deleted file mode 100644
index f1bec238cf..0000000000
--- a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py
+++ /dev/null
@@ -1,187 +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.
-
-# Fork of grpc._adapter._low_test; the grpc._cython.types adapter in
-# grpc._cython.low should transparently support the semantics expected of
-# grpc._adapter._low.
-
-import time
-import unittest
-
-from grpc._adapter import _types
-from grpc._cython import adapter_low as _low
-
-
-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().type !=
- _types.EventType.QUEUE_SHUTDOWN):
- pass
- self.server_completion_queue.shutdown()
- while (self.server_completion_queue.next().type !=
- _types.EventType.QUEUE_SHUTDOWN):
- pass
-
- del self.client_completion_queue
- del self.server_completion_queue
- del self.server
-
- @unittest.skip('TODO(atash): implement grpc._cython.adapter_low')
- def testEcho(self):
- DEADLINE = time.time()+5
- 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 = 'in death a member of project mayhem has a name'
- 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),
- _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)
-
- request_event = self.server_completion_queue.next(DEADLINE)
- 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))
- self.assertEqual(dict(client_initial_metadata),
- dict(request_event.results[0].initial_metadata))
- 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)
-
- 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),
- _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 = self.client_completion_queue.next(DEADLINE)
- server_event = self.server_completion_queue.next(DEADLINE)
-
- 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.assertEqual(dict(server_initial_metadata),
- dict(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.assertEqual(dict(server_trailing_metadata),
- dict(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
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/conftest.py b/src/python/grpcio_test/grpc_test/conftest.py
deleted file mode 100644
index 357320ec64..0000000000
--- a/src/python/grpcio_test/grpc_test/conftest.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import types
-import unittest
-
-import pytest
-
-
-class LoadTestsSuiteCollector(pytest.Collector):
-
- def __init__(self, name, parent, suite):
- super(LoadTestsSuiteCollector, self).__init__(name, parent=parent)
- self.suite = suite
- self.obj = suite
-
- def collect(self):
- collected = []
- for case in self.suite:
- if isinstance(case, unittest.TestCase):
- collected.append(LoadTestsCase(case.id(), self, case))
- elif isinstance(case, unittest.TestSuite):
- collected.append(
- LoadTestsSuiteCollector('suite_child_of_mine', self, case))
- return collected
-
- def reportinfo(self):
- return str(self.suite)
-
-
-class LoadTestsCase(pytest.Function):
-
- def __init__(self, name, parent, item):
- super(LoadTestsCase, self).__init__(name, parent, callobj=self._item_run)
- self.item = item
-
- def _item_run(self):
- result = unittest.TestResult()
- self.item(result)
- if result.failures:
- test_method, trace = result.failures[0]
- pytest.fail(trace, False)
- elif result.errors:
- test_method, trace = result.errors[0]
- pytest.fail(trace, False)
- elif result.skipped:
- test_method, reason = result.skipped[0]
- pytest.skip(reason)
-
-
-def pytest_pycollect_makeitem(collector, name, obj):
- if name == 'load_tests' and isinstance(obj, types.FunctionType):
- suite = unittest.TestSuite()
- loader = unittest.TestLoader()
- pattern = '*'
- try:
- # Check that the 'load_tests' object is actually a callable that actually
- # accepts the arguments expected for the load_tests protocol.
- suite = obj(loader, suite, pattern)
- except Exception as e:
- return None
- else:
- return LoadTestsSuiteCollector(name, collector, suite)
diff --git a/src/python/grpcio_test/requirements.txt b/src/python/grpcio_test/requirements.txt
deleted file mode 100644
index fea80ca07f..0000000000
--- a/src/python/grpcio_test/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-grpcio>=0.11.0b0
-oauth2client>=1.4.7
-protobuf>=3.0.0a3
-pytest>=2.6
-pytest-cov>=2.0
-pytest-xdist>=1.11
diff --git a/src/python/grpcio_test/setup.cfg b/src/python/grpcio_test/setup.cfg
deleted file mode 100644
index 3be93cb918..0000000000
--- a/src/python/grpcio_test/setup.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-[pytest]
-python_files = *_test.py
diff --git a/src/ruby/bin/apis/pubsub_demo.rb b/src/ruby/bin/apis/pubsub_demo.rb
index 003e91a6b3..143ecc7a8f 100755
--- a/src/ruby/bin/apis/pubsub_demo.rb
+++ b/src/ruby/bin/apis/pubsub_demo.rb
@@ -32,7 +32,6 @@
# pubsub_demo demos accesses the Google PubSub API via its gRPC interface
#
# $ GOOGLE_APPLICATION_CREDENTIALS=<path_to_service_account_key_file> \
-# SSL_CERT_FILE=<path/to/ssl/certs> \
# path/to/pubsub_demo.rb \
# [--action=<chosen_demo_action> ]
#
@@ -55,18 +54,9 @@ require 'google/protobuf/empty'
require 'tech/pubsub/proto/pubsub'
require 'tech/pubsub/proto/pubsub_services'
-# loads the certificates used to access the test server securely.
-def load_prod_cert
- fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
- p "loading prod certs from #{ENV['SSL_CERT_FILE']}"
- File.open(ENV['SSL_CERT_FILE']) do |f|
- return f.read
- end
-end
-
# creates a SSL Credentials from the production certificates.
def ssl_creds
- GRPC::Core::ChannelCredentials.new(load_prod_cert)
+ GRPC::Core::ChannelCredentials.new()
end
# Builds the metadata authentication update proc.
@@ -80,8 +70,9 @@ def publisher_stub(opts)
address = "#{opts.host}:#{opts.port}"
stub_clz = Tech::Pubsub::PublisherService::Stub # shorter
GRPC.logger.info("... access PublisherService at #{address}")
- stub_clz.new(address,
- creds: ssl_creds, update_metadata: auth_proc(opts),
+ call_creds = GRPC::Core::CallCredentials.new(auth_proc(opts))
+ combined_creds = ssl_creds.compose(call_creds)
+ stub_clz.new(address, creds: combined_creds,
GRPC::Core::Channel::SSL_TARGET => opts.host)
end
@@ -90,8 +81,9 @@ def subscriber_stub(opts)
address = "#{opts.host}:#{opts.port}"
stub_clz = Tech::Pubsub::SubscriberService::Stub # shorter
GRPC.logger.info("... access SubscriberService at #{address}")
- stub_clz.new(address,
- creds: ssl_creds, update_metadata: auth_proc(opts),
+ call_creds = GRPC::Core::CallCredentials.new(auth_proc(opts))
+ combined_creds = ssl_creds.compose(call_creds)
+ stub_clz.new(address, creds: combined_creds,
GRPC::Core::Channel::SSL_TARGET => opts.host)
end
diff --git a/src/ruby/bin/math.proto b/src/ruby/bin/math.proto
deleted file mode 100755
index 311e148c02..0000000000
--- a/src/ruby/bin/math.proto
+++ /dev/null
@@ -1,80 +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.
-
-syntax = "proto3";
-
-package math;
-
-message DivArgs {
- int64 dividend = 1;
- int64 divisor = 2;
-}
-
-message DivReply {
- int64 quotient = 1;
- int64 remainder = 2;
-}
-
-message FibArgs {
- int64 limit = 1;
-}
-
-message Num {
- int64 num = 1;
-}
-
-message FibReply {
- int64 count = 1;
-}
-
-service Math {
- // Div divides args.dividend by args.divisor and returns the quotient and
- // remainder.
- rpc Div (DivArgs) returns (DivReply) {
- }
-
- // 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.
- rpc DivMany (stream DivArgs) returns (stream DivReply) {
- }
-
- // 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.
- rpc Fib (FibArgs) returns (stream Num) {
- }
-
- // Sum sums a stream of numbers, returning the final result once the stream
- // is closed.
- rpc Sum (stream Num) returns (Num) {
- }
-}
diff --git a/src/ruby/bin/math.rb b/src/ruby/bin/math.rb
index 323993ed43..60429a1505 100755
--- a/src/ruby/bin/math.rb
+++ b/src/ruby/bin/math.rb
@@ -1,32 +1,3 @@
-# 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: math.proto
diff --git a/src/ruby/bin/math_services.rb b/src/ruby/bin/math_services.rb
index cf58a53913..2d482129c2 100755
--- a/src/ruby/bin/math_services.rb
+++ b/src/ruby/bin/math_services.rb
@@ -1,32 +1,3 @@
-# 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: math.proto for package 'math'
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 40364328ee..1647d9b484 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -39,6 +39,7 @@
#include <grpc/support/alloc.h>
#include "rb_byte_buffer.h"
+#include "rb_call_credentials.h"
#include "rb_completion_queue.h"
#include "rb_grpc.h"
@@ -279,6 +280,26 @@ static VALUE grpc_rb_call_set_write_flag(VALUE self, VALUE write_flag) {
return rb_ivar_set(self, id_write_flag, write_flag);
}
+/*
+ call-seq:
+ call.set_credentials call_credentials
+
+ Sets credentials on a call */
+static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
+ grpc_call *call = NULL;
+ grpc_call_credentials *creds;
+ grpc_call_error err;
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
+ creds = grpc_rb_get_wrapped_call_credentials(credentials);
+ err = grpc_call_set_credentials(call, creds);
+ if (err != GRPC_CALL_OK) {
+ rb_raise(grpc_rb_eCallError,
+ "grpc_call_set_credentials failed with %s (code=%d)",
+ grpc_call_error_detail_of(err), err);
+ }
+ return Qnil;
+}
+
/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
to fill grpc_metadata_array.
@@ -347,7 +368,7 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
/* grpc_rb_md_ary_convert converts a ruby metadata hash into
a grpc_metadata_array.
*/
-static void grpc_rb_md_ary_convert(VALUE md_ary_hash,
+void grpc_rb_md_ary_convert(VALUE md_ary_hash,
grpc_metadata_array *md_ary) {
VALUE md_ary_obj = Qnil;
if (md_ary_hash == Qnil) {
@@ -795,6 +816,8 @@ void Init_grpc_call() {
rb_define_method(grpc_rb_cCall, "write_flag", grpc_rb_call_get_write_flag, 0);
rb_define_method(grpc_rb_cCall, "write_flag=", grpc_rb_call_set_write_flag,
1);
+ rb_define_method(grpc_rb_cCall, "set_credentials!",
+ grpc_rb_call_set_credentials, 1);
/* Ids used to support call attributes */
id_metadata = rb_intern("metadata");
diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h
index 1d2fbc3580..24adb3477b 100644
--- a/src/ruby/ext/grpc/rb_call.h
+++ b/src/ruby/ext/grpc/rb_call.h
@@ -50,6 +50,12 @@ const char* grpc_call_error_detail_of(grpc_call_error err);
/* Converts a metadata array to a hash. */
VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary);
+/* grpc_rb_md_ary_convert converts a ruby metadata hash into
+ a grpc_metadata_array.
+*/
+void grpc_rb_md_ary_convert(VALUE md_ary_hash,
+ grpc_metadata_array *md_ary);
+
/* grpc_rb_eCallError is the ruby class of the exception thrown during call
operations. */
extern VALUE grpc_rb_eCallError;
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
new file mode 100644
index 0000000000..acc5472799
--- /dev/null
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * 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 "rb_call_credentials.h"
+
+#include <ruby/ruby.h>
+#include <ruby/thread.h>
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+#include "rb_call.h"
+#include "rb_grpc.h"
+
+/* grpc_rb_cCallCredentials is the ruby class that proxies
+ * grpc_call_credentials */
+static VALUE grpc_rb_cCallCredentials = Qnil;
+
+/* grpc_rb_call_credentials wraps a grpc_call_credentials. It provides a peer
+ * ruby object, 'mark' to minimize copying when a credential is created from
+ * ruby. */
+typedef struct grpc_rb_call_credentials {
+ /* Holder of ruby objects involved in contructing the credentials */
+ VALUE mark;
+
+ /* The actual credentials */
+ grpc_call_credentials *wrapped;
+} grpc_rb_call_credentials;
+
+typedef struct callback_params {
+ VALUE get_metadata;
+ grpc_auth_metadata_context context;
+ void *user_data;
+ grpc_credentials_plugin_metadata_cb callback;
+} callback_params;
+
+static VALUE grpc_rb_call_credentials_callback(VALUE callback_args) {
+ VALUE result = rb_hash_new();
+ VALUE metadata = rb_funcall(rb_ary_entry(callback_args, 0), rb_intern("call"),
+ 1, rb_ary_entry(callback_args, 1));
+ rb_hash_aset(result, rb_str_new2("metadata"), metadata);
+ rb_hash_aset(result, rb_str_new2("status"), INT2NUM(GRPC_STATUS_OK));
+ rb_hash_aset(result, rb_str_new2("details"), rb_str_new2(""));
+ return result;
+}
+
+static VALUE grpc_rb_call_credentials_callback_rescue(VALUE args,
+ VALUE exception_object) {
+ VALUE result = rb_hash_new();
+ rb_hash_aset(result, rb_str_new2("metadata"), Qnil);
+ /* Currently only gives the exception class name. It should be possible get
+ more details */
+ rb_hash_aset(result, rb_str_new2("status"),
+ INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
+ rb_hash_aset(result, rb_str_new2("details"),
+ rb_str_new2(rb_obj_classname(exception_object)));
+ return result;
+}
+
+static void *grpc_rb_call_credentials_callback_with_gil(void *param) {
+ callback_params *const params = (callback_params *)param;
+ VALUE auth_uri = rb_str_new_cstr(params->context.service_url);
+ /* Pass the arguments to the proc in a hash, which currently only has they key
+ 'auth_uri' */
+ VALUE callback_args = rb_ary_new();
+ VALUE args = rb_hash_new();
+ VALUE result;
+ grpc_metadata_array md_ary;
+ grpc_status_code status;
+ VALUE details;
+ char *error_details;
+ grpc_metadata_array_init(&md_ary);
+ rb_hash_aset(args, ID2SYM(rb_intern("jwt_aud_uri")), auth_uri);
+ rb_ary_push(callback_args, params->get_metadata);
+ rb_ary_push(callback_args, args);
+ result = rb_rescue(grpc_rb_call_credentials_callback, callback_args,
+ grpc_rb_call_credentials_callback_rescue, Qnil);
+ // Both callbacks return a hash, so result should be a hash
+ grpc_rb_md_ary_convert(rb_hash_aref(result, rb_str_new2("metadata")), &md_ary);
+ status = NUM2INT(rb_hash_aref(result, rb_str_new2("status")));
+ details = rb_hash_aref(result, rb_str_new2("details"));
+ error_details = StringValueCStr(details);
+ params->callback(params->user_data, md_ary.metadata, md_ary.count, status,
+ error_details);
+ grpc_metadata_array_destroy(&md_ary);
+
+ return NULL;
+}
+
+static void grpc_rb_call_credentials_plugin_get_metadata(
+ void *state, grpc_auth_metadata_context context,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data) {
+ callback_params params;
+ params.get_metadata = (VALUE)state;
+ params.context = context;
+ params.user_data = user_data;
+ params.callback = cb;
+
+ rb_thread_call_with_gvl(grpc_rb_call_credentials_callback_with_gil,
+ (void*)(&params));
+}
+
+static void grpc_rb_call_credentials_plugin_destroy(void *state) {
+ // Not sure what needs to be done here
+}
+
+/* Destroys the credentials instances. */
+static void grpc_rb_call_credentials_free(void *p) {
+ grpc_rb_call_credentials *wrapper;
+ if (p == NULL) {
+ return;
+ }
+ wrapper = (grpc_rb_call_credentials *)p;
+
+ /* Delete the wrapped object if the mark object is Qnil, which indicates that
+ * no other object is the actual owner. */
+ if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
+ grpc_call_credentials_release(wrapper->wrapped);
+ wrapper->wrapped = NULL;
+ }
+
+ xfree(p);
+}
+
+/* Protects the mark object from GC */
+static void grpc_rb_call_credentials_mark(void *p) {
+ grpc_rb_call_credentials *wrapper = NULL;
+ if (p == NULL) {
+ return;
+ }
+ wrapper = (grpc_rb_call_credentials *)p;
+
+ /* If it's not already cleaned up, mark the mark object */
+ if (wrapper->mark != Qnil) {
+ rb_gc_mark(wrapper->mark);
+ }
+}
+
+static rb_data_type_t grpc_rb_call_credentials_data_type = {
+ "grpc_call_credentials",
+ {grpc_rb_call_credentials_mark, grpc_rb_call_credentials_free,
+ GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
+ NULL,
+ NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ RUBY_TYPED_FREE_IMMEDIATELY
+#endif
+};
+
+/* Allocates CallCredentials instances.
+ Provides safe initial defaults for the instance fields. */
+static VALUE grpc_rb_call_credentials_alloc(VALUE cls) {
+ grpc_rb_call_credentials *wrapper = ALLOC(grpc_rb_call_credentials);
+ wrapper->wrapped = NULL;
+ wrapper->mark = Qnil;
+ return TypedData_Wrap_Struct(cls, &grpc_rb_call_credentials_data_type, wrapper);
+}
+
+/* Creates a wrapping object for a given call credentials. This should only be
+ * called with grpc_call_credentials objects that are not already associated
+ * with any Ruby object */
+VALUE grpc_rb_wrap_call_credentials(grpc_call_credentials *c) {
+ VALUE rb_wrapper;
+ grpc_rb_call_credentials *wrapper;
+ if (c == NULL) {
+ return Qnil;
+ }
+ rb_wrapper = grpc_rb_call_credentials_alloc(grpc_rb_cCallCredentials);
+ TypedData_Get_Struct(rb_wrapper, grpc_rb_call_credentials,
+ &grpc_rb_call_credentials_data_type, wrapper);
+ wrapper->wrapped = c;
+ return rb_wrapper;
+}
+
+/* Clones CallCredentials instances.
+ Gives CallCredentials a consistent implementation of Ruby's object copy/dup
+ protocol. */
+static VALUE grpc_rb_call_credentials_init_copy(VALUE copy, VALUE orig) {
+ grpc_rb_call_credentials *orig_cred = NULL;
+ grpc_rb_call_credentials *copy_cred = NULL;
+
+ if (copy == orig) {
+ return copy;
+ }
+
+ /* Raise an error if orig is not a credentials object or a subclass. */
+ if (TYPE(orig) != T_DATA ||
+ RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_call_credentials_free) {
+ rb_raise(rb_eTypeError, "not a %s",
+ rb_obj_classname(grpc_rb_cCallCredentials));
+ }
+
+ TypedData_Get_Struct(orig, grpc_rb_call_credentials,
+ &grpc_rb_call_credentials_data_type, orig_cred);
+ TypedData_Get_Struct(copy, grpc_rb_call_credentials,
+ &grpc_rb_call_credentials_data_type, copy_cred);
+
+ /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials
+ * wrapper object. */
+ MEMCPY(copy_cred, orig_cred, grpc_rb_call_credentials, 1);
+ return copy;
+}
+
+/* The attribute used on the mark object to hold the callback */
+static ID id_callback;
+
+/*
+ call-seq:
+ creds = Credentials.new auth_proc
+ proc: (required) Proc that generates auth metadata
+ Initializes CallCredential instances. */
+static VALUE grpc_rb_call_credentials_init(VALUE self, VALUE proc) {
+ grpc_rb_call_credentials *wrapper = NULL;
+ grpc_call_credentials *creds = NULL;
+ grpc_metadata_credentials_plugin plugin;
+
+ TypedData_Get_Struct(self, grpc_rb_call_credentials,
+ &grpc_rb_call_credentials_data_type, wrapper);
+
+ plugin.get_metadata = grpc_rb_call_credentials_plugin_get_metadata;
+ plugin.destroy = grpc_rb_call_credentials_plugin_destroy;
+ if (!rb_obj_is_proc(proc)) {
+ rb_raise(rb_eTypeError, "Argument to CallCredentials#new must be a proc");
+ return Qnil;
+ }
+ plugin.state = (void*)proc;
+ plugin.type = "";
+
+ creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+ if (creds == NULL) {
+ rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
+ return Qnil;
+ }
+
+ wrapper->wrapped = creds;
+ rb_ivar_set(self, id_callback, proc);
+
+ return self;
+}
+
+static VALUE grpc_rb_call_credentials_compose(int argc, VALUE *argv,
+ VALUE self) {
+ grpc_call_credentials *creds;
+ grpc_call_credentials *other;
+ if (argc == 0) {
+ return self;
+ }
+ creds = grpc_rb_get_wrapped_call_credentials(self);
+ for (int i = 0; i < argc; i++) {
+ other = grpc_rb_get_wrapped_call_credentials(argv[i]);
+ creds = grpc_composite_call_credentials_create(creds, other, NULL);
+ }
+ return grpc_rb_wrap_call_credentials(creds);
+}
+
+void Init_grpc_call_credentials() {
+ grpc_rb_cCallCredentials =
+ rb_define_class_under(grpc_rb_mGrpcCore, "CallCredentials", rb_cObject);
+
+ /* Allocates an object managed by the ruby runtime */
+ rb_define_alloc_func(grpc_rb_cCallCredentials,
+ grpc_rb_call_credentials_alloc);
+
+ /* Provides a ruby constructor and support for dup/clone. */
+ rb_define_method(grpc_rb_cCallCredentials, "initialize",
+ grpc_rb_call_credentials_init, 1);
+ rb_define_method(grpc_rb_cCallCredentials, "initialize_copy",
+ grpc_rb_call_credentials_init_copy, 1);
+ rb_define_method(grpc_rb_cCallCredentials, "compose",
+ grpc_rb_call_credentials_compose, -1);
+
+ id_callback = rb_intern("__callback");
+}
+
+/* Gets the wrapped grpc_call_credentials from the ruby wrapper */
+grpc_call_credentials *grpc_rb_get_wrapped_call_credentials(VALUE v) {
+ grpc_rb_call_credentials *wrapper = NULL;
+ TypedData_Get_Struct(v, grpc_rb_call_credentials,
+ &grpc_rb_call_credentials_data_type,
+ wrapper);
+ return wrapper->wrapped;
+}
diff --git a/src/core/channel/noop_filter.h b/src/ruby/ext/grpc/rb_call_credentials.h
index ded9b33117..5350a8f7ff 100644
--- a/src/core/channel/noop_filter.h
+++ b/src/ruby/ext/grpc/rb_call_credentials.h
@@ -31,14 +31,16 @@
*
*/
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H
+#ifndef GRPC_RB_CALL_CREDENTIALS_H_
+#define GRPC_RB_CALL_CREDENTIALS_H_
-#include "src/core/channel/channel_stack.h"
+#include <ruby/ruby.h>
-/* No-op filter: simply takes everything it's given, and passes it on to the
- next filter. Exists simply as a starting point that others can take and
- customize for their own filters */
-extern const grpc_channel_filter grpc_no_op_filter;
+#include <grpc/grpc_security.h>
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_NOOP_FILTER_H */
+/* Initializes the ruby CallCredentials class. */
+void Init_grpc_call_credentials();
+
+grpc_call_credentials* grpc_rb_get_wrapped_call_credentials(VALUE v);
+
+#endif /* GRPC_RB_CALL_CREDENTIALS_H_ */
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 072a6f54ab..3530081c6b 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -37,7 +37,9 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
+#include <grpc/support/log.h>
+#include "rb_call_credentials.h"
#include "rb_grpc.h"
/* grpc_rb_cChannelCredentials is the ruby class that proxies
@@ -107,6 +109,22 @@ static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) {
return TypedData_Wrap_Struct(cls, &grpc_rb_channel_credentials_data_type, wrapper);
}
+/* Creates a wrapping object for a given channel credentials. This should only
+ * be called with grpc_channel_credentials objects that are not already
+ * associated with any Ruby object. */
+VALUE grpc_rb_wrap_channel_credentials(grpc_channel_credentials *c) {
+ VALUE rb_wrapper;
+ grpc_rb_channel_credentials *wrapper;
+ if (c == NULL) {
+ return Qnil;
+ }
+ rb_wrapper = grpc_rb_channel_credentials_alloc(grpc_rb_cChannelCredentials);
+ TypedData_Get_Struct(rb_wrapper, grpc_rb_channel_credentials,
+ &grpc_rb_channel_credentials_data_type, wrapper);
+ wrapper->wrapped = c;
+ return rb_wrapper;
+}
+
/* Clones ChannelCredentials instances.
Gives ChannelCredentials a consistent implementation of Ruby's object copy/dup
protocol. */
@@ -148,11 +166,13 @@ static ID id_pem_cert_chain;
/*
call-seq:
- creds1 = Credentials.new(pem_root_certs)
+ creds1 = Credentials.new()
+ ...
+ creds2 = Credentials.new(pem_root_certs)
...
- creds2 = Credentials.new(pem_root_certs, pem_private_key,
+ creds3 = Credentials.new(pem_root_certs, pem_private_key,
pem_cert_chain)
- pem_root_certs: (required) PEM encoding of the server root certificate
+ pem_root_certs: (optional) PEM encoding of the server root certificate
pem_private_key: (optional) PEM encoding of the client's private key
pem_cert_chain: (optional) PEM encoding of the client's cert chain
Initializes Credential instances. */
@@ -163,26 +183,23 @@ static VALUE grpc_rb_channel_credentials_init(int argc, VALUE *argv, VALUE self)
grpc_rb_channel_credentials *wrapper = NULL;
grpc_channel_credentials *creds = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair;
+ const char *pem_root_certs_cstr = NULL;
MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1);
- /* TODO: Remove mandatory arg when we support default roots. */
- /* "12" == 1 mandatory arg, 2 (credentials) is optional */
- rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key,
+ /* "03" == no mandatory arg, 3 optional */
+ rb_scan_args(argc, argv, "03", &pem_root_certs, &pem_private_key,
&pem_cert_chain);
TypedData_Get_Struct(self, grpc_rb_channel_credentials,
&grpc_rb_channel_credentials_data_type, wrapper);
- if (pem_root_certs == Qnil) {
- rb_raise(rb_eRuntimeError,
- "could not create a credential: nil pem_root_certs");
- return Qnil;
+ if (pem_root_certs != Qnil) {
+ pem_root_certs_cstr = RSTRING_PTR(pem_root_certs);
}
if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
- creds =
- grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL, NULL);
+ creds = grpc_ssl_credentials_create(pem_root_certs_cstr, NULL, NULL);
} else {
key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
- creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs),
+ creds = grpc_ssl_credentials_create(pem_root_certs_cstr,
&key_cert_pair, NULL);
}
if (creds == NULL) {
@@ -199,6 +216,25 @@ static VALUE grpc_rb_channel_credentials_init(int argc, VALUE *argv, VALUE self)
return self;
}
+static VALUE grpc_rb_channel_credentials_compose(int argc, VALUE *argv,
+ VALUE self) {
+ grpc_channel_credentials *creds;
+ grpc_call_credentials *other;
+ if (argc == 0) {
+ return self;
+ }
+ creds = grpc_rb_get_wrapped_channel_credentials(self);
+ for (int i = 0; i < argc; i++) {
+ other = grpc_rb_get_wrapped_call_credentials(argv[i]);
+ creds = grpc_composite_channel_credentials_create(creds, other, NULL);
+ if (creds == NULL) {
+ rb_raise(rb_eRuntimeError,
+ "Failed to compose channel and call credentials");
+ }
+ }
+ return grpc_rb_wrap_channel_credentials(creds);
+}
+
void Init_grpc_channel_credentials() {
grpc_rb_cChannelCredentials =
rb_define_class_under(grpc_rb_mGrpcCore, "ChannelCredentials", rb_cObject);
@@ -212,6 +248,8 @@ void Init_grpc_channel_credentials() {
grpc_rb_channel_credentials_init, -1);
rb_define_method(grpc_rb_cChannelCredentials, "initialize_copy",
grpc_rb_channel_credentials_init_copy, 1);
+ rb_define_method(grpc_rb_cChannelCredentials, "compose",
+ grpc_rb_channel_credentials_compose, -1);
id_pem_cert_chain = rb_intern("__pem_cert_chain");
id_pem_private_key = rb_intern("__pem_private_key");
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 7c7c2d3440..a752a5f879 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -41,6 +41,7 @@
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#include "rb_call.h"
+#include "rb_call_credentials.h"
#include "rb_channel.h"
#include "rb_channel_credentials.h"
#include "rb_completion_queue.h"
@@ -91,7 +92,7 @@ static ID id_tv_sec;
static ID id_tv_nsec;
/**
- * grpc_rb_time_timeval creates a time_eval from a ruby time object.
+ * grpc_rb_time_timeval creates a timeval from a ruby time object.
*
* This func is copied from ruby source, MRI/source/time.c, which is published
* under the same license as the ruby.h, on which the entire extensions is
@@ -137,7 +138,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
d += 1;
f -= 1;
}
- t.tv_sec = (time_t)f;
+ t.tv_sec = (gpr_int64)f;
if (f != t.tv_sec) {
rb_raise(rb_eRangeError, "%f out of Time range",
RFLOAT_VALUE(time));
@@ -318,6 +319,7 @@ void Init_grpc() {
Init_grpc_channel();
Init_grpc_completion_queue();
Init_grpc_call();
+ Init_grpc_call_credentials();
Init_grpc_channel_credentials();
Init_grpc_server();
Init_grpc_server_credentials();
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 61cf18cf54..363abe9a46 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'rake-compiler', '~> 0.9'
s.add_development_dependency 'rspec', '~> 3.2'
s.add_development_dependency 'rubocop', '~> 0.30.0'
+ s.add_development_dependency 'signet', '~>0.6.0'
s.extensions = %w(ext/grpc/extconf.rb)
end
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 90aaa026ec..13100a614c 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -57,21 +57,6 @@ module GRPC
Core::Channel.new(host, kw, creds)
end
- def self.update_with_jwt_aud_uri(a_hash, host, method)
- last_slash_idx, res = method.rindex('/'), a_hash.clone
- return res if last_slash_idx.nil?
- service_name = method[0..(last_slash_idx - 1)]
- res[:jwt_aud_uri] = "https://#{host}#{service_name}"
- res
- end
-
- # check_update_metadata is used by #initialize verify that it's a Proc.
- def self.check_update_metadata(update_metadata)
- return update_metadata if update_metadata.nil?
- fail(TypeError, '!is_a?Proc') unless update_metadata.is_a?(Proc)
- update_metadata
- end
-
# Allows users of the stub to modify the propagate mask.
#
# This is an advanced feature for use when making calls to another gRPC
@@ -99,29 +84,21 @@ module GRPC
# - :timeout
# when present, this is the default timeout used for calls
#
- # - :update_metadata
- # when present, this a func that takes a hash and returns a hash
- # it can be used to update metadata, i.e, remove, or amend
- # metadata values.
- #
# @param host [String] the host the stub connects to
# @param q [Core::CompletionQueue] used to wait for events
# @param channel_override [Core::Channel] a pre-created channel
# @param timeout [Number] the default timeout to use in requests
# @param creds [Core::ChannelCredentials] the channel credentials
- # @param update_metadata a func that updates metadata as described above
# @param kw [KeywordArgs]the channel arguments
def initialize(host, q,
channel_override: nil,
timeout: nil,
creds: nil,
propagate_mask: nil,
- update_metadata: nil,
**kw)
fail(TypeError, '!CompletionQueue') unless q.is_a?(Core::CompletionQueue)
@queue = q
@ch = ClientStub.setup_channel(channel_override, host, creds, **kw)
- @update_metadata = ClientStub.check_update_metadata(update_metadata)
alt_host = kw[Core::Channel::SSL_TARGET]
@host = alt_host.nil? ? host : alt_host
@propagate_mask = propagate_mask
@@ -166,6 +143,8 @@ module GRPC
# @param deadline [Time] (optional) the time the request should complete
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
+ # @param credentials [Core::CallCredentials] credentials to use when making
+ # the call
# @param return_op [true|false] return an Operation if true
# @return [Object] the response received from the server
def request_response(method, req, marshal, unmarshal,
@@ -173,19 +152,20 @@ module GRPC
timeout: nil,
return_op: false,
parent: nil,
+ credentials: nil,
**kw)
c = new_active_call(method, marshal, unmarshal,
deadline: deadline,
timeout: timeout,
- parent: parent)
- md = update_metadata(kw, method)
- return c.request_response(req, **md) unless return_op
+ parent: parent,
+ credentials: credentials)
+ return c.request_response(req, **kw) unless return_op
# return the operation view of the active_call; define #execute as a
# new method for this instance that invokes #request_response.
op = c.operation
op.define_singleton_method(:execute) do
- c.request_response(req, **md)
+ c.request_response(req, **kw)
end
op
end
@@ -234,25 +214,28 @@ module GRPC
# @param return_op [true|false] return an Operation if true
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
+ # @param credentials [Core::CallCredentials] credentials to use when making
+ # the call
# @return [Object|Operation] the response received from the server
def client_streamer(method, requests, marshal, unmarshal,
deadline: nil,
timeout: nil,
return_op: false,
parent: nil,
+ credentials: nil,
**kw)
c = new_active_call(method, marshal, unmarshal,
deadline: deadline,
timeout: timeout,
- parent: parent)
- md = update_metadata(kw, method)
- return c.client_streamer(requests, **md) unless return_op
+ parent: parent,
+ credentials: credentials)
+ return c.client_streamer(requests, **kw) unless return_op
# return the operation view of the active_call; define #execute as a
# new method for this instance that invokes #client_streamer.
op = c.operation
op.define_singleton_method(:execute) do
- c.client_streamer(requests, **md)
+ c.client_streamer(requests, **kw)
end
op
end
@@ -309,6 +292,8 @@ module GRPC
# @param return_op [true|false]return an Operation if true
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
+ # @param credentials [Core::CallCredentials] credentials to use when making
+ # the call
# @param blk [Block] when provided, is executed for each response
# @return [Enumerator|Operation|nil] as discussed above
def server_streamer(method, req, marshal, unmarshal,
@@ -316,20 +301,21 @@ module GRPC
timeout: nil,
return_op: false,
parent: nil,
+ credentials: nil,
**kw,
&blk)
c = new_active_call(method, marshal, unmarshal,
deadline: deadline,
timeout: timeout,
- parent: parent)
- md = update_metadata(kw, method)
- return c.server_streamer(req, **md, &blk) unless return_op
+ parent: parent,
+ credentials: credentials)
+ return c.server_streamer(req, **kw, &blk) unless return_op
# return the operation view of the active_call; define #execute
# as a new method for this instance that invokes #server_streamer
op = c.operation
op.define_singleton_method(:execute) do
- c.server_streamer(req, **md, &blk)
+ c.server_streamer(req, **kw, &blk)
end
op
end
@@ -424,6 +410,8 @@ module GRPC
# @param deadline [Time] (optional) the time the request should complete
# @param parent [Core::Call] a prior call whose reserved metadata
# will be propagated by this one.
+ # @param credentials [Core::CallCredentials] credentials to use when making
+ # the call
# @param return_op [true|false] return an Operation if true
# @param blk [Block] when provided, is executed for each response
# @return [Enumerator|nil|Operation] as discussed above
@@ -432,36 +420,28 @@ module GRPC
timeout: nil,
return_op: false,
parent: nil,
+ credentials: nil,
**kw,
&blk)
c = new_active_call(method, marshal, unmarshal,
deadline: deadline,
timeout: timeout,
- parent: parent)
- md = update_metadata(kw, method)
- return c.bidi_streamer(requests, **md, &blk) unless return_op
+ parent: parent,
+ credentials: credentials)
+
+ return c.bidi_streamer(requests, **kw, &blk) unless return_op
# return the operation view of the active_call; define #execute
# as a new method for this instance that invokes #bidi_streamer
op = c.operation
op.define_singleton_method(:execute) do
- c.bidi_streamer(requests, **md, &blk)
+ c.bidi_streamer(requests, **kw, &blk)
end
op
end
private
- def update_metadata(kw, method)
- return kw if @update_metadata.nil?
- just_jwt_uri = self.class.update_with_jwt_aud_uri({}, @host, method)
- updated = @update_metadata.call(just_jwt_uri)
-
- # keys should be lowercase
- updated = Hash[updated.each_pair.map { |k, v| [k.downcase, v] }]
- kw.merge(updated)
- end
-
# Creates a new active stub
#
# @param method [string] the method being called.
@@ -473,7 +453,8 @@ module GRPC
def new_active_call(method, marshal, unmarshal,
deadline: nil,
timeout: nil,
- parent: nil)
+ parent: nil,
+ credentials: nil)
if deadline.nil?
deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
end
@@ -483,6 +464,7 @@ module GRPC
method,
nil, # host use nil,
deadline)
+ call.set_credentials credentials unless credentials.nil?
ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false)
end
end
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 0e318bd53b..410156ff03 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -48,6 +48,8 @@ module GRPC
return false
when 'TERM'
return false
+ when nil
+ return true
end
end
true
diff --git a/src/ruby/pb/README.md b/src/ruby/pb/README.md
index 84644e1098..e04aef185c 100644
--- a/src/ruby/pb/README.md
+++ b/src/ruby/pb/README.md
@@ -20,7 +20,7 @@ re-generate the surface.
```bash
$ # (from this directory)
-$ protoc -I . grpc/health/v1alpha/health.proto \
+$ protoc -I ../../proto ../../proto/grpc/health/v1alpha/health.proto \
--grpc_out=. \
--ruby_out=. \
--plugin=protoc-gen-grpc=`which grpc_ruby_plugin`
diff --git a/src/ruby/pb/generate_proto_ruby.sh b/src/ruby/pb/generate_proto_ruby.sh
new file mode 100755
index 0000000000..576b1c08d3
--- /dev/null
+++ b/src/ruby/pb/generate_proto_ruby.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# 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.
+
+# Regenerates gRPC service stubs from proto files.
+set +e
+cd $(dirname $0)/../../..
+
+PROTOC=bins/opt/protobuf/protoc
+PLUGIN=protoc-gen-grpc=bins/opt/grpc_ruby_plugin
+
+$PROTOC -I src/proto src/proto/grpc/health/v1alpha/health.proto \
+ --grpc_out=src/ruby/pb \
+ --ruby_out=src/ruby/pb \
+ --plugin=$PLUGIN
+
+$PROTOC -I . test/proto/{messages,test,empty}.proto \
+ --grpc_out=src/ruby/pb \
+ --ruby_out=src/ruby/pb \
+ --plugin=$PLUGIN
+
+$PROTOC -I src/proto/math src/proto/math/math.proto \
+ --grpc_out=src/ruby/bin \
+ --ruby_out=src/ruby/bin \
+ --plugin=$PLUGIN
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 30550d6cc0..6cc616e5cb 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -93,13 +93,6 @@ def load_test_certs
files.map { |f| File.open(File.join(data_dir, f)).read }
end
-# loads the certificates used to access the test server securely.
-def load_prod_cert
- fail 'could not find a production cert' if ENV['SSL_CERT_FILE'].nil?
- GRPC.logger.info("loading prod certs from #{ENV['SSL_CERT_FILE']}")
- File.open(ENV['SSL_CERT_FILE']).read
-end
-
# creates SSL Credentials from the test certificates.
def test_creds
certs = load_test_certs
@@ -108,8 +101,7 @@ end
# creates SSL Credentials from the production certificates.
def prod_creds
- cert_text = load_prod_cert
- GRPC::Core::ChannelCredentials.new(cert_text)
+ GRPC::Core::ChannelCredentials.new()
end
# creates the SSL Credentials.
@@ -132,7 +124,8 @@ def create_stub(opts)
if wants_creds.include?(opts.test_case)
unless opts.oauth_scope.nil?
auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
- stub_opts[:update_metadata] = auth_creds.updater_proc
+ call_creds = GRPC::Core::CallCredentials.new(auth_creds.updater_proc)
+ stub_opts[:creds] = stub_opts[:creds].compose call_creds
end
end
@@ -141,12 +134,14 @@ def create_stub(opts)
kw = auth_creds.updater_proc.call({}) # gives as an auth token
# use a metadata update proc that just adds the auth token.
- stub_opts[:update_metadata] = proc { |md| md.merge(kw) }
+ call_creds = GRPC::Core::CallCredentials.new(proc { |md| md.merge(kw) })
+ stub_opts[:creds] = stub_opts[:creds].compose call_creds
end
if opts.test_case == 'jwt_token_creds' # don't use a scope
auth_creds = Google::Auth.get_application_default
- stub_opts[:update_metadata] = auth_creds.updater_proc
+ call_creds = GRPC::Core::CallCredentials.new(auth_creds.updater_proc)
+ stub_opts[:creds] = stub_opts[:creds].compose call_creds
end
GRPC.logger.info("... connecting securely to #{address}")
@@ -160,7 +155,7 @@ end
# produces a string of null chars (\0) of length l.
def nulls(l)
fail 'requires #{l} to be +ve' if l < 0
- [].pack('x' * l).force_encoding('utf-8')
+ [].pack('x' * l).force_encoding('ascii-8bit')
end
# a PingPongPlayer implements the ping pong bidi test.
diff --git a/src/ruby/pb/test/proto/messages.rb b/src/ruby/pb/test/proto/messages.rb
index 9b7f977285..5222c9824a 100644
--- a/src/ruby/pb/test/proto/messages.rb
+++ b/src/ruby/pb/test/proto/messages.rb
@@ -6,7 +6,7 @@ require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "grpc.testing.Payload" do
optional :type, :enum, 1, "grpc.testing.PayloadType"
- optional :body, :string, 2
+ optional :body, :bytes, 2
end
add_message "grpc.testing.EchoStatus" do
optional :code, :int32, 1
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 67877a191f..851e815222 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -126,7 +126,7 @@ end
# produces a string of null chars (\0) of length l.
def nulls(l)
fail 'requires #{l} to be +ve' if l < 0
- [].pack('x' * l).force_encoding('utf-8')
+ [].pack('x' * l).force_encoding('ascii-8bit')
end
# A EnumeratorQueue wraps a Queue yielding the items added to it via each_item.
diff --git a/src/python/grpcio_test/setup.py b/src/ruby/spec/call_credentials_spec.rb
index e9ee45a92a..32a0ad44b7 100644
--- a/src/python/grpcio_test/setup.py
+++ b/src/ruby/spec/call_credentials_spec.rb
@@ -27,68 +27,31 @@
# (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 setup module for the GRPC Python interop testing package."""
-
-import os
-import os.path
-
-import setuptools
-
-# Ensure we're in the proper directory whether or not we're being used by pip.
-os.chdir(os.path.dirname(os.path.abspath(__file__)))
-
-# Break import-style to ensure we can actually find our commands module.
-import commands
-
-_PACKAGES = setuptools.find_packages('.')
-
-_PACKAGE_DIRECTORIES = {
- '': '.',
-}
-
-_PACKAGE_DATA = {
- 'grpc_interop': [
- 'credentials/ca.pem',
- 'credentials/server1.key',
- 'credentials/server1.pem',
- ],
- 'grpc_protoc_plugin': [
- 'test.proto',
- ],
- 'grpc_test': [
- 'credentials/ca.pem',
- 'credentials/server1.key',
- 'credentials/server1.pem',
- ],
-}
-
-_SETUP_REQUIRES = (
- 'pytest>=2.6',
- 'pytest-cov>=2.0',
- 'pytest-xdist>=1.11',
- 'pytest-timeout>=0.5',
-)
-
-_INSTALL_REQUIRES = (
- 'oauth2client>=1.4.7',
- 'grpcio>=0.11.0b0',
- # TODO(issue 3321): Unpin protobuf dependency.
- 'protobuf==3.0.0a3',
-)
-
-_COMMAND_CLASS = {
- 'test': commands.RunTests,
- 'build_proto_modules': commands.BuildProtoModules,
- 'build_py': commands.BuildPy,
-}
-
-setuptools.setup(
- name='grpcio_test',
- version='0.11.0b0',
- packages=_PACKAGES,
- package_dir=_PACKAGE_DIRECTORIES,
- package_data=_PACKAGE_DATA,
- install_requires=_INSTALL_REQUIRES + _SETUP_REQUIRES,
- setup_requires=_SETUP_REQUIRES,
- cmdclass=_COMMAND_CLASS,
-)
+require 'grpc'
+
+describe GRPC::Core::CallCredentials do
+ CallCredentials = GRPC::Core::CallCredentials
+
+ let(:auth_proc) { proc { { 'plugin_key' => 'plugin_value' } } }
+
+ describe '#new' do
+ it 'can successfully create a CallCredentials from a proc' do
+ expect { CallCredentials.new(auth_proc) }.not_to raise_error
+ end
+ end
+
+ describe '#compose' do
+ it 'can compose with another CallCredentials' do
+ creds1 = CallCredentials.new(auth_proc)
+ creds2 = CallCredentials.new(auth_proc)
+ expect { creds1.compose creds2 }.not_to raise_error
+ end
+
+ it 'can compose with multiple CallCredentials' do
+ creds1 = CallCredentials.new(auth_proc)
+ creds2 = CallCredentials.new(auth_proc)
+ creds3 = CallCredentials.new(auth_proc)
+ expect { creds1.compose(creds2, creds3) }.not_to raise_error
+ end
+ end
+end
diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb
index dd3c45f754..6629570fba 100644
--- a/src/ruby/spec/call_spec.rb
+++ b/src/ruby/spec/call_spec.rb
@@ -144,6 +144,15 @@ describe GRPC::Core::Call do
end
end
+ describe '#set_credentials!' do
+ it 'can set a valid CallCredentials object' do
+ call = make_test_call
+ auth_proc = proc { { 'plugin_key' => 'plugin_value' } }
+ creds = GRPC::Core::CallCredentials.new auth_proc
+ expect { call.set_credentials! creds }.not_to raise_error
+ end
+ end
+
def make_test_call
@ch.create_call(client_queue, nil, nil, 'dummy_method', nil, deadline)
end
diff --git a/src/ruby/spec/channel_credentials_spec.rb b/src/ruby/spec/channel_credentials_spec.rb
index b2bdf7032e..0bcfc752a0 100644
--- a/src/ruby/spec/channel_credentials_spec.rb
+++ b/src/ruby/spec/channel_credentials_spec.rb
@@ -31,6 +31,7 @@ require 'grpc'
describe GRPC::Core::ChannelCredentials do
ChannelCredentials = GRPC::Core::ChannelCredentials
+ CallCredentials = GRPC::Core::CallCredentials
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
@@ -54,10 +55,43 @@ describe GRPC::Core::ChannelCredentials do
expect { ChannelCredentials.new(root_cert) }.not_to raise_error
end
- it 'cannot be constructed with a nil server roots' do
+ it 'can be constructed with a nil server roots' do
_, client_key, client_chain = load_test_certs
blk = proc { ChannelCredentials.new(nil, client_key, client_chain) }
- expect(&blk).to raise_error
+ expect(&blk).not_to raise_error
+ end
+
+ it 'can be constructed with no params' do
+ blk = proc { ChannelCredentials.new(nil) }
+ expect(&blk).not_to raise_error
+ end
+ end
+
+ describe '#compose' do
+ it 'can compose with a CallCredentials' do
+ certs = load_test_certs
+ channel_creds = ChannelCredentials.new(*certs)
+ auth_proc = proc { { 'plugin_key' => 'plugin_value' } }
+ call_creds = CallCredentials.new auth_proc
+ expect { channel_creds.compose call_creds }.not_to raise_error
+ end
+
+ it 'can compose with multiple CallCredentials' do
+ certs = load_test_certs
+ channel_creds = ChannelCredentials.new(*certs)
+ auth_proc = proc { { 'plugin_key' => 'plugin_value' } }
+ call_creds1 = CallCredentials.new auth_proc
+ call_creds2 = CallCredentials.new auth_proc
+ expect do
+ channel_creds.compose(call_creds1, call_creds2)
+ end.not_to raise_error
+ end
+
+ it 'cannot compose with ChannelCredentials' do
+ certs = load_test_certs
+ channel_creds1 = ChannelCredentials.new(*certs)
+ channel_creds2 = ChannelCredentials.new(*certs)
+ expect { channel_creds1.compose channel_creds2 }.to raise_error(TypeError)
end
end
end
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 734f176e94..7cce2076c9 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -413,6 +413,8 @@ describe 'the http client/server' do
end
describe 'the secure http client/server' do
+ include_context 'setup: tags'
+
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
files = ['ca.pem', 'server1.key', 'server1.pem']
@@ -443,4 +445,31 @@ describe 'the secure http client/server' do
it_behaves_like 'GRPC metadata delivery works OK' do
end
+
+ it 'modifies metadata with CallCredentials' do
+ auth_proc = proc { { 'k1' => 'updated-v1' } }
+ call_creds = GRPC::Core::CallCredentials.new(auth_proc)
+ md = { 'k2' => 'v2' }
+ expected_md = { 'k1' => 'updated-v1', 'k2' => 'v2' }
+ recvd_rpc = nil
+ rcv_thread = Thread.new do
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ end
+
+ call = new_client_call
+ call.set_credentials! call_creds
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => md
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+
+ # confirm the server can receive the client metadata
+ rcv_thread.join
+ expect(recvd_rpc).to_not eq nil
+ recvd_md = recvd_rpc.metadata
+ replace_symbols = Hash[expected_md.each_pair.collect { |x, y| [x.to_s, y] }]
+ expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
+ end
end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index da5bc6c9e5..40550230dd 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -145,34 +145,6 @@ describe 'ClientStub' do
th.join
end
- it 'should update the sent metadata with a provided metadata updater' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
- th = run_request_response(@sent_msg, @resp, @pass,
- k1: 'updated-v1', k2: 'v2')
- update_md = proc do |md|
- md[:k1] = 'updated-v1'
- md
- end
- stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
- expect(get_response(stub)).to eq(@resp)
- th.join
- end
-
- it 'should downcase the keys provided by the metadata updater' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
- th = run_request_response(@sent_msg, @resp, @pass,
- k1: 'downcased-key-v1', k2: 'v2')
- update_md = proc do |md|
- md[:K1] = 'downcased-key-v1'
- md
- end
- stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
- expect(get_response(stub)).to eq(@resp)
- th.join
- end
-
it 'should send a request when configured using an override channel' do
server_port = create_test_server
alt_host = "localhost:#{server_port}"
@@ -241,20 +213,6 @@ describe 'ClientStub' do
th.join
end
- it 'should update the sent metadata with a provided metadata updater' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
- th = run_client_streamer(@sent_msgs, @resp, @pass,
- k1: 'updated-v1', k2: 'v2')
- update_md = proc do |md|
- md[:k1] = 'updated-v1'
- md
- end
- stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
- expect(get_response(stub)).to eq(@resp)
- th.join
- end
-
it 'should raise an error if the status is not ok' do
server_port = create_test_server
host = "localhost:#{server_port}"
@@ -323,21 +281,6 @@ describe 'ClientStub' do
expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
th.join
end
-
- it 'should update the sent metadata with a provided metadata updater' do
- server_port = create_test_server
- host = "localhost:#{server_port}"
- th = run_server_streamer(@sent_msg, @replys, @pass,
- k1: 'updated-v1', k2: 'v2')
- update_md = proc do |md|
- md[:k1] = 'updated-v1'
- md
- end
- stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
- e = get_responses(stub)
- expect(e.collect { |r| r }).to eq(@replys)
- th.join
- end
end
describe 'without a call operation' do
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index efe07f734e..d95a021311 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -422,25 +422,6 @@ describe GRPC::RpcServer do
t.join
end
- it 'should receive updated metadata', server: true do
- service = EchoService.new
- @srv.handle(service)
- t = Thread.new { @srv.run }
- @srv.wait_till_running
- req = EchoMsg.new
- client_opts[:update_metadata] = proc do |md|
- md[:k1] = 'updated-v1'
- md
- end
- stub = EchoStub.new(@host, **client_opts)
- expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
- wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2',
- 'jwt_aud_uri' => "https://#{@host}/EchoService" }]
- check_md(wanted_md, service.received_md)
- @srv.stop
- t.join
- end
-
it 'should handle multiple parallel requests', server: true do
@srv.handle(EchoService)
t = Thread.new { @srv.run }