aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2015-09-10 11:46:52 -0700
committerGravatar Craig Tiller <ctiller@google.com>2015-09-10 11:46:52 -0700
commitbe947697d7c5edb1f67c9df5ef024e3eaf98e9e6 (patch)
tree774f0d333b48de97236fdb3e9382765a575a75ce /src
parent3121fd4d757991e7ef95a7b6b370b83c23ba61b6 (diff)
parent374cd9b0abbcd0dc3f1e65777e0dd37a9d5c447f (diff)
Merge github.com:grpc/grpc into immolating-conversion
Diffstat (limited to 'src')
-rw-r--r--src/compiler/csharp_generator.cc62
-rw-r--r--src/compiler/csharp_generator.h2
-rw-r--r--src/compiler/python_generator.cc314
-rw-r--r--src/compiler/python_generator.h3
-rw-r--r--src/compiler/python_plugin.cc3
-rw-r--r--src/core/census/aggregation.h66
-rw-r--r--src/core/census/context.c13
-rw-r--r--src/core/census/grpc_context.c15
-rw-r--r--src/core/census/grpc_filter.c33
-rw-r--r--src/core/census/grpc_filter.h6
-rw-r--r--src/core/census/operation.c63
-rw-r--r--src/core/census/rpc_metric_id.h51
-rw-r--r--src/core/census/tracing.c (renamed from src/core/census/rpc_stat_id.h)21
-rw-r--r--src/core/channel/http_client_filter.c18
-rw-r--r--src/core/httpcli/httpcli.c95
-rw-r--r--src/core/iomgr/endpoint.c17
-rw-r--r--src/core/iomgr/endpoint.h63
-rw-r--r--src/core/iomgr/iocp_windows.c21
-rw-r--r--src/core/iomgr/iocp_windows.h1
-rw-r--r--src/core/iomgr/iomgr.c26
-rw-r--r--src/core/iomgr/pollset_multipoller_with_epoll.c1
-rw-r--r--src/core/iomgr/socket_windows.c56
-rw-r--r--src/core/iomgr/socket_windows.h16
-rw-r--r--src/core/iomgr/tcp_client_windows.c46
-rw-r--r--src/core/iomgr/tcp_posix.c525
-rw-r--r--src/core/iomgr/tcp_server_windows.c79
-rw-r--r--src/core/iomgr/tcp_windows.c262
-rw-r--r--src/core/security/client_auth_filter.c3
-rw-r--r--src/core/security/credentials.c222
-rw-r--r--src/core/security/credentials.h29
-rw-r--r--src/core/security/google_default_credentials.c6
-rw-r--r--src/core/security/secure_endpoint.c188
-rw-r--r--src/core/security/secure_transport_setup.c119
-rw-r--r--src/core/security/security_context.c13
-rw-r--r--src/core/security/server_auth_filter.c19
-rw-r--r--src/core/security/server_secure_chttp2.c9
-rw-r--r--src/core/support/log_win32.c10
-rw-r--r--src/core/support/slice_buffer.c22
-rw-r--r--src/core/support/sync_win32.c4
-rw-r--r--src/core/surface/call.c28
-rw-r--r--src/core/surface/completion_queue.h2
-rw-r--r--src/core/surface/secure_channel_create.c4
-rw-r--r--src/core/surface/version.c2
-rw-r--r--src/core/transport/chttp2/internal.h15
-rw-r--r--src/core/transport/chttp2/stream_lists.c44
-rw-r--r--src/core/transport/chttp2/writing.c28
-rw-r--r--src/core/transport/chttp2_transport.c202
-rw-r--r--src/core/transport/metadata.c2
-rw-r--r--src/cpp/client/channel.cc2
-rw-r--r--src/cpp/client/client_context.cc2
-rw-r--r--src/cpp/client/create_channel.cc7
-rw-r--r--src/cpp/client/credentials.cc2
-rw-r--r--src/cpp/client/insecure_credentials.cc2
-rw-r--r--src/cpp/client/secure_credentials.cc45
-rw-r--r--src/cpp/client/secure_credentials.h2
-rw-r--r--src/cpp/common/auth_property_iterator.cc8
-rw-r--r--src/cpp/common/create_auth_context.h2
-rw-r--r--src/cpp/common/insecure_create_auth_context.cc2
-rw-r--r--src/cpp/common/secure_auth_context.cc42
-rw-r--r--src/cpp/common/secure_auth_context.h19
-rw-r--r--src/cpp/common/secure_create_auth_context.cc4
-rw-r--r--src/cpp/server/insecure_server_credentials.cc8
-rw-r--r--src/cpp/server/secure_server_credentials.cc85
-rw-r--r--src/cpp/server/secure_server_credentials.h32
-rw-r--r--src/cpp/server/server.cc6
-rw-r--r--src/cpp/server/server_builder.cc3
-rw-r--r--src/cpp/server/server_credentials.cc2
-rw-r--r--src/cpp/util/byte_buffer.cc6
-rw-r--r--src/cpp/util/string_ref.cc3
-rw-r--r--src/csharp/.gitignore3
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj1
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs176
-rw-r--r--src/csharp/Grpc.Core.Tests/MetadataTest.cs11
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs80
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec13
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs17
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs50
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs5
-rw-r--r--src/csharp/Grpc.Core/Marshaller.cs2
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs8
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs2
-rw-r--r--src/csharp/Grpc.Examples.MathServer/MathServer.cs2
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj7
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs26
-rw-r--r--src/csharp/Grpc.Examples.Tests/packages.config2
-rw-r--r--src/csharp/Grpc.Examples/Grpc.Examples.csproj7
-rw-r--r--src/csharp/Grpc.Examples/Math.cs1651
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs28
-rw-r--r--src/csharp/Grpc.Examples/MathGrpc.cs72
-rw-r--r--src/csharp/Grpc.Examples/MathServiceImpl.cs10
-rw-r--r--src/csharp/Grpc.Examples/packages.config2
-rw-r--r--src/csharp/Grpc.Examples/proto/math.proto16
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj8
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs4
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/packages.config2
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj8
-rw-r--r--src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec2
-rw-r--r--src/csharp/Grpc.HealthCheck/Health.cs716
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthGrpc.cs10
-rw-r--r--src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs6
-rw-r--r--src/csharp/Grpc.HealthCheck/packages.config2
-rw-r--r--src/csharp/Grpc.HealthCheck/proto/health.proto8
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Empty.cs284
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj19
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs365
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs85
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs3205
-rw-r--r--src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Test.cs48
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs110
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs23
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/empty.proto2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/messages.proto36
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/test.proto2
-rw-r--r--src/csharp/Grpc.Tools.nuspec7
-rw-r--r--src/csharp/README.md23
-rw-r--r--src/csharp/build_packages.bat12
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c8
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh8
-rw-r--r--src/node/README.md8
-rw-r--r--src/node/examples/route_guide.proto120
-rw-r--r--src/node/examples/route_guide_client.js240
-rw-r--r--src/node/examples/route_guide_db.json601
-rw-r--r--src/node/examples/route_guide_server.js255
-rw-r--r--src/node/ext/call.cc46
-rw-r--r--src/node/ext/call.h1
-rw-r--r--src/node/ext/channel.cc2
-rw-r--r--src/node/ext/credentials.cc11
-rw-r--r--src/node/ext/server.cc51
-rw-r--r--src/node/ext/server.h3
-rw-r--r--src/node/ext/server_credentials.cc7
-rw-r--r--src/node/index.js25
-rw-r--r--src/node/interop/interop_client.js18
-rw-r--r--src/node/package.json2
-rw-r--r--src/node/src/client.js234
-rw-r--r--src/node/src/metadata.js181
-rw-r--r--src/node/src/server.js86
-rw-r--r--src/node/test/call_test.js2
-rw-r--r--src/node/test/end_to_end_test.js2
-rw-r--r--src/node/test/health_test.js2
-rw-r--r--src/node/test/interop_sanity_test.js2
-rw-r--r--src/node/test/math_client_test.js2
-rw-r--r--src/node/test/metadata_test.js193
-rw-r--r--src/node/test/server_test.js31
-rw-r--r--src/node/test/surface_test.js113
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h107
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m21
-rw-r--r--src/objective-c/GRPCClient/private/GRPCHost.m5
-rw-r--r--src/objective-c/GRPCClient/private/GRPCRequestHeaders.h52
-rw-r--r--src/objective-c/GRPCClient/private/GRPCRequestHeaders.m119
-rw-r--r--src/objective-c/GRPCClient/private/GRPCSecureChannel.m7
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.h3
-rw-r--r--src/objective-c/GRPCClient/private/GRPCWrappedCall.m2
-rw-r--r--src/objective-c/GRPCClient/private/NSDictionary+GRPC.m47
-rw-r--r--src/objective-c/GRPCClient/private/NSError+GRPC.h23
-rw-r--r--src/objective-c/ProtoRPC/ProtoRPC.m33
-rw-r--r--src/objective-c/README.md2
-rw-r--r--src/objective-c/examples/RemoteTestClient/RemoteTest.podspec28
-rw-r--r--src/objective-c/examples/RemoteTestClient/empty.proto44
-rw-r--r--src/objective-c/examples/RemoteTestClient/messages.proto133
-rw-r--r--src/objective-c/examples/RemoteTestClient/test.proto73
-rw-r--r--src/objective-c/examples/SwiftSample/AppDelegate.swift (renamed from src/core/census/record_stat.c)9
-rw-r--r--src/objective-c/examples/SwiftSample/Base.lproj/Main.storyboard25
-rw-r--r--src/objective-c/examples/SwiftSample/Bridging-Header.h45
-rw-r--r--src/objective-c/examples/SwiftSample/Images.xcassets/AppIcon.appiconset/Contents.json68
-rw-r--r--src/objective-c/examples/SwiftSample/Info.plist47
-rw-r--r--src/objective-c/examples/SwiftSample/Podfile9
-rw-r--r--src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj354
-rw-r--r--src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--src/objective-c/examples/SwiftSample/ViewController.swift99
-rw-r--r--src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto2
-rw-r--r--src/objective-c/tests/LocalClearTextTests.m4
-rw-r--r--src/php/README.md23
-rw-r--r--src/php/composer.json2
-rw-r--r--src/php/ext/grpc/README.md23
-rw-r--r--src/php/ext/grpc/call.c27
-rw-r--r--src/php/ext/grpc/channel.c2
-rw-r--r--src/php/ext/grpc/credentials.c6
-rw-r--r--src/php/ext/grpc/package.xml57
-rw-r--r--src/php/ext/grpc/server_credentials.c2
-rw-r--r--src/php/lib/Grpc/AbstractCall.php2
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php13
-rw-r--r--src/php/lib/Grpc/BidiStreamingCall.php14
-rw-r--r--src/php/lib/Grpc/ClientStreamingCall.php23
-rw-r--r--src/php/lib/Grpc/ServerStreamingCall.php16
-rw-r--r--src/php/lib/Grpc/UnaryCall.php14
-rw-r--r--src/php/tests/generated_code/AbstractGeneratedCodeTest.php30
-rwxr-xr-xsrc/php/tests/interop/interop_client.php29
-rwxr-xr-xsrc/php/tests/unit_tests/EndToEndTest.php49
-rwxr-xr-xsrc/php/tests/unit_tests/SecureEndToEndTest.php51
-rw-r--r--src/python/README.md8
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types.h4
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/call.c15
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/channel.c5
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c45
-rw-r--r--src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c13
-rw-r--r--src/python/grpcio/grpc/_adapter/_intermediary_low.py16
-rw-r--r--src/python/grpcio/grpc/_adapter/_low.py3
-rw-r--r--src/python/grpcio/grpc/_adapter/fore.py6
-rw-r--r--src/python/grpcio/grpc/_adapter/rear.py6
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx20
-rw-r--r--src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd4
-rw-r--r--src/python/grpcio/grpc/_cython/adapter_low.py4
-rw-r--r--src/python/grpcio/grpc/_links/_constants.py42
-rw-r--r--src/python/grpcio/grpc/_links/invocation.py217
-rw-r--r--src/python/grpcio/grpc/_links/service.py197
-rw-r--r--src/python/grpcio/grpc/beta/__init__.py28
-rw-r--r--src/python/grpcio/grpc/beta/_connectivity_channel.py156
-rw-r--r--src/python/grpcio/grpc/beta/_server.py132
-rw-r--r--src/python/grpcio/grpc/beta/_stub.py111
-rw-r--r--src/python/grpcio/grpc/beta/implementations.py367
-rw-r--r--src/python/grpcio/grpc/beta/interfaces.py214
-rw-r--r--src/python/grpcio/grpc/beta/utilities.py164
-rw-r--r--src/python/grpcio/grpc/framework/core/_constants.py17
-rw-r--r--src/python/grpcio/grpc/framework/core/_context.py10
-rw-r--r--src/python/grpcio/grpc/framework/core/_emission.py8
-rw-r--r--src/python/grpcio/grpc/framework/core/_end.py36
-rw-r--r--src/python/grpcio/grpc/framework/core/_expiration.py4
-rw-r--r--src/python/grpcio/grpc/framework/core/_ingestion.py48
-rw-r--r--src/python/grpcio/grpc/framework/core/_interfaces.py69
-rw-r--r--src/python/grpcio/grpc/framework/core/_operation.py34
-rw-r--r--src/python/grpcio/grpc/framework/core/_protocol.py176
-rw-r--r--src/python/grpcio/grpc/framework/core/_reception.py46
-rw-r--r--src/python/grpcio/grpc/framework/core/_termination.py34
-rw-r--r--src/python/grpcio/grpc/framework/core/_transmission.py115
-rw-r--r--src/python/grpcio/grpc/framework/core/_utilities.py8
-rw-r--r--src/python/grpcio/grpc/framework/crust/__init__.py30
-rw-r--r--src/python/grpcio/grpc/framework/crust/_calls.py223
-rw-r--r--src/python/grpcio/grpc/framework/crust/_control.py581
-rw-r--r--src/python/grpcio/grpc/framework/crust/_service.py173
-rw-r--r--src/python/grpcio/grpc/framework/crust/implementations.py364
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/base/base.py62
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/base/utilities.py13
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/face/face.py99
-rw-r--r--src/python/grpcio/grpc/framework/interfaces/links/links.py18
-rw-r--r--src/python/grpcio/setup.py2
-rw-r--r--src/python/grpcio_test/grpc_interop/client.py8
-rw-r--r--src/python/grpcio_test/grpc_interop/methods.py9
-rw-r--r--src/python/grpcio_test/grpc_protoc_plugin/alpha_python_plugin_test.py541
-rw-r--r--src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py501
-rw-r--r--src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py8
-rw-r--r--src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py32
-rw-r--r--src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py161
-rw-r--r--src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py6
-rw-r--r--src/python/grpcio_test/grpc_test/_links/_transmission_test.py31
-rw-r--r--src/python/grpcio_test/grpc_test/beta/__init__.py30
-rw-r--r--src/python/grpcio_test/grpc_test/beta/_beta_features_test.py232
-rw-r--r--src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py191
-rw-r--r--src/python/grpcio_test/grpc_test/beta/_face_interface_test.py138
-rw-r--r--src/python/grpcio_test/grpc_test/beta/_not_found_test.py75
-rw-r--r--src/python/grpcio_test/grpc_test/beta/_utilities_test.py123
-rw-r--r--src/python/grpcio_test/grpc_test/beta/test_utilities.py56
-rw-r--r--src/python/grpcio_test/grpc_test/credentials/README1
-rwxr-xr-xsrc/python/grpcio_test/grpc_test/credentials/ca.pem15
-rwxr-xr-xsrc/python/grpcio_test/grpc_test/credentials/server1.key16
-rwxr-xr-xsrc/python/grpcio_test/grpc_test/credentials/server1.pem16
-rw-r--r--src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py111
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py20
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py19
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py30
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py37
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py18
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py12
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py18
-rw-r--r--src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py2
-rw-r--r--src/python/grpcio_test/grpc_test/resources.py56
-rw-r--r--src/python/grpcio_test/grpc_test/test_common.py5
-rw-r--r--src/python/grpcio_test/setup.py5
-rwxr-xr-xsrc/ruby/.rspec1
-rw-r--r--src/ruby/README.md6
-rwxr-xr-xsrc/ruby/bin/math_client.rb6
-rwxr-xr-xsrc/ruby/bin/math_server.rb19
-rwxr-xr-xsrc/ruby/bin/noproto_server.rb3
-rw-r--r--src/ruby/ext/grpc/rb_channel.c2
-rw-r--r--src/ruby/ext/grpc/rb_credentials.c11
-rw-r--r--src/ruby/ext/grpc/rb_server.c53
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.c124
-rwxr-xr-xsrc/ruby/grpc.gemspec2
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb27
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rwxr-xr-xsrc/ruby/pb/test/server.rb3
-rw-r--r--src/ruby/spec/client_server_spec.rb20
-rw-r--r--src/ruby/spec/credentials_spec.rb14
-rw-r--r--src/ruby/spec/generic/active_call_spec.rb2
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb2
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb2
-rw-r--r--src/ruby/spec/pb/health/checker_spec.rb3
-rw-r--r--src/ruby/spec/server_credentials_spec.rb39
-rw-r--r--src/ruby/spec/server_spec.rb12
294 files changed, 12408 insertions, 8747 deletions
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 9432bdda96..7b497df7f4 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -33,12 +33,18 @@
#include <cctype>
#include <map>
+#include <sstream>
#include <vector>
+#include "src/compiler/csharp_generator.h"
#include "src/compiler/config.h"
#include "src/compiler/csharp_generator_helpers.h"
#include "src/compiler/csharp_generator.h"
+
+using google::protobuf::compiler::csharp::GetFileNamespace;
+using google::protobuf::compiler::csharp::GetClassName;
+using google::protobuf::compiler::csharp::GetUmbrellaClassName;
using grpc::protobuf::FileDescriptor;
using grpc::protobuf::Descriptor;
using grpc::protobuf::ServiceDescriptor;
@@ -55,47 +61,10 @@ using grpc_generator::StringReplace;
using std::map;
using std::vector;
+
namespace grpc_csharp_generator {
namespace {
-// TODO(jtattermusch): make GetFileNamespace part of libprotoc public API.
-// NOTE: Implementation needs to match exactly to GetFileNamespace
-// defined in csharp_helpers.h in protoc csharp plugin.
-// We cannot reference it directly because google3 protobufs
-// don't have a csharp protoc plugin.
-std::string GetFileNamespace(const FileDescriptor* file) {
- if (file->options().has_csharp_namespace()) {
- return file->options().csharp_namespace();
- }
- return file->package();
-}
-
-std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
- std::string result = GetFileNamespace(file);
- if (result != "") {
- result += '.';
- }
- std::string classname;
- if (file->package().empty()) {
- classname = name;
- } else {
- // Strip the proto package from full_name since we've replaced it with
- // the C# namespace.
- classname = name.substr(file->package().size() + 1);
- }
- result += StringReplace(classname, ".", ".Types.", false);
- return "global::" + result;
-}
-
-// TODO(jtattermusch): make GetClassName part of libprotoc public API.
-// NOTE: Implementation needs to match exactly to GetClassName
-// defined in csharp_helpers.h in protoc csharp plugin.
-// We cannot reference it directly because google3 protobufs
-// don't have a csharp protoc plugin.
-std::string GetClassName(const Descriptor* message) {
- return ToCSharpName(message->full_name(), message->file());
-}
-
std::string GetServiceClassName(const ServiceDescriptor* service) {
return service->name();
}
@@ -229,7 +198,7 @@ void GenerateMarshallerFields(Printer* out, const ServiceDescriptor *service) {
for (size_t i = 0; i < used_messages.size(); i++) {
const Descriptor *message = used_messages[i];
out->Print(
- "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => arg.ToByteArray(), $type$.ParseFrom);\n",
+ "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), $type$.Parser.ParseFrom);\n",
"fieldname", GetMarshallerFieldName(message), "type",
GetClassName(message));
}
@@ -258,6 +227,19 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
out->Outdent();
}
+void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
+ std::ostringstream index;
+ index << service->index();
+ out->Print("// service descriptor\n");
+ out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
+ out->Print("{\n");
+ out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n",
+ "umbrella", GetUmbrellaClassName(service->file()), "index",
+ index.str());
+ out->Print("}\n");
+ out->Print("\n");
+}
+
void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
out->Print("// client interface\n");
out->Print("public interface $name$\n", "name",
@@ -504,6 +486,7 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) {
for (int i = 0; i < service->method_count(); i++) {
GenerateStaticMethodField(out, service->method(i));
}
+ GenerateServiceDescriptorProperty(out, service);
GenerateClientInterface(out, service);
GenerateServerInterface(out, service);
GenerateClientStub(out, service);
@@ -539,7 +522,6 @@ grpc::string GetServices(const FileDescriptor *file) {
out.Print("using System.Threading;\n");
out.Print("using System.Threading.Tasks;\n");
out.Print("using Grpc.Core;\n");
- // TODO(jtattermusch): add using for protobuf message classes
out.Print("\n");
out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
diff --git a/src/compiler/csharp_generator.h b/src/compiler/csharp_generator.h
index ec537d3f1d..90eb7e2984 100644
--- a/src/compiler/csharp_generator.h
+++ b/src/compiler/csharp_generator.h
@@ -36,6 +36,8 @@
#include "src/compiler/config.h"
+#include <google/protobuf/compiler/csharp/csharp_names.h>
+
namespace grpc_csharp_generator {
grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 72c457ac6b..83133f2b6e 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -148,8 +148,8 @@ class IndentScope {
// END FORMATTING BOILERPLATE //
////////////////////////////////
-bool PrintServicer(const ServiceDescriptor* service,
- Printer* out) {
+bool PrintAlphaServicer(const ServiceDescriptor* service,
+ Printer* out) {
grpc::string doc = "<fill me in later!>";
map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
@@ -176,7 +176,7 @@ bool PrintServicer(const ServiceDescriptor* service,
return true;
}
-bool PrintServer(const ServiceDescriptor* service, Printer* out) {
+bool PrintAlphaServer(const ServiceDescriptor* service, Printer* out) {
grpc::string doc = "<fill me in later!>";
map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
@@ -204,8 +204,8 @@ bool PrintServer(const ServiceDescriptor* service, Printer* out) {
return true;
}
-bool PrintStub(const ServiceDescriptor* service,
- Printer* out) {
+bool PrintAlphaStub(const ServiceDescriptor* service,
+ Printer* out) {
grpc::string doc = "<fill me in later!>";
map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
@@ -268,8 +268,8 @@ bool GetModuleAndMessagePath(const Descriptor* type,
return true;
}
-bool PrintServerFactory(const grpc::string& package_qualified_service_name,
- const ServiceDescriptor* service, Printer* out) {
+bool PrintAlphaServerFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
out->Print("def early_adopter_create_$Service$_server(servicer, port, "
"private_key=None, certificate_chain=None):\n",
"Service", service->name());
@@ -320,7 +320,7 @@ bool PrintServerFactory(const grpc::string& package_qualified_service_name,
input_message_modules_and_classes.find(method_name);
auto output_message_module_and_class =
output_message_modules_and_classes.find(method_name);
- out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
+ out->Print("\"$Method$\": alpha_utilities.$Constructor$(\n", "Method",
method_name, "Constructor",
name_and_description_constructor->second);
{
@@ -339,7 +339,7 @@ bool PrintServerFactory(const grpc::string& package_qualified_service_name,
}
out->Print("}\n");
out->Print(
- "return implementations.server("
+ "return early_adopter_implementations.server("
"\"$PackageQualifiedServiceName$\","
" method_service_descriptions, port, private_key=private_key,"
" certificate_chain=certificate_chain)\n",
@@ -348,8 +348,8 @@ bool PrintServerFactory(const grpc::string& package_qualified_service_name,
return true;
}
-bool PrintStubFactory(const grpc::string& package_qualified_service_name,
- const ServiceDescriptor* service, Printer* out) {
+bool PrintAlphaStubFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
});
@@ -404,7 +404,7 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
input_message_modules_and_classes.find(method_name);
auto output_message_module_and_class =
output_message_modules_and_classes.find(method_name);
- out->Print("\"$Method$\": utilities.$Constructor$(\n", "Method",
+ out->Print("\"$Method$\": alpha_utilities.$Constructor$(\n", "Method",
method_name, "Constructor",
name_and_description_constructor->second);
{
@@ -422,7 +422,7 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
}
out->Print("}\n");
out->Print(
- "return implementations.stub("
+ "return early_adopter_implementations.stub("
"\"$PackageQualifiedServiceName$\","
" method_invocation_descriptions, host, port,"
" metadata_transformer=metadata_transformer, secure=secure,"
@@ -434,12 +434,280 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
return true;
}
+bool PrintBetaServicer(const ServiceDescriptor* service,
+ Printer* out) {
+ grpc::string doc = "<fill me in later!>";
+ map<grpc::string, grpc::string> dict = ListToDict({
+ "Service", service->name(),
+ "Documentation", doc,
+ });
+ out->Print("\n");
+ out->Print(dict, "class Beta$Service$Servicer(object):\n");
+ {
+ IndentScope raii_class_indent(out);
+ out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
+ out->Print("__metaclass__ = abc.ABCMeta\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto meth = service->method(i);
+ grpc::string arg_name = meth->client_streaming() ?
+ "request_iterator" : "request";
+ out->Print("@abc.abstractmethod\n");
+ out->Print("def $Method$(self, $ArgName$, context):\n",
+ "Method", meth->name(), "ArgName", arg_name);
+ {
+ IndentScope raii_method_indent(out);
+ out->Print("raise NotImplementedError()\n");
+ }
+ }
+ }
+ return true;
+}
+
+bool PrintBetaStub(const ServiceDescriptor* service,
+ Printer* out) {
+ grpc::string doc = "The interface to which stubs will conform.";
+ map<grpc::string, grpc::string> dict = ListToDict({
+ "Service", service->name(),
+ "Documentation", doc,
+ });
+ out->Print("\n");
+ out->Print(dict, "class Beta$Service$Stub(object):\n");
+ {
+ IndentScope raii_class_indent(out);
+ out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
+ out->Print("__metaclass__ = abc.ABCMeta\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ const MethodDescriptor* meth = service->method(i);
+ grpc::string arg_name = meth->client_streaming() ?
+ "request_iterator" : "request";
+ auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
+ out->Print("@abc.abstractmethod\n");
+ out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
+ {
+ IndentScope raii_method_indent(out);
+ out->Print("raise NotImplementedError()\n");
+ }
+ if (!meth->server_streaming()) {
+ out->Print(methdict, "$Method$.future = None\n");
+ }
+ }
+ }
+ return true;
+}
+
+bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
+ out->Print("\n");
+ out->Print("def beta_create_$Service$_server(servicer, pool=None, "
+ "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
+ "Service", service->name());
+ {
+ IndentScope raii_create_server_indent(out);
+ map<grpc::string, grpc::string> method_implementation_constructors;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ input_message_modules_and_classes;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ output_message_modules_and_classes;
+ for (int i = 0; i < service->method_count(); ++i) {
+ const MethodDescriptor* method = service->method(i);
+ const grpc::string method_implementation_constructor =
+ grpc::string(method->client_streaming() ? "stream_" : "unary_") +
+ grpc::string(method->server_streaming() ? "stream_" : "unary_") +
+ "inline";
+ pair<grpc::string, grpc::string> input_message_module_and_class;
+ if (!GetModuleAndMessagePath(method->input_type(),
+ &input_message_module_and_class)) {
+ return false;
+ }
+ pair<grpc::string, grpc::string> output_message_module_and_class;
+ if (!GetModuleAndMessagePath(method->output_type(),
+ &output_message_module_and_class)) {
+ return false;
+ }
+ // Import the modules that define the messages used in RPCs.
+ out->Print("import $Module$\n", "Module",
+ input_message_module_and_class.first);
+ out->Print("import $Module$\n", "Module",
+ output_message_module_and_class.first);
+ method_implementation_constructors.insert(
+ make_pair(method->name(), method_implementation_constructor));
+ input_message_modules_and_classes.insert(
+ make_pair(method->name(), input_message_module_and_class));
+ output_message_modules_and_classes.insert(
+ make_pair(method->name(), output_message_module_and_class));
+ }
+ out->Print("request_deserializers = {\n");
+ for (auto name_and_input_module_class_pair =
+ input_message_modules_and_classes.begin();
+ name_and_input_module_class_pair !=
+ input_message_modules_and_classes.end();
+ name_and_input_module_class_pair++) {
+ IndentScope raii_indent(out);
+ out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+ "$InputTypeModule$.$InputTypeClass$.FromString,\n",
+ "PackageQualifiedServiceName", package_qualified_service_name,
+ "MethodName", name_and_input_module_class_pair->first,
+ "InputTypeModule",
+ name_and_input_module_class_pair->second.first,
+ "InputTypeClass",
+ name_and_input_module_class_pair->second.second);
+ }
+ out->Print("}\n");
+ out->Print("response_serializers = {\n");
+ for (auto name_and_output_module_class_pair =
+ output_message_modules_and_classes.begin();
+ name_and_output_module_class_pair !=
+ output_message_modules_and_classes.end();
+ name_and_output_module_class_pair++) {
+ IndentScope raii_indent(out);
+ out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+ "$OutputTypeModule$.$OutputTypeClass$.SerializeToString,\n",
+ "PackageQualifiedServiceName", package_qualified_service_name,
+ "MethodName", name_and_output_module_class_pair->first,
+ "OutputTypeModule",
+ name_and_output_module_class_pair->second.first,
+ "OutputTypeClass",
+ name_and_output_module_class_pair->second.second);
+ }
+ out->Print("}\n");
+ out->Print("method_implementations = {\n");
+ for (auto name_and_implementation_constructor =
+ method_implementation_constructors.begin();
+ name_and_implementation_constructor !=
+ method_implementation_constructors.end();
+ name_and_implementation_constructor++) {
+ IndentScope raii_descriptions_indent(out);
+ const grpc::string method_name =
+ name_and_implementation_constructor->first;
+ out->Print("(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
+ "face_utilities.$Constructor$(servicer.$Method$),\n",
+ "PackageQualifiedServiceName", package_qualified_service_name,
+ "Method", name_and_implementation_constructor->first,
+ "Constructor", name_and_implementation_constructor->second);
+ }
+ out->Print("}\n");
+ out->Print("server_options = beta_implementations.server_options("
+ "request_deserializers=request_deserializers, "
+ "response_serializers=response_serializers, "
+ "thread_pool=pool, thread_pool_size=pool_size, "
+ "default_timeout=default_timeout, "
+ "maximum_timeout=maximum_timeout)\n");
+ out->Print("return beta_implementations.server(method_implementations, "
+ "options=server_options)\n");
+ }
+ return true;
+}
+
+bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
+ const ServiceDescriptor* service, Printer* out) {
+ map<grpc::string, grpc::string> dict = ListToDict({
+ "Service", service->name(),
+ });
+ out->Print("\n");
+ out->Print(dict, "def beta_create_$Service$_stub(channel, host=None,"
+ " metadata_transformer=None, pool=None, pool_size=None):\n");
+ {
+ IndentScope raii_create_server_indent(out);
+ map<grpc::string, grpc::string> method_cardinalities;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ input_message_modules_and_classes;
+ map<grpc::string, pair<grpc::string, grpc::string>>
+ output_message_modules_and_classes;
+ for (int i = 0; i < service->method_count(); ++i) {
+ const MethodDescriptor* method = service->method(i);
+ const grpc::string method_cardinality =
+ grpc::string(method->client_streaming() ? "STREAM" : "UNARY") +
+ "_" +
+ grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
+ pair<grpc::string, grpc::string> input_message_module_and_class;
+ if (!GetModuleAndMessagePath(method->input_type(),
+ &input_message_module_and_class)) {
+ return false;
+ }
+ pair<grpc::string, grpc::string> output_message_module_and_class;
+ if (!GetModuleAndMessagePath(method->output_type(),
+ &output_message_module_and_class)) {
+ return false;
+ }
+ // Import the modules that define the messages used in RPCs.
+ out->Print("import $Module$\n", "Module",
+ input_message_module_and_class.first);
+ out->Print("import $Module$\n", "Module",
+ output_message_module_and_class.first);
+ method_cardinalities.insert(
+ make_pair(method->name(), method_cardinality));
+ input_message_modules_and_classes.insert(
+ make_pair(method->name(), input_message_module_and_class));
+ output_message_modules_and_classes.insert(
+ make_pair(method->name(), output_message_module_and_class));
+ }
+ out->Print("request_serializers = {\n");
+ for (auto name_and_input_module_class_pair =
+ input_message_modules_and_classes.begin();
+ name_and_input_module_class_pair !=
+ input_message_modules_and_classes.end();
+ name_and_input_module_class_pair++) {
+ IndentScope raii_indent(out);
+ out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+ "$InputTypeModule$.$InputTypeClass$.SerializeToString,\n",
+ "PackageQualifiedServiceName", package_qualified_service_name,
+ "MethodName", name_and_input_module_class_pair->first,
+ "InputTypeModule",
+ name_and_input_module_class_pair->second.first,
+ "InputTypeClass",
+ name_and_input_module_class_pair->second.second);
+ }
+ out->Print("}\n");
+ out->Print("response_deserializers = {\n");
+ for (auto name_and_output_module_class_pair =
+ output_message_modules_and_classes.begin();
+ name_and_output_module_class_pair !=
+ output_message_modules_and_classes.end();
+ name_and_output_module_class_pair++) {
+ IndentScope raii_indent(out);
+ out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+ "$OutputTypeModule$.$OutputTypeClass$.FromString,\n",
+ "PackageQualifiedServiceName", package_qualified_service_name,
+ "MethodName", name_and_output_module_class_pair->first,
+ "OutputTypeModule",
+ name_and_output_module_class_pair->second.first,
+ "OutputTypeClass",
+ name_and_output_module_class_pair->second.second);
+ }
+ out->Print("}\n");
+ out->Print("cardinalities = {\n");
+ for (auto name_and_cardinality = method_cardinalities.begin();
+ name_and_cardinality != method_cardinalities.end();
+ name_and_cardinality++) {
+ IndentScope raii_descriptions_indent(out);
+ out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
+ "Method", name_and_cardinality->first,
+ "Cardinality", name_and_cardinality->second);
+ }
+ out->Print("}\n");
+ out->Print("stub_options = beta_implementations.stub_options("
+ "host=host, metadata_transformer=metadata_transformer, "
+ "request_serializers=request_serializers, "
+ "response_deserializers=response_deserializers, "
+ "thread_pool=pool, thread_pool_size=pool_size)\n");
+ out->Print(
+ "return beta_implementations.dynamic_stub(channel, \'$PackageQualifiedServiceName$\', "
+ "cardinalities, options=stub_options)\n",
+ "PackageQualifiedServiceName", package_qualified_service_name);
+ }
+ return true;
+}
+
bool PrintPreamble(const FileDescriptor* file,
const GeneratorConfiguration& config, Printer* out) {
out->Print("import abc\n");
- out->Print("from $Package$ import implementations\n",
- "Package", config.implementations_package_root);
- out->Print("from grpc.framework.alpha import utilities\n");
+ out->Print("from $Package$ import implementations as beta_implementations\n",
+ "Package", config.beta_package_root);
+ out->Print("from $Package$ import implementations as early_adopter_implementations\n",
+ "Package", config.early_adopter_package_root);
+ out->Print("from grpc.framework.alpha import utilities as alpha_utilities\n");
+ out->Print("from grpc.framework.common import cardinality\n");
+ out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
return true;
}
@@ -462,11 +730,15 @@ pair<bool, grpc::string> GetServices(const FileDescriptor* file,
for (int i = 0; i < file->service_count(); ++i) {
auto service = file->service(i);
auto package_qualified_service_name = package + service->name();
- if (!(PrintServicer(service, &out) &&
- PrintServer(service, &out) &&
- PrintStub(service, &out) &&
- PrintServerFactory(package_qualified_service_name, service, &out) &&
- PrintStubFactory(package_qualified_service_name, service, &out))) {
+ if (!(PrintAlphaServicer(service, &out) &&
+ PrintAlphaServer(service, &out) &&
+ PrintAlphaStub(service, &out) &&
+ PrintAlphaServerFactory(package_qualified_service_name, service, &out) &&
+ PrintAlphaStubFactory(package_qualified_service_name, service, &out) &&
+ PrintBetaServicer(service, &out) &&
+ PrintBetaStub(service, &out) &&
+ PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
+ PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
return make_pair(false, "");
}
}
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index b47f3c1243..44ed4b3f98 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -43,7 +43,8 @@ namespace grpc_python_generator {
// Data pertaining to configuration of the generator with respect to anything
// that may be used internally at Google.
struct GeneratorConfiguration {
- grpc::string implementations_package_root;
+ grpc::string early_adopter_package_root;
+ grpc::string beta_package_root;
};
class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc
index d1f49442da..c7cef54900 100644
--- a/src/compiler/python_plugin.cc
+++ b/src/compiler/python_plugin.cc
@@ -38,7 +38,8 @@
int main(int argc, char* argv[]) {
grpc_python_generator::GeneratorConfiguration config;
- config.implementations_package_root = "grpc.early_adopter";
+ config.early_adopter_package_root = "grpc.early_adopter";
+ config.beta_package_root = "grpc.beta";
grpc_python_generator::PythonGrpcGenerator generator(config);
return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
}
diff --git a/src/core/census/aggregation.h b/src/core/census/aggregation.h
new file mode 100644
index 0000000000..e9bc6ada96
--- /dev/null
+++ b/src/core/census/aggregation.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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 <stddef.h>
+
+#ifndef GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H
+#define GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H
+
+/** Structure used to describe an aggregation type. */
+struct census_aggregation_ops {
+ /* Create a new aggregation. The pointer returned can be used in future calls
+ to clone(), free(), record(), data() and reset(). */
+ void *(*create)(const void *create_arg);
+ /* Make a copy of an aggregation created by create() */
+ void *(*clone)(const void *aggregation);
+ /* Destroy an aggregation created by create() */
+ void (*free)(void *aggregation);
+ /* Record a new value against aggregation. */
+ void (*record)(void *aggregation, double value);
+ /* Return current aggregation data. The caller must cast this object into
+ the correct type for the aggregation result. The object returned can be
+ freed by using free_data(). */
+ void *(*data)(const void *aggregation);
+ /* free data returned by data() */
+ void (*free_data)(void *data);
+ /* Reset an aggregation to default (zero) values. */
+ void (*reset)(void *aggregation);
+ /* Merge 'from' aggregation into 'to'. Both aggregations must be compatible */
+ void (*merge)(void *to, const void *from);
+ /* Fill buffer with printable string version of aggregation contents. For
+ debugging only. Returns the number of bytes added to buffer (a value == n
+ implies the buffer was of insufficient size). */
+ size_t (*print)(const void *aggregation, char *buffer, size_t n);
+};
+
+#endif /* GRPC_INTERNAL_CORE_CENSUS_AGGREGATION_H */
diff --git a/src/core/census/context.c b/src/core/census/context.c
index df238ec98c..cab58b653c 100644
--- a/src/core/census/context.c
+++ b/src/core/census/context.c
@@ -44,16 +44,3 @@ size_t census_context_serialize(const census_context *context, char *buffer,
/* TODO(aveitch): implement serialization */
return 0;
}
-
-int census_context_deserialize(const char *buffer, census_context **context) {
- int ret = 0;
- if (buffer != NULL) {
- /* TODO(aveitch): implement deserialization. */
- ret = 1;
- }
- *context = gpr_malloc(sizeof(census_context));
- memset(*context, 0, sizeof(census_context));
- return ret;
-}
-
-void census_context_destroy(census_context *context) { gpr_free(context); }
diff --git a/src/core/census/grpc_context.c b/src/core/census/grpc_context.c
index 11f1eb3d5d..429f3ec9db 100644
--- a/src/core/census/grpc_context.c
+++ b/src/core/census/grpc_context.c
@@ -35,24 +35,11 @@
#include <grpc/grpc.h>
#include "src/core/surface/call.h"
-static void grpc_census_context_destroy(void *context) {
- census_context_destroy((census_context *)context);
-}
-
void grpc_census_call_set_context(grpc_call *call, census_context *context) {
if (census_enabled() == CENSUS_FEATURE_NONE) {
return;
}
- if (context == NULL) {
- if (grpc_call_is_client(call)) {
- census_context *context_ptr;
- census_context_deserialize(NULL, &context_ptr);
- grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context_ptr,
- grpc_census_context_destroy);
- } else {
- /* TODO(aveitch): server side context code to be implemented. */
- }
- } else {
+ if (context != NULL) {
grpc_call_context_set(call, GRPC_CONTEXT_TRACING, context, NULL);
}
}
diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
index fbedb35661..8b6ba1d472 100644
--- a/src/core/census/grpc_filter.c
+++ b/src/core/census/grpc_filter.c
@@ -36,12 +36,11 @@
#include <stdio.h>
#include <string.h>
-#include "include/grpc/census.h"
-#include "src/core/census/rpc_stat_id.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 <grpc/census.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
@@ -173,25 +172,15 @@ static void destroy_channel_elem(grpc_channel_element* elem) {
}
const grpc_channel_filter grpc_client_census_filter = {
- client_start_transport_op,
- grpc_channel_next_op,
- sizeof(call_data),
- client_init_call_elem,
- client_destroy_call_elem,
- sizeof(channel_data),
- init_channel_elem,
- destroy_channel_elem,
- grpc_call_next_get_peer,
- "census-client"};
+ client_start_transport_op, grpc_channel_next_op,
+ sizeof(call_data), client_init_call_elem,
+ client_destroy_call_elem, sizeof(channel_data),
+ init_channel_elem, destroy_channel_elem,
+ grpc_call_next_get_peer, "census-client"};
const grpc_channel_filter grpc_server_census_filter = {
- server_start_transport_op,
- grpc_channel_next_op,
- sizeof(call_data),
- server_init_call_elem,
- server_destroy_call_elem,
- sizeof(channel_data),
- init_channel_elem,
- destroy_channel_elem,
- grpc_call_next_get_peer,
- "census-server"};
+ server_start_transport_op, grpc_channel_next_op,
+ sizeof(call_data), server_init_call_elem,
+ server_destroy_call_elem, sizeof(channel_data),
+ init_channel_elem, destroy_channel_elem,
+ grpc_call_next_get_peer, "census-server"};
diff --git a/src/core/census/grpc_filter.h b/src/core/census/grpc_filter.h
index 1453c05d28..b3de3adc94 100644
--- a/src/core/census/grpc_filter.h
+++ b/src/core/census/grpc_filter.h
@@ -31,8 +31,8 @@
*
*/
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H
+#ifndef GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
+#define GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H
#include "src/core/channel/channel_stack.h"
@@ -41,4 +41,4 @@
extern const grpc_channel_filter grpc_client_census_filter;
extern const grpc_channel_filter grpc_server_census_filter;
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */
+#endif /* GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H */
diff --git a/src/core/census/operation.c b/src/core/census/operation.c
new file mode 100644
index 0000000000..118eb0a47a
--- /dev/null
+++ b/src/core/census/operation.c
@@ -0,0 +1,63 @@
+/*
+ * 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/census.h>
+
+/* TODO(aveitch): These are all placeholder implementations. */
+
+census_timestamp census_start_rpc_op_timestamp(void) {
+ census_timestamp ct;
+ /* TODO(aveitch): assumes gpr_timespec implementation of census_timestamp. */
+ ct.ts = gpr_now(GPR_CLOCK_MONOTONIC);
+ return ct;
+}
+
+census_context *census_start_client_rpc_op(
+ const census_context *context, gpr_int64 rpc_name_id,
+ const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
+ const census_timestamp *start_time) {
+ return NULL;
+}
+
+census_context *census_start_server_rpc_op(
+ const char *buffer, gpr_int64 rpc_name_id,
+ const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
+ census_timestamp *start_time) {
+ return NULL;
+}
+
+census_context *census_start_op(census_context *context, const char *family,
+ const char *name, int trace_mask) {
+ return NULL;
+}
+
+void census_end_op(census_context *context, int status) {}
diff --git a/src/core/census/rpc_metric_id.h b/src/core/census/rpc_metric_id.h
new file mode 100644
index 0000000000..1d8e8806f5
--- /dev/null
+++ b/src/core/census/rpc_metric_id.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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 CENSUS_RPC_METRIC_ID_H
+#define CENSUS_RPC_METRIC_ID_H
+
+/* Metric ID's used for RPC measurements. */
+/* Count of client requests sent. */
+#define CENSUS_METRIC_RPC_CLIENT_REQUESTS ((gpr_uint32)0)
+/* Count of server requests sent. */
+#define CENSUS_METRIC_RPC_SERVER_REQUESTS ((gpr_uint32)1)
+/* Client error counts. */
+#define CENSUS_METRIC_RPC_CLIENT_ERRORS ((gpr_uint32)2)
+/* Server error counts. */
+#define CENSUS_METRIC_RPC_SERVER_ERRORS ((gpr_uint32)3)
+/* Client side request latency. */
+#define CENSUS_METRIC_RPC_CLIENT_LATENCY ((gpr_uint32)4)
+/* Server side request latency. */
+#define CENSUS_METRIC_RPC_SERVER_LATENCY ((gpr_uint32)5)
+
+#endif /* CENSUS_RPC_METRIC_ID_H */
diff --git a/src/core/census/rpc_stat_id.h b/src/core/census/tracing.c
index fc0aa6f43f..ae38773c0a 100644
--- a/src/core/census/rpc_stat_id.h
+++ b/src/core/census/tracing.c
@@ -31,16 +31,15 @@
*
*/
-#ifndef CENSUS_RPC_STAT_ID_H
-#define CENSUS_RPC_STAT_ID_H
+#include <grpc/census.h>
-/* Stats ID's used for RPC measurements. */
-#define CENSUS_INVALID_STAT_ID 0 /* ID 0 is always invalid */
-#define CENSUS_RPC_CLIENT_REQUESTS 1 /* Count of client requests sent. */
-#define CENSUS_RPC_SERVER_REQUESTS 2 /* Count of server requests sent. */
-#define CENSUS_RPC_CLIENT_ERRORS 3 /* Client error counts. */
-#define CENSUS_RPC_SERVER_ERRORS 4 /* Server error counts. */
-#define CENSUS_RPC_CLIENT_LATENCY 5 /* Client side request latency. */
-#define CENSUS_RPC_SERVER_LATENCY 6 /* Server side request latency. */
+/* TODO(aveitch): These are all placeholder implementations. */
-#endif /* CENSUS_RPC_STAT_ID_H */
+int census_trace_mask(const census_context *context) {
+ return CENSUS_TRACE_MASK_NONE;
+}
+
+void census_set_trace_mask(int trace_mask) {}
+
+void census_trace_print(census_context *context, gpr_uint32 type,
+ const char *buffer, size_t n) {}
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 2b61d33c29..ec832a0367 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -85,16 +85,14 @@ static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) {
static void hc_on_recv(void *user_data, int success) {
grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- if (success) {
- size_t i;
- size_t nops = calld->recv_ops->nops;
- grpc_stream_op *ops = calld->recv_ops->ops;
- for (i = 0; i < nops; i++) {
- grpc_stream_op *op = &ops[i];
- if (op->type != GRPC_OP_METADATA) continue;
- calld->got_initial_metadata = 1;
- grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem);
- }
+ size_t i;
+ size_t nops = calld->recv_ops->nops;
+ grpc_stream_op *ops = calld->recv_ops->ops;
+ for (i = 0; i < nops; i++) {
+ grpc_stream_op *op = &ops[i];
+ if (op->type != GRPC_OP_METADATA) continue;
+ calld->got_initial_metadata = 1;
+ grpc_metadata_batch_filter(&op->data.metadata, client_filter, elem);
}
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
}
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index 9012070e8e..1e38479eb1 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -61,6 +61,10 @@ typedef struct {
grpc_httpcli_context *context;
grpc_pollset *pollset;
grpc_iomgr_object iomgr_obj;
+ gpr_slice_buffer incoming;
+ gpr_slice_buffer outgoing;
+ grpc_iomgr_closure on_read;
+ grpc_iomgr_closure done_write;
} internal_request;
static grpc_httpcli_get_override g_get_override = NULL;
@@ -99,73 +103,70 @@ static void finish(internal_request *req, int success) {
gpr_slice_unref(req->request_text);
gpr_free(req->host);
grpc_iomgr_unregister_object(&req->iomgr_obj);
+ gpr_slice_buffer_destroy(&req->incoming);
+ gpr_slice_buffer_destroy(&req->outgoing);
gpr_free(req);
}
-static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status status) {
+static void on_read(void *user_data, int success);
+
+static void do_read(internal_request *req) {
+ switch (grpc_endpoint_read(req->ep, &req->incoming, &req->on_read)) {
+ case GRPC_ENDPOINT_DONE:
+ on_read(req, 1);
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ break;
+ case GRPC_ENDPOINT_ERROR:
+ on_read(req, 0);
+ break;
+ }
+}
+
+static void on_read(void *user_data, int success) {
internal_request *req = user_data;
size_t i;
- for (i = 0; i < nslices; i++) {
- if (GPR_SLICE_LENGTH(slices[i])) {
+ for (i = 0; i < req->incoming.count; i++) {
+ if (GPR_SLICE_LENGTH(req->incoming.slices[i])) {
req->have_read_byte = 1;
- if (!grpc_httpcli_parser_parse(&req->parser, slices[i])) {
+ if (!grpc_httpcli_parser_parse(&req->parser, req->incoming.slices[i])) {
finish(req, 0);
- goto done;
+ return;
}
}
}
- switch (status) {
- case GRPC_ENDPOINT_CB_OK:
- grpc_endpoint_notify_on_read(req->ep, on_read, req);
- break;
- case GRPC_ENDPOINT_CB_EOF:
- case GRPC_ENDPOINT_CB_ERROR:
- case GRPC_ENDPOINT_CB_SHUTDOWN:
- if (!req->have_read_byte) {
- next_address(req);
- } else {
- finish(req, grpc_httpcli_parser_eof(&req->parser));
- }
- break;
- }
-
-done:
- for (i = 0; i < nslices; i++) {
- gpr_slice_unref(slices[i]);
+ if (success) {
+ do_read(req);
+ } else if (!req->have_read_byte) {
+ next_address(req);
+ } else {
+ finish(req, grpc_httpcli_parser_eof(&req->parser));
}
}
-static void on_written(internal_request *req) {
- grpc_endpoint_notify_on_read(req->ep, on_read, req);
-}
+static void on_written(internal_request *req) { do_read(req); }
-static void done_write(void *arg, grpc_endpoint_cb_status status) {
+static void done_write(void *arg, int success) {
internal_request *req = arg;
- switch (status) {
- case GRPC_ENDPOINT_CB_OK:
- on_written(req);
- break;
- case GRPC_ENDPOINT_CB_EOF:
- case GRPC_ENDPOINT_CB_SHUTDOWN:
- case GRPC_ENDPOINT_CB_ERROR:
- next_address(req);
- break;
+ if (success) {
+ on_written(req);
+ } else {
+ next_address(req);
}
}
static void start_write(internal_request *req) {
gpr_slice_ref(req->request_text);
- switch (
- grpc_endpoint_write(req->ep, &req->request_text, 1, done_write, req)) {
- case GRPC_ENDPOINT_WRITE_DONE:
+ gpr_slice_buffer_add(&req->outgoing, req->request_text);
+ switch (grpc_endpoint_write(req->ep, &req->outgoing, &req->done_write)) {
+ case GRPC_ENDPOINT_DONE:
on_written(req);
break;
- case GRPC_ENDPOINT_WRITE_PENDING:
+ case GRPC_ENDPOINT_PENDING:
break;
- case GRPC_ENDPOINT_WRITE_ERROR:
+ case GRPC_ENDPOINT_ERROR:
finish(req, 0);
break;
}
@@ -237,6 +238,10 @@ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
req->context = context;
req->pollset = pollset;
+ grpc_iomgr_closure_init(&req->on_read, on_read, req);
+ grpc_iomgr_closure_init(&req->done_write, done_write, req);
+ gpr_slice_buffer_init(&req->incoming);
+ gpr_slice_buffer_init(&req->outgoing);
gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
grpc_iomgr_register_object(&req->iomgr_obj, name);
gpr_free(name);
@@ -270,7 +275,11 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
request->handshaker ? request->handshaker : &grpc_httpcli_plaintext;
req->context = context;
req->pollset = pollset;
- gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
+ grpc_iomgr_closure_init(&req->on_read, on_read, req);
+ grpc_iomgr_closure_init(&req->done_write, done_write, req);
+ gpr_slice_buffer_init(&req->incoming);
+ gpr_slice_buffer_init(&req->outgoing);
+ gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path);
grpc_iomgr_register_object(&req->iomgr_obj, name);
gpr_free(name);
req->host = gpr_strdup(request->host);
diff --git a/src/core/iomgr/endpoint.c b/src/core/iomgr/endpoint.c
index 8ee14bce9b..a7878e31dd 100644
--- a/src/core/iomgr/endpoint.c
+++ b/src/core/iomgr/endpoint.c
@@ -33,17 +33,16 @@
#include "src/core/iomgr/endpoint.h"
-void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
- void *user_data) {
- ep->vtable->notify_on_read(ep, cb, user_data);
+grpc_endpoint_op_status grpc_endpoint_read(grpc_endpoint *ep,
+ gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) {
+ return ep->vtable->read(ep, slices, cb);
}
-grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep,
- gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_write_cb cb,
- void *user_data) {
- return ep->vtable->write(ep, slices, nslices, cb, user_data);
+grpc_endpoint_op_status grpc_endpoint_write(grpc_endpoint *ep,
+ gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) {
+ return ep->vtable->write(ep, slices, cb);
}
void grpc_endpoint_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
diff --git a/src/core/iomgr/endpoint.h b/src/core/iomgr/endpoint.h
index ea92a500e8..d14d52d561 100644
--- a/src/core/iomgr/endpoint.h
+++ b/src/core/iomgr/endpoint.h
@@ -37,6 +37,7 @@
#include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/pollset_set.h"
#include <grpc/support/slice.h>
+#include <grpc/support/slice_buffer.h>
#include <grpc/support/time.h>
/* An endpoint caps a streaming channel between two communicating processes.
@@ -45,31 +46,17 @@
typedef struct grpc_endpoint grpc_endpoint;
typedef struct grpc_endpoint_vtable grpc_endpoint_vtable;
-typedef enum grpc_endpoint_cb_status {
- GRPC_ENDPOINT_CB_OK = 0, /* Call completed successfully */
- GRPC_ENDPOINT_CB_EOF, /* Call completed successfully, end of file reached */
- GRPC_ENDPOINT_CB_SHUTDOWN, /* Call interrupted by shutdown */
- GRPC_ENDPOINT_CB_ERROR /* Call interrupted by socket error */
-} grpc_endpoint_cb_status;
-
-typedef enum grpc_endpoint_write_status {
- GRPC_ENDPOINT_WRITE_DONE, /* completed immediately, cb won't be called */
- GRPC_ENDPOINT_WRITE_PENDING, /* cb will be called when completed */
- GRPC_ENDPOINT_WRITE_ERROR /* write errored out, cb won't be called */
-} grpc_endpoint_write_status;
-
-typedef void (*grpc_endpoint_read_cb)(void *user_data, gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_cb_status error);
-typedef void (*grpc_endpoint_write_cb)(void *user_data,
- grpc_endpoint_cb_status error);
+typedef enum grpc_endpoint_op_status {
+ GRPC_ENDPOINT_DONE, /* completed immediately, cb won't be called */
+ GRPC_ENDPOINT_PENDING, /* cb will be called when completed */
+ GRPC_ENDPOINT_ERROR /* write errored out, cb won't be called */
+} grpc_endpoint_op_status;
struct grpc_endpoint_vtable {
- void (*notify_on_read)(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
- void *user_data);
- grpc_endpoint_write_status (*write)(grpc_endpoint *ep, gpr_slice *slices,
- size_t nslices, grpc_endpoint_write_cb cb,
- void *user_data);
+ grpc_endpoint_op_status (*read)(grpc_endpoint *ep, gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb);
+ grpc_endpoint_op_status (*write)(grpc_endpoint *ep, gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb);
void (*add_to_pollset)(grpc_endpoint *ep, grpc_pollset *pollset);
void (*add_to_pollset_set)(grpc_endpoint *ep, grpc_pollset_set *pollset);
void (*shutdown)(grpc_endpoint *ep);
@@ -77,26 +64,32 @@ struct grpc_endpoint_vtable {
char *(*get_peer)(grpc_endpoint *ep);
};
-/* When data is available on the connection, calls the callback with slices. */
-void grpc_endpoint_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
- void *user_data);
+/* When data is available on the connection, calls the callback with slices.
+ Callback success indicates that the endpoint can accept more reads, failure
+ indicates the endpoint is closed.
+ Valid slices may be placed into \a slices even on callback success == 0. */
+grpc_endpoint_op_status grpc_endpoint_read(
+ grpc_endpoint *ep, gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT;
char *grpc_endpoint_get_peer(grpc_endpoint *ep);
/* Write slices out to the socket.
If the connection is ready for more data after the end of the call, it
- returns GRPC_ENDPOINT_WRITE_DONE.
- Otherwise it returns GRPC_ENDPOINT_WRITE_PENDING and calls cb when the
- connection is ready for more data. */
-grpc_endpoint_write_status grpc_endpoint_write(grpc_endpoint *ep,
- gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_write_cb cb,
- void *user_data);
+ returns GRPC_ENDPOINT_DONE.
+ Otherwise it returns GRPC_ENDPOINT_PENDING and calls cb when the
+ connection is ready for more data.
+ \a slices may be mutated at will by the endpoint until cb is called.
+ No guarantee is made to the content of slices after a write EXCEPT that
+ it is a valid slice buffer.
+ */
+grpc_endpoint_op_status grpc_endpoint_write(
+ grpc_endpoint *ep, gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) GRPC_MUST_USE_RESULT;
/* Causes any pending read/write callbacks to run immediately with
- GRPC_ENDPOINT_CB_SHUTDOWN status */
+ success==0 */
void grpc_endpoint_shutdown(grpc_endpoint *ep);
void grpc_endpoint_destroy(grpc_endpoint *ep);
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 09a457dd9a..006f8b2abf 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -52,7 +52,6 @@ static OVERLAPPED g_iocp_custom_overlap;
static gpr_event g_shutdown_iocp;
static gpr_event g_iocp_done;
-static gpr_atm g_orphans = 0;
static gpr_atm g_custom_events = 0;
static HANDLE g_iocp;
@@ -92,22 +91,13 @@ static void do_iocp_work() {
gpr_log(GPR_ERROR, "Unknown IOCP operation");
abort();
}
- GPR_ASSERT(info->outstanding);
- if (socket->orphan) {
- info->outstanding = 0;
- if (!socket->read_info.outstanding && !socket->write_info.outstanding) {
- grpc_winsocket_destroy(socket);
- gpr_atm_full_fetch_add(&g_orphans, -1);
- }
- return;
- }
success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
FALSE, &flags);
info->bytes_transfered = bytes;
info->wsa_error = success ? 0 : WSAGetLastError();
GPR_ASSERT(overlapped == &info->overlapped);
- gpr_mu_lock(&socket->state_mu);
GPR_ASSERT(!info->has_pending_iocp);
+ gpr_mu_lock(&socket->state_mu);
if (info->cb) {
f = info->cb;
opaque = info->opaque;
@@ -120,9 +110,8 @@ static void do_iocp_work() {
}
static void iocp_loop(void *p) {
- while (gpr_atm_acq_load(&g_orphans) || gpr_atm_acq_load(&g_custom_events) ||
+ while (gpr_atm_acq_load(&g_custom_events) ||
!gpr_event_get(&g_shutdown_iocp)) {
- grpc_maybe_call_delayed_callbacks(NULL, 1);
do_iocp_work();
}
@@ -175,12 +164,6 @@ void grpc_iocp_add_socket(grpc_winsocket *socket) {
GPR_ASSERT(ret == g_iocp);
}
-void grpc_iocp_socket_orphan(grpc_winsocket *socket) {
- GPR_ASSERT(!socket->orphan);
- gpr_atm_full_fetch_add(&g_orphans, 1);
- socket->orphan = 1;
-}
-
/* Calling notify_on_read or write means either of two things:
-) The IOCP already completed in the background, and we need to call
the callback now.
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index ee3847a229..7d2dc45176 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -42,7 +42,6 @@ void grpc_iocp_init(void);
void grpc_iocp_kick(void);
void grpc_iocp_shutdown(void);
void grpc_iocp_add_socket(grpc_winsocket *);
-void grpc_iocp_socket_orphan(grpc_winsocket *);
void grpc_socket_notify_on_write(grpc_winsocket *,
void (*cb)(void *, int success), void *opaque);
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index fdc9adf4af..1dd03992ae 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -108,8 +108,14 @@ static size_t count_objects(void) {
return n;
}
-void grpc_iomgr_shutdown(void) {
+static void dump_objects(const char *kind) {
grpc_iomgr_object *obj;
+ for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
+ gpr_log(GPR_DEBUG, "%s OBJECT: %s %p", kind, obj->name, obj);
+ }
+}
+
+void grpc_iomgr_shutdown(void) {
grpc_iomgr_closure *closure;
gpr_timespec shutdown_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN));
@@ -151,12 +157,14 @@ void grpc_iomgr_shutdown(void) {
}
if (g_root_object.next != &g_root_object) {
int timeout = 0;
- gpr_timespec short_deadline = gpr_time_add(
+ while (g_cbs_head == NULL) {
+ gpr_timespec short_deadline = gpr_time_add(
gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100, GPR_TIMESPAN));
- while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
- if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
- timeout = 1;
- break;
+ if (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
+ if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
+ timeout = 1;
+ break;
+ }
}
}
if (timeout) {
@@ -164,9 +172,7 @@ void grpc_iomgr_shutdown(void) {
"Failed to free %d iomgr objects before shutdown deadline: "
"memory leaks are likely",
count_objects());
- for (obj = g_root_object.next; obj != &g_root_object; obj = obj->next) {
- gpr_log(GPR_DEBUG, "LEAKED OBJECT: %s %p", obj->name, obj);
- }
+ dump_objects("LEAKED");
break;
}
}
@@ -188,7 +194,7 @@ void grpc_iomgr_register_object(grpc_iomgr_object *obj, const char *name) {
obj->name = gpr_strdup(name);
gpr_mu_lock(&g_mu);
obj->next = &g_root_object;
- obj->prev = obj->next->prev;
+ obj->prev = g_root_object.prev;
obj->next->prev = obj->prev->next = obj;
gpr_mu_unlock(&g_mu);
}
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index fe66ebed77..8f62ce2954 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -99,7 +99,6 @@ static void perform_delayed_add(void *arg, int iomgr_status) {
if (da->pollset->shutting_down) {
/* We don't care about this pollset anymore. */
if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
- GPR_ASSERT(!grpc_pollset_has_workers(da->pollset));
da->pollset->called_shutdown = 1;
do_shutdown_cb = 1;
}
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index 7d8421376b..557ca82226 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -35,8 +35,12 @@
#ifdef GPR_WINSOCK_SOCKET
+#include <winsock2.h>
+#include <mswsock.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/log_win32.h>
#include <grpc/support/string_util.h>
#include "src/core/iomgr/iocp_windows.h"
@@ -62,46 +66,30 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name) {
operations to abort them. We need to do that this way because of the
various callsites of that function, which happens to be in various
mutex hold states, and that'd be unsafe to call them directly. */
-int grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
- int callbacks_set = 0;
- SOCKET socket;
- gpr_mu_lock(&winsocket->state_mu);
- socket = winsocket->socket;
- if (winsocket->read_info.cb) {
- callbacks_set++;
- grpc_iomgr_closure_init(&winsocket->shutdown_closure,
- winsocket->read_info.cb,
- winsocket->read_info.opaque);
- grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
- }
- if (winsocket->write_info.cb) {
- callbacks_set++;
- grpc_iomgr_closure_init(&winsocket->shutdown_closure,
- winsocket->write_info.cb,
- winsocket->write_info.opaque);
- grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
- }
- gpr_mu_unlock(&winsocket->state_mu);
- closesocket(socket);
- return callbacks_set;
-}
+void grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
+ /* Grab the function pointer for DisconnectEx for that specific socket.
+ It may change depending on the interface. */
+ int status;
+ GUID guid = WSAID_DISCONNECTEX;
+ LPFN_DISCONNECTEX DisconnectEx;
+ DWORD ioctl_num_bytes;
-/* Abandons a socket. Either we're going to queue it up for garbage collecting
- from the IO Completion Port thread, or destroy it immediately. Note that this
- mechanisms assumes that we're either always waiting for an operation, or we
- explicitly know that we don't. If there is a future case where we can have
- an "idle" socket which is neither trying to read or write, we'd start leaking
- both memory and sockets. */
-void grpc_winsocket_orphan(grpc_winsocket *winsocket) {
- grpc_iomgr_unregister_object(&winsocket->iomgr_object);
- if (winsocket->read_info.outstanding || winsocket->write_info.outstanding) {
- grpc_iocp_socket_orphan(winsocket);
+ status = WSAIoctl(winsocket->socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid, sizeof(guid), &DisconnectEx, sizeof(DisconnectEx),
+ &ioctl_num_bytes, NULL, NULL);
+
+ if (status == 0) {
+ DisconnectEx(winsocket->socket, NULL, 0, 0);
} else {
- grpc_winsocket_destroy(winsocket);
+ char *utf8_message = gpr_format_message(WSAGetLastError());
+ gpr_log(GPR_ERROR, "Unable to retrieve DisconnectEx pointer : %s", utf8_message);
+ gpr_free(utf8_message);
}
+ closesocket(winsocket->socket);
}
void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
+ grpc_iomgr_unregister_object(&winsocket->iomgr_object);
gpr_mu_destroy(&winsocket->state_mu);
gpr_free(winsocket);
}
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index ecf2530173..498921e0fd 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -68,8 +68,6 @@ typedef struct grpc_winsocket_callback_info {
/* The results of the overlapped operation. */
DWORD bytes_transfered;
int wsa_error;
- /* A boolean indicating that we started an operation. */
- int outstanding;
} grpc_winsocket_callback_info;
/* This is a wrapper to a Windows socket. A socket can have one outstanding
@@ -92,10 +90,6 @@ typedef struct grpc_winsocket {
/* You can't add the same socket twice to the same IO Completion Port.
This prevents that. */
int added_to_iocp;
- /* A boolean to indicate that the caller has abandoned that socket, but
- there is a pending operation that the IO Completion Port will have to
- wait for. The socket will be collected at that time. */
- int orphan;
grpc_iomgr_closure shutdown_closure;
@@ -108,14 +102,10 @@ typedef struct grpc_winsocket {
grpc_winsocket *grpc_winsocket_create(SOCKET socket, const char *name);
/* Initiate an asynchronous shutdown of the socket. Will call off any pending
- operation to cancel them. Returns the number of callbacks that got setup. */
-int grpc_winsocket_shutdown(grpc_winsocket *socket);
+ operation to cancel them. */
+void grpc_winsocket_shutdown(grpc_winsocket *socket);
-/* Abandon a socket. */
-void grpc_winsocket_orphan(grpc_winsocket *socket);
-
-/* Destroy a socket. Should only be called by the IO Completion Port thread,
- or by grpc_winsocket_orphan if there's no pending operation. */
+/* Destroy a socket. Should only be called if there's no pending operation. */
void grpc_winsocket_destroy(grpc_winsocket *socket);
#endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
index 79a58fe2af..05198dbff4 100644
--- a/src/core/iomgr/tcp_client_windows.c
+++ b/src/core/iomgr/tcp_client_windows.c
@@ -60,13 +60,13 @@ typedef struct {
grpc_alarm alarm;
char *addr_name;
int refs;
- int aborted;
} async_connect;
-static void async_connect_cleanup(async_connect *ac) {
+static void async_connect_unlock_and_cleanup(async_connect *ac) {
int done = (--ac->refs == 0);
gpr_mu_unlock(&ac->mu);
if (done) {
+ if (ac->socket != NULL) grpc_winsocket_destroy(ac->socket);
gpr_mu_destroy(&ac->mu);
gpr_free(ac->addr_name);
gpr_free(ac);
@@ -77,10 +77,11 @@ static void on_alarm(void *acp, int occured) {
async_connect *ac = acp;
gpr_mu_lock(&ac->mu);
/* If the alarm didn't occur, it got cancelled. */
+ gpr_log(GPR_DEBUG, "on_alarm: %p", ac->socket);
if (ac->socket != NULL && occured) {
grpc_winsocket_shutdown(ac->socket);
}
- async_connect_cleanup(ac);
+ async_connect_unlock_and_cleanup(ac);
}
static void on_connect(void *acp, int from_iocp) {
@@ -90,51 +91,33 @@ static void on_connect(void *acp, int from_iocp) {
grpc_winsocket_callback_info *info = &ac->socket->write_info;
void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
void *cb_arg = ac->cb_arg;
- int aborted;
-
+
grpc_alarm_cancel(&ac->alarm);
gpr_mu_lock(&ac->mu);
- aborted = ac->aborted;
+
+ gpr_log(GPR_DEBUG, "on_connect: %p", ac->socket);
if (from_iocp) {
DWORD transfered_bytes = 0;
DWORD flags;
BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
&transfered_bytes, FALSE, &flags);
- info->outstanding = 0;
GPR_ASSERT(transfered_bytes == 0);
if (!wsa_success) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "on_connect error: %s", utf8_message);
gpr_free(utf8_message);
- } else if (!aborted) {
+ } else {
ep = grpc_tcp_create(ac->socket, ac->addr_name);
+ ac->socket = NULL;
}
- } else {
- gpr_log(GPR_ERROR, "on_connect is shutting down");
- /* If the connection timeouts, we will still get a notification from
- the IOCP whatever happens. So we're just going to flag that connection
- as being in the process of being aborted, and wait for the IOCP. We
- can't just orphan the socket now, because the IOCP might already have
- gotten a successful connection, which is our worst-case scenario.
- We need to call our callback now to respect the deadline. */
- ac->aborted = 1;
- gpr_mu_unlock(&ac->mu);
- cb(cb_arg, NULL);
- return;
}
- ac->socket->write_info.outstanding = 0;
-
- /* If we don't have an endpoint, it means the connection failed,
- so it doesn't matter if it aborted or failed. We need to orphan
- that socket. */
- if (!ep || aborted) grpc_winsocket_orphan(ac->socket);
- async_connect_cleanup(ac);
+ async_connect_unlock_and_cleanup(ac);
/* If the connection was aborted, the callback was already called when
the deadline was met. */
- if (!aborted) cb(cb_arg, ep);
+ cb(cb_arg, ep);
}
/* Tries to issue one async connection, then schedules both an IOCP
@@ -196,7 +179,6 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
socket = grpc_winsocket_create(sock, "client");
info = &socket->write_info;
- info->outstanding = 1;
success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped);
/* It wouldn't be unusual to get a success immediately. But we'll still get
@@ -216,11 +198,9 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *tcp),
gpr_mu_init(&ac->mu);
ac->refs = 2;
ac->addr_name = grpc_sockaddr_to_uri(addr);
- ac->aborted = 0;
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
gpr_now(GPR_CLOCK_MONOTONIC));
- socket->write_info.outstanding = 1;
grpc_socket_notify_on_write(socket, on_connect, ac);
return;
@@ -228,8 +208,8 @@ failure:
utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, message, utf8_message);
gpr_free(utf8_message);
- if (socket) {
- grpc_winsocket_orphan(socket);
+ if (socket != NULL) {
+ grpc_winsocket_destroy(socket);
} else if (sock != INVALID_SOCKET) {
closesocket(sock);
}
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 360e6ebd8c..0db7cd9f0e 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -61,209 +61,8 @@
#define SENDMSG_FLAGS 0
#endif
-/* Holds a slice array and associated state. */
-typedef struct grpc_tcp_slice_state {
- gpr_slice *slices; /* Array of slices */
- size_t nslices; /* Size of slices array. */
- ssize_t first_slice; /* First valid slice in array */
- ssize_t last_slice; /* Last valid slice in array */
- gpr_slice working_slice; /* pointer to original final slice */
- int working_slice_valid; /* True if there is a working slice */
- int memory_owned; /* True if slices array is owned */
-} grpc_tcp_slice_state;
-
int grpc_tcp_trace = 0;
-static void slice_state_init(grpc_tcp_slice_state *state, gpr_slice *slices,
- size_t nslices, size_t valid_slices) {
- state->slices = slices;
- state->nslices = nslices;
- if (valid_slices == 0) {
- state->first_slice = -1;
- } else {
- state->first_slice = 0;
- }
- state->last_slice = valid_slices - 1;
- state->working_slice_valid = 0;
- state->memory_owned = 0;
-}
-
-/* Returns true if there is still available data */
-static int slice_state_has_available(grpc_tcp_slice_state *state) {
- return state->first_slice != -1 && state->last_slice >= state->first_slice;
-}
-
-static ssize_t slice_state_slices_allocated(grpc_tcp_slice_state *state) {
- if (state->first_slice == -1) {
- return 0;
- } else {
- return state->last_slice - state->first_slice + 1;
- }
-}
-
-static void slice_state_realloc(grpc_tcp_slice_state *state, size_t new_size) {
- /* TODO(klempner): use realloc instead when first_slice is 0 */
- /* TODO(klempner): Avoid a realloc in cases where it is unnecessary */
- gpr_slice *slices = state->slices;
- size_t original_size = slice_state_slices_allocated(state);
- size_t i;
- gpr_slice *new_slices = gpr_malloc(sizeof(gpr_slice) * new_size);
-
- for (i = 0; i < original_size; ++i) {
- new_slices[i] = slices[i + state->first_slice];
- }
-
- state->slices = new_slices;
- state->last_slice = original_size - 1;
- if (original_size > 0) {
- state->first_slice = 0;
- } else {
- state->first_slice = -1;
- }
- state->nslices = new_size;
-
- if (state->memory_owned) {
- gpr_free(slices);
- }
- state->memory_owned = 1;
-}
-
-static void slice_state_remove_prefix(grpc_tcp_slice_state *state,
- size_t prefix_bytes) {
- gpr_slice *current_slice = &state->slices[state->first_slice];
- size_t current_slice_size;
-
- while (slice_state_has_available(state)) {
- current_slice_size = GPR_SLICE_LENGTH(*current_slice);
- if (current_slice_size > prefix_bytes) {
- /* TODO(klempner): Get rid of the extra refcount created here by adding a
- native "trim the first N bytes" operation to splice */
- /* TODO(klempner): This really shouldn't be modifying the current slice
- unless we own the slices array. */
- gpr_slice tail;
- tail = gpr_slice_split_tail(current_slice, prefix_bytes);
- gpr_slice_unref(*current_slice);
- *current_slice = tail;
- return;
- } else {
- gpr_slice_unref(*current_slice);
- ++state->first_slice;
- ++current_slice;
- prefix_bytes -= current_slice_size;
- }
- }
-}
-
-static void slice_state_destroy(grpc_tcp_slice_state *state) {
- while (slice_state_has_available(state)) {
- gpr_slice_unref(state->slices[state->first_slice]);
- ++state->first_slice;
- }
-
- if (state->memory_owned) {
- gpr_free(state->slices);
- state->memory_owned = 0;
- }
-}
-
-void slice_state_transfer_ownership(grpc_tcp_slice_state *state,
- gpr_slice **slices, size_t *nslices) {
- *slices = state->slices + state->first_slice;
- *nslices = state->last_slice - state->first_slice + 1;
-
- state->first_slice = -1;
- state->last_slice = -1;
-}
-
-/* Fills iov with the first min(iov_size, available) slices, returns number
- filled */
-static size_t slice_state_to_iovec(grpc_tcp_slice_state *state,
- struct iovec *iov, size_t iov_size) {
- size_t nslices = state->last_slice - state->first_slice + 1;
- gpr_slice *slices = state->slices + state->first_slice;
- size_t i;
- if (nslices < iov_size) {
- iov_size = nslices;
- }
-
- for (i = 0; i < iov_size; ++i) {
- iov[i].iov_base = GPR_SLICE_START_PTR(slices[i]);
- iov[i].iov_len = GPR_SLICE_LENGTH(slices[i]);
- }
- return iov_size;
-}
-
-/* Makes n blocks available at the end of state, writes them into iov, and
- returns the number of bytes allocated */
-static size_t slice_state_append_blocks_into_iovec(grpc_tcp_slice_state *state,
- struct iovec *iov, size_t n,
- size_t slice_size) {
- size_t target_size;
- size_t i;
- size_t allocated_bytes;
- ssize_t allocated_slices = slice_state_slices_allocated(state);
-
- if (n - state->working_slice_valid >= state->nslices - state->last_slice) {
- /* Need to grow the slice array */
- target_size = state->nslices;
- do {
- target_size = target_size * 2;
- } while (target_size < allocated_slices + n - state->working_slice_valid);
- /* TODO(klempner): If this ever needs to support both prefix removal and
- append, we should be smarter about the growth logic here */
- slice_state_realloc(state, target_size);
- }
-
- i = 0;
- allocated_bytes = 0;
-
- if (state->working_slice_valid) {
- iov[0].iov_base = GPR_SLICE_END_PTR(state->slices[state->last_slice]);
- iov[0].iov_len = GPR_SLICE_LENGTH(state->working_slice) -
- GPR_SLICE_LENGTH(state->slices[state->last_slice]);
- allocated_bytes += iov[0].iov_len;
- ++i;
- state->slices[state->last_slice] = state->working_slice;
- state->working_slice_valid = 0;
- }
-
- for (; i < n; ++i) {
- ++state->last_slice;
- state->slices[state->last_slice] = gpr_slice_malloc(slice_size);
- iov[i].iov_base = GPR_SLICE_START_PTR(state->slices[state->last_slice]);
- iov[i].iov_len = slice_size;
- allocated_bytes += slice_size;
- }
- if (state->first_slice == -1) {
- state->first_slice = 0;
- }
- return allocated_bytes;
-}
-
-/* Remove the last n bytes from state */
-/* TODO(klempner): Consider having this defer actual deletion until later */
-static void slice_state_remove_last(grpc_tcp_slice_state *state, size_t bytes) {
- while (bytes > 0 && slice_state_has_available(state)) {
- if (GPR_SLICE_LENGTH(state->slices[state->last_slice]) > bytes) {
- state->working_slice = state->slices[state->last_slice];
- state->working_slice_valid = 1;
- /* TODO(klempner): Combine these into a single operation that doesn't need
- to refcount */
- gpr_slice_unref(gpr_slice_split_tail(
- &state->slices[state->last_slice],
- GPR_SLICE_LENGTH(state->slices[state->last_slice]) - bytes));
- bytes = 0;
- } else {
- bytes -= GPR_SLICE_LENGTH(state->slices[state->last_slice]);
- gpr_slice_unref(state->slices[state->last_slice]);
- --state->last_slice;
- if (state->last_slice == -1) {
- state->first_slice = -1;
- }
- }
- }
-}
-
typedef struct {
grpc_endpoint base;
grpc_fd *em_fd;
@@ -273,80 +72,111 @@ typedef struct {
size_t slice_size;
gpr_refcount refcount;
- grpc_endpoint_read_cb read_cb;
- void *read_user_data;
- grpc_endpoint_write_cb write_cb;
- void *write_user_data;
+ gpr_slice_buffer *incoming_buffer;
+ gpr_slice_buffer *outgoing_buffer;
+ /** slice within outgoing_buffer to write next */
+ size_t outgoing_slice_idx;
+ /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */
+ size_t outgoing_byte_idx;
- grpc_tcp_slice_state write_state;
+ grpc_iomgr_closure *read_cb;
+ grpc_iomgr_closure *write_cb;
grpc_iomgr_closure read_closure;
grpc_iomgr_closure write_closure;
- grpc_iomgr_closure handle_read_closure;
-
char *peer_string;
} grpc_tcp;
-static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success);
-static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success);
+static void tcp_handle_read(void *arg /* grpc_tcp */, int success);
+static void tcp_handle_write(void *arg /* grpc_tcp */, int success);
-static void grpc_tcp_shutdown(grpc_endpoint *ep) {
+static void tcp_shutdown(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_fd_shutdown(tcp->em_fd);
}
-static void grpc_tcp_unref(grpc_tcp *tcp) {
- int refcount_zero = gpr_unref(&tcp->refcount);
- if (refcount_zero) {
- grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan");
- gpr_free(tcp->peer_string);
- gpr_free(tcp);
+static void tcp_free(grpc_tcp *tcp) {
+ grpc_fd_orphan(tcp->em_fd, NULL, "tcp_unref_orphan");
+ gpr_free(tcp->peer_string);
+ gpr_free(tcp);
+}
+
+/*#define GRPC_TCP_REFCOUNT_DEBUG*/
+#ifdef GRPC_TCP_REFCOUNT_DEBUG
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
+ int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
+ reason, tcp->refcount.count, tcp->refcount.count - 1);
+ if (gpr_unref(&tcp->refcount)) {
+ tcp_free(tcp);
}
}
-static void grpc_tcp_destroy(grpc_endpoint *ep) {
+static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
+ int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
+ reason, tcp->refcount.count, tcp->refcount.count + 1);
+ gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
+static void tcp_unref(grpc_tcp *tcp) {
+ if (gpr_unref(&tcp->refcount)) {
+ tcp_free(tcp);
+ }
+}
+
+static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
+static void tcp_destroy(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- grpc_tcp_unref(tcp);
+ TCP_UNREF(tcp, "destroy");
}
-static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status status) {
- grpc_endpoint_read_cb cb = tcp->read_cb;
+static void call_read_cb(grpc_tcp *tcp, int success) {
+ grpc_iomgr_closure *cb = tcp->read_cb;
if (grpc_tcp_trace) {
size_t i;
- gpr_log(GPR_DEBUG, "read: status=%d", status);
- for (i = 0; i < nslices; i++) {
- char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ gpr_log(GPR_DEBUG, "read: success=%d", success);
+ for (i = 0; i < tcp->incoming_buffer->count; i++) {
+ char *dump = gpr_dump_slice(tcp->incoming_buffer->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump);
gpr_free(dump);
}
}
tcp->read_cb = NULL;
- cb(tcp->read_user_data, slices, nslices, status);
+ tcp->incoming_buffer = NULL;
+ cb->cb(cb->cb_arg, success);
}
-#define INLINE_SLICE_BUFFER_SIZE 8
#define MAX_READ_IOVEC 4
-static void grpc_tcp_continue_read(grpc_tcp *tcp) {
- gpr_slice static_read_slices[INLINE_SLICE_BUFFER_SIZE];
+static void tcp_continue_read(grpc_tcp *tcp) {
struct msghdr msg;
struct iovec iov[MAX_READ_IOVEC];
ssize_t read_bytes;
- ssize_t allocated_bytes;
- struct grpc_tcp_slice_state read_state;
- gpr_slice *final_slices;
- size_t final_nslices;
+ size_t i;
GPR_ASSERT(!tcp->finished_edge);
+ GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
+ GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_READ, 0);
- slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
- 0);
- allocated_bytes = slice_state_append_blocks_into_iovec(
- &read_state, iov, tcp->iov_size, tcp->slice_size);
+ while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
+ gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
+ gpr_slice_malloc(tcp->slice_size));
+ }
+ for (i = 0; i < tcp->incoming_buffer->count; i++) {
+ iov[i].iov_base = GPR_SLICE_START_PTR(tcp->incoming_buffer->slices[i]);
+ iov[i].iov_len = GPR_SLICE_LENGTH(tcp->incoming_buffer->slices[i]);
+ }
msg.msg_name = NULL;
msg.msg_namelen = 0;
@@ -362,106 +192,105 @@ static void grpc_tcp_continue_read(grpc_tcp *tcp) {
} while (read_bytes < 0 && errno == EINTR);
GRPC_TIMER_END(GRPC_PTAG_RECVMSG, 0);
- if (read_bytes < allocated_bytes) {
- /* TODO(klempner): Consider a second read first, in hopes of getting a
- * quick EAGAIN and saving a bunch of allocations. */
- slice_state_remove_last(&read_state, read_bytes < 0
- ? allocated_bytes
- : allocated_bytes - read_bytes);
- }
-
if (read_bytes < 0) {
- /* NB: After calling the user_cb a parallel call of the read handler may
+ /* NB: After calling call_read_cb a parallel call of the read handler may
* be running. */
if (errno == EAGAIN) {
if (tcp->iov_size > 1) {
tcp->iov_size /= 2;
}
- if (slice_state_has_available(&read_state)) {
- /* TODO(klempner): We should probably do the call into the application
- without all this junk on the stack */
- /* FIXME(klempner): Refcount properly */
- slice_state_transfer_ownership(&read_state, &final_slices,
- &final_nslices);
- tcp->finished_edge = 1;
- call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
- slice_state_destroy(&read_state);
- grpc_tcp_unref(tcp);
- } else {
- /* We've consumed the edge, request a new one */
- slice_state_destroy(&read_state);
- grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure);
- }
+ /* We've consumed the edge, request a new one */
+ grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure);
} else {
/* TODO(klempner): Log interesting errors */
- call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
- slice_state_destroy(&read_state);
- grpc_tcp_unref(tcp);
+ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ call_read_cb(tcp, 0);
+ TCP_UNREF(tcp, "read");
}
} else if (read_bytes == 0) {
/* 0 read size ==> end of stream */
- if (slice_state_has_available(&read_state)) {
- /* there were bytes already read: pass them up to the application */
- slice_state_transfer_ownership(&read_state, &final_slices,
- &final_nslices);
- call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_EOF);
- } else {
- call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_EOF);
- }
- slice_state_destroy(&read_state);
- grpc_tcp_unref(tcp);
+ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ call_read_cb(tcp, 0);
+ TCP_UNREF(tcp, "read");
} else {
- if (tcp->iov_size < MAX_READ_IOVEC) {
+ GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
+ if ((size_t)read_bytes < tcp->incoming_buffer->length) {
+ gpr_slice_buffer_trim_end(tcp->incoming_buffer,
+ tcp->incoming_buffer->length - read_bytes);
+ } else if (tcp->iov_size < MAX_READ_IOVEC) {
++tcp->iov_size;
}
- GPR_ASSERT(slice_state_has_available(&read_state));
- slice_state_transfer_ownership(&read_state, &final_slices, &final_nslices);
- call_read_cb(tcp, final_slices, final_nslices, GRPC_ENDPOINT_CB_OK);
- slice_state_destroy(&read_state);
- grpc_tcp_unref(tcp);
+ GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
+ call_read_cb(tcp, 1);
+ TCP_UNREF(tcp, "read");
}
GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0);
}
-static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) {
+static void tcp_handle_read(void *arg /* grpc_tcp */, int success) {
grpc_tcp *tcp = (grpc_tcp *)arg;
GPR_ASSERT(!tcp->finished_edge);
if (!success) {
- call_read_cb(tcp, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
- grpc_tcp_unref(tcp);
+ gpr_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+ call_read_cb(tcp, 0);
+ TCP_UNREF(tcp, "read");
} else {
- grpc_tcp_continue_read(tcp);
+ tcp_continue_read(tcp);
}
}
-static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
- void *user_data) {
+static grpc_endpoint_op_status tcp_read(grpc_endpoint *ep,
+ gpr_slice_buffer *incoming_buffer,
+ grpc_iomgr_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
GPR_ASSERT(tcp->read_cb == NULL);
tcp->read_cb = cb;
- tcp->read_user_data = user_data;
- gpr_ref(&tcp->refcount);
+ tcp->incoming_buffer = incoming_buffer;
+ gpr_slice_buffer_reset_and_unref(incoming_buffer);
+ TCP_REF(tcp, "read");
if (tcp->finished_edge) {
tcp->finished_edge = 0;
grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure);
} else {
- tcp->handle_read_closure.cb_arg = tcp;
- grpc_iomgr_add_delayed_callback(&tcp->handle_read_closure, 1);
+ grpc_iomgr_add_delayed_callback(&tcp->read_closure, 1);
}
+ /* TODO(ctiller): immediate return */
+ return GRPC_ENDPOINT_PENDING;
}
#define MAX_WRITE_IOVEC 16
-static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) {
+static grpc_endpoint_op_status tcp_flush(grpc_tcp *tcp) {
struct msghdr msg;
struct iovec iov[MAX_WRITE_IOVEC];
int iov_size;
ssize_t sent_length;
- grpc_tcp_slice_state *state = &tcp->write_state;
+ ssize_t sending_length;
+ ssize_t trailing;
+ ssize_t unwind_slice_idx;
+ ssize_t unwind_byte_idx;
for (;;) {
- iov_size = slice_state_to_iovec(state, iov, MAX_WRITE_IOVEC);
+ sending_length = 0;
+ unwind_slice_idx = tcp->outgoing_slice_idx;
+ unwind_byte_idx = tcp->outgoing_byte_idx;
+ for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
+ iov_size != MAX_WRITE_IOVEC;
+ iov_size++) {
+ iov[iov_size].iov_base =
+ GPR_SLICE_START_PTR(
+ tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
+ tcp->outgoing_byte_idx;
+ iov[iov_size].iov_len =
+ GPR_SLICE_LENGTH(
+ tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
+ tcp->outgoing_byte_idx;
+ sending_length += iov[iov_size].iov_len;
+ tcp->outgoing_slice_idx++;
+ tcp->outgoing_byte_idx = 0;
+ }
+ GPR_ASSERT(iov_size > 0);
msg.msg_name = NULL;
msg.msg_namelen = 0;
@@ -480,70 +309,75 @@ static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) {
if (sent_length < 0) {
if (errno == EAGAIN) {
- return GRPC_ENDPOINT_WRITE_PENDING;
+ tcp->outgoing_slice_idx = unwind_slice_idx;
+ tcp->outgoing_byte_idx = unwind_byte_idx;
+ return GRPC_ENDPOINT_PENDING;
} else {
/* TODO(klempner): Log some of these */
- slice_state_destroy(state);
- return GRPC_ENDPOINT_WRITE_ERROR;
+ return GRPC_ENDPOINT_ERROR;
}
}
- /* TODO(klempner): Probably better to batch this after we finish flushing */
- slice_state_remove_prefix(state, sent_length);
+ GPR_ASSERT(tcp->outgoing_byte_idx == 0);
+ trailing = sending_length - sent_length;
+ while (trailing > 0) {
+ ssize_t slice_length;
+
+ tcp->outgoing_slice_idx--;
+ slice_length = GPR_SLICE_LENGTH(
+ tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
+ if (slice_length > trailing) {
+ tcp->outgoing_byte_idx = slice_length - trailing;
+ break;
+ } else {
+ trailing -= slice_length;
+ }
+ }
- if (!slice_state_has_available(state)) {
- return GRPC_ENDPOINT_WRITE_DONE;
+ if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
+ return GRPC_ENDPOINT_DONE;
}
};
}
-static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) {
+static void tcp_handle_write(void *arg /* grpc_tcp */, int success) {
grpc_tcp *tcp = (grpc_tcp *)arg;
- grpc_endpoint_write_status write_status;
- grpc_endpoint_cb_status cb_status;
- grpc_endpoint_write_cb cb;
+ grpc_endpoint_op_status status;
+ grpc_iomgr_closure *cb;
if (!success) {
- slice_state_destroy(&tcp->write_state);
cb = tcp->write_cb;
tcp->write_cb = NULL;
- cb(tcp->write_user_data, GRPC_ENDPOINT_CB_SHUTDOWN);
- grpc_tcp_unref(tcp);
+ cb->cb(cb->cb_arg, 0);
+ TCP_UNREF(tcp, "write");
return;
}
GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0);
- write_status = grpc_tcp_flush(tcp);
- if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
+ status = tcp_flush(tcp);
+ if (status == GRPC_ENDPOINT_PENDING) {
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
} else {
- slice_state_destroy(&tcp->write_state);
- if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
- cb_status = GRPC_ENDPOINT_CB_OK;
- } else {
- cb_status = GRPC_ENDPOINT_CB_ERROR;
- }
cb = tcp->write_cb;
tcp->write_cb = NULL;
- cb(tcp->write_user_data, cb_status);
- grpc_tcp_unref(tcp);
+ cb->cb(cb->cb_arg, status == GRPC_ENDPOINT_DONE);
+ TCP_UNREF(tcp, "write");
}
GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0);
}
-static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
- gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_write_cb cb,
- void *user_data) {
+static grpc_endpoint_op_status tcp_write(grpc_endpoint *ep,
+ gpr_slice_buffer *buf,
+ grpc_iomgr_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- grpc_endpoint_write_status status;
+ grpc_endpoint_op_status status;
if (grpc_tcp_trace) {
size_t i;
- for (i = 0; i < nslices; i++) {
- char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ for (i = 0; i < buf->count; i++) {
+ char *data =
+ gpr_dump_slice(buf->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "WRITE %p: %s", tcp, data);
gpr_free(data);
}
@@ -551,15 +385,19 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0);
GPR_ASSERT(tcp->write_cb == NULL);
- slice_state_init(&tcp->write_state, slices, nslices, nslices);
- status = grpc_tcp_flush(tcp);
- if (status == GRPC_ENDPOINT_WRITE_PENDING) {
- /* TODO(klempner): Consider inlining rather than malloc for small nslices */
- slice_state_realloc(&tcp->write_state, nslices);
- gpr_ref(&tcp->refcount);
+ if (buf->length == 0) {
+ GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
+ return GRPC_ENDPOINT_DONE;
+ }
+ tcp->outgoing_buffer = buf;
+ tcp->outgoing_slice_idx = 0;
+ tcp->outgoing_byte_idx = 0;
+
+ status = tcp_flush(tcp);
+ if (status == GRPC_ENDPOINT_PENDING) {
+ TCP_REF(tcp, "write");
tcp->write_cb = cb;
- tcp->write_user_data = user_data;
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
}
@@ -567,27 +405,25 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
return status;
}
-static void grpc_tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
+static void tcp_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_pollset_add_fd(pollset, tcp->em_fd);
}
-static void grpc_tcp_add_to_pollset_set(grpc_endpoint *ep,
- grpc_pollset_set *pollset_set) {
+static void tcp_add_to_pollset_set(grpc_endpoint *ep,
+ grpc_pollset_set *pollset_set) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_pollset_set_add_fd(pollset_set, tcp->em_fd);
}
-static char *grpc_tcp_get_peer(grpc_endpoint *ep) {
+static char *tcp_get_peer(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
return gpr_strdup(tcp->peer_string);
}
static const grpc_endpoint_vtable vtable = {
- grpc_tcp_notify_on_read, grpc_tcp_write,
- grpc_tcp_add_to_pollset, grpc_tcp_add_to_pollset_set,
- grpc_tcp_shutdown, grpc_tcp_destroy,
- grpc_tcp_get_peer};
+ tcp_read, tcp_write, tcp_add_to_pollset, tcp_add_to_pollset_set,
+ tcp_shutdown, tcp_destroy, tcp_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
const char *peer_string) {
@@ -597,21 +433,18 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size,
tcp->fd = em_fd->fd;
tcp->read_cb = NULL;
tcp->write_cb = NULL;
- tcp->read_user_data = NULL;
- tcp->write_user_data = NULL;
+ tcp->incoming_buffer = NULL;
tcp->slice_size = slice_size;
tcp->iov_size = 1;
tcp->finished_edge = 1;
- slice_state_init(&tcp->write_state, NULL, 0, 0);
/* paired with unref in grpc_tcp_destroy */
gpr_ref_init(&tcp->refcount, 1);
tcp->em_fd = em_fd;
- tcp->read_closure.cb = grpc_tcp_handle_read;
+ tcp->read_closure.cb = tcp_handle_read;
tcp->read_closure.cb_arg = tcp;
- tcp->write_closure.cb = grpc_tcp_handle_write;
+ tcp->write_closure.cb = tcp_handle_write;
tcp->write_closure.cb_arg = tcp;
- tcp->handle_read_closure.cb = grpc_tcp_handle_read;
return &tcp->base;
}
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index d0478d3604..b513d854aa 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -75,18 +75,18 @@ struct grpc_tcp_server {
void *cb_arg;
gpr_mu mu;
- gpr_cv cv;
/* active port count: how many ports are actually still listening */
int active_ports;
- /* number of iomgr callbacks that have been explicitly scheduled during
- * shutdown */
- int iomgr_callbacks_pending;
/* all listening ports */
server_port *ports;
size_t nports;
size_t port_capacity;
+
+ /* shutdown callback */
+ void(*shutdown_complete)(void *);
+ void *shutdown_complete_arg;
};
/* Public function. Allocates the proper data structures to hold a
@@ -94,48 +94,61 @@ struct grpc_tcp_server {
grpc_tcp_server *grpc_tcp_server_create(void) {
grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
gpr_mu_init(&s->mu);
- gpr_cv_init(&s->cv);
s->active_ports = 0;
- s->iomgr_callbacks_pending = 0;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
s->nports = 0;
s->port_capacity = INIT_PORT_CAP;
+ s->shutdown_complete = NULL;
return s;
}
+static void dont_care_about_shutdown_completion(void *arg) {}
+
+static void finish_shutdown(grpc_tcp_server *s) {
+ size_t i;
+
+ s->shutdown_complete(s->shutdown_complete_arg);
+
+ /* Now that the accepts have been aborted, we can destroy the sockets.
+ The IOCP won't get notified on these, so we can flag them as already
+ closed by the system. */
+ for (i = 0; i < s->nports; i++) {
+ server_port *sp = &s->ports[i];
+ grpc_winsocket_destroy(sp->socket);
+ }
+ gpr_free(s->ports);
+ gpr_free(s);
+}
+
/* Public function. Stops and destroys a grpc_tcp_server. */
void grpc_tcp_server_destroy(grpc_tcp_server *s,
- void (*shutdown_done)(void *shutdown_done_arg),
- void *shutdown_done_arg) {
+ void (*shutdown_complete)(void *shutdown_done_arg),
+ void *shutdown_complete_arg) {
size_t i;
+ int immediately_done = 0;
gpr_mu_lock(&s->mu);
+
+ s->shutdown_complete = shutdown_complete
+ ? shutdown_complete
+ : dont_care_about_shutdown_completion;
+ s->shutdown_complete_arg = shutdown_complete_arg;
+
/* First, shutdown all fd's. This will queue abortion calls for all
of the pending accepts due to the normal operation mechanism. */
+ if (s->active_ports == 0) {
+ immediately_done = 1;
+ }
for (i = 0; i < s->nports; i++) {
server_port *sp = &s->ports[i];
sp->shutting_down = 1;
- s->iomgr_callbacks_pending += grpc_winsocket_shutdown(sp->socket);
- }
- /* This happens asynchronously. Wait while that happens. */
- while (s->active_ports || s->iomgr_callbacks_pending) {
- gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
+ grpc_winsocket_shutdown(sp->socket);
}
gpr_mu_unlock(&s->mu);
- /* Now that the accepts have been aborted, we can destroy the sockets.
- The IOCP won't get notified on these, so we can flag them as already
- closed by the system. */
- for (i = 0; i < s->nports; i++) {
- server_port *sp = &s->ports[i];
- grpc_winsocket_orphan(sp->socket);
- }
- gpr_free(s->ports);
- gpr_free(s);
-
- if (shutdown_done) {
- shutdown_done(shutdown_done_arg);
+ if (immediately_done) {
+ finish_shutdown(s);
}
}
@@ -188,14 +201,17 @@ error:
}
static void decrement_active_ports_and_notify(server_port *sp) {
+ int notify = 0;
sp->shutting_down = 0;
- sp->socket->read_info.outstanding = 0;
gpr_mu_lock(&sp->server->mu);
GPR_ASSERT(sp->server->active_ports > 0);
- if (0 == --sp->server->active_ports) {
- gpr_cv_broadcast(&sp->server->cv);
+ if (0 == --sp->server->active_ports && sp->server->shutdown_complete != NULL) {
+ notify = 1;
}
gpr_mu_unlock(&sp->server->mu);
+ if (notify) {
+ finish_shutdown(sp->server);
+ }
}
/* start_accept will reference that for the IOCP notification request. */
@@ -280,12 +296,6 @@ static void on_accept(void *arg, int from_iocp) {
this is necessary in the read/write case, it's useless for the accept
case. We only need to adjust the pending callback count */
if (!from_iocp) {
- gpr_mu_lock(&sp->server->mu);
- GPR_ASSERT(sp->server->iomgr_callbacks_pending > 0);
- if (0 == --sp->server->iomgr_callbacks_pending) {
- gpr_cv_broadcast(&sp->server->cv);
- }
- gpr_mu_unlock(&sp->server->mu);
return;
}
@@ -462,7 +472,6 @@ void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
s->cb = cb;
s->cb_arg = cb_arg;
for (i = 0; i < s->nports; i++) {
- s->ports[i].socket->read_info.outstanding = 1;
start_accept(s->ports + i);
s->active_ports++;
}
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 901793ec43..fe3673c607 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -82,13 +82,11 @@ typedef struct grpc_tcp {
/* Refcounting how many operations are in progress. */
gpr_refcount refcount;
- grpc_endpoint_read_cb read_cb;
- void *read_user_data;
+ grpc_iomgr_closure *read_cb;
+ grpc_iomgr_closure *write_cb;
gpr_slice read_slice;
-
- grpc_endpoint_write_cb write_cb;
- void *write_user_data;
- gpr_slice_buffer write_slices;
+ gpr_slice_buffer *write_slices;
+ gpr_slice_buffer *read_slices;
/* The IO Completion Port runs from another thread. We need some mechanism
to protect ourselves when requesting a shutdown. */
@@ -98,82 +96,91 @@ typedef struct grpc_tcp {
char *peer_string;
} grpc_tcp;
-static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
+static void tcp_free(grpc_tcp *tcp) {
+ grpc_winsocket_destroy(tcp->socket);
+ gpr_mu_destroy(&tcp->mu);
+ gpr_free(tcp->peer_string);
+ gpr_free(tcp);
+}
+/*#define GRPC_TCP_REFCOUNT_DEBUG*/
+#ifdef GRPC_TCP_REFCOUNT_DEBUG
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp), (reason), __FILE__, __LINE__)
+#define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
+static void tcp_unref(grpc_tcp *tcp, const char *reason, const char *file,
+ int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %d -> %d", tcp,
+ reason, tcp->refcount.count, tcp->refcount.count - 1);
+ if (gpr_unref(&tcp->refcount)) {
+ tcp_free(tcp);
+ }
+}
+
+static void tcp_ref(grpc_tcp *tcp, const char *reason, const char *file,
+ int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %d -> %d", tcp,
+ reason, tcp->refcount.count, tcp->refcount.count + 1);
+ gpr_ref(&tcp->refcount);
+}
+#else
+#define TCP_UNREF(tcp, reason) tcp_unref((tcp))
+#define TCP_REF(tcp, reason) tcp_ref((tcp))
static void tcp_unref(grpc_tcp *tcp) {
if (gpr_unref(&tcp->refcount)) {
- gpr_slice_buffer_destroy(&tcp->write_slices);
- grpc_winsocket_orphan(tcp->socket);
- gpr_mu_destroy(&tcp->mu);
- gpr_free(tcp->peer_string);
- gpr_free(tcp);
+ tcp_free(tcp);
}
}
+static void tcp_ref(grpc_tcp *tcp) { gpr_ref(&tcp->refcount); }
+#endif
+
/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(void *tcpp, int from_iocp) {
- grpc_tcp *tcp = (grpc_tcp *)tcpp;
+static int on_read(grpc_tcp *tcp, int success) {
grpc_winsocket *socket = tcp->socket;
gpr_slice sub;
gpr_slice *slice = NULL;
size_t nslices = 0;
- grpc_endpoint_cb_status status;
- grpc_endpoint_read_cb cb;
grpc_winsocket_callback_info *info = &socket->read_info;
- void *opaque = tcp->read_user_data;
int do_abort = 0;
- gpr_mu_lock(&tcp->mu);
- cb = tcp->read_cb;
- tcp->read_cb = NULL;
- if (!from_iocp || tcp->shutting_down) {
- /* If we are here with from_iocp set to true, it means we got raced to
- shutting down the endpoint. No actual abort callback will happen
- though, so we're going to do it from here. */
- do_abort = 1;
- }
- gpr_mu_unlock(&tcp->mu);
-
- if (do_abort) {
- if (from_iocp) {
- tcp->socket->read_info.outstanding = 0;
+ if (success) {
+ if (socket->read_info.wsa_error != 0) {
+ if (socket->read_info.wsa_error != WSAECONNRESET) {
+ char *utf8_message = gpr_format_message(info->wsa_error);
+ gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
+ gpr_free(utf8_message);
+ }
+ success = 0;
gpr_slice_unref(tcp->read_slice);
- }
- tcp_unref(tcp);
- if (cb) cb(opaque, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
- return;
- }
-
- GPR_ASSERT(tcp->socket->read_info.outstanding);
-
- if (socket->read_info.wsa_error != 0) {
- if (socket->read_info.wsa_error != WSAECONNRESET) {
- char *utf8_message = gpr_format_message(info->wsa_error);
- gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
- gpr_free(utf8_message);
- }
- gpr_slice_unref(tcp->read_slice);
- status = GRPC_ENDPOINT_CB_ERROR;
- } else {
- if (info->bytes_transfered != 0) {
- sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
- status = GRPC_ENDPOINT_CB_OK;
- slice = &sub;
- nslices = 1;
} else {
- gpr_slice_unref(tcp->read_slice);
- status = GRPC_ENDPOINT_CB_EOF;
+ if (info->bytes_transfered != 0) {
+ sub = gpr_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
+ gpr_slice_buffer_add(tcp->read_slices, sub);
+ success = 1;
+ } else {
+ gpr_slice_unref(tcp->read_slice);
+ success = 0;
+ }
}
}
- tcp->socket->read_info.outstanding = 0;
+ return success;
+}
- tcp_unref(tcp);
- cb(opaque, slice, nslices, status);
+static void on_read_cb(void *tcpp, int from_iocp) {
+ grpc_tcp *tcp = tcpp;
+ grpc_iomgr_closure *cb = tcp->read_cb;
+ int success = on_read(tcp, from_iocp);
+ tcp->read_cb = NULL;
+ TCP_UNREF(tcp, "read");
+ if (cb) {
+ cb->cb(cb->cb_arg, success);
+ }
}
-static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
- void *arg) {
+static grpc_endpoint_op_status win_read(grpc_endpoint *ep,
+ gpr_slice_buffer *read_slices,
+ grpc_iomgr_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->read_info;
@@ -182,15 +189,13 @@ static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
DWORD flags = 0;
WSABUF buffer;
- GPR_ASSERT(!tcp->socket->read_info.outstanding);
if (tcp->shutting_down) {
- cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
- return;
+ return GRPC_ENDPOINT_ERROR;
}
- tcp_ref(tcp);
- tcp->socket->read_info.outstanding = 1;
+
tcp->read_cb = cb;
- tcp->read_user_data = arg;
+ tcp->read_slices = read_slices;
+ gpr_slice_buffer_reset_and_unref(read_slices);
tcp->read_slice = gpr_slice_malloc(8192);
@@ -204,12 +209,14 @@ static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
/* Did we get data immediately ? Yay. */
if (info->wsa_error != WSAEWOULDBLOCK) {
+ int ok;
info->bytes_transfered = bytes_read;
- /* This might heavily recurse. */
- on_read(tcp, 1);
- return;
+ ok = on_read(tcp, 1);
+ return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR;
}
+ TCP_REF(tcp, "read");
+
/* Otherwise, let's retry, by queuing a read. */
memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
@@ -218,71 +225,51 @@ static void win_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
if (status != 0) {
int wsa_error = WSAGetLastError();
if (wsa_error != WSA_IO_PENDING) {
+ int ok;
info->wsa_error = wsa_error;
- on_read(tcp, 1);
- return;
+ ok = on_read(tcp, 1);
+ return ok ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR;
}
}
- grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
+ grpc_socket_notify_on_read(tcp->socket, on_read_cb, tcp);
+ return GRPC_ENDPOINT_PENDING;
}
/* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(void *tcpp, int from_iocp) {
+static void on_write(void *tcpp, int success) {
grpc_tcp *tcp = (grpc_tcp *)tcpp;
grpc_winsocket *handle = tcp->socket;
grpc_winsocket_callback_info *info = &handle->write_info;
- grpc_endpoint_cb_status status = GRPC_ENDPOINT_CB_OK;
- grpc_endpoint_write_cb cb;
- void *opaque = tcp->write_user_data;
+ grpc_iomgr_closure *cb;
int do_abort = 0;
gpr_mu_lock(&tcp->mu);
cb = tcp->write_cb;
tcp->write_cb = NULL;
- if (!from_iocp || tcp->shutting_down) {
- /* If we are here with from_iocp set to true, it means we got raced to
- shutting down the endpoint. No actual abort callback will happen
- though, so we're going to do it from here. */
- do_abort = 1;
- }
gpr_mu_unlock(&tcp->mu);
- if (do_abort) {
- if (from_iocp) {
- tcp->socket->write_info.outstanding = 0;
- gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
- }
- tcp_unref(tcp);
- if (cb) cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
- return;
- }
-
- GPR_ASSERT(tcp->socket->write_info.outstanding);
-
- if (info->wsa_error != 0) {
- if (info->wsa_error != WSAECONNRESET) {
- char *utf8_message = gpr_format_message(info->wsa_error);
- gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
- gpr_free(utf8_message);
+ if (success) {
+ if (info->wsa_error != 0) {
+ if (info->wsa_error != WSAECONNRESET) {
+ char *utf8_message = gpr_format_message(info->wsa_error);
+ gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
+ gpr_free(utf8_message);
+ }
+ success = 0;
+ } else {
+ GPR_ASSERT(info->bytes_transfered == tcp->write_slices->length);
}
- status = GRPC_ENDPOINT_CB_ERROR;
- } else {
- GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
}
- gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
- tcp->socket->write_info.outstanding = 0;
-
- tcp_unref(tcp);
- cb(opaque, status);
+ TCP_UNREF(tcp, "write");
+ cb->cb(cb->cb_arg, success);
}
/* Initiates a write. */
-static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
- gpr_slice *slices, size_t nslices,
- grpc_endpoint_write_cb cb,
- void *arg) {
+static grpc_endpoint_op_status win_write(grpc_endpoint *ep,
+ gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) {
grpc_tcp *tcp = (grpc_tcp *)ep;
grpc_winsocket *socket = tcp->socket;
grpc_winsocket_callback_info *info = &socket->write_info;
@@ -293,30 +280,25 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
WSABUF *allocated = NULL;
WSABUF *buffers = local_buffers;
- GPR_ASSERT(!tcp->socket->write_info.outstanding);
if (tcp->shutting_down) {
- return GRPC_ENDPOINT_WRITE_ERROR;
+ return GRPC_ENDPOINT_ERROR;
}
- tcp_ref(tcp);
- tcp->socket->write_info.outstanding = 1;
tcp->write_cb = cb;
- tcp->write_user_data = arg;
+ tcp->write_slices = slices;
- gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);
-
- if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
- buffers = (WSABUF *)gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
+ 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]);
- buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
+ for (i = 0; i < tcp->write_slices->count; i++) {
+ buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices->slices[i]);
+ 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, tcp->write_slices->count,
&bytes_sent, 0, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
@@ -324,10 +306,10 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
connection that has its send queue filled up. But if we don't, then we can
avoid doing an async write operation at all. */
if (info->wsa_error != WSAEWOULDBLOCK) {
- grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
+ grpc_endpoint_op_status ret = GRPC_ENDPOINT_ERROR;
if (status == 0) {
- ret = GRPC_ENDPOINT_WRITE_DONE;
- GPR_ASSERT(bytes_sent == tcp->write_slices.length);
+ ret = GRPC_ENDPOINT_DONE;
+ GPR_ASSERT(bytes_sent == tcp->write_slices->length);
} else {
if (socket->read_info.wsa_error != WSAECONNRESET) {
char *utf8_message = gpr_format_message(info->wsa_error);
@@ -336,33 +318,30 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
}
}
if (allocated) gpr_free(allocated);
- gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
- tcp->socket->write_info.outstanding = 0;
- tcp_unref(tcp);
return ret;
}
+ TCP_REF(tcp, "write");
+
/* 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, tcp->write_slices->count,
&bytes_sent, 0, &socket->write_info.overlapped, NULL);
if (allocated) gpr_free(allocated);
if (status != 0) {
int wsa_error = WSAGetLastError();
if (wsa_error != WSA_IO_PENDING) {
- gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
- tcp->socket->write_info.outstanding = 0;
- tcp_unref(tcp);
- return GRPC_ENDPOINT_WRITE_ERROR;
+ TCP_UNREF(tcp, "write");
+ return GRPC_ENDPOINT_ERROR;
}
}
/* As all is now setup, we can now ask for the IOCP notification. It may
trigger the callback immediately however, but no matter. */
grpc_socket_notify_on_write(socket, on_write, tcp);
- return GRPC_ENDPOINT_WRITE_PENDING;
+ return GRPC_ENDPOINT_PENDING;
}
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *ps) {
@@ -387,19 +366,17 @@ static void win_add_to_pollset_set(grpc_endpoint *ep, grpc_pollset_set *pss) {
concurrent access of the data structure in that regard. */
static void win_shutdown(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- int extra_refs = 0;
gpr_mu_lock(&tcp->mu);
/* At that point, what may happen is that we're already inside the IOCP
callback. See the comments in on_read and on_write. */
tcp->shutting_down = 1;
- extra_refs = grpc_winsocket_shutdown(tcp->socket);
- while (extra_refs--) tcp_ref(tcp);
+ grpc_winsocket_shutdown(tcp->socket);
gpr_mu_unlock(&tcp->mu);
}
static void win_destroy(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *)ep;
- tcp_unref(tcp);
+ TCP_UNREF(tcp, "destroy");
}
static char *win_get_peer(grpc_endpoint *ep) {
@@ -408,8 +385,8 @@ static char *win_get_peer(grpc_endpoint *ep) {
}
static grpc_endpoint_vtable vtable = {
- win_notify_on_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
- win_shutdown, win_destroy, win_get_peer};
+ win_read, win_write, win_add_to_pollset, win_add_to_pollset_set,
+ win_shutdown, win_destroy, win_get_peer};
grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
@@ -417,7 +394,6 @@ grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket, char *peer_string) {
tcp->base.vtable = &vtable;
tcp->socket = socket;
gpr_mu_init(&tcp->mu);
- gpr_slice_buffer_init(&tcp->write_slices);
gpr_ref_init(&tcp->refcount, 1);
tcp->peer_string = gpr_strdup(peer_string);
return &tcp->base;
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 8e63978b82..f3ecfd0e60 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -153,7 +153,8 @@ static void send_security_metadata(grpc_call_element *elem,
}
if (channel_creds_has_md && call_creds_has_md) {
- calld->creds = grpc_composite_credentials_create(channel_creds, ctx->creds);
+ calld->creds =
+ grpc_composite_credentials_create(channel_creds, ctx->creds, NULL);
if (calld->creds == NULL) {
bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT,
"Incompatible credentials set on channel and call.");
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 8852cab3e7..a764413300 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -87,7 +87,10 @@ grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
void grpc_credentials_unref(grpc_credentials *creds) {
if (creds == NULL) return;
- if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
+ if (gpr_unref(&creds->refcount)) {
+ creds->vtable->destruct(creds);
+ gpr_free(creds);
+ }
}
void grpc_credentials_release(grpc_credentials *creds) {
@@ -135,9 +138,26 @@ grpc_security_status grpc_credentials_create_security_connector(
creds, target, args, request_metadata_creds, sc, new_args);
}
-void grpc_server_credentials_release(grpc_server_credentials *creds) {
+grpc_server_credentials *grpc_server_credentials_ref(
+ grpc_server_credentials *creds) {
+ if (creds == NULL) return NULL;
+ gpr_ref(&creds->refcount);
+ return creds;
+}
+
+void grpc_server_credentials_unref(grpc_server_credentials *creds) {
if (creds == NULL) return;
- creds->vtable->destroy(creds);
+ if (gpr_unref(&creds->refcount)) {
+ creds->vtable->destruct(creds);
+ if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
+ creds->processor.destroy(creds->processor.state);
+ }
+ gpr_free(creds);
+ }
+}
+
+void grpc_server_credentials_release(grpc_server_credentials *creds) {
+ grpc_server_credentials_unref(creds);
}
grpc_security_status grpc_server_credentials_create_security_connector(
@@ -152,20 +172,22 @@ grpc_security_status grpc_server_credentials_create_security_connector(
void grpc_server_credentials_set_auth_metadata_processor(
grpc_server_credentials *creds, grpc_auth_metadata_processor processor) {
if (creds == NULL) return;
+ if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
+ creds->processor.destroy(creds->processor.state);
+ }
creds->processor = processor;
}
/* -- Ssl credentials. -- */
-static void ssl_destroy(grpc_credentials *creds) {
+static void ssl_destruct(grpc_credentials *creds) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
- gpr_free(creds);
}
-static void ssl_server_destroy(grpc_server_credentials *creds) {
+static void ssl_server_destruct(grpc_server_credentials *creds) {
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
size_t i;
for (i = 0; i < c->config.num_key_cert_pairs; i++) {
@@ -185,7 +207,6 @@ static void ssl_server_destroy(grpc_server_credentials *creds) {
gpr_free(c->config.pem_cert_chains_sizes);
}
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
- gpr_free(creds);
}
static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
@@ -231,11 +252,11 @@ static grpc_security_status ssl_server_create_security_connector(
}
static grpc_credentials_vtable ssl_vtable = {
- ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL,
+ ssl_destruct, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL,
ssl_create_security_connector};
static grpc_server_credentials_vtable ssl_server_vtable = {
- ssl_server_destroy, ssl_server_create_security_connector};
+ ssl_server_destruct, ssl_server_create_security_connector};
static void ssl_copy_key_material(const char *input, unsigned char **output,
size_t *output_size) {
@@ -298,8 +319,10 @@ static void ssl_build_server_config(
}
grpc_credentials *grpc_ssl_credentials_create(
- const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair) {
+ const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
+ void *reserved) {
grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
+ GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(grpc_ssl_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_vtable;
@@ -310,11 +333,13 @@ grpc_credentials *grpc_ssl_credentials_create(
grpc_server_credentials *grpc_ssl_server_credentials_create(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
- size_t num_key_cert_pairs, int force_client_auth) {
+ size_t num_key_cert_pairs, int force_client_auth, void *reserved) {
grpc_ssl_server_credentials *c =
gpr_malloc(sizeof(grpc_ssl_server_credentials));
+ GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(grpc_ssl_server_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+ gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &ssl_server_vtable;
ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
num_key_cert_pairs, force_client_auth, &c->config);
@@ -335,13 +360,12 @@ static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
}
-static void jwt_destroy(grpc_credentials *creds) {
+static void jwt_destruct(grpc_credentials *creds) {
grpc_service_account_jwt_access_credentials *c =
(grpc_service_account_jwt_access_credentials *)creds;
grpc_auth_json_key_destruct(&c->key);
jwt_reset_cache(c);
gpr_mu_destroy(&c->cache_mu);
- gpr_free(c);
}
static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; }
@@ -406,7 +430,7 @@ static void jwt_get_request_metadata(grpc_credentials *creds,
}
static grpc_credentials_vtable jwt_vtable = {
- jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
+ jwt_destruct, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_request_metadata, NULL};
grpc_credentials *
@@ -430,20 +454,20 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
}
grpc_credentials *grpc_service_account_jwt_access_credentials_create(
- const char *json_key, gpr_timespec token_lifetime) {
+ const char *json_key, gpr_timespec token_lifetime, void *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);
}
/* -- Oauth2TokenFetcher credentials -- */
-static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
+static void oauth2_token_fetcher_destruct(grpc_credentials *creds) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
grpc_credentials_md_store_unref(c->access_token_md);
gpr_mu_destroy(&c->mu);
grpc_httpcli_context_destroy(&c->httpcli_context);
- gpr_free(c);
}
static int oauth2_token_fetcher_has_request_metadata(
@@ -613,10 +637,10 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
grpc_httpcli_context_init(&c->httpcli_context);
}
-/* -- ComputeEngine credentials. -- */
+/* -- GoogleComputeEngine credentials. -- */
static grpc_credentials_vtable compute_engine_vtable = {
- oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
+ oauth2_token_fetcher_destruct, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only,
oauth2_token_fetcher_get_request_metadata, NULL};
@@ -635,94 +659,27 @@ static void compute_engine_fetch_oauth2(
metadata_req);
}
-grpc_credentials *grpc_compute_engine_credentials_create(void) {
+grpc_credentials *grpc_google_compute_engine_credentials_create(
+ void *reserved) {
grpc_oauth2_token_fetcher_credentials *c =
gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
+ GPR_ASSERT(reserved == NULL);
init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
c->base.vtable = &compute_engine_vtable;
return &c->base;
}
-/* -- ServiceAccount credentials. -- */
-
-static void service_account_destroy(grpc_credentials *creds) {
- grpc_service_account_credentials *c =
- (grpc_service_account_credentials *)creds;
- if (c->scope != NULL) gpr_free(c->scope);
- grpc_auth_json_key_destruct(&c->key);
- oauth2_token_fetcher_destroy(&c->base.base);
-}
-
-static grpc_credentials_vtable service_account_vtable = {
- service_account_destroy, oauth2_token_fetcher_has_request_metadata,
- oauth2_token_fetcher_has_request_metadata_only,
- oauth2_token_fetcher_get_request_metadata, NULL};
-
-static void service_account_fetch_oauth2(
- grpc_credentials_metadata_request *metadata_req,
- grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
- grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
- grpc_service_account_credentials *c =
- (grpc_service_account_credentials *)metadata_req->creds;
- grpc_httpcli_header header = {"Content-Type",
- "application/x-www-form-urlencoded"};
- grpc_httpcli_request request;
- char *body = NULL;
- char *jwt = grpc_jwt_encode_and_sign(&c->key, GRPC_JWT_OAUTH2_AUDIENCE,
- c->token_lifetime, c->scope);
- if (jwt == NULL) {
- grpc_httpcli_response response;
- memset(&response, 0, sizeof(grpc_httpcli_response));
- response.status = 400; /* Invalid request. */
- gpr_log(GPR_ERROR, "Could not create signed jwt.");
- /* Do not even send the request, just call the response callback. */
- response_cb(metadata_req, &response);
- return;
- }
- gpr_asprintf(&body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
- memset(&request, 0, sizeof(grpc_httpcli_request));
- request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
- request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
- request.hdr_count = 1;
- request.hdrs = &header;
- request.handshaker = &grpc_httpcli_ssl;
- grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
- deadline, response_cb, metadata_req);
- gpr_free(body);
- gpr_free(jwt);
-}
-
-grpc_credentials *grpc_service_account_credentials_create(
- const char *json_key, const char *scope, gpr_timespec token_lifetime) {
- grpc_service_account_credentials *c;
- grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
+/* -- GoogleRefreshToken credentials. -- */
- if (scope == NULL || (strlen(scope) == 0) ||
- !grpc_auth_json_key_is_valid(&key)) {
- gpr_log(GPR_ERROR,
- "Invalid input for service account credentials creation");
- return NULL;
- }
- c = gpr_malloc(sizeof(grpc_service_account_credentials));
- memset(c, 0, sizeof(grpc_service_account_credentials));
- init_oauth2_token_fetcher(&c->base, service_account_fetch_oauth2);
- c->base.base.vtable = &service_account_vtable;
- c->scope = gpr_strdup(scope);
- c->key = key;
- c->token_lifetime = token_lifetime;
- return &c->base.base;
-}
-
-/* -- RefreshToken credentials. -- */
-
-static void refresh_token_destroy(grpc_credentials *creds) {
- grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
+static void refresh_token_destruct(grpc_credentials *creds) {
+ grpc_google_refresh_token_credentials *c =
+ (grpc_google_refresh_token_credentials *)creds;
grpc_auth_refresh_token_destruct(&c->refresh_token);
- oauth2_token_fetcher_destroy(&c->base.base);
+ oauth2_token_fetcher_destruct(&c->base.base);
}
static grpc_credentials_vtable refresh_token_vtable = {
- refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
+ refresh_token_destruct, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only,
oauth2_token_fetcher_get_request_metadata, NULL};
@@ -730,8 +687,8 @@ static void refresh_token_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req,
grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
- grpc_refresh_token_credentials *c =
- (grpc_refresh_token_credentials *)metadata_req->creds;
+ grpc_google_refresh_token_credentials *c =
+ (grpc_google_refresh_token_credentials *)metadata_req->creds;
grpc_httpcli_header header = {"Content-Type",
"application/x-www-form-urlencoded"};
grpc_httpcli_request request;
@@ -750,33 +707,34 @@ static void refresh_token_fetch_oauth2(
gpr_free(body);
}
-grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+grpc_credentials *
+grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token refresh_token) {
- grpc_refresh_token_credentials *c;
+ grpc_google_refresh_token_credentials *c;
if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
return NULL;
}
- c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
- memset(c, 0, sizeof(grpc_refresh_token_credentials));
+ c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials));
+ memset(c, 0, sizeof(grpc_google_refresh_token_credentials));
init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
c->base.base.vtable = &refresh_token_vtable;
c->refresh_token = refresh_token;
return &c->base.base;
}
-grpc_credentials *grpc_refresh_token_credentials_create(
- const char *json_refresh_token) {
+grpc_credentials *grpc_google_refresh_token_credentials_create(
+ const char *json_refresh_token, void *reserved) {
+ GPR_ASSERT(reserved == NULL);
return grpc_refresh_token_credentials_create_from_auth_refresh_token(
grpc_auth_refresh_token_create_from_string(json_refresh_token));
}
/* -- Metadata-only credentials. -- */
-static void md_only_test_destroy(grpc_credentials *creds) {
+static void md_only_test_destruct(grpc_credentials *creds) {
grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
grpc_credentials_md_store_unref(c->md_store);
- gpr_free(c);
}
static int md_only_test_has_request_metadata(const grpc_credentials *creds) {
@@ -817,7 +775,7 @@ static void md_only_test_get_request_metadata(grpc_credentials *creds,
}
static grpc_credentials_vtable md_only_test_vtable = {
- md_only_test_destroy, md_only_test_has_request_metadata,
+ md_only_test_destruct, md_only_test_has_request_metadata,
md_only_test_has_request_metadata_only, md_only_test_get_request_metadata,
NULL};
@@ -838,10 +796,9 @@ grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
/* -- Oauth2 Access Token credentials. -- */
-static void access_token_destroy(grpc_credentials *creds) {
+static void access_token_destruct(grpc_credentials *creds) {
grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
grpc_credentials_md_store_unref(c->access_token_md);
- gpr_free(c);
}
static int access_token_has_request_metadata(const grpc_credentials *creds) {
@@ -863,15 +820,16 @@ static void access_token_get_request_metadata(grpc_credentials *creds,
}
static grpc_credentials_vtable access_token_vtable = {
- access_token_destroy, access_token_has_request_metadata,
+ access_token_destruct, access_token_has_request_metadata,
access_token_has_request_metadata_only, access_token_get_request_metadata,
NULL};
-grpc_credentials *grpc_access_token_credentials_create(
- const char *access_token) {
+grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
+ void *reserved) {
grpc_access_token_credentials *c =
gpr_malloc(sizeof(grpc_access_token_credentials));
char *token_md_value;
+ GPR_ASSERT(reserved == NULL);
memset(c, 0, sizeof(grpc_access_token_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
c->base.vtable = &access_token_vtable;
@@ -886,14 +844,14 @@ grpc_credentials *grpc_access_token_credentials_create(
/* -- Fake transport security credentials. -- */
-static void fake_transport_security_credentials_destroy(
+static void fake_transport_security_credentials_destruct(
grpc_credentials *creds) {
- gpr_free(creds);
+ /* Nothing to do here. */
}
-static void fake_transport_security_server_credentials_destroy(
+static void fake_transport_security_server_credentials_destruct(
grpc_server_credentials *creds) {
- gpr_free(creds);
+ /* Nothing to do here. */
}
static int fake_transport_security_has_request_metadata(
@@ -922,14 +880,14 @@ fake_transport_security_server_create_security_connector(
}
static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
- fake_transport_security_credentials_destroy,
+ fake_transport_security_credentials_destruct,
fake_transport_security_has_request_metadata,
fake_transport_security_has_request_metadata_only, NULL,
fake_transport_security_create_security_connector};
static grpc_server_credentials_vtable
fake_transport_security_server_credentials_vtable = {
- fake_transport_security_server_credentials_destroy,
+ fake_transport_security_server_credentials_destruct,
fake_transport_security_server_create_security_connector};
grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
@@ -946,6 +904,7 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
memset(c, 0, sizeof(grpc_server_credentials));
c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+ gpr_ref_init(&c->refcount, 1);
c->vtable = &fake_transport_security_server_credentials_vtable;
return c;
}
@@ -962,14 +921,13 @@ typedef struct {
grpc_credentials_metadata_cb cb;
} grpc_composite_credentials_metadata_context;
-static void composite_destroy(grpc_credentials *creds) {
+static void composite_destruct(grpc_credentials *creds) {
grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
size_t i;
for (i = 0; i < c->inner.num_creds; i++) {
grpc_credentials_unref(c->inner.creds_array[i]);
}
gpr_free(c->inner.creds_array);
- gpr_free(creds);
}
static int composite_has_request_metadata(const grpc_credentials *creds) {
@@ -1085,7 +1043,7 @@ static grpc_security_status composite_create_security_connector(
}
static grpc_credentials_vtable composite_credentials_vtable = {
- composite_destroy, composite_has_request_metadata,
+ composite_destruct, composite_has_request_metadata,
composite_has_request_metadata_only, composite_get_request_metadata,
composite_create_security_connector};
@@ -1101,12 +1059,14 @@ static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
}
grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
- grpc_credentials *creds2) {
+ grpc_credentials *creds2,
+ void *reserved) {
size_t i;
size_t creds_array_byte_size;
grpc_credentials_array creds1_array;
grpc_credentials_array creds2_array;
grpc_composite_credentials *c;
+ GPR_ASSERT(reserved == NULL);
GPR_ASSERT(creds1 != NULL);
GPR_ASSERT(creds2 != NULL);
c = gpr_malloc(sizeof(grpc_composite_credentials));
@@ -1182,10 +1142,9 @@ grpc_credentials *grpc_credentials_contains_type(
/* -- IAM credentials. -- */
-static void iam_destroy(grpc_credentials *creds) {
- grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
+static void iam_destruct(grpc_credentials *creds) {
+ grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
grpc_credentials_md_store_unref(c->iam_md);
- gpr_free(c);
}
static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
@@ -1199,22 +1158,23 @@ static void iam_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data) {
- grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
+ grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
cb(user_data, c->iam_md->entries, c->iam_md->num_entries,
GRPC_CREDENTIALS_OK);
}
static grpc_credentials_vtable iam_vtable = {
- iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
+ iam_destruct, iam_has_request_metadata, iam_has_request_metadata_only,
iam_get_request_metadata, NULL};
-grpc_credentials *grpc_iam_credentials_create(const char *token,
- const char *authority_selector) {
- grpc_iam_credentials *c;
+grpc_credentials *grpc_google_iam_credentials_create(
+ const char *token, const char *authority_selector, void *reserved) {
+ grpc_google_iam_credentials *c;
+ GPR_ASSERT(reserved == NULL);
GPR_ASSERT(token != NULL);
GPR_ASSERT(authority_selector != NULL);
- c = gpr_malloc(sizeof(grpc_iam_credentials));
- memset(c, 0, sizeof(grpc_iam_credentials));
+ c = gpr_malloc(sizeof(grpc_google_iam_credentials));
+ memset(c, 0, sizeof(grpc_google_iam_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
c->base.vtable = &iam_vtable;
gpr_ref_init(&c->base.refcount, 1);
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 29cd1ac87f..8e4fed7615 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -129,7 +129,7 @@ typedef void (*grpc_credentials_metadata_cb)(void *user_data,
grpc_credentials_status status);
typedef struct {
- void (*destroy)(grpc_credentials *c);
+ void (*destruct)(grpc_credentials *c);
int (*has_request_metadata)(const grpc_credentials *c);
int (*has_request_metadata_only)(const grpc_credentials *c);
void (*get_request_metadata)(grpc_credentials *c, grpc_pollset *pollset,
@@ -210,20 +210,28 @@ grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
/* --- grpc_server_credentials. --- */
typedef struct {
- void (*destroy)(grpc_server_credentials *c);
+ void (*destruct)(grpc_server_credentials *c);
grpc_security_status (*create_security_connector)(
grpc_server_credentials *c, grpc_security_connector **sc);
} grpc_server_credentials_vtable;
+
+/* TODO(jboeuf): Add a refcount. */
struct grpc_server_credentials {
const grpc_server_credentials_vtable *vtable;
const char *type;
+ gpr_refcount refcount;
grpc_auth_metadata_processor processor;
};
grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc);
+grpc_server_credentials *grpc_server_credentials_ref(
+ grpc_server_credentials *creds);
+
+void grpc_server_credentials_unref(grpc_server_credentials *creds);
+
/* -- Ssl credentials. -- */
typedef struct {
@@ -277,21 +285,12 @@ typedef struct {
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
-/* -- ServiceAccount credentials. -- */
-
-typedef struct {
- grpc_oauth2_token_fetcher_credentials base;
- grpc_auth_json_key key;
- char *scope;
- gpr_timespec token_lifetime;
-} grpc_service_account_credentials;
-
-/* -- RefreshToken credentials. -- */
+/* -- GoogleRefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
-} grpc_refresh_token_credentials;
+} grpc_google_refresh_token_credentials;
/* -- Oauth2 Access Token credentials. -- */
@@ -308,12 +307,12 @@ typedef struct {
int is_async;
} grpc_md_only_test_credentials;
-/* -- IAM credentials. -- */
+/* -- GoogleIAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
-} grpc_iam_credentials;
+} grpc_google_iam_credentials;
/* -- Composite credentials. -- */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 3631de867a..874dd59e84 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -194,7 +194,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
int need_compute_engine_creds = is_stack_running_on_compute_engine();
compute_engine_detection_done = 1;
if (need_compute_engine_creds) {
- result = grpc_compute_engine_credentials_create();
+ result = grpc_google_compute_engine_credentials_create(NULL);
}
}
@@ -202,9 +202,9 @@ end:
if (!serving_cached_credentials && result != NULL) {
/* Blend with default ssl credentials and add a global reference so that it
can be cached and re-served. */
- grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
+ grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
default_credentials = grpc_credentials_ref(
- grpc_composite_credentials_create(ssl_creds, result));
+ grpc_composite_credentials_create(ssl_creds, result, NULL));
GPR_ASSERT(default_credentials != NULL);
grpc_credentials_unref(ssl_creds);
grpc_credentials_unref(result);
diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c
index 81b3e33cb2..b696e384fc 100644
--- a/src/core/security/secure_endpoint.c
+++ b/src/core/security/secure_endpoint.c
@@ -49,15 +49,15 @@ typedef struct {
struct tsi_frame_protector *protector;
gpr_mu protector_mu;
/* saved upper level callbacks and user_data. */
- grpc_endpoint_read_cb read_cb;
- void *read_user_data;
- grpc_endpoint_write_cb write_cb;
- void *write_user_data;
+ grpc_iomgr_closure *read_cb;
+ grpc_iomgr_closure *write_cb;
+ grpc_iomgr_closure on_read;
+ gpr_slice_buffer *read_buffer;
+ gpr_slice_buffer source_buffer;
/* saved handshaker leftover data to unprotect. */
gpr_slice_buffer leftover_bytes;
/* buffers for read and write */
gpr_slice read_staging_buffer;
- gpr_slice_buffer input_buffer;
gpr_slice write_staging_buffer;
gpr_slice_buffer output_buffer;
@@ -67,62 +67,91 @@ typedef struct {
int grpc_trace_secure_endpoint = 0;
-static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
-
static void destroy(secure_endpoint *secure_ep) {
secure_endpoint *ep = secure_ep;
grpc_endpoint_destroy(ep->wrapped_ep);
tsi_frame_protector_destroy(ep->protector);
gpr_slice_buffer_destroy(&ep->leftover_bytes);
gpr_slice_unref(ep->read_staging_buffer);
- gpr_slice_buffer_destroy(&ep->input_buffer);
gpr_slice_unref(ep->write_staging_buffer);
gpr_slice_buffer_destroy(&ep->output_buffer);
+ gpr_slice_buffer_destroy(&ep->source_buffer);
gpr_mu_destroy(&ep->protector_mu);
gpr_free(ep);
}
+/*#define GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG*/
+#ifdef GRPC_SECURE_ENDPOINT_REFCOUNT_DEBUG
+#define SECURE_ENDPOINT_UNREF(ep, reason) \
+ secure_endpoint_unref((ep), (reason), __FILE__, __LINE__)
+#define SECURE_ENDPOINT_REF(ep, reason) \
+ secure_endpoint_ref((ep), (reason), __FILE__, __LINE__)
+static void secure_endpoint_unref(secure_endpoint *ep, const char *reason,
+ const char *file, int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %d -> %d",
+ ep, reason, ep->ref.count, ep->ref.count - 1);
+ if (gpr_unref(&ep->ref)) {
+ destroy(ep);
+ }
+}
+
+static void secure_endpoint_ref(secure_endpoint *ep, const char *reason,
+ const char *file, int line) {
+ gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %d -> %d",
+ ep, reason, ep->ref.count, ep->ref.count + 1);
+ gpr_ref(&ep->ref);
+}
+#else
+#define SECURE_ENDPOINT_UNREF(ep, reason) secure_endpoint_unref((ep))
+#define SECURE_ENDPOINT_REF(ep, reason) secure_endpoint_ref((ep))
static void secure_endpoint_unref(secure_endpoint *ep) {
if (gpr_unref(&ep->ref)) {
destroy(ep);
}
}
+static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); }
+#endif
+
static void flush_read_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
gpr_uint8 **end) {
- gpr_slice_buffer_add(&ep->input_buffer, ep->read_staging_buffer);
+ gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer);
ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
*cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
*end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
}
-static void call_read_cb(secure_endpoint *ep, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status error) {
+static void call_read_cb(secure_endpoint *ep, int success) {
if (grpc_trace_secure_endpoint) {
size_t i;
- for (i = 0; i < nslices; i++) {
- char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ for (i = 0; i < ep->read_buffer->count; i++) {
+ char *data = gpr_dump_slice(ep->read_buffer->slices[i],
+ GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "READ %p: %s", ep, data);
gpr_free(data);
}
}
- ep->read_cb(ep->read_user_data, slices, nslices, error);
- secure_endpoint_unref(ep);
+ ep->read_buffer = NULL;
+ ep->read_cb->cb(ep->read_cb->cb_arg, success);
+ SECURE_ENDPOINT_UNREF(ep, "read");
}
-static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status error) {
+static int on_read(void *user_data, int success) {
unsigned i;
gpr_uint8 keep_looping = 0;
- size_t input_buffer_count = 0;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)user_data;
gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer);
gpr_uint8 *end = GPR_SLICE_END_PTR(ep->read_staging_buffer);
+ if (!success) {
+ gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+ return 0;
+ }
+
/* TODO(yangg) check error, maybe bail out early */
- for (i = 0; i < nslices; i++) {
- gpr_slice encrypted = slices[i];
+ for (i = 0; i < ep->source_buffer.count; i++) {
+ gpr_slice encrypted = ep->source_buffer.slices[i];
gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(encrypted);
size_t message_size = GPR_SLICE_LENGTH(encrypted);
@@ -161,7 +190,7 @@ static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) {
gpr_slice_buffer_add(
- &ep->input_buffer,
+ ep->read_buffer,
gpr_slice_split_head(
&ep->read_staging_buffer,
(size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer))));
@@ -169,38 +198,53 @@ static void on_read(void *user_data, gpr_slice *slices, size_t nslices,
/* TODO(yangg) experiment with moving this block after read_cb to see if it
helps latency */
- for (i = 0; i < nslices; i++) {
- gpr_slice_unref(slices[i]);
- }
+ gpr_slice_buffer_reset_and_unref(&ep->source_buffer);
if (result != TSI_OK) {
- gpr_slice_buffer_reset_and_unref(&ep->input_buffer);
- call_read_cb(ep, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
- return;
+ gpr_slice_buffer_reset_and_unref(ep->read_buffer);
+ return 0;
}
- /* The upper level will unref the slices. */
- input_buffer_count = ep->input_buffer.count;
- ep->input_buffer.count = 0;
- call_read_cb(ep, ep->input_buffer.slices, input_buffer_count, error);
+
+ return 1;
+}
+
+static void on_read_cb(void *user_data, int success) {
+ call_read_cb(user_data, on_read(user_data, success));
}
-static void endpoint_notify_on_read(grpc_endpoint *secure_ep,
- grpc_endpoint_read_cb cb, void *user_data) {
+static grpc_endpoint_op_status endpoint_read(grpc_endpoint *secure_ep,
+ gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
+ int immediate_read_success = -1;
ep->read_cb = cb;
- ep->read_user_data = user_data;
-
- secure_endpoint_ref(ep);
+ ep->read_buffer = slices;
+ gpr_slice_buffer_reset_and_unref(ep->read_buffer);
if (ep->leftover_bytes.count) {
- size_t leftover_nslices = ep->leftover_bytes.count;
- ep->leftover_bytes.count = 0;
- on_read(ep, ep->leftover_bytes.slices, leftover_nslices,
- GRPC_ENDPOINT_CB_OK);
- return;
+ gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer);
+ GPR_ASSERT(ep->leftover_bytes.count == 0);
+ return on_read(ep, 1) ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR;
}
- grpc_endpoint_notify_on_read(ep->wrapped_ep, on_read, ep);
+ SECURE_ENDPOINT_REF(ep, "read");
+
+ switch (
+ grpc_endpoint_read(ep->wrapped_ep, &ep->source_buffer, &ep->on_read)) {
+ case GRPC_ENDPOINT_DONE:
+ immediate_read_success = on_read(ep, 1);
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ return GRPC_ENDPOINT_PENDING;
+ case GRPC_ENDPOINT_ERROR:
+ immediate_read_success = on_read(ep, 0);
+ break;
+ }
+
+ GPR_ASSERT(immediate_read_success != -1);
+ SECURE_ENDPOINT_UNREF(ep, "read");
+
+ return immediate_read_success ? GRPC_ENDPOINT_DONE : GRPC_ENDPOINT_ERROR;
}
static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
@@ -211,36 +255,28 @@ static void flush_write_staging_buffer(secure_endpoint *ep, gpr_uint8 **cur,
*end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
}
-static void on_write(void *data, grpc_endpoint_cb_status error) {
- secure_endpoint *ep = data;
- ep->write_cb(ep->write_user_data, error);
- secure_endpoint_unref(ep);
-}
-
-static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep,
- gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_write_cb cb,
- void *user_data) {
+static grpc_endpoint_op_status endpoint_write(grpc_endpoint *secure_ep,
+ gpr_slice_buffer *slices,
+ grpc_iomgr_closure *cb) {
unsigned i;
- size_t output_buffer_count = 0;
tsi_result result = TSI_OK;
secure_endpoint *ep = (secure_endpoint *)secure_ep;
gpr_uint8 *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer);
gpr_uint8 *end = GPR_SLICE_END_PTR(ep->write_staging_buffer);
- grpc_endpoint_write_status status;
- GPR_ASSERT(ep->output_buffer.count == 0);
+
+ gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
if (grpc_trace_secure_endpoint) {
- for (i = 0; i < nslices; i++) {
- char *data = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
+ for (i = 0; i < slices->count; i++) {
+ char *data =
+ gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data);
gpr_free(data);
}
}
- for (i = 0; i < nslices; i++) {
- gpr_slice plain = slices[i];
+ for (i = 0; i < slices->count; i++) {
+ gpr_slice plain = slices->slices[i];
gpr_uint8 *message_bytes = GPR_SLICE_START_PTR(plain);
size_t message_size = GPR_SLICE_LENGTH(plain);
while (message_size > 0) {
@@ -290,29 +326,13 @@ static grpc_endpoint_write_status endpoint_write(grpc_endpoint *secure_ep,
}
}
- for (i = 0; i < nslices; i++) {
- gpr_slice_unref(slices[i]);
- }
-
if (result != TSI_OK) {
/* TODO(yangg) do different things according to the error type? */
gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
- return GRPC_ENDPOINT_WRITE_ERROR;
+ return GRPC_ENDPOINT_ERROR;
}
- /* clear output_buffer and let the lower level handle its slices. */
- output_buffer_count = ep->output_buffer.count;
- ep->output_buffer.count = 0;
- ep->write_cb = cb;
- ep->write_user_data = user_data;
- /* Need to keep the endpoint alive across a transport */
- secure_endpoint_ref(ep);
- status = grpc_endpoint_write(ep->wrapped_ep, ep->output_buffer.slices,
- output_buffer_count, on_write, ep);
- if (status != GRPC_ENDPOINT_WRITE_PENDING) {
- secure_endpoint_unref(ep);
- }
- return status;
+ return grpc_endpoint_write(ep->wrapped_ep, &ep->output_buffer, cb);
}
static void endpoint_shutdown(grpc_endpoint *secure_ep) {
@@ -320,9 +340,9 @@ static void endpoint_shutdown(grpc_endpoint *secure_ep) {
grpc_endpoint_shutdown(ep->wrapped_ep);
}
-static void endpoint_unref(grpc_endpoint *secure_ep) {
+static void endpoint_destroy(grpc_endpoint *secure_ep) {
secure_endpoint *ep = (secure_endpoint *)secure_ep;
- secure_endpoint_unref(ep);
+ SECURE_ENDPOINT_UNREF(ep, "destroy");
}
static void endpoint_add_to_pollset(grpc_endpoint *secure_ep,
@@ -343,9 +363,9 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) {
}
static const grpc_endpoint_vtable vtable = {
- endpoint_notify_on_read, endpoint_write,
+ endpoint_read, endpoint_write,
endpoint_add_to_pollset, endpoint_add_to_pollset_set,
- endpoint_shutdown, endpoint_unref,
+ endpoint_shutdown, endpoint_destroy,
endpoint_get_peer};
grpc_endpoint *grpc_secure_endpoint_create(
@@ -363,8 +383,10 @@ grpc_endpoint *grpc_secure_endpoint_create(
}
ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE);
- gpr_slice_buffer_init(&ep->input_buffer);
gpr_slice_buffer_init(&ep->output_buffer);
+ gpr_slice_buffer_init(&ep->source_buffer);
+ ep->read_buffer = NULL;
+ grpc_iomgr_closure_init(&ep->on_read, on_read_cb, ep);
gpr_mu_init(&ep->protector_mu);
gpr_ref_init(&ep->ref, 1);
return &ep->base;
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
index 0c3572b53c..bf0079577e 100644
--- a/src/core/security/secure_transport_setup.c
+++ b/src/core/security/secure_transport_setup.c
@@ -50,16 +50,17 @@ typedef struct {
grpc_endpoint *wrapped_endpoint;
grpc_endpoint *secure_endpoint;
gpr_slice_buffer left_overs;
+ gpr_slice_buffer incoming;
+ gpr_slice_buffer outgoing;
grpc_secure_transport_setup_done_cb cb;
void *user_data;
+ grpc_iomgr_closure on_handshake_data_sent_to_peer;
+ grpc_iomgr_closure on_handshake_data_received_from_peer;
} grpc_secure_transport_setup;
-static void on_handshake_data_received_from_peer(void *setup, gpr_slice *slices,
- size_t nslices,
- grpc_endpoint_cb_status error);
+static void on_handshake_data_received_from_peer(void *setup, int success);
-static void on_handshake_data_sent_to_peer(void *setup,
- grpc_endpoint_cb_status error);
+static void on_handshake_data_sent_to_peer(void *setup, int success);
static void secure_transport_setup_done(grpc_secure_transport_setup *s,
int is_success) {
@@ -78,6 +79,8 @@ static void secure_transport_setup_done(grpc_secure_transport_setup *s,
if (s->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
gpr_slice_buffer_destroy(&s->left_overs);
+ gpr_slice_buffer_destroy(&s->outgoing);
+ gpr_slice_buffer_destroy(&s->incoming);
GRPC_SECURITY_CONNECTOR_UNREF(s->connector, "secure_transport_setup");
gpr_free(s);
}
@@ -102,6 +105,8 @@ static void on_peer_checked(void *user_data, grpc_security_status status) {
s->secure_endpoint =
grpc_secure_endpoint_create(protector, s->wrapped_endpoint,
s->left_overs.slices, s->left_overs.count);
+ s->left_overs.count = 0;
+ s->left_overs.length = 0;
secure_transport_setup_done(s, 1);
return;
}
@@ -132,7 +137,6 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) {
size_t offset = 0;
tsi_result result = TSI_OK;
gpr_slice to_send;
- grpc_endpoint_write_status write_status;
do {
size_t to_send_size = s->handshake_buffer_size - offset;
@@ -155,28 +159,25 @@ static void send_handshake_bytes_to_peer(grpc_secure_transport_setup *s) {
to_send =
gpr_slice_from_copied_buffer((const char *)s->handshake_buffer, offset);
+ gpr_slice_buffer_reset_and_unref(&s->outgoing);
+ gpr_slice_buffer_add(&s->outgoing, to_send);
/* TODO(klempner,jboeuf): This should probably use the client setup
deadline */
- write_status = grpc_endpoint_write(s->wrapped_endpoint, &to_send, 1,
- on_handshake_data_sent_to_peer, s);
- if (write_status == GRPC_ENDPOINT_WRITE_ERROR) {
- gpr_log(GPR_ERROR, "Could not send handshake data to peer.");
- secure_transport_setup_done(s, 0);
- } else if (write_status == GRPC_ENDPOINT_WRITE_DONE) {
- on_handshake_data_sent_to_peer(s, GRPC_ENDPOINT_CB_OK);
- }
-}
-
-static void cleanup_slices(gpr_slice *slices, size_t num_slices) {
- size_t i;
- for (i = 0; i < num_slices; i++) {
- gpr_slice_unref(slices[i]);
+ switch (grpc_endpoint_write(s->wrapped_endpoint, &s->outgoing,
+ &s->on_handshake_data_sent_to_peer)) {
+ case GRPC_ENDPOINT_ERROR:
+ gpr_log(GPR_ERROR, "Could not send handshake data to peer.");
+ secure_transport_setup_done(s, 0);
+ break;
+ case GRPC_ENDPOINT_DONE:
+ on_handshake_data_sent_to_peer(s, 1);
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ break;
}
}
-static void on_handshake_data_received_from_peer(
- void *setup, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status error) {
+static void on_handshake_data_received_from_peer(void *setup, int success) {
grpc_secure_transport_setup *s = setup;
size_t consumed_slice_size = 0;
tsi_result result = TSI_OK;
@@ -184,32 +185,37 @@ static void on_handshake_data_received_from_peer(
size_t num_left_overs;
int has_left_overs_in_current_slice = 0;
- if (error != GRPC_ENDPOINT_CB_OK) {
+ if (!success) {
gpr_log(GPR_ERROR, "Read failed.");
- cleanup_slices(slices, nslices);
secure_transport_setup_done(s, 0);
return;
}
- for (i = 0; i < nslices; i++) {
- consumed_slice_size = GPR_SLICE_LENGTH(slices[i]);
+ for (i = 0; i < s->incoming.count; i++) {
+ consumed_slice_size = GPR_SLICE_LENGTH(s->incoming.slices[i]);
result = tsi_handshaker_process_bytes_from_peer(
- s->handshaker, GPR_SLICE_START_PTR(slices[i]), &consumed_slice_size);
+ s->handshaker, GPR_SLICE_START_PTR(s->incoming.slices[i]),
+ &consumed_slice_size);
if (!tsi_handshaker_is_in_progress(s->handshaker)) break;
}
if (tsi_handshaker_is_in_progress(s->handshaker)) {
/* We may need more data. */
if (result == TSI_INCOMPLETE_DATA) {
- /* TODO(klempner,jboeuf): This should probably use the client setup
- deadline */
- grpc_endpoint_notify_on_read(s->wrapped_endpoint,
- on_handshake_data_received_from_peer, setup);
- cleanup_slices(slices, nslices);
+ switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming,
+ &s->on_handshake_data_received_from_peer)) {
+ case GRPC_ENDPOINT_DONE:
+ on_handshake_data_received_from_peer(s, 1);
+ break;
+ case GRPC_ENDPOINT_ERROR:
+ on_handshake_data_received_from_peer(s, 0);
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ break;
+ }
return;
} else {
send_handshake_bytes_to_peer(s);
- cleanup_slices(slices, nslices);
return;
}
}
@@ -217,42 +223,40 @@ static void on_handshake_data_received_from_peer(
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshake failed with error %s",
tsi_result_to_string(result));
- cleanup_slices(slices, nslices);
secure_transport_setup_done(s, 0);
return;
}
/* Handshake is done and successful this point. */
has_left_overs_in_current_slice =
- (consumed_slice_size < GPR_SLICE_LENGTH(slices[i]));
- num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + nslices - i - 1;
+ (consumed_slice_size < GPR_SLICE_LENGTH(s->incoming.slices[i]));
+ num_left_overs =
+ (has_left_overs_in_current_slice ? 1 : 0) + s->incoming.count - i - 1;
if (num_left_overs == 0) {
- cleanup_slices(slices, nslices);
check_peer(s);
return;
}
- cleanup_slices(slices, nslices - num_left_overs);
-
/* Put the leftovers in our buffer (ownership transfered). */
if (has_left_overs_in_current_slice) {
- gpr_slice_buffer_add(&s->left_overs,
- gpr_slice_split_tail(&slices[i], consumed_slice_size));
- gpr_slice_unref(slices[i]); /* split_tail above increments refcount. */
+ gpr_slice_buffer_add(
+ &s->left_overs,
+ gpr_slice_split_tail(&s->incoming.slices[i], consumed_slice_size));
+ gpr_slice_unref(
+ s->incoming.slices[i]); /* split_tail above increments refcount. */
}
gpr_slice_buffer_addn(
- &s->left_overs, &slices[i + 1],
+ &s->left_overs, &s->incoming.slices[i + 1],
num_left_overs - (size_t)has_left_overs_in_current_slice);
check_peer(s);
}
/* If setup is NULL, the setup is done. */
-static void on_handshake_data_sent_to_peer(void *setup,
- grpc_endpoint_cb_status error) {
+static void on_handshake_data_sent_to_peer(void *setup, int success) {
grpc_secure_transport_setup *s = setup;
/* Make sure that write is OK. */
- if (error != GRPC_ENDPOINT_CB_OK) {
- gpr_log(GPR_ERROR, "Write failed with error %d.", error);
+ if (!success) {
+ gpr_log(GPR_ERROR, "Write failed.");
if (setup != NULL) secure_transport_setup_done(s, 0);
return;
}
@@ -261,8 +265,17 @@ static void on_handshake_data_sent_to_peer(void *setup,
if (tsi_handshaker_is_in_progress(s->handshaker)) {
/* TODO(klempner,jboeuf): This should probably use the client setup
deadline */
- grpc_endpoint_notify_on_read(s->wrapped_endpoint,
- on_handshake_data_received_from_peer, setup);
+ switch (grpc_endpoint_read(s->wrapped_endpoint, &s->incoming,
+ &s->on_handshake_data_received_from_peer)) {
+ case GRPC_ENDPOINT_ERROR:
+ on_handshake_data_received_from_peer(s, 0);
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ break;
+ case GRPC_ENDPOINT_DONE:
+ on_handshake_data_received_from_peer(s, 1);
+ break;
+ }
} else {
check_peer(s);
}
@@ -288,6 +301,12 @@ void grpc_setup_secure_transport(grpc_security_connector *connector,
s->wrapped_endpoint = nonsecure_endpoint;
s->user_data = user_data;
s->cb = cb;
+ grpc_iomgr_closure_init(&s->on_handshake_data_sent_to_peer,
+ on_handshake_data_sent_to_peer, s);
+ grpc_iomgr_closure_init(&s->on_handshake_data_received_from_peer,
+ on_handshake_data_received_from_peer, s);
gpr_slice_buffer_init(&s->left_overs);
+ gpr_slice_buffer_init(&s->outgoing);
+ gpr_slice_buffer_init(&s->incoming);
send_handshake_bytes_to_peer(s);
}
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index c1b434f302..95d80ba122 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -42,19 +42,6 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
-/* --- grpc_process_auth_metadata_func --- */
-
-static grpc_auth_metadata_processor server_processor = {NULL, NULL};
-
-grpc_auth_metadata_processor grpc_server_get_auth_metadata_processor(void) {
- return server_processor;
-}
-
-void grpc_server_register_auth_metadata_processor(
- grpc_auth_metadata_processor processor) {
- server_processor = processor;
-}
-
/* --- grpc_call --- */
grpc_call_error grpc_call_set_credentials(grpc_call *call,
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index 6e831431fa..d134201e87 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -50,6 +50,7 @@ typedef struct call_data {
handling it. */
grpc_iomgr_closure auth_on_recv;
grpc_transport_stream_op transport_op;
+ grpc_metadata_array md;
const grpc_metadata *consumed_md;
size_t num_consumed_md;
grpc_stream_op *md_op;
@@ -90,13 +91,17 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
call_data *calld = elem->call_data;
size_t i;
for (i = 0; i < calld->num_consumed_md; i++) {
+ const grpc_metadata *consumed_md = &calld->consumed_md[i];
/* Maybe we could do a pointer comparison but we do not have any guarantee
that the metadata processor used the same pointers for consumed_md in the
callback. */
- if (memcmp(GPR_SLICE_START_PTR(md->key->slice), calld->consumed_md[i].key,
+ if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
+ GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
+ continue;
+ }
+ if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key,
GPR_SLICE_LENGTH(md->key->slice)) == 0 &&
- memcmp(GPR_SLICE_START_PTR(md->value->slice),
- calld->consumed_md[i].value,
+ memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value,
GPR_SLICE_LENGTH(md->value->slice)) == 0) {
return NULL; /* Delete. */
}
@@ -123,9 +128,11 @@ static void on_md_processing_done(
calld->num_consumed_md = num_consumed_md;
grpc_metadata_batch_filter(&calld->md_op->data.metadata, remove_consumed_md,
elem);
+ grpc_metadata_array_destroy(&calld->md);
calld->on_done_recv->cb(calld->on_done_recv->cb_arg, 1);
} else {
gpr_slice message;
+ grpc_metadata_array_destroy(&calld->md);
error_details = error_details != NULL
? error_details
: "Authentication metadata processing failed.";
@@ -145,17 +152,15 @@ static void auth_on_recv(void *user_data, int success) {
size_t nops = calld->recv_ops->nops;
grpc_stream_op *ops = calld->recv_ops->ops;
for (i = 0; i < nops; i++) {
- grpc_metadata_array md_array;
grpc_stream_op *op = &ops[i];
if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue;
calld->got_client_metadata = 1;
if (chand->processor.process == NULL) continue;
calld->md_op = op;
- md_array = metadata_batch_to_md_array(&op->data.metadata);
+ calld->md = metadata_batch_to_md_array(&op->data.metadata);
chand->processor.process(chand->processor.state, calld->auth_context,
- md_array.metadata, md_array.count,
+ calld->md.metadata, calld->md.count,
on_md_processing_done, elem);
- grpc_metadata_array_destroy(&md_array);
return;
}
}
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 8d9d036d80..4749f5f516 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -61,7 +61,7 @@ typedef struct grpc_server_secure_state {
grpc_server *server;
grpc_tcp_server *tcp;
grpc_security_connector *sc;
- grpc_auth_metadata_processor processor;
+ grpc_server_credentials *creds;
tcp_endpoint_list *handshaking_tcp_endpoints;
int is_shutdown;
gpr_mu mu;
@@ -79,6 +79,7 @@ static void state_unref(grpc_server_secure_state *state) {
gpr_mu_unlock(&state->mu);
/* clean up */
GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server");
+ grpc_server_credentials_unref(state->creds);
gpr_free(state);
}
}
@@ -91,7 +92,8 @@ static void setup_transport(void *statep, grpc_transport *transport,
grpc_channel_args *args_copy;
grpc_arg args_to_add[2];
args_to_add[0] = grpc_security_connector_to_arg(state->sc);
- args_to_add[1] = grpc_auth_metadata_processor_to_arg(&state->processor);
+ args_to_add[1] =
+ grpc_auth_metadata_processor_to_arg(&state->creds->processor);
args_copy = grpc_channel_args_copy_and_add(
grpc_server_get_channel_args(state->server), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
@@ -262,7 +264,8 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
state->server = server;
state->tcp = tcp;
state->sc = sc;
- state->processor = creds->processor;
+ state->creds = grpc_server_credentials_ref(creds);
+
state->handshaking_tcp_endpoints = NULL;
state->is_shutdown = 0;
gpr_mu_init(&state->mu);
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index 629781da8a..b68239f8f5 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -81,10 +81,18 @@ void gpr_log(const char *file, int line, gpr_log_severity severity,
/* Simple starter implementation */
void gpr_default_log(gpr_log_func_args *args) {
+ char *final_slash;
+ const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
+ 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)) {
strcpy(time_buffer, "error:localtime");
} else if (0 ==
@@ -94,7 +102,7 @@ void gpr_default_log(gpr_log_func_args *args) {
fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n",
gpr_log_severity_string(args->severity), time_buffer,
- (int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line,
+ (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line,
args->message);
}
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index 987d5cb9b5..6482ef9c9f 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -207,3 +207,25 @@ void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) {
src->count = 0;
src->length = 0;
}
+
+void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n) {
+ GPR_ASSERT(n <= sb->length);
+ sb->length -= n;
+ for (;;) {
+ size_t idx = sb->count - 1;
+ gpr_slice slice = sb->slices[idx];
+ size_t slice_len = GPR_SLICE_LENGTH(slice);
+ if (slice_len > n) {
+ sb->slices[idx] = gpr_slice_sub_no_ref(slice, 0, slice_len - n);
+ return;
+ } else if (slice_len == n) {
+ gpr_slice_unref(slice);
+ sb->count = idx;
+ return;
+ } else {
+ gpr_slice_unref(slice);
+ n -= slice_len;
+ sb->count = idx;
+ }
+ }
+}
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index df23492171..f546477067 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -88,9 +88,9 @@ int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) {
SleepConditionVariableCS(cv, &mu->cs, INFINITE);
} else {
gpr_timespec now = gpr_now(abs_deadline.clock_type);
- gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
+ gpr_int64 now_ms = (gpr_int64)now.tv_sec * 1000 + now.tv_nsec / 1000000;
gpr_int64 deadline_ms =
- abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;
+ (gpr_int64)abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;
if (now_ms >= deadline_ms) {
timeout = 1;
} else {
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 4426bbbce9..6ece56371b 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -61,18 +61,6 @@
- status/close recv (depending on client/server) */
#define MAX_CONCURRENT_COMPLETIONS 6
-typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
-
-typedef enum {
- SEND_NOTHING,
- SEND_INITIAL_METADATA,
- SEND_BUFFERED_INITIAL_METADATA,
- SEND_MESSAGE,
- SEND_BUFFERED_MESSAGE,
- SEND_TRAILING_METADATA_AND_FINISH,
- SEND_FINISH
-} send_action;
-
typedef struct {
grpc_ioreq_completion_func on_complete;
void *user_data;
@@ -630,9 +618,6 @@ static void unlock(grpc_call *call) {
call->cancel_alarm = 0;
if (!call->receiving && need_more_data(call)) {
- op.recv_ops = &call->recv_ops;
- op.recv_state = &call->recv_state;
- op.on_done_recv = &call->on_done_recv;
if (grpc_bbq_empty(&call->incoming_queue) && call->reading_message) {
op.max_recv_bytes = call->incoming_message_length -
call->incoming_message.length + MAX_RECV_PEEK_AHEAD;
@@ -644,9 +629,16 @@ static void unlock(grpc_call *call) {
op.max_recv_bytes = MAX_RECV_PEEK_AHEAD - buffered_bytes;
}
}
- call->receiving = 1;
- GRPC_CALL_INTERNAL_REF(call, "receiving");
- start_op = 1;
+ /* TODO(ctiller): 1024 is basically to cover a bug
+ I don't understand yet */
+ if (op.max_recv_bytes > 1024) {
+ op.recv_ops = &call->recv_ops;
+ op.recv_state = &call->recv_state;
+ op.on_done_recv = &call->on_done_recv;
+ call->receiving = 1;
+ GRPC_CALL_INTERNAL_REF(call, "receiving");
+ start_op = 1;
+ }
}
if (!call->sending) {
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 8de024aaea..74dc09e36e 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -34,7 +34,7 @@
#ifndef GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H
#define GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H
-/* Internal API for completion channels */
+/* Internal API for completion queues */
#include "src/core/iomgr/pollset.h"
#include <grpc/grpc.h>
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index c68ba0e44b..9b554eeb70 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -185,7 +185,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
- perform handshakes */
grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const char *target,
- const grpc_channel_args *args) {
+ const grpc_channel_args *args,
+ void *reserved) {
grpc_channel *channel;
grpc_arg connector_arg;
grpc_channel_args *args_copy;
@@ -198,6 +199,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const grpc_channel_filter *filters[MAX_FILTERS];
size_t n = 0;
+ GPR_ASSERT(reserved == NULL);
if (grpc_find_security_connector_in_args(args) != NULL) {
gpr_log(GPR_ERROR, "Cannot set security context in channel args.");
return grpc_lame_client_channel_create(
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
index d7aaba3868..4b90e06a04 100644
--- a/src/core/surface/version.c
+++ b/src/core/surface/version.c
@@ -37,5 +37,5 @@
#include <grpc/grpc.h>
const char *grpc_version_string(void) {
- return "0.10.1.0";
+ return "0.11.0.0";
}
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 42cf0ecd5b..7a42de9245 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -214,6 +214,8 @@ typedef struct {
grpc_chttp2_hpack_compressor hpack_compressor;
/** is this a client? */
gpr_uint8 is_client;
+ /** callback for when writing is done */
+ grpc_iomgr_closure done_cb;
} grpc_chttp2_transport_writing;
struct grpc_chttp2_transport_parsing {
@@ -291,6 +293,9 @@ struct grpc_chttp2_transport {
gpr_refcount refs;
char *peer_string;
+ /** when this drops to zero it's safe to shutdown the endpoint */
+ gpr_refcount shutdown_ep_refs;
+
gpr_mu mu;
/** is the transport destroying itself? */
@@ -329,8 +334,11 @@ struct grpc_chttp2_transport {
/** closure to execute writing */
grpc_iomgr_closure writing_action;
- /** closure to start reading from the endpoint */
- grpc_iomgr_closure reading_action;
+ /** closure to finish reading from the endpoint */
+ grpc_iomgr_closure recv_data;
+
+ /** incoming read bytes */
+ gpr_slice_buffer read_buffer;
/** address to place a newly accepted stream - set and unset by
grpc_chttp2_parsing_accept_stream; used by init_stream to
@@ -463,8 +471,7 @@ int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing);
void grpc_chttp2_perform_writes(
grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint);
-void grpc_chttp2_terminate_writing(
- grpc_chttp2_transport_writing *transport_writing, int success);
+void grpc_chttp2_terminate_writing(void *transport_writing, int success);
void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global,
grpc_chttp2_transport_writing *writing);
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
index 38c6052f9c..781db7b0d6 100644
--- a/src/core/transport/chttp2/stream_lists.c
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -177,8 +177,10 @@ int grpc_chttp2_list_pop_writable_stream(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_WRITABLE);
- *stream_global = &stream->global;
- *stream_writing = &stream->writing;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ *stream_writing = &stream->writing;
+ }
return r;
}
@@ -210,7 +212,9 @@ int grpc_chttp2_list_pop_writing_stream(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
GRPC_CHTTP2_LIST_WRITING);
- *stream_writing = &stream->writing;
+ if (r != 0) {
+ *stream_writing = &stream->writing;
+ }
return r;
}
@@ -230,8 +234,10 @@ int grpc_chttp2_list_pop_written_stream(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
GRPC_CHTTP2_LIST_WRITTEN);
- *stream_global = &stream->global;
- *stream_writing = &stream->writing;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ *stream_writing = &stream->writing;
+ }
return r;
}
@@ -251,8 +257,10 @@ int grpc_chttp2_list_pop_parsing_seen_stream(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream,
GRPC_CHTTP2_LIST_PARSING_SEEN);
- *stream_global = &stream->global;
- *stream_parsing = &stream->parsing;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ *stream_parsing = &stream->parsing;
+ }
return r;
}
@@ -270,7 +278,9 @@ int grpc_chttp2_list_pop_waiting_for_concurrency(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
- *stream_global = &stream->global;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ }
return r;
}
@@ -288,7 +298,9 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING);
- *stream_global = &stream->global;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ }
return r;
}
@@ -306,7 +318,9 @@ int grpc_chttp2_list_pop_cancelled_waiting_for_writing(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING);
- *stream_global = &stream->global;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ }
return r;
}
@@ -326,8 +340,10 @@ int grpc_chttp2_list_pop_incoming_window_updated(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED);
- *stream_global = &stream->global;
- *stream_parsing = &stream->parsing;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ *stream_parsing = &stream->parsing;
+ }
return r;
}
@@ -353,7 +369,9 @@ int grpc_chttp2_list_pop_read_write_state_changed(
grpc_chttp2_stream *stream;
int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED);
- *stream_global = &stream->global;
+ if (r != 0) {
+ *stream_global = &stream->global;
+ }
return r;
}
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 123061b3fc..ac79044e08 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -37,7 +37,6 @@
#include <grpc/support/log.h>
static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing);
-static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status);
int grpc_chttp2_unlocking_check_writes(
grpc_chttp2_transport_global *transport_global,
@@ -114,6 +113,10 @@ int grpc_chttp2_unlocking_check_writes(
if (!stream_global->read_closed &&
stream_global->unannounced_incoming_window > 0) {
+ GPR_ASSERT(stream_writing->announce_window == 0);
+ GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+ "write", transport_writing, stream_writing, announce_window,
+ stream_global->unannounced_incoming_window);
stream_writing->announce_window =
stream_global->unannounced_incoming_window;
GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
@@ -165,16 +168,15 @@ void grpc_chttp2_perform_writes(
GPR_ASSERT(transport_writing->outbuf.count > 0);
GPR_ASSERT(endpoint);
- switch (grpc_endpoint_write(endpoint, transport_writing->outbuf.slices,
- transport_writing->outbuf.count, finish_write_cb,
- transport_writing)) {
- case GRPC_ENDPOINT_WRITE_DONE:
+ switch (grpc_endpoint_write(endpoint, &transport_writing->outbuf,
+ &transport_writing->done_cb)) {
+ case GRPC_ENDPOINT_DONE:
grpc_chttp2_terminate_writing(transport_writing, 1);
break;
- case GRPC_ENDPOINT_WRITE_ERROR:
+ case GRPC_ENDPOINT_ERROR:
grpc_chttp2_terminate_writing(transport_writing, 0);
break;
- case GRPC_ENDPOINT_WRITE_PENDING:
+ case GRPC_ENDPOINT_PENDING:
break;
}
}
@@ -198,6 +200,9 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
&transport_writing->outbuf,
grpc_chttp2_window_update_create(stream_writing->id,
stream_writing->announce_window));
+ GRPC_CHTTP2_FLOWCTL_TRACE_STREAM(
+ "write", transport_writing, stream_writing, announce_window,
+ -(gpr_int64)stream_writing->announce_window);
stream_writing->announce_window = 0;
}
if (stream_writing->send_closed == GRPC_SEND_CLOSED_WITH_RST_STREAM) {
@@ -209,12 +214,6 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
}
}
-static void finish_write_cb(void *tw, grpc_endpoint_cb_status write_status) {
- grpc_chttp2_transport_writing *transport_writing = tw;
- grpc_chttp2_terminate_writing(transport_writing,
- write_status == GRPC_ENDPOINT_CB_OK);
-}
-
void grpc_chttp2_cleanup_writing(
grpc_chttp2_transport_global *transport_global,
grpc_chttp2_transport_writing *transport_writing) {
@@ -243,6 +242,5 @@ void grpc_chttp2_cleanup_writing(
grpc_chttp2_list_add_read_write_state_changed(transport_global,
stream_global);
}
- transport_writing->outbuf.count = 0;
- transport_writing->outbuf.length = 0;
+ 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 1bbd210e46..9e3d7dd551 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -84,15 +84,13 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t);
/* forward declarations of various callbacks that we'll build closures around */
static void writing_action(void *t, int iomgr_success_ignored);
-static void reading_action(void *t, int iomgr_success_ignored);
/** Set a transport level setting, and push it to our peer */
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
gpr_uint32 value);
/** Endpoint callback to process incoming data */
-static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status error);
+static void recv_data(void *tp, int success);
/** Start disconnection chain */
static void drop_connection(grpc_chttp2_transport *t);
@@ -143,6 +141,7 @@ static void destruct_transport(grpc_chttp2_transport *t) {
grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
gpr_slice_buffer_destroy(&t->parsing.qbuf);
+ gpr_slice_buffer_destroy(&t->read_buffer);
grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
@@ -223,6 +222,8 @@ static void init_transport(grpc_chttp2_transport *t,
t->ep = ep;
/* one ref is for destroy, the other for when ep becomes NULL */
gpr_ref_init(&t->refs, 2);
+ /* ref is dropped at transport close() */
+ gpr_ref_init(&t->shutdown_ep_refs, 1);
gpr_mu_init(&t->mu);
grpc_mdctx_ref(mdctx);
t->peer_string = grpc_endpoint_get_peer(ep);
@@ -249,12 +250,16 @@ static void init_transport(grpc_chttp2_transport *t,
gpr_slice_buffer_init(&t->writing.outbuf);
grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
grpc_iomgr_closure_init(&t->writing_action, writing_action, t);
- grpc_iomgr_closure_init(&t->reading_action, reading_action, t);
gpr_slice_buffer_init(&t->parsing.qbuf);
grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);
+ grpc_iomgr_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
+ &t->writing);
+ grpc_iomgr_closure_init(&t->recv_data, recv_data, t);
+ gpr_slice_buffer_init(&t->read_buffer);
+
if (is_client) {
gpr_slice_buffer_add(
&t->global.qbuf,
@@ -333,13 +338,45 @@ static void destroy_transport(grpc_transport *gt) {
UNREF_TRANSPORT(t, "destroy");
}
+/** block grpc_endpoint_shutdown being called until a paired
+ allow_endpoint_shutdown is made */
+static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
+ GPR_ASSERT(t->ep);
+ gpr_ref(&t->shutdown_ep_refs);
+}
+
+static void allow_endpoint_shutdown_locked(grpc_chttp2_transport *t) {
+ if (gpr_unref(&t->shutdown_ep_refs)) {
+ if (t->ep) {
+ grpc_endpoint_shutdown(t->ep);
+ }
+ }
+}
+
+static void allow_endpoint_shutdown_unlocked(grpc_chttp2_transport *t) {
+ if (gpr_unref(&t->shutdown_ep_refs)) {
+ gpr_mu_lock(&t->mu);
+ if (t->ep) {
+ grpc_endpoint_shutdown(t->ep);
+ }
+ gpr_mu_unlock(&t->mu);
+ }
+}
+
+static void destroy_endpoint(grpc_chttp2_transport *t) {
+ grpc_endpoint_destroy(t->ep);
+ t->ep = NULL;
+ UNREF_TRANSPORT(
+ t, "disconnect"); /* safe because we'll still have the ref for write */
+}
+
static void close_transport_locked(grpc_chttp2_transport *t) {
if (!t->closed) {
t->closed = 1;
connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE,
"close_transport");
if (t->ep) {
- grpc_endpoint_shutdown(t->ep);
+ allow_endpoint_shutdown_locked(t);
}
}
}
@@ -468,6 +505,7 @@ static void unlock(grpc_chttp2_transport *t) {
t->writing_active = 1;
REF_TRANSPORT(t, "writing");
grpc_chttp2_schedule_closure(&t->global, &t->writing_action, 1);
+ prevent_endpoint_shutdown(t);
}
run_closures = t->global.pending_closures_head;
@@ -502,12 +540,14 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
}
}
-void grpc_chttp2_terminate_writing(
- grpc_chttp2_transport_writing *transport_writing, int success) {
+void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) {
+ grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
lock(t);
+ allow_endpoint_shutdown_locked(t);
+
if (!success) {
drop_connection(t);
}
@@ -519,10 +559,7 @@ void grpc_chttp2_terminate_writing(
from starting */
t->writing_active = 0;
if (t->ep && !t->endpoint_reading) {
- grpc_endpoint_destroy(t->ep);
- t->ep = NULL;
- UNREF_TRANSPORT(
- t, "disconnect"); /* safe because we'll still have the ref for write */
+ destroy_endpoint(t);
}
unlock(t);
@@ -658,9 +695,9 @@ static void perform_stream_op_locked(
}
grpc_chttp2_incoming_metadata_live_op_buffer_end(
&stream_global->outstanding_metadata);
+ grpc_chttp2_list_add_read_write_state_changed(transport_global,
+ stream_global);
if (stream_global->id != 0) {
- grpc_chttp2_list_add_read_write_state_changed(transport_global,
- stream_global);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
}
}
@@ -1052,82 +1089,90 @@ static void update_global_window(void *args, gpr_uint32 id, void *stream) {
static void read_error_locked(grpc_chttp2_transport *t) {
t->endpoint_reading = 0;
if (!t->writing_active && t->ep) {
- grpc_endpoint_destroy(t->ep);
- t->ep = NULL;
- /* safe as we still have a ref for read */
- UNREF_TRANSPORT(t, "disconnect");
+ destroy_endpoint(t);
}
}
/* tcp read callback */
-static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
- grpc_endpoint_cb_status error) {
- grpc_chttp2_transport *t = tp;
+static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
size_t i;
- int unref = 0;
+ int keep_reading = 0;
- switch (error) {
- case GRPC_ENDPOINT_CB_SHUTDOWN:
- case GRPC_ENDPOINT_CB_EOF:
- case GRPC_ENDPOINT_CB_ERROR:
- lock(t);
+ lock(t);
+ i = 0;
+ GPR_ASSERT(!t->parsing_active);
+ if (!t->closed) {
+ t->parsing_active = 1;
+ /* merge stream lists */
+ grpc_chttp2_stream_map_move_into(&t->new_stream_map,
+ &t->parsing_stream_map);
+ grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
+ gpr_mu_unlock(&t->mu);
+ for (; i < t->read_buffer.count &&
+ grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]);
+ i++)
+ ;
+ gpr_mu_lock(&t->mu);
+ if (i != t->read_buffer.count) {
drop_connection(t);
- read_error_locked(t);
- unlock(t);
- unref = 1;
- for (i = 0; i < nslices; i++) gpr_slice_unref(slices[i]);
- break;
- case GRPC_ENDPOINT_CB_OK:
- lock(t);
- i = 0;
- GPR_ASSERT(!t->parsing_active);
- if (!t->closed) {
- t->parsing_active = 1;
- /* merge stream lists */
- grpc_chttp2_stream_map_move_into(&t->new_stream_map,
- &t->parsing_stream_map);
- grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
- gpr_mu_unlock(&t->mu);
- for (; i < nslices && grpc_chttp2_perform_read(&t->parsing, slices[i]);
- i++) {
- gpr_slice_unref(slices[i]);
- }
- gpr_mu_lock(&t->mu);
- if (i != nslices) {
- drop_connection(t);
- }
- /* merge stream lists */
- grpc_chttp2_stream_map_move_into(&t->new_stream_map,
- &t->parsing_stream_map);
- t->global.concurrent_stream_count =
- grpc_chttp2_stream_map_size(&t->parsing_stream_map);
- if (t->parsing.initial_window_update != 0) {
- grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
- update_global_window, t);
- t->parsing.initial_window_update = 0;
- }
- /* handle higher level things */
- grpc_chttp2_publish_reads(&t->global, &t->parsing);
- t->parsing_active = 0;
- }
- if (i == nslices) {
- grpc_chttp2_schedule_closure(&t->global, &t->reading_action, 1);
- } else {
- read_error_locked(t);
- unref = 1;
- }
- unlock(t);
- for (; i < nslices; i++) gpr_slice_unref(slices[i]);
- break;
+ }
+ /* merge stream lists */
+ grpc_chttp2_stream_map_move_into(&t->new_stream_map,
+ &t->parsing_stream_map);
+ t->global.concurrent_stream_count =
+ grpc_chttp2_stream_map_size(&t->parsing_stream_map);
+ if (t->parsing.initial_window_update != 0) {
+ grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
+ update_global_window, t);
+ t->parsing.initial_window_update = 0;
+ }
+ /* handle higher level things */
+ grpc_chttp2_publish_reads(&t->global, &t->parsing);
+ t->parsing_active = 0;
+ }
+ if (!*success || i != t->read_buffer.count) {
+ drop_connection(t);
+ read_error_locked(t);
+ } else if (!t->closed) {
+ keep_reading = 1;
+ REF_TRANSPORT(t, "keep_reading");
+ prevent_endpoint_shutdown(t);
}
- if (unref) {
+ gpr_slice_buffer_reset_and_unref(&t->read_buffer);
+ unlock(t);
+
+ if (keep_reading) {
+ int ret = -1;
+ switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) {
+ case GRPC_ENDPOINT_DONE:
+ *success = 1;
+ ret = 1;
+ break;
+ case GRPC_ENDPOINT_ERROR:
+ *success = 0;
+ ret = 1;
+ break;
+ case GRPC_ENDPOINT_PENDING:
+ ret = 0;
+ break;
+ }
+ allow_endpoint_shutdown_unlocked(t);
+ UNREF_TRANSPORT(t, "keep_reading");
+ return ret;
+ } else {
UNREF_TRANSPORT(t, "recv_data");
+ return 0;
}
+
+ gpr_log(GPR_ERROR, "should never reach here");
+ abort();
}
-static void reading_action(void *pt, int iomgr_success_ignored) {
- grpc_chttp2_transport *t = pt;
- grpc_endpoint_notify_on_read(t->ep, recv_data, t);
+static void recv_data(void *tp, int success) {
+ grpc_chttp2_transport *t = tp;
+
+ while (recv_data_loop(t, &success))
+ ;
}
/*
@@ -1240,5 +1285,6 @@ void grpc_chttp2_transport_start_reading(grpc_transport *transport,
gpr_slice *slices, size_t nslices) {
grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
- recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
+ gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
+ recv_data(t, 1);
}
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 3fd21a2f5d..61638764a6 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -703,7 +703,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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 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/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 8bf2e4687e..dc8e304664 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -40,7 +40,7 @@
#include <grpc/support/slice.h>
#include <grpc++/client_context.h>
#include <grpc++/completion_queue.h>
-#include <grpc++/credentials.h>
+#include <grpc++/security/credentials.h>
#include <grpc++/impl/call.h>
#include <grpc++/impl/rpc_method.h>
#include <grpc++/support/channel_arguments.h>
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index c4d7cf2e51..574656a7e9 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -36,7 +36,7 @@
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
-#include <grpc++/credentials.h>
+#include <grpc++/security/credentials.h>
#include <grpc++/server_context.h>
#include <grpc++/support/time.h>
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index 8c571cbbaa..d2b2d30126 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -44,8 +44,14 @@ namespace grpc {
class ChannelArguments;
std::shared_ptr<Channel> CreateChannel(
+ const grpc::string& target, const std::shared_ptr<Credentials>& creds) {
+ return CreateCustomChannel(target, creds, ChannelArguments());
+}
+
+std::shared_ptr<Channel> CreateCustomChannel(
const grpc::string& target, const std::shared_ptr<Credentials>& creds,
const ChannelArguments& args) {
+ GrpcLibrary init_lib; // We need to call init in case of a bad creds.
ChannelArguments cp_args = args;
std::ostringstream user_agent_prefix;
user_agent_prefix << "grpc-c++/" << grpc_version_string();
@@ -57,4 +63,5 @@ std::shared_ptr<Channel> CreateChannel(
NULL, GRPC_STATUS_INVALID_ARGUMENT,
"Invalid credentials."));
}
+
} // namespace grpc
diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc
index e806284988..7a8149e9c7 100644
--- a/src/cpp/client/credentials.cc
+++ b/src/cpp/client/credentials.cc
@@ -31,7 +31,7 @@
*
*/
-#include <grpc++/credentials.h>
+#include <grpc++/security/credentials.h>
namespace grpc {
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index 4a4d2cb97d..c476f3ce95 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -31,7 +31,7 @@
*
*/
-#include <grpc++/credentials.h>
+#include <grpc++/security/credentials.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index f368f2590a..2260f6d33e 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -46,7 +46,8 @@ std::shared_ptr<grpc::Channel> SecureCredentials::CreateChannel(
args.SetChannelArgs(&channel_args);
return CreateChannelInternal(
args.GetSslTargetNameOverride(),
- grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args));
+ grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args,
+ nullptr));
}
bool SecureCredentials::ApplyToCall(grpc_call* call) {
@@ -75,31 +76,15 @@ std::shared_ptr<Credentials> SslCredentials(
grpc_credentials* c_creds = grpc_ssl_credentials_create(
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
- options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair);
+ options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr);
return WrapCredentials(c_creds);
}
// Builds credentials for use when running in GCE
-std::shared_ptr<Credentials> ComputeEngineCredentials() {
+std::shared_ptr<Credentials> GoogleComputeEngineCredentials() {
GrpcLibrary init; // To call grpc_init().
- return WrapCredentials(grpc_compute_engine_credentials_create());
-}
-
-// Builds service account credentials.
-std::shared_ptr<Credentials> ServiceAccountCredentials(
- const grpc::string& json_key, const grpc::string& scope,
- long token_lifetime_seconds) {
- GrpcLibrary init; // To call grpc_init().
- if (token_lifetime_seconds <= 0) {
- gpr_log(GPR_ERROR,
- "Trying to create ServiceAccountCredentials "
- "with non-positive lifetime");
- return WrapCredentials(nullptr);
- }
- gpr_timespec lifetime =
- gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
- return WrapCredentials(grpc_service_account_credentials_create(
- json_key.c_str(), scope.c_str(), lifetime));
+ return WrapCredentials(
+ grpc_google_compute_engine_credentials_create(nullptr));
}
// Builds JWT credentials.
@@ -114,15 +99,15 @@ std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials(
gpr_timespec lifetime =
gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
return WrapCredentials(grpc_service_account_jwt_access_credentials_create(
- json_key.c_str(), lifetime));
+ json_key.c_str(), lifetime, nullptr));
}
// Builds refresh token credentials.
-std::shared_ptr<Credentials> RefreshTokenCredentials(
+std::shared_ptr<Credentials> GoogleRefreshTokenCredentials(
const grpc::string& json_refresh_token) {
GrpcLibrary init; // To call grpc_init().
- return WrapCredentials(
- grpc_refresh_token_credentials_create(json_refresh_token.c_str()));
+ return WrapCredentials(grpc_google_refresh_token_credentials_create(
+ json_refresh_token.c_str(), nullptr));
}
// Builds access token credentials.
@@ -130,16 +115,16 @@ std::shared_ptr<Credentials> AccessTokenCredentials(
const grpc::string& access_token) {
GrpcLibrary init; // To call grpc_init().
return WrapCredentials(
- grpc_access_token_credentials_create(access_token.c_str()));
+ grpc_access_token_credentials_create(access_token.c_str(), nullptr));
}
// Builds IAM credentials.
-std::shared_ptr<Credentials> IAMCredentials(
+std::shared_ptr<Credentials> GoogleIAMCredentials(
const grpc::string& authorization_token,
const grpc::string& authority_selector) {
GrpcLibrary init; // To call grpc_init().
- return WrapCredentials(grpc_iam_credentials_create(
- authorization_token.c_str(), authority_selector.c_str()));
+ return WrapCredentials(grpc_google_iam_credentials_create(
+ authorization_token.c_str(), authority_selector.c_str(), nullptr));
}
// Combines two credentials objects into a composite credentials.
@@ -154,7 +139,7 @@ std::shared_ptr<Credentials> CompositeCredentials(
SecureCredentials* s2 = creds2->AsSecureCredentials();
if (s1 && s2) {
return WrapCredentials(grpc_composite_credentials_create(
- s1->GetRawCreds(), s2->GetRawCreds()));
+ s1->GetRawCreds(), s2->GetRawCreds(), nullptr));
}
return nullptr;
}
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index 62d3185477..8deff856c4 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -37,7 +37,7 @@
#include <grpc/grpc_security.h>
#include <grpc++/support/config.h>
-#include <grpc++/credentials.h>
+#include <grpc++/security/credentials.h>
namespace grpc {
diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc
index 5ccf8cf72c..a47abaf4b8 100644
--- a/src/cpp/common/auth_property_iterator.cc
+++ b/src/cpp/common/auth_property_iterator.cc
@@ -31,7 +31,7 @@
*
*/
-#include <grpc++/support/auth_context.h>
+#include <grpc++/security/auth_context.h>
#include <grpc/grpc_security.h>
@@ -77,9 +77,9 @@ bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const {
}
const AuthProperty AuthPropertyIterator::operator*() {
- return std::make_pair<grpc::string, grpc::string>(
- grpc::string(property_->name),
- grpc::string(property_->value, property_->value_length));
+ return std::pair<grpc::string_ref, grpc::string_ref>(
+ property_->name,
+ grpc::string_ref(property_->value, property_->value_length));
}
} // namespace grpc
diff --git a/src/cpp/common/create_auth_context.h b/src/cpp/common/create_auth_context.h
index b4962bae4e..4f3da397ba 100644
--- a/src/cpp/common/create_auth_context.h
+++ b/src/cpp/common/create_auth_context.h
@@ -33,7 +33,7 @@
#include <memory>
#include <grpc/grpc.h>
-#include <grpc++/support/auth_context.h>
+#include <grpc++/security/auth_context.h>
namespace grpc {
diff --git a/src/cpp/common/insecure_create_auth_context.cc b/src/cpp/common/insecure_create_auth_context.cc
index fe80c1a80c..b2e153229a 100644
--- a/src/cpp/common/insecure_create_auth_context.cc
+++ b/src/cpp/common/insecure_create_auth_context.cc
@@ -33,7 +33,7 @@
#include <memory>
#include <grpc/grpc.h>
-#include <grpc++/support/auth_context.h>
+#include <grpc++/security/auth_context.h>
namespace grpc {
diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc
index 87d7bab75c..8615ac8aeb 100644
--- a/src/cpp/common/secure_auth_context.cc
+++ b/src/cpp/common/secure_auth_context.cc
@@ -37,19 +37,24 @@
namespace grpc {
-SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {}
+SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx,
+ bool take_ownership)
+ : ctx_(ctx), take_ownership_(take_ownership) {}
-SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); }
+SecureAuthContext::~SecureAuthContext() {
+ if (take_ownership_) grpc_auth_context_release(ctx_);
+}
-std::vector<grpc::string> SecureAuthContext::GetPeerIdentity() const {
+std::vector<grpc::string_ref> SecureAuthContext::GetPeerIdentity() const {
if (!ctx_) {
- return std::vector<grpc::string>();
+ return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_);
- std::vector<grpc::string> identity;
+ std::vector<grpc::string_ref> identity;
const grpc_auth_property* property = nullptr;
while ((property = grpc_auth_property_iterator_next(&iter))) {
- identity.push_back(grpc::string(property->value, property->value_length));
+ identity.push_back(
+ grpc::string_ref(property->value, property->value_length));
}
return identity;
}
@@ -62,17 +67,17 @@ grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const {
return name == nullptr ? "" : name;
}
-std::vector<grpc::string> SecureAuthContext::FindPropertyValues(
+std::vector<grpc::string_ref> SecureAuthContext::FindPropertyValues(
const grpc::string& name) const {
if (!ctx_) {
- return std::vector<grpc::string>();
+ return std::vector<grpc::string_ref>();
}
grpc_auth_property_iterator iter =
grpc_auth_context_find_properties_by_name(ctx_, name.c_str());
const grpc_auth_property* property = nullptr;
- std::vector<grpc::string> values;
+ std::vector<grpc::string_ref> values;
while ((property = grpc_auth_property_iterator_next(&iter))) {
- values.push_back(grpc::string(property->value, property->value_length));
+ values.push_back(grpc::string_ref(property->value, property->value_length));
}
return values;
}
@@ -93,4 +98,21 @@ AuthPropertyIterator SecureAuthContext::end() const {
return AuthPropertyIterator();
}
+void SecureAuthContext::AddProperty(const grpc::string& key,
+ const grpc::string_ref& value) {
+ if (!ctx_) return;
+ grpc_auth_context_add_property(ctx_, key.c_str(), value.data(), value.size());
+}
+
+bool SecureAuthContext::SetPeerIdentityPropertyName(const grpc::string& name) {
+ if (!ctx_) return false;
+ return grpc_auth_context_set_peer_identity_property_name(ctx_,
+ name.c_str()) != 0;
+}
+
+bool SecureAuthContext::IsPeerAuthenticated() const {
+ if (!ctx_) return false;
+ return grpc_auth_context_peer_is_authenticated(ctx_) != 0;
+}
+
} // namespace grpc
diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h
index 01b7126189..c9f1dad131 100644
--- a/src/cpp/common/secure_auth_context.h
+++ b/src/cpp/common/secure_auth_context.h
@@ -34,7 +34,7 @@
#ifndef GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
#define GRPC_INTERNAL_CPP_COMMON_SECURE_AUTH_CONTEXT_H
-#include <grpc++/support/auth_context.h>
+#include <grpc++/security/auth_context.h>
struct grpc_auth_context;
@@ -42,23 +42,32 @@ namespace grpc {
class SecureAuthContext GRPC_FINAL : public AuthContext {
public:
- SecureAuthContext(grpc_auth_context* ctx);
+ SecureAuthContext(grpc_auth_context* ctx, bool take_ownership);
~SecureAuthContext() GRPC_OVERRIDE;
- std::vector<grpc::string> GetPeerIdentity() const GRPC_OVERRIDE;
+ bool IsPeerAuthenticated() const GRPC_OVERRIDE;
+
+ std::vector<grpc::string_ref> GetPeerIdentity() const GRPC_OVERRIDE;
grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE;
- std::vector<grpc::string> FindPropertyValues(const grpc::string& name) const
- GRPC_OVERRIDE;
+ std::vector<grpc::string_ref> FindPropertyValues(
+ const grpc::string& name) const GRPC_OVERRIDE;
AuthPropertyIterator begin() const GRPC_OVERRIDE;
AuthPropertyIterator end() const GRPC_OVERRIDE;
+ void AddProperty(const grpc::string& key,
+ const grpc::string_ref& value) GRPC_OVERRIDE;
+
+ virtual bool SetPeerIdentityPropertyName(const grpc::string& name)
+ GRPC_OVERRIDE;
+
private:
grpc_auth_context* ctx_;
+ bool take_ownership_;
};
} // namespace grpc
diff --git a/src/cpp/common/secure_create_auth_context.cc b/src/cpp/common/secure_create_auth_context.cc
index f13d25a1dd..40bc298b64 100644
--- a/src/cpp/common/secure_create_auth_context.cc
+++ b/src/cpp/common/secure_create_auth_context.cc
@@ -34,7 +34,7 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
-#include <grpc++/support/auth_context.h>
+#include <grpc++/security/auth_context.h>
#include "src/cpp/common/secure_auth_context.h"
namespace grpc {
@@ -44,7 +44,7 @@ std::shared_ptr<const AuthContext> CreateAuthContext(grpc_call* call) {
return std::shared_ptr<const AuthContext>();
}
return std::shared_ptr<const AuthContext>(
- new SecureAuthContext(grpc_call_auth_context(call)));
+ new SecureAuthContext(grpc_call_auth_context(call), true));
}
} // namespace grpc
diff --git a/src/cpp/server/insecure_server_credentials.cc b/src/cpp/server/insecure_server_credentials.cc
index 800cd36caa..ef3cae5fd7 100644
--- a/src/cpp/server/insecure_server_credentials.cc
+++ b/src/cpp/server/insecure_server_credentials.cc
@@ -31,9 +31,10 @@
*
*/
-#include <grpc++/server_credentials.h>
+#include <grpc++/security/server_credentials.h>
#include <grpc/grpc.h>
+#include <grpc/support/log.h>
namespace grpc {
namespace {
@@ -43,6 +44,11 @@ class InsecureServerCredentialsImpl GRPC_FINAL : public ServerCredentials {
grpc_server* server) GRPC_OVERRIDE {
return grpc_server_add_insecure_http2_port(server, addr.c_str());
}
+ void SetAuthMetadataProcessor(
+ const std::shared_ptr<AuthMetadataProcessor>& processor) GRPC_OVERRIDE {
+ (void)processor;
+ GPR_ASSERT(0); // Should not be called on InsecureServerCredentials.
+ }
};
} // namespace
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index f203cf7f49..90afebfd2e 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -31,15 +31,96 @@
*
*/
+#include <functional>
+#include <map>
+#include <memory>
+
+
+#include "src/cpp/common/secure_auth_context.h"
#include "src/cpp/server/secure_server_credentials.h"
+#include <grpc++/security/auth_metadata_processor.h>
+
namespace grpc {
+void AuthMetadataProcessorAyncWrapper::Destroy(void *wrapper) {
+ auto* w = reinterpret_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
+ delete w;
+}
+
+void AuthMetadataProcessorAyncWrapper::Process(
+ void* wrapper, grpc_auth_context* context, const grpc_metadata* md,
+ size_t num_md, grpc_process_auth_metadata_done_cb cb, void* user_data) {
+ auto* w = reinterpret_cast<AuthMetadataProcessorAyncWrapper*>(wrapper);
+ if (w->processor_ == nullptr) {
+ // Early exit.
+ cb(user_data, nullptr, 0, nullptr, 0, GRPC_STATUS_OK, nullptr);
+ return;
+ }
+ if (w->processor_->IsBlocking()) {
+ w->thread_pool_->Add(
+ std::bind(&AuthMetadataProcessorAyncWrapper::InvokeProcessor, w,
+ context, md, num_md, cb, user_data));
+ } else {
+ // invoke directly.
+ w->InvokeProcessor(context, md, num_md, cb, user_data);
+ }
+}
+
+void AuthMetadataProcessorAyncWrapper::InvokeProcessor(
+ grpc_auth_context* ctx,
+ const grpc_metadata* md, size_t num_md,
+ grpc_process_auth_metadata_done_cb cb, void* user_data) {
+ AuthMetadataProcessor::InputMetadata metadata;
+ for (size_t i = 0; i < num_md; i++) {
+ metadata.insert(std::make_pair(
+ md[i].key, grpc::string_ref(md[i].value, md[i].value_length)));
+ }
+ SecureAuthContext context(ctx, false);
+ AuthMetadataProcessor::OutputMetadata consumed_metadata;
+ AuthMetadataProcessor::OutputMetadata response_metadata;
+
+ Status status = processor_->Process(metadata, &context, &consumed_metadata,
+ &response_metadata);
+
+ std::vector<grpc_metadata> consumed_md;
+ for (auto it = consumed_metadata.begin(); it != consumed_metadata.end();
+ ++it) {
+ consumed_md.push_back({it->first.c_str(),
+ it->second.data(),
+ it->second.size(),
+ 0,
+ {{nullptr, nullptr, nullptr, nullptr}}});
+ }
+ std::vector<grpc_metadata> response_md;
+ for (auto it = response_metadata.begin(); it != response_metadata.end();
+ ++it) {
+ response_md.push_back({it->first.c_str(),
+ it->second.data(),
+ it->second.size(),
+ 0,
+ {{nullptr, nullptr, nullptr, nullptr}}});
+ }
+ auto consumed_md_data = consumed_md.empty() ? nullptr : &consumed_md[0];
+ auto response_md_data = response_md.empty() ? nullptr : &response_md[0];
+ cb(user_data, consumed_md_data, consumed_md.size(), response_md_data,
+ response_md.size(), static_cast<grpc_status_code>(status.error_code()),
+ status.error_message().c_str());
+}
+
int SecureServerCredentials::AddPortToServer(const grpc::string& addr,
grpc_server* server) {
return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
}
+void SecureServerCredentials::SetAuthMetadataProcessor(
+ const std::shared_ptr<AuthMetadataProcessor>& processor) {
+ auto *wrapper = new AuthMetadataProcessorAyncWrapper(processor);
+ grpc_server_credentials_set_auth_metadata_processor(
+ creds_, {AuthMetadataProcessorAyncWrapper::Process,
+ AuthMetadataProcessorAyncWrapper::Destroy, wrapper});
+}
+
std::shared_ptr<ServerCredentials> SslServerCredentials(
const SslServerCredentialsOptions& options) {
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
@@ -51,8 +132,8 @@ std::shared_ptr<ServerCredentials> SslServerCredentials(
}
grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
- &pem_key_cert_pairs[0], pem_key_cert_pairs.size(),
- options.force_client_auth);
+ pem_key_cert_pairs.empty() ? nullptr : &pem_key_cert_pairs[0],
+ pem_key_cert_pairs.size(), options.force_client_auth, nullptr);
return std::shared_ptr<ServerCredentials>(
new SecureServerCredentials(c_creds));
}
diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h
index d3d37b188d..4f003c6b7e 100644
--- a/src/cpp/server/secure_server_credentials.h
+++ b/src/cpp/server/secure_server_credentials.h
@@ -34,12 +34,36 @@
#ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
#define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
-#include <grpc++/server_credentials.h>
+#include <memory>
+
+#include <grpc++/security/server_credentials.h>
#include <grpc/grpc_security.h>
+#include "src/cpp/server/thread_pool_interface.h"
+
namespace grpc {
+class AuthMetadataProcessorAyncWrapper GRPC_FINAL {
+ public:
+ static void Destroy(void *wrapper);
+
+ static void Process(void* wrapper, grpc_auth_context* context,
+ const grpc_metadata* md, size_t num_md,
+ grpc_process_auth_metadata_done_cb cb, void* user_data);
+
+ AuthMetadataProcessorAyncWrapper(
+ const std::shared_ptr<AuthMetadataProcessor>& processor)
+ : thread_pool_(CreateDefaultThreadPool()), processor_(processor) {}
+
+ private:
+ void InvokeProcessor(grpc_auth_context* context, const grpc_metadata* md,
+ size_t num_md, grpc_process_auth_metadata_done_cb cb,
+ void* user_data);
+ std::unique_ptr<ThreadPoolInterface> thread_pool_;
+ std::shared_ptr<AuthMetadataProcessor> processor_;
+};
+
class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
public:
explicit SecureServerCredentials(grpc_server_credentials* creds)
@@ -51,8 +75,12 @@ class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
int AddPortToServer(const grpc::string& addr,
grpc_server* server) GRPC_OVERRIDE;
+ void SetAuthMetadataProcessor(
+ const std::shared_ptr<AuthMetadataProcessor>& processor) GRPC_OVERRIDE;
+
private:
- grpc_server_credentials* const creds_;
+ grpc_server_credentials* creds_;
+ std::unique_ptr<AuthMetadataProcessorAyncWrapper> processor_;
};
} // namespace grpc
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index bb83c7d887..d67205e822 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -43,7 +43,7 @@
#include <grpc++/impl/rpc_service_method.h>
#include <grpc++/impl/service_type.h>
#include <grpc++/server_context.h>
-#include <grpc++/server_credentials.h>
+#include <grpc++/security/server_credentials.h>
#include <grpc++/support/time.h>
#include "src/core/profiling/timers.h"
@@ -354,7 +354,7 @@ bool Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) {
unknown_method_.reset(new RpcServiceMethod(
"unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler));
// Use of emplace_back with just constructor arguments is not accepted
- // here by gcc-4.4 because it can't match the anonymous nullptr with a
+ // here by gcc-4.4 because it can't match the anonymous nullptr with a
// proper constructor implicitly. Construct the object and use push_back.
sync_methods_->push_back(SyncRequest(unknown_method_.get(), nullptr));
}
@@ -384,7 +384,7 @@ void Server::ShutdownInternal(gpr_timespec deadline) {
// Spin, eating requests until the completion queue is completely shutdown.
// If the deadline expires then cancel anything that's pending and keep
// spinning forever until the work is actually drained.
- // Since nothing else needs to touch state guarded by mu_, holding it
+ // Since nothing else needs to touch state guarded by mu_, holding it
// through this loop is fine.
SyncRequest* request;
bool ok;
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index b739cbfe62..99bc8147a0 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -128,7 +128,8 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
*port->selected_port = r;
}
}
- if (!server->Start(&cqs_[0], cqs_.size())) {
+ auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
+ if (!server->Start(cqs_data, cqs_.size())) {
return nullptr;
}
return server;
diff --git a/src/cpp/server/server_credentials.cc b/src/cpp/server/server_credentials.cc
index be3a7425e0..8495916178 100644
--- a/src/cpp/server/server_credentials.cc
+++ b/src/cpp/server/server_credentials.cc
@@ -31,7 +31,7 @@
*
*/
-#include <grpc++/server_credentials.h>
+#include <grpc++/security/server_credentials.h>
namespace grpc {
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index e46e656beb..755234d7e8 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -45,6 +45,12 @@ ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) {
buffer_ = grpc_raw_byte_buffer_create(c_slices.data(), nslices);
}
+ByteBuffer::~ByteBuffer() {
+ if (buffer_) {
+ grpc_byte_buffer_destroy(buffer_);
+ }
+}
+
void ByteBuffer::Clear() {
if (buffer_) {
grpc_byte_buffer_destroy(buffer_);
diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc
index eb54f65e3a..c42033f61f 100644
--- a/src/cpp/util/string_ref.cc
+++ b/src/cpp/util/string_ref.cc
@@ -36,6 +36,7 @@
#include <string.h>
#include <algorithm>
+#include <iostream>
namespace grpc {
@@ -80,7 +81,7 @@ size_t string_ref::find(string_ref s) const {
}
size_t string_ref::find(char c) const {
- auto it = std::find_if(cbegin(), cend(), [c](char cc) { return cc == c; });
+ auto it = std::find(cbegin(), cend(), c);
return it == cend() ? npos : std::distance(cbegin(), it);
}
diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore
index 48365e32a5..deac55029e 100644
--- a/src/csharp/.gitignore
+++ b/src/csharp/.gitignore
@@ -4,6 +4,9 @@ StyleCop.Cache
test-results
packages
Grpc.v12.suo
+Grpc.sdf
+
TestResult.xml
/TestResults
+.vs/
*.nupkg
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index b571fe9025..f730936062 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -64,6 +64,7 @@
<Link>Version.cs</Link>
</Compile>
<Compile Include="ClientBaseTest.cs" />
+ <Compile Include="MarshallingErrorsTest.cs" />
<Compile Include="ShutdownTest.cs" />
<Compile Include="Internal\AsyncCallTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
new file mode 100644
index 0000000000..83707e0c6d
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
@@ -0,0 +1,176 @@
+#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.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+ public class MarshallingErrorsTest
+ {
+ const string Host = "127.0.0.1";
+
+ MockServiceHelper helper;
+ Server server;
+ Channel channel;
+
+ [SetUp]
+ public void Init()
+ {
+ var marshaller = new Marshaller<string>(
+ (str) =>
+ {
+ if (str == "UNSERIALIZABLE_VALUE")
+ {
+ // Google.Protobuf throws exception inherited from IOException
+ throw new IOException("Error serializing the message.");
+ }
+ return System.Text.Encoding.UTF8.GetBytes(str);
+ },
+ (payload) =>
+ {
+ var s = System.Text.Encoding.UTF8.GetString(payload);
+ if (s == "UNPARSEABLE_VALUE")
+ {
+ // Google.Protobuf throws exception inherited from IOException
+ throw new IOException("Error parsing the message.");
+ }
+ return s;
+ });
+ helper = new MockServiceHelper(Host, marshaller);
+ server = helper.GetServer();
+ server.Start();
+ channel = helper.GetChannel();
+ }
+
+ [TearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void ResponseParsingError_UnaryResponse()
+ {
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ return Task.FromResult("UNPARSEABLE_VALUE");
+ });
+
+ var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST"));
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public void ResponseParsingError_StreamingResponse()
+ {
+ helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+ {
+ await responseStream.WriteAsync("UNPARSEABLE_VALUE");
+ await Task.Delay(10000);
+ });
+
+ var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "REQUEST");
+ var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.MoveNext());
+ Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public void RequestParsingError_UnaryRequest()
+ {
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ {
+ return Task.FromResult("RESPONSE");
+ });
+
+ var ex = Assert.Throws<RpcException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNPARSEABLE_VALUE"));
+ // Spec doesn't define the behavior. With the current implementation server handler throws exception which results in StatusCode.Unknown.
+ Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
+ }
+
+ [Test]
+ public async Task RequestParsingError_StreamingRequest()
+ {
+ helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+ {
+ Assert.Throws<IOException>(async () => await requestStream.MoveNext());
+ return "RESPONSE";
+ });
+
+ var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
+ await call.RequestStream.WriteAsync("UNPARSEABLE_VALUE");
+
+ Assert.AreEqual("RESPONSE", await call);
+ }
+
+ [Test]
+ public void RequestSerializationError_BlockingUnary()
+ {
+ Assert.Throws<IOException>(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE"));
+ }
+
+ [Test]
+ public void RequestSerializationError_AsyncUnary()
+ {
+ Assert.Throws<IOException>(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE"));
+ }
+
+ [Test]
+ public async Task RequestSerializationError_ClientStreaming()
+ {
+ helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+ {
+ CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync());
+ return "RESPONSE";
+ });
+ var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
+ await call.RequestStream.WriteAsync("A");
+ Assert.Throws<IOException>(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE"));
+ await call.RequestStream.WriteAsync("B");
+ await call.RequestStream.CompleteAsync();
+
+ Assert.AreEqual("RESPONSE", await call);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
index c00f945d6a..ddeb7d0926 100644
--- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
@@ -75,6 +75,17 @@ namespace Grpc.Core.Tests
}
[Test]
+ public void AsciiEntry_KeyValidity()
+ {
+ new Metadata.Entry("ABC", "XYZ");
+ new Metadata.Entry("0123456789abc", "XYZ");
+ new Metadata.Entry("-abc", "XYZ");
+ new Metadata.Entry("a_bc_", "XYZ");
+ Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz"));
+ Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz"));
+ }
+
+ [Test]
public void Entry_ConstructionPreconditions()
{
Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz"));
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index bb69648d8b..765732c768 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -50,37 +50,14 @@ namespace Grpc.Core.Tests
{
public const string ServiceName = "tests.Test";
- public static readonly Method<string, string> UnaryMethod = new Method<string, string>(
- MethodType.Unary,
- ServiceName,
- "Unary",
- Marshallers.StringMarshaller,
- Marshallers.StringMarshaller);
-
- public static readonly Method<string, string> ClientStreamingMethod = new Method<string, string>(
- MethodType.ClientStreaming,
- ServiceName,
- "ClientStreaming",
- Marshallers.StringMarshaller,
- Marshallers.StringMarshaller);
-
- public static readonly Method<string, string> ServerStreamingMethod = new Method<string, string>(
- MethodType.ServerStreaming,
- ServiceName,
- "ServerStreaming",
- Marshallers.StringMarshaller,
- Marshallers.StringMarshaller);
-
- public static readonly Method<string, string> DuplexStreamingMethod = new Method<string, string>(
- MethodType.DuplexStreaming,
- ServiceName,
- "DuplexStreaming",
- Marshallers.StringMarshaller,
- Marshallers.StringMarshaller);
-
readonly string host;
readonly ServerServiceDefinition serviceDefinition;
+ readonly Method<string, string> unaryMethod;
+ readonly Method<string, string> clientStreamingMethod;
+ readonly Method<string, string> serverStreamingMethod;
+ readonly Method<string, string> duplexStreamingMethod;
+
UnaryServerMethod<string, string> unaryHandler;
ClientStreamingServerMethod<string, string> clientStreamingHandler;
ServerStreamingServerMethod<string, string> serverStreamingHandler;
@@ -89,15 +66,44 @@ namespace Grpc.Core.Tests
Server server;
Channel channel;
- public MockServiceHelper(string host = null)
+ public MockServiceHelper(string host = null, Marshaller<string> marshaller = null)
{
this.host = host ?? "localhost";
+ marshaller = marshaller ?? Marshallers.StringMarshaller;
+
+ unaryMethod = new Method<string, string>(
+ MethodType.Unary,
+ ServiceName,
+ "Unary",
+ marshaller,
+ marshaller);
+
+ clientStreamingMethod = new Method<string, string>(
+ MethodType.ClientStreaming,
+ ServiceName,
+ "ClientStreaming",
+ marshaller,
+ marshaller);
+
+ serverStreamingMethod = new Method<string, string>(
+ MethodType.ServerStreaming,
+ ServiceName,
+ "ServerStreaming",
+ marshaller,
+ marshaller);
+
+ duplexStreamingMethod = new Method<string, string>(
+ MethodType.DuplexStreaming,
+ ServiceName,
+ "DuplexStreaming",
+ marshaller,
+ marshaller);
serviceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName)
- .AddMethod(UnaryMethod, (request, context) => unaryHandler(request, context))
- .AddMethod(ClientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context))
- .AddMethod(ServerStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context))
- .AddMethod(DuplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context))
+ .AddMethod(unaryMethod, (request, context) => unaryHandler(request, context))
+ .AddMethod(clientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context))
+ .AddMethod(serverStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context))
+ .AddMethod(duplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context))
.Build();
var defaultStatus = new Status(StatusCode.Unknown, "Default mock implementation. Please provide your own.");
@@ -155,22 +161,22 @@ namespace Grpc.Core.Tests
public CallInvocationDetails<string, string> CreateUnaryCall(CallOptions options = default(CallOptions))
{
- return new CallInvocationDetails<string, string>(channel, UnaryMethod, options);
+ return new CallInvocationDetails<string, string>(channel, unaryMethod, options);
}
public CallInvocationDetails<string, string> CreateClientStreamingCall(CallOptions options = default(CallOptions))
{
- return new CallInvocationDetails<string, string>(channel, ClientStreamingMethod, options);
+ return new CallInvocationDetails<string, string>(channel, clientStreamingMethod, options);
}
public CallInvocationDetails<string, string> CreateServerStreamingCall(CallOptions options = default(CallOptions))
{
- return new CallInvocationDetails<string, string>(channel, ServerStreamingMethod, options);
+ return new CallInvocationDetails<string, string>(channel, serverStreamingMethod, options);
}
public CallInvocationDetails<string, string> CreateDuplexStreamingCall(CallOptions options = default(CallOptions))
{
- return new CallInvocationDetails<string, string>(channel, DuplexStreamingMethod, options);
+ return new CallInvocationDetails<string, string>(channel, duplexStreamingMethod, options);
}
public string Host
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index fe49efc7ec..06de55c8c3 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -14,15 +14,16 @@
<releaseNotes>Release $version$ of gRPC C#</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
- <dependencies>
- <dependency id="Ix-Async" version="1.2.3" />
- <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
+ <dependencies>
+ <dependency id="Ix-Async" version="1.2.3" />
+ <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
</dependencies>
</metadata>
<files>
+ <file src="..\..\..\etc\roots.pem" target="tools" />
<file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" />
- <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
- <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
- <file src="**\*.cs" target="src" />
+ <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
+ <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
+ <file src="**\*.cs" target="src" />
</files>
</package>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index be5d611a53..e3b00781c6 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -322,6 +322,11 @@ namespace Grpc.Core.Internal
details.Channel.RemoveCallReference(this);
}
+ protected override bool IsClient
+ {
+ get { return true; }
+ }
+
private void Initialize(CompletionQueueSafeHandle cq)
{
var call = CreateNativeCall(cq);
@@ -376,9 +381,17 @@ namespace Grpc.Core.Internal
/// </summary>
private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
{
+ TResponse msg = default(TResponse);
+ var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null;
+
lock (myLock)
{
finished = true;
+
+ if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK)
+ {
+ receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers);
+ }
finishedStatus = receivedStatus;
ReleaseResourcesIfPossible();
@@ -394,10 +407,6 @@ namespace Grpc.Core.Internal
return;
}
- // TODO: handle deserialization error
- TResponse msg;
- TryDeserialize(receivedMessage, out msg);
-
unaryResponseTcs.SetResult(msg);
}
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 4d20394644..3e2c57c9b5 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -33,10 +33,12 @@
using System;
using System.Diagnostics;
+using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+
using Grpc.Core.Internal;
using Grpc.Core.Logging;
using Grpc.Core.Utils;
@@ -50,6 +52,7 @@ namespace Grpc.Core.Internal
internal abstract class AsyncCallBase<TWrite, TRead>
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
+ protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message.");
readonly Func<TWrite, byte[]> serializer;
readonly Func<byte[], TRead> deserializer;
@@ -100,11 +103,10 @@ namespace Grpc.Core.Internal
/// <summary>
/// Requests cancelling the call with given status.
/// </summary>
- public void CancelWithStatus(Status status)
+ protected void CancelWithStatus(Status status)
{
lock (myLock)
{
- Preconditions.CheckState(started);
cancelRequested = true;
if (!disposed)
@@ -177,6 +179,11 @@ namespace Grpc.Core.Internal
return false;
}
+ protected abstract bool IsClient
+ {
+ get;
+ }
+
private void ReleaseResources()
{
if (call != null)
@@ -224,33 +231,31 @@ namespace Grpc.Core.Internal
return serializer(msg);
}
- protected bool TrySerialize(TWrite msg, out byte[] payload)
+ protected Exception TrySerialize(TWrite msg, out byte[] payload)
{
try
{
payload = serializer(msg);
- return true;
+ return null;
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while trying to serialize message");
payload = null;
- return false;
+ return e;
}
}
- protected bool TryDeserialize(byte[] payload, out TRead msg)
+ protected Exception TryDeserialize(byte[] payload, out TRead msg)
{
try
{
msg = deserializer(payload);
- return true;
+ return null;
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while trying to deserialize message.");
msg = default(TRead);
- return false;
+ return e;
}
}
@@ -319,6 +324,9 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleReadFinished(bool success, byte[] receivedMessage)
{
+ TRead msg = default(TRead);
+ var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
+
AsyncCompletionDelegate<TRead> origCompletionDelegate = null;
lock (myLock)
{
@@ -331,23 +339,23 @@ namespace Grpc.Core.Internal
readingDone = true;
}
+ if (deserializeException != null && IsClient)
+ {
+ readingDone = true;
+ CancelWithStatus(DeserializeResponseFailureStatus);
+ }
+
ReleaseResourcesIfPossible();
}
- // TODO: handle the case when error occured...
+ // TODO: handle the case when success==false
- if (receivedMessage != null)
- {
- // TODO: handle deserialization error
- TRead msg;
- TryDeserialize(receivedMessage, out msg);
-
- FireCompletion(origCompletionDelegate, msg, null);
- }
- else
+ if (deserializeException != null && !IsClient)
{
- FireCompletion(origCompletionDelegate, default(TRead), null);
+ FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException));
+ return;
}
+ FireCompletion(origCompletionDelegate, msg, null);
}
}
} \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 5c47251030..46ca459349 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -169,6 +169,11 @@ namespace Grpc.Core.Internal
}
}
+ protected override bool IsClient
+ {
+ get { return false; }
+ }
+
protected override void CheckReadingAllowed()
{
base.CheckReadingAllowed();
diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs
index f38cb0863f..3493d2d38f 100644
--- a/src/csharp/Grpc.Core/Marshaller.cs
+++ b/src/csharp/Grpc.Core/Marshaller.cs
@@ -39,7 +39,7 @@ namespace Grpc.Core
/// <summary>
/// Encapsulates the logic for serializing and deserializing messages.
/// </summary>
- public struct Marshaller<T>
+ public class Marshaller<T>
{
readonly Func<T, byte[]> serializer;
readonly Func<byte[], T> deserializer;
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index 99fe0b5478..21bdf4f114 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -33,8 +33,10 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
+using System.Text.RegularExpressions;
using Grpc.Core.Utils;
@@ -188,6 +190,7 @@ namespace Grpc.Core
public struct Entry
{
private static readonly Encoding Encoding = Encoding.ASCII;
+ private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$");
readonly string key;
readonly string value;
@@ -320,7 +323,10 @@ namespace Grpc.Core
private static string NormalizeKey(string key)
{
- return Preconditions.CheckNotNull(key, "key").ToLower();
+ var normalized = Preconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture);
+ Preconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized),
+ "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
+ return normalized;
}
}
}
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index b6dbd3b49c..eda821bc31 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -39,8 +39,8 @@ namespace Grpc.Core
public static class VersionInfo
{
/// <summary>
- /// Current version of gRPC
+ /// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "0.6.1";
+ public const string CurrentVersion = "0.7.0";
}
}
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index abd95cb905..01e4a80bab 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -33,7 +33,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core;
-namespace math
+namespace Math
{
class MathClient
{
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
index 26bef646ec..6e974a0871 100644
--- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -34,7 +34,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using Grpc.Core;
-namespace math
+namespace Math
{
class MainClass
{
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 9a8f780b24..c4c1ee6d00 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -37,13 +37,14 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ </Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
- <Reference Include="Google.ProtocolBuffers">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
- </Reference>
<Reference Include="System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 36c1c947bd..e2975b5da9 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -40,7 +40,7 @@ using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
-namespace math.Tests
+namespace Math.Tests
{
/// <summary>
/// Math client talks to local math server.
@@ -75,7 +75,7 @@ namespace math.Tests
[Test]
public void Div1()
{
- DivReply response = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+ DivReply response = client.Div(new DivArgs { Dividend = 10, Divisor = 3 });
Assert.AreEqual(3, response.Quotient);
Assert.AreEqual(1, response.Remainder);
}
@@ -83,7 +83,7 @@ namespace math.Tests
[Test]
public void Div2()
{
- DivReply response = client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 1 }.Build());
+ DivReply response = client.Div(new DivArgs { Dividend = 0, Divisor = 1 });
Assert.AreEqual(0, response.Quotient);
Assert.AreEqual(0, response.Remainder);
}
@@ -91,14 +91,14 @@ namespace math.Tests
[Test]
public void DivByZero()
{
- var ex = Assert.Throws<RpcException>(() => client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 0 }.Build()));
+ var ex = Assert.Throws<RpcException>(() => client.Div(new DivArgs { Dividend = 0, Divisor = 0 }));
Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode);
}
[Test]
public async Task DivAsync()
{
- DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+ DivReply response = await client.DivAsync(new DivArgs { Dividend = 10, Divisor = 3 });
Assert.AreEqual(3, response.Quotient);
Assert.AreEqual(1, response.Remainder);
}
@@ -106,7 +106,7 @@ namespace math.Tests
[Test]
public async Task Fib()
{
- using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build()))
+ using (var call = client.Fib(new FibArgs { Limit = 6 }))
{
var responses = await call.ResponseStream.ToListAsync();
CollectionAssert.AreEqual(new List<long> { 1, 1, 2, 3, 5, 8 },
@@ -119,8 +119,7 @@ namespace math.Tests
{
var cts = new CancellationTokenSource();
- using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
- cancellationToken: cts.Token))
+ using (var call = client.Fib(new FibArgs { Limit = 0 }, cancellationToken: cts.Token))
{
List<long> responses = new List<long>();
@@ -147,7 +146,7 @@ namespace math.Tests
[Test]
public async Task FibWithDeadline()
{
- using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(),
+ using (var call = client.Fib(new FibArgs { Limit = 0 },
deadline: DateTime.UtcNow.AddMilliseconds(500)))
{
var ex = Assert.Throws<RpcException>(async () => await call.ResponseStream.ToListAsync());
@@ -163,8 +162,7 @@ namespace math.Tests
{
using (var call = client.Sum())
{
- var numbers = new List<long> { 10, 20, 30 }.ConvertAll(
- n => Num.CreateBuilder().SetNum_(n).Build());
+ var numbers = new List<long> { 10, 20, 30 }.ConvertAll(n => new Num { Num_ = n });
await call.RequestStream.WriteAllAsync(numbers);
var result = await call.ResponseAsync;
@@ -177,9 +175,9 @@ namespace math.Tests
{
var divArgsList = new List<DivArgs>
{
- new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
- new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
- new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
+ new DivArgs { Dividend = 10, Divisor = 3 },
+ new DivArgs { Dividend = 100, Divisor = 21 },
+ new DivArgs { Dividend = 7, Divisor = 2 }
};
using (var call = client.DivMany())
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
index cc6e9af40f..7266fa1763 100644
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ b/src/csharp/Grpc.Examples.Tests/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-alpha4" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index c1aa40500e..55462e02fd 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -37,11 +37,12 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.Data.Linq" />
- <Reference Include="Google.ProtocolBuffers">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
- </Reference>
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
diff --git a/src/csharp/Grpc.Examples/Math.cs b/src/csharp/Grpc.Examples/Math.cs
index 75b1e9dbc2..d0e1ee8aae 100644
--- a/src/csharp/Grpc.Examples/Math.cs
+++ b/src/csharp/Grpc.Examples/Math.cs
@@ -1,80 +1,46 @@
-// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT!
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: math.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
-using pb = global::Google.ProtocolBuffers;
-using pbc = global::Google.ProtocolBuffers.Collections;
-using pbd = global::Google.ProtocolBuffers.Descriptors;
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
-namespace math {
+namespace Math {
namespace Proto {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Math {
- #region Extension registration
- public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
- }
- #endregion
- #region Static variables
- internal static pbd::MessageDescriptor internal__static_math_DivArgs__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::math.DivArgs, global::math.DivArgs.Builder> internal__static_math_DivArgs__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_math_DivReply__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::math.DivReply, global::math.DivReply.Builder> internal__static_math_DivReply__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_math_FibArgs__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::math.FibArgs, global::math.FibArgs.Builder> internal__static_math_FibArgs__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_math_Num__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::math.Num, global::math.Num.Builder> internal__static_math_Num__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_math_FibReply__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::math.FibReply, global::math.FibReply.Builder> internal__static_math_FibReply__FieldAccessorTable;
- #endregion
#region Descriptor
- public static pbd::FileDescriptor Descriptor {
+ public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
- private static pbd::FileDescriptor descriptor;
+ private static pbr::FileDescriptor descriptor;
static Math() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB",
- "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB",
- "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB",
- "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50",
- "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu",
- "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E",
- "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51",
- "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAE="));
- pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
- descriptor = root;
- internal__static_math_DivArgs__Descriptor = Descriptor.MessageTypes[0];
- internal__static_math_DivArgs__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::math.DivArgs, global::math.DivArgs.Builder>(internal__static_math_DivArgs__Descriptor,
- new string[] { "Dividend", "Divisor", });
- internal__static_math_DivReply__Descriptor = Descriptor.MessageTypes[1];
- internal__static_math_DivReply__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::math.DivReply, global::math.DivReply.Builder>(internal__static_math_DivReply__Descriptor,
- new string[] { "Quotient", "Remainder", });
- internal__static_math_FibArgs__Descriptor = Descriptor.MessageTypes[2];
- internal__static_math_FibArgs__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::math.FibArgs, global::math.FibArgs.Builder>(internal__static_math_FibArgs__Descriptor,
- new string[] { "Limit", });
- internal__static_math_Num__Descriptor = Descriptor.MessageTypes[3];
- internal__static_math_Num__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::math.Num, global::math.Num.Builder>(internal__static_math_Num__Descriptor,
- new string[] { "Num_", });
- internal__static_math_FibReply__Descriptor = Descriptor.MessageTypes[4];
- internal__static_math_FibReply__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::math.FibReply, global::math.FibReply.Builder>(internal__static_math_FibReply__Descriptor,
- new string[] { "Count", });
- pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
- RegisterAllExtensions(registry);
- return registry;
- };
- pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
- new pbd::FileDescriptor[] {
- }, assigner);
+ "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB",
+ "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB",
+ "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB",
+ "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50",
+ "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu",
+ "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E",
+ "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51",
+ "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAFiBnByb3Rv",
+ "Mw=="));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Math.DivArgs), new[]{ "Dividend", "Divisor" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Math.DivReply), new[]{ "Quotient", "Remainder" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Math.FibArgs), new[]{ "Limit" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Math.Num), new[]{ "Num_" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Math.FibReply), new[]{ "Count" }, null, null, null)
+ }));
}
#endregion
@@ -82,1448 +48,567 @@ namespace math {
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class DivArgs : pb::GeneratedMessage<DivArgs, DivArgs.Builder> {
- private DivArgs() { }
- private static readonly DivArgs defaultInstance = new DivArgs().MakeReadOnly();
- private static readonly string[] _divArgsFieldNames = new string[] { "dividend", "divisor" };
- private static readonly uint[] _divArgsFieldTags = new uint[] { 8, 16 };
- public static DivArgs DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class DivArgs : pb::IMessage<DivArgs> {
+ private static readonly pb::MessageParser<DivArgs> _parser = new pb::MessageParser<DivArgs>(() => new DivArgs());
+ public static pb::MessageParser<DivArgs> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Math.Proto.Math.Descriptor.MessageTypes[0]; }
}
- public override DivArgs DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override DivArgs ThisMessage {
- get { return this; }
+ public DivArgs() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::math.Proto.Math.internal__static_math_DivArgs__Descriptor; }
+ partial void OnConstruction();
+
+ public DivArgs(DivArgs other) : this() {
+ dividend_ = other.dividend_;
+ divisor_ = other.divisor_;
}
- protected override pb::FieldAccess.FieldAccessorTable<DivArgs, DivArgs.Builder> InternalFieldAccessors {
- get { return global::math.Proto.Math.internal__static_math_DivArgs__FieldAccessorTable; }
+ public DivArgs Clone() {
+ return new DivArgs(this);
}
public const int DividendFieldNumber = 1;
- private bool hasDividend;
private long dividend_;
- public bool HasDividend {
- get { return hasDividend; }
- }
public long Dividend {
get { return dividend_; }
+ set {
+ dividend_ = value;
+ }
}
public const int DivisorFieldNumber = 2;
- private bool hasDivisor;
private long divisor_;
- public bool HasDivisor {
- get { return hasDivisor; }
- }
public long Divisor {
get { return divisor_; }
+ set {
+ divisor_ = value;
+ }
}
- public override bool IsInitialized {
- get {
- return true;
- }
+ public override bool Equals(object other) {
+ return Equals(other as DivArgs);
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _divArgsFieldNames;
- if (hasDividend) {
- output.WriteInt64(1, field_names[0], Dividend);
+ public bool Equals(DivArgs other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
- if (hasDivisor) {
- output.WriteInt64(2, field_names[1], Divisor);
+ if (ReferenceEquals(other, this)) {
+ return true;
}
- UnknownFields.WriteTo(output);
+ if (Dividend != other.Dividend) return false;
+ if (Divisor != other.Divisor) return false;
+ return true;
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasDividend) {
- size += pb::CodedOutputStream.ComputeInt64Size(1, Dividend);
- }
- if (hasDivisor) {
- size += pb::CodedOutputStream.ComputeInt64Size(2, Divisor);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
- }
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Dividend != 0L) hash ^= Dividend.GetHashCode();
+ if (Divisor != 0L) hash ^= Divisor.GetHashCode();
+ return hash;
}
- public static DivArgs ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static DivArgs ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static DivArgs ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static DivArgs ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static DivArgs ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static DivArgs ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- public static DivArgs ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static DivArgs ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static DivArgs ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static DivArgs ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private DivArgs MakeReadOnly() {
- return this;
- }
-
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(DivArgs prototype) {
- return new Builder(prototype);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<DivArgs, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(DivArgs cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private DivArgs result;
-
- private DivArgs PrepareBuilder() {
- if (resultIsReadOnly) {
- DivArgs original = result;
- result = new DivArgs();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
- public override bool IsInitialized {
- get { return result.IsInitialized; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Dividend != 0L) {
+ output.WriteRawTag(8);
+ output.WriteInt64(Dividend);
}
-
- protected override DivArgs MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::math.DivArgs.Descriptor; }
+ if (Divisor != 0L) {
+ output.WriteRawTag(16);
+ output.WriteInt64(Divisor);
}
+ }
- public override DivArgs DefaultInstanceForType {
- get { return global::math.DivArgs.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (Dividend != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Dividend);
}
-
- public override DivArgs BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (Divisor != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Divisor);
}
+ return size;
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is DivArgs) {
- return MergeFrom((DivArgs) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public void MergeFrom(DivArgs other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(DivArgs other) {
- if (other == global::math.DivArgs.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasDividend) {
- Dividend = other.Dividend;
- }
- if (other.HasDivisor) {
- Divisor = other.Divisor;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ if (other.Dividend != 0L) {
+ Dividend = other.Dividend;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Divisor != 0L) {
+ Divisor = other.Divisor;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_divArgsFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _divArgsFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Dividend = input.ReadInt64();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasDividend = input.ReadInt64(ref result.dividend_);
- break;
- }
- case 16: {
- result.hasDivisor = input.ReadInt64(ref result.divisor_);
- break;
- }
+ case 16: {
+ Divisor = input.ReadInt64();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasDividend {
- get { return result.hasDividend; }
- }
- public long Dividend {
- get { return result.Dividend; }
- set { SetDividend(value); }
}
- public Builder SetDividend(long value) {
- PrepareBuilder();
- result.hasDividend = true;
- result.dividend_ = value;
- return this;
- }
- public Builder ClearDividend() {
- PrepareBuilder();
- result.hasDividend = false;
- result.dividend_ = 0L;
- return this;
- }
-
- public bool HasDivisor {
- get { return result.hasDivisor; }
- }
- public long Divisor {
- get { return result.Divisor; }
- set { SetDivisor(value); }
- }
- public Builder SetDivisor(long value) {
- PrepareBuilder();
- result.hasDivisor = true;
- result.divisor_ = value;
- return this;
- }
- public Builder ClearDivisor() {
- PrepareBuilder();
- result.hasDivisor = false;
- result.divisor_ = 0L;
- return this;
- }
- }
- static DivArgs() {
- object.ReferenceEquals(global::math.Proto.Math.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class DivReply : pb::GeneratedMessage<DivReply, DivReply.Builder> {
- private DivReply() { }
- private static readonly DivReply defaultInstance = new DivReply().MakeReadOnly();
- private static readonly string[] _divReplyFieldNames = new string[] { "quotient", "remainder" };
- private static readonly uint[] _divReplyFieldTags = new uint[] { 8, 16 };
- public static DivReply DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class DivReply : pb::IMessage<DivReply> {
+ private static readonly pb::MessageParser<DivReply> _parser = new pb::MessageParser<DivReply>(() => new DivReply());
+ public static pb::MessageParser<DivReply> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Math.Proto.Math.Descriptor.MessageTypes[1]; }
}
- public override DivReply DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override DivReply ThisMessage {
- get { return this; }
+ public DivReply() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::math.Proto.Math.internal__static_math_DivReply__Descriptor; }
+ partial void OnConstruction();
+
+ public DivReply(DivReply other) : this() {
+ quotient_ = other.quotient_;
+ remainder_ = other.remainder_;
}
- protected override pb::FieldAccess.FieldAccessorTable<DivReply, DivReply.Builder> InternalFieldAccessors {
- get { return global::math.Proto.Math.internal__static_math_DivReply__FieldAccessorTable; }
+ public DivReply Clone() {
+ return new DivReply(this);
}
public const int QuotientFieldNumber = 1;
- private bool hasQuotient;
private long quotient_;
- public bool HasQuotient {
- get { return hasQuotient; }
- }
public long Quotient {
get { return quotient_; }
+ set {
+ quotient_ = value;
+ }
}
public const int RemainderFieldNumber = 2;
- private bool hasRemainder;
private long remainder_;
- public bool HasRemainder {
- get { return hasRemainder; }
- }
public long Remainder {
get { return remainder_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ remainder_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _divReplyFieldNames;
- if (hasQuotient) {
- output.WriteInt64(1, field_names[0], Quotient);
- }
- if (hasRemainder) {
- output.WriteInt64(2, field_names[1], Remainder);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as DivReply);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasQuotient) {
- size += pb::CodedOutputStream.ComputeInt64Size(1, Quotient);
- }
- if (hasRemainder) {
- size += pb::CodedOutputStream.ComputeInt64Size(2, Remainder);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(DivReply other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Quotient != other.Quotient) return false;
+ if (Remainder != other.Remainder) return false;
+ return true;
}
- public static DivReply ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static DivReply ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static DivReply ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static DivReply ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static DivReply ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static DivReply ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static DivReply ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static DivReply ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static DivReply ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static DivReply ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private DivReply MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Quotient != 0L) hash ^= Quotient.GetHashCode();
+ if (Remainder != 0L) hash ^= Remainder.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(DivReply prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<DivReply, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(DivReply cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private DivReply result;
-
- private DivReply PrepareBuilder() {
- if (resultIsReadOnly) {
- DivReply original = result;
- result = new DivReply();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override DivReply MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Quotient != 0L) {
+ output.WriteRawTag(8);
+ output.WriteInt64(Quotient);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::math.DivReply.Descriptor; }
+ if (Remainder != 0L) {
+ output.WriteRawTag(16);
+ output.WriteInt64(Remainder);
}
+ }
- public override DivReply DefaultInstanceForType {
- get { return global::math.DivReply.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (Quotient != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Quotient);
}
-
- public override DivReply BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (Remainder != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Remainder);
}
+ return size;
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is DivReply) {
- return MergeFrom((DivReply) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public void MergeFrom(DivReply other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(DivReply other) {
- if (other == global::math.DivReply.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasQuotient) {
- Quotient = other.Quotient;
- }
- if (other.HasRemainder) {
- Remainder = other.Remainder;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ if (other.Quotient != 0L) {
+ Quotient = other.Quotient;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Remainder != 0L) {
+ Remainder = other.Remainder;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_divReplyFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _divReplyFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Quotient = input.ReadInt64();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasQuotient = input.ReadInt64(ref result.quotient_);
- break;
- }
- case 16: {
- result.hasRemainder = input.ReadInt64(ref result.remainder_);
- break;
- }
+ case 16: {
+ Remainder = input.ReadInt64();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasQuotient {
- get { return result.hasQuotient; }
- }
- public long Quotient {
- get { return result.Quotient; }
- set { SetQuotient(value); }
- }
- public Builder SetQuotient(long value) {
- PrepareBuilder();
- result.hasQuotient = true;
- result.quotient_ = value;
- return this;
- }
- public Builder ClearQuotient() {
- PrepareBuilder();
- result.hasQuotient = false;
- result.quotient_ = 0L;
- return this;
- }
-
- public bool HasRemainder {
- get { return result.hasRemainder; }
- }
- public long Remainder {
- get { return result.Remainder; }
- set { SetRemainder(value); }
- }
- public Builder SetRemainder(long value) {
- PrepareBuilder();
- result.hasRemainder = true;
- result.remainder_ = value;
- return this;
}
- public Builder ClearRemainder() {
- PrepareBuilder();
- result.hasRemainder = false;
- result.remainder_ = 0L;
- return this;
- }
- }
- static DivReply() {
- object.ReferenceEquals(global::math.Proto.Math.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class FibArgs : pb::GeneratedMessage<FibArgs, FibArgs.Builder> {
- private FibArgs() { }
- private static readonly FibArgs defaultInstance = new FibArgs().MakeReadOnly();
- private static readonly string[] _fibArgsFieldNames = new string[] { "limit" };
- private static readonly uint[] _fibArgsFieldTags = new uint[] { 8 };
- public static FibArgs DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class FibArgs : pb::IMessage<FibArgs> {
+ private static readonly pb::MessageParser<FibArgs> _parser = new pb::MessageParser<FibArgs>(() => new FibArgs());
+ public static pb::MessageParser<FibArgs> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Math.Proto.Math.Descriptor.MessageTypes[2]; }
}
- public override FibArgs DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override FibArgs ThisMessage {
- get { return this; }
+ public FibArgs() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::math.Proto.Math.internal__static_math_FibArgs__Descriptor; }
+ partial void OnConstruction();
+
+ public FibArgs(FibArgs other) : this() {
+ limit_ = other.limit_;
}
- protected override pb::FieldAccess.FieldAccessorTable<FibArgs, FibArgs.Builder> InternalFieldAccessors {
- get { return global::math.Proto.Math.internal__static_math_FibArgs__FieldAccessorTable; }
+ public FibArgs Clone() {
+ return new FibArgs(this);
}
public const int LimitFieldNumber = 1;
- private bool hasLimit;
private long limit_;
- public bool HasLimit {
- get { return hasLimit; }
- }
public long Limit {
get { return limit_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ limit_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _fibArgsFieldNames;
- if (hasLimit) {
- output.WriteInt64(1, field_names[0], Limit);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as FibArgs);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasLimit) {
- size += pb::CodedOutputStream.ComputeInt64Size(1, Limit);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(FibArgs other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Limit != other.Limit) return false;
+ return true;
}
- public static FibArgs ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static FibArgs ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static FibArgs ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static FibArgs ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static FibArgs ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static FibArgs ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static FibArgs ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static FibArgs ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static FibArgs ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static FibArgs ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private FibArgs MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Limit != 0L) hash ^= Limit.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(FibArgs prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<FibArgs, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(FibArgs cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private FibArgs result;
-
- private FibArgs PrepareBuilder() {
- if (resultIsReadOnly) {
- FibArgs original = result;
- result = new FibArgs();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override FibArgs MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::math.FibArgs.Descriptor; }
- }
-
- public override FibArgs DefaultInstanceForType {
- get { return global::math.FibArgs.DefaultInstance; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Limit != 0L) {
+ output.WriteRawTag(8);
+ output.WriteInt64(Limit);
}
+ }
- public override FibArgs BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
- }
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is FibArgs) {
- return MergeFrom((FibArgs) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Limit != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Limit);
}
+ return size;
+ }
- public override Builder MergeFrom(FibArgs other) {
- if (other == global::math.FibArgs.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasLimit) {
- Limit = other.Limit;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ public void MergeFrom(FibArgs other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Limit != 0L) {
+ Limit = other.Limit;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_fibArgsFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _fibArgsFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Limit = input.ReadInt64();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasLimit = input.ReadInt64(ref result.limit_);
- break;
- }
- }
- }
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
}
- return this;
- }
-
-
- public bool HasLimit {
- get { return result.hasLimit; }
- }
- public long Limit {
- get { return result.Limit; }
- set { SetLimit(value); }
- }
- public Builder SetLimit(long value) {
- PrepareBuilder();
- result.hasLimit = true;
- result.limit_ = value;
- return this;
}
- public Builder ClearLimit() {
- PrepareBuilder();
- result.hasLimit = false;
- result.limit_ = 0L;
- return this;
- }
- }
- static FibArgs() {
- object.ReferenceEquals(global::math.Proto.Math.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Num : pb::GeneratedMessage<Num, Num.Builder> {
- private Num() { }
- private static readonly Num defaultInstance = new Num().MakeReadOnly();
- private static readonly string[] _numFieldNames = new string[] { "num" };
- private static readonly uint[] _numFieldTags = new uint[] { 8 };
- public static Num DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class Num : pb::IMessage<Num> {
+ private static readonly pb::MessageParser<Num> _parser = new pb::MessageParser<Num>(() => new Num());
+ public static pb::MessageParser<Num> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Math.Proto.Math.Descriptor.MessageTypes[3]; }
}
- public override Num DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override Num ThisMessage {
- get { return this; }
+ public Num() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::math.Proto.Math.internal__static_math_Num__Descriptor; }
+ partial void OnConstruction();
+
+ public Num(Num other) : this() {
+ num_ = other.num_;
}
- protected override pb::FieldAccess.FieldAccessorTable<Num, Num.Builder> InternalFieldAccessors {
- get { return global::math.Proto.Math.internal__static_math_Num__FieldAccessorTable; }
+ public Num Clone() {
+ return new Num(this);
}
public const int Num_FieldNumber = 1;
- private bool hasNum_;
private long num_;
- public bool HasNum_ {
- get { return hasNum_; }
- }
public long Num_ {
get { return num_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ num_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _numFieldNames;
- if (hasNum_) {
- output.WriteInt64(1, field_names[0], Num_);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as Num);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasNum_) {
- size += pb::CodedOutputStream.ComputeInt64Size(1, Num_);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(Num other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Num_ != other.Num_) return false;
+ return true;
}
- public static Num ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Num ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Num ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Num ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Num ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Num ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static Num ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static Num ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static Num ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Num ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private Num MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Num_ != 0L) hash ^= Num_.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(Num prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<Num, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(Num cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private Num result;
-
- private Num PrepareBuilder() {
- if (resultIsReadOnly) {
- Num original = result;
- result = new Num();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override Num MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::math.Num.Descriptor; }
- }
-
- public override Num DefaultInstanceForType {
- get { return global::math.Num.DefaultInstance; }
- }
-
- public override Num BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Num_ != 0L) {
+ output.WriteRawTag(8);
+ output.WriteInt64(Num_);
}
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is Num) {
- return MergeFrom((Num) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Num_ != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Num_);
}
+ return size;
+ }
- public override Builder MergeFrom(Num other) {
- if (other == global::math.Num.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasNum_) {
- Num_ = other.Num_;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ public void MergeFrom(Num other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Num_ != 0L) {
+ Num_ = other.Num_;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_numFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _numFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
- }
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasNum_ = input.ReadInt64(ref result.num_);
- break;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Num_ = input.ReadInt64();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasNum_ {
- get { return result.hasNum_; }
- }
- public long Num_ {
- get { return result.Num_; }
- set { SetNum_(value); }
- }
- public Builder SetNum_(long value) {
- PrepareBuilder();
- result.hasNum_ = true;
- result.num_ = value;
- return this;
- }
- public Builder ClearNum_() {
- PrepareBuilder();
- result.hasNum_ = false;
- result.num_ = 0L;
- return this;
}
}
- static Num() {
- object.ReferenceEquals(global::math.Proto.Math.Descriptor, null);
- }
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class FibReply : pb::GeneratedMessage<FibReply, FibReply.Builder> {
- private FibReply() { }
- private static readonly FibReply defaultInstance = new FibReply().MakeReadOnly();
- private static readonly string[] _fibReplyFieldNames = new string[] { "count" };
- private static readonly uint[] _fibReplyFieldTags = new uint[] { 8 };
- public static FibReply DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class FibReply : pb::IMessage<FibReply> {
+ private static readonly pb::MessageParser<FibReply> _parser = new pb::MessageParser<FibReply>(() => new FibReply());
+ public static pb::MessageParser<FibReply> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Math.Proto.Math.Descriptor.MessageTypes[4]; }
}
- public override FibReply DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override FibReply ThisMessage {
- get { return this; }
+ public FibReply() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::math.Proto.Math.internal__static_math_FibReply__Descriptor; }
+ partial void OnConstruction();
+
+ public FibReply(FibReply other) : this() {
+ count_ = other.count_;
}
- protected override pb::FieldAccess.FieldAccessorTable<FibReply, FibReply.Builder> InternalFieldAccessors {
- get { return global::math.Proto.Math.internal__static_math_FibReply__FieldAccessorTable; }
+ public FibReply Clone() {
+ return new FibReply(this);
}
public const int CountFieldNumber = 1;
- private bool hasCount;
private long count_;
- public bool HasCount {
- get { return hasCount; }
- }
public long Count {
get { return count_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ count_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _fibReplyFieldNames;
- if (hasCount) {
- output.WriteInt64(1, field_names[0], Count);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as FibReply);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasCount) {
- size += pb::CodedOutputStream.ComputeInt64Size(1, Count);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(FibReply other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ if (Count != other.Count) return false;
+ return true;
}
- public static FibReply ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static FibReply ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static FibReply ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static FibReply ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static FibReply ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static FibReply ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static FibReply ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static FibReply ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static FibReply ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static FibReply ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private FibReply MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Count != 0L) hash ^= Count.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(FibReply prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<FibReply, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(FibReply cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private FibReply result;
-
- private FibReply PrepareBuilder() {
- if (resultIsReadOnly) {
- FibReply original = result;
- result = new FibReply();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override FibReply MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::math.FibReply.Descriptor; }
- }
-
- public override FibReply DefaultInstanceForType {
- get { return global::math.FibReply.DefaultInstance; }
- }
-
- public override FibReply BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Count != 0L) {
+ output.WriteRawTag(8);
+ output.WriteInt64(Count);
}
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is FibReply) {
- return MergeFrom((FibReply) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Count != 0L) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count);
}
+ return size;
+ }
- public override Builder MergeFrom(FibReply other) {
- if (other == global::math.FibReply.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasCount) {
- Count = other.Count;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ public void MergeFrom(FibReply other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Count != 0L) {
+ Count = other.Count;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_fibReplyFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _fibReplyFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
- }
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasCount = input.ReadInt64(ref result.count_);
- break;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Count = input.ReadInt64();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
}
-
-
- public bool HasCount {
- get { return result.hasCount; }
- }
- public long Count {
- get { return result.Count; }
- set { SetCount(value); }
- }
- public Builder SetCount(long value) {
- PrepareBuilder();
- result.hasCount = true;
- result.count_ = value;
- return this;
- }
- public Builder ClearCount() {
- PrepareBuilder();
- result.hasCount = false;
- result.count_ = 0L;
- return this;
- }
- }
- static FibReply() {
- object.ReferenceEquals(global::math.Proto.Math.Descriptor, null);
}
- }
- #endregion
+ }
- #region Services
- /*
- * Service generation is now disabled by default, use the following option to enable:
- * option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;
- */
#endregion
}
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index dc1bf43995..8009ccbbfa 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -34,25 +34,25 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core.Utils;
-namespace math
+namespace Math
{
public static class MathExamples
{
public static void DivExample(Math.IMathClient client)
{
- DivReply result = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
+ DivReply result = client.Div(new DivArgs { Dividend = 10, Divisor = 3 });
Console.WriteLine("Div Result: " + result);
}
public static async Task DivAsyncExample(Math.IMathClient client)
{
- DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+ DivReply result = await client.DivAsync(new DivArgs { Dividend = 4, Divisor = 5 });
Console.WriteLine("DivAsync Result: " + result);
}
public static async Task FibExample(Math.IMathClient client)
{
- using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build()))
+ using (var call = client.Fib(new FibArgs { Limit = 5 }))
{
List<Num> result = await call.ResponseStream.ToListAsync();
Console.WriteLine("Fib Result: " + string.Join("|", result));
@@ -63,9 +63,9 @@ namespace math
{
var numbers = new List<Num>
{
- new Num.Builder { Num_ = 1 }.Build(),
- new Num.Builder { Num_ = 2 }.Build(),
- new Num.Builder { Num_ = 3 }.Build()
+ new Num { Num_ = 1 },
+ new Num { Num_ = 2 },
+ new Num { Num_ = 3 }
};
using (var call = client.Sum())
@@ -79,9 +79,9 @@ namespace math
{
var divArgsList = new List<DivArgs>
{
- new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
- new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
- new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
+ new DivArgs { Dividend = 10, Divisor = 3 },
+ new DivArgs { Dividend = 100, Divisor = 21 },
+ new DivArgs { Dividend = 7, Divisor = 2 }
};
using (var call = client.DivMany())
{
@@ -94,9 +94,9 @@ namespace math
{
var numbers = new List<Num>
{
- new Num.Builder { Num_ = 1 }.Build(),
- new Num.Builder { Num_ = 2 }.Build(),
- new Num.Builder { Num_ = 3 }.Build()
+ new Num { Num_ = 1 },
+ new Num { Num_ = 2 },
+ new Num { Num_ = 3 }
};
Num sum;
@@ -106,7 +106,7 @@ namespace math
sum = await sumCall.ResponseAsync;
}
- DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build());
+ DivReply result = await client.DivAsync(new DivArgs { Dividend = sum.Num_, Divisor = numbers.Count });
Console.WriteLine("Avg Result: " + result);
}
}
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index 4941ff35f7..175d110f76 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -7,66 +7,72 @@ using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
-namespace math {
+namespace Math {
public static class Math
{
static readonly string __ServiceName = "math.Math";
- static readonly Marshaller<global::math.DivArgs> __Marshaller_DivArgs = Marshallers.Create((arg) => arg.ToByteArray(), global::math.DivArgs.ParseFrom);
- static readonly Marshaller<global::math.DivReply> __Marshaller_DivReply = Marshallers.Create((arg) => arg.ToByteArray(), global::math.DivReply.ParseFrom);
- static readonly Marshaller<global::math.FibArgs> __Marshaller_FibArgs = Marshallers.Create((arg) => arg.ToByteArray(), global::math.FibArgs.ParseFrom);
- static readonly Marshaller<global::math.Num> __Marshaller_Num = Marshallers.Create((arg) => arg.ToByteArray(), global::math.Num.ParseFrom);
+ static readonly Marshaller<global::Math.DivArgs> __Marshaller_DivArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom);
+ static readonly Marshaller<global::Math.DivReply> __Marshaller_DivReply = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom);
+ static readonly Marshaller<global::Math.FibArgs> __Marshaller_FibArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom);
+ static readonly Marshaller<global::Math.Num> __Marshaller_Num = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom);
- static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_Div = new Method<global::math.DivArgs, global::math.DivReply>(
+ static readonly Method<global::Math.DivArgs, global::Math.DivReply> __Method_Div = new Method<global::Math.DivArgs, global::Math.DivReply>(
MethodType.Unary,
__ServiceName,
"Div",
__Marshaller_DivArgs,
__Marshaller_DivReply);
- static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_DivMany = new Method<global::math.DivArgs, global::math.DivReply>(
+ static readonly Method<global::Math.DivArgs, global::Math.DivReply> __Method_DivMany = new Method<global::Math.DivArgs, global::Math.DivReply>(
MethodType.DuplexStreaming,
__ServiceName,
"DivMany",
__Marshaller_DivArgs,
__Marshaller_DivReply);
- static readonly Method<global::math.FibArgs, global::math.Num> __Method_Fib = new Method<global::math.FibArgs, global::math.Num>(
+ static readonly Method<global::Math.FibArgs, global::Math.Num> __Method_Fib = new Method<global::Math.FibArgs, global::Math.Num>(
MethodType.ServerStreaming,
__ServiceName,
"Fib",
__Marshaller_FibArgs,
__Marshaller_Num);
- static readonly Method<global::math.Num, global::math.Num> __Method_Sum = new Method<global::math.Num, global::math.Num>(
+ static readonly Method<global::Math.Num, global::Math.Num> __Method_Sum = new Method<global::Math.Num, global::Math.Num>(
MethodType.ClientStreaming,
__ServiceName,
"Sum",
__Marshaller_Num,
__Marshaller_Num);
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Math.Proto.Math.Descriptor.Services[0]; }
+ }
+
// client interface
public interface IMathClient
{
- global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::math.DivReply Div(global::math.DivArgs request, CallOptions options);
- AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options);
- AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options);
- AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options);
- AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options);
+ global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
+ AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
+ AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
+ AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
+ AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
}
// server-side interface
public interface IMath
{
- Task<global::math.DivReply> Div(global::math.DivArgs request, ServerCallContext context);
- Task DivMany(IAsyncStreamReader<global::math.DivArgs> requestStream, IServerStreamWriter<global::math.DivReply> responseStream, ServerCallContext context);
- Task Fib(global::math.FibArgs request, IServerStreamWriter<global::math.Num> responseStream, ServerCallContext context);
- Task<global::math.Num> Sum(IAsyncStreamReader<global::math.Num> requestStream, ServerCallContext context);
+ Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
+ Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
+ Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
+ Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
}
// client stub
@@ -75,52 +81,52 @@ namespace math {
public MathClient(Channel channel) : base(channel)
{
}
- public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
- public global::math.DivReply Div(global::math.DivArgs request, CallOptions options)
+ public global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
{
var call = CreateCall(__Method_Div, options);
return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
- public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options)
+ public AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
{
var call = CreateCall(__Method_Div, options);
return Calls.AsyncUnaryCall(call, request);
}
- public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
- public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options)
+ public AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
{
var call = CreateCall(__Method_DivMany, options);
return Calls.AsyncDuplexStreamingCall(call);
}
- public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncServerStreamingCall(call, request);
}
- public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options)
+ public AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
{
var call = CreateCall(__Method_Fib, options);
return Calls.AsyncServerStreamingCall(call, request);
}
- public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncClientStreamingCall(call);
}
- public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options)
+ public AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
{
var call = CreateCall(__Method_Sum, options);
return Calls.AsyncClientStreamingCall(call);
diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs
index 7b2684615c..71dc655e46 100644
--- a/src/csharp/Grpc.Examples/MathServiceImpl.cs
+++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs
@@ -38,7 +38,7 @@ using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Utils;
-namespace math
+namespace Math
{
/// <summary>
/// Implementation of MathService server
@@ -79,7 +79,7 @@ namespace math
{
sum += num.Num_;
});
- return Num.CreateBuilder().SetNum_(sum).Build();
+ return new Num { Num_ = sum };
}
public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream, ServerCallContext context)
@@ -91,13 +91,13 @@ namespace math
{
long quotient = args.Dividend / args.Divisor;
long remainder = args.Dividend % args.Divisor;
- return new DivReply.Builder { Quotient = quotient, Remainder = remainder }.Build();
+ return new DivReply { Quotient = quotient, Remainder = remainder };
}
static IEnumerable<Num> FibInternal(long n)
{
long a = 1;
- yield return new Num.Builder { Num_ = a }.Build();
+ yield return new Num { Num_ = a };
long b = 1;
for (long i = 0; i < n - 1; i++)
@@ -105,7 +105,7 @@ namespace math
long temp = a;
a = b;
b = temp + b;
- yield return new Num.Builder { Num_ = a }.Build();
+ yield return new Num { Num_ = a };
}
}
}
diff --git a/src/csharp/Grpc.Examples/packages.config b/src/csharp/Grpc.Examples/packages.config
index 4c8d60fa62..adf8da2363 100644
--- a/src/csharp/Grpc.Examples/packages.config
+++ b/src/csharp/Grpc.Examples/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-alpha4" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/proto/math.proto b/src/csharp/Grpc.Examples/proto/math.proto
index 5485d580c3..311e148c02 100644
--- a/src/csharp/Grpc.Examples/proto/math.proto
+++ b/src/csharp/Grpc.Examples/proto/math.proto
@@ -28,30 +28,30 @@
// (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 = "proto2";
+syntax = "proto3";
package math;
message DivArgs {
- optional int64 dividend = 1;
- optional int64 divisor = 2;
+ int64 dividend = 1;
+ int64 divisor = 2;
}
message DivReply {
- optional int64 quotient = 1;
- optional int64 remainder = 2;
+ int64 quotient = 1;
+ int64 remainder = 2;
}
message FibArgs {
- optional int64 limit = 1;
+ int64 limit = 1;
}
message Num {
- optional int64 num = 1;
+ int64 num = 1;
}
message FibReply {
- optional int64 count = 1;
+ int64 count = 1;
}
service Math {
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index c922ddfb9e..396dc43a02 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -37,11 +37,9 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.ProtocolBuffers">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
- </Reference>
- <Reference Include="Google.ProtocolBuffers.Serialization">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+ <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index 80c35fb197..6c3a53bec0 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -81,14 +81,14 @@ namespace Grpc.HealthCheck.Tests
{
serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
- var response = client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("").Build());
+ var response = client.Check(new HealthCheckRequest { Host = "", Service = "" });
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
}
[Test]
public void ServiceDoesntExist()
{
- Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("nonexistent.service").Build()));
+ Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Host = "", Service = "nonexistent.service" }));
}
// TODO(jtattermusch): add test with timeout once timeouts are supported
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
index c4caa3b57a..2097c0dc8c 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -101,7 +101,7 @@ namespace Grpc.HealthCheck.Tests
private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
{
- return impl.Check(HealthCheckRequest.CreateBuilder().SetHost(host).SetService(service).Build(), null).Result.Status;
+ return impl.Check(new HealthCheckRequest { Host = host, Service = service }, null).Result.Status;
}
}
}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
index 050c4eaed6..40ffb85203 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/packages.config
+++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-alpha4" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
index 0b7a7b91c6..8fce5d39aa 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -38,11 +38,9 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
- <Reference Include="Google.ProtocolBuffers">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
- </Reference>
- <Reference Include="Google.ProtocolBuffers.Serialization">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+ <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
index acdfba42c8..66386288df 100644
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -14,7 +14,7 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC health check</tags>
<dependencies>
- <dependency id="Google.ProtocolBuffers" version="2.4.1.555" />
+ <dependency id="Google.Protobuf" version="$ProtobufVersion$" />
<dependency id="Grpc.Core" version="$version$" />
<dependency id="Ix-Async" version="1.2.3" />
</dependencies>
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
index 361382d4bd..570e274544 100644
--- a/src/csharp/Grpc.HealthCheck/Health.cs
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -3,9 +3,9 @@
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
-using pb = global::Google.ProtocolBuffers;
-using pbc = global::Google.ProtocolBuffers.Collections;
-using pbd = global::Google.ProtocolBuffers.Descriptors;
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Grpc.Health.V1Alpha {
@@ -14,21 +14,11 @@ namespace Grpc.Health.V1Alpha {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Health {
- #region Extension registration
- public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
- }
- #endregion
- #region Static variables
- internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder> internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder> internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable;
- #endregion
#region Descriptor
- public static pbd::FileDescriptor Descriptor {
+ public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
- private static pbd::FileDescriptor descriptor;
+ private static pbr::FileDescriptor descriptor;
static Health() {
byte[] descriptorData = global::System.Convert.FromBase64String(
@@ -41,24 +31,13 @@ namespace Grpc.Health.V1Alpha {
"EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj",
"LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh",
"bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs",
- "dGguVjFBbHBoYQ=="));
- pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
- descriptor = root;
- internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0];
- internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder>(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor,
- new string[] { "Host", "Service", });
- internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1];
- internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder>(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor,
- new string[] { "Status", });
- pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
- RegisterAllExtensions(registry);
- return registry;
- };
- pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
- new pbd::FileDescriptor[] {
- }, assigner);
+ "dGguVjFBbHBoYWIGcHJvdG8z"));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckRequest), new[]{ "Host", "Service" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse), new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) }, null)
+ }));
}
#endregion
@@ -66,618 +45,245 @@ namespace Grpc.Health.V1Alpha {
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class HealthCheckRequest : pb::GeneratedMessage<HealthCheckRequest, HealthCheckRequest.Builder> {
- private HealthCheckRequest() { }
- private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly();
- private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" };
- private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 };
- public static HealthCheckRequest DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class HealthCheckRequest : pb::IMessage<HealthCheckRequest> {
+ private static readonly pb::MessageParser<HealthCheckRequest> _parser = new pb::MessageParser<HealthCheckRequest>(() => new HealthCheckRequest());
+ public static pb::MessageParser<HealthCheckRequest> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[0]; }
}
- public override HealthCheckRequest DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override HealthCheckRequest ThisMessage {
- get { return this; }
+ public HealthCheckRequest() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; }
+ partial void OnConstruction();
+
+ public HealthCheckRequest(HealthCheckRequest other) : this() {
+ host_ = other.host_;
+ service_ = other.service_;
}
- protected override pb::FieldAccess.FieldAccessorTable<HealthCheckRequest, HealthCheckRequest.Builder> InternalFieldAccessors {
- get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; }
+ public HealthCheckRequest Clone() {
+ return new HealthCheckRequest(this);
}
public const int HostFieldNumber = 1;
- private bool hasHost;
private string host_ = "";
- public bool HasHost {
- get { return hasHost; }
- }
public string Host {
get { return host_; }
+ set {
+ host_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
}
public const int ServiceFieldNumber = 2;
- private bool hasService;
private string service_ = "";
- public bool HasService {
- get { return hasService; }
- }
public string Service {
get { return service_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
- }
- }
-
- public override void WriteTo(pb::ICodedOutputStream output) {
- CalcSerializedSize();
- string[] field_names = _healthCheckRequestFieldNames;
- if (hasHost) {
- output.WriteString(1, field_names[0], Host);
- }
- if (hasService) {
- output.WriteString(2, field_names[1], Service);
+ set {
+ service_ = pb::Preconditions.CheckNotNull(value, "value");
}
- UnknownFields.WriteTo(output);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
- return CalcSerializedSize();
- }
+ public override bool Equals(object other) {
+ return Equals(other as HealthCheckRequest);
}
- private int CalcSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasHost) {
- size += pb::CodedOutputStream.ComputeStringSize(1, Host);
+ public bool Equals(HealthCheckRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
- if (hasService) {
- size += pb::CodedOutputStream.ComputeStringSize(2, Service);
+ if (ReferenceEquals(other, this)) {
+ return true;
}
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
- }
- public static HealthCheckRequest ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private HealthCheckRequest MakeReadOnly() {
- return this;
+ if (Host != other.Host) return false;
+ if (Service != other.Service) return false;
+ return true;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(HealthCheckRequest prototype) {
- return new Builder(prototype);
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Host.Length != 0) hash ^= Host.GetHashCode();
+ if (Service.Length != 0) hash ^= Service.GetHashCode();
+ return hash;
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckRequest, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(HealthCheckRequest cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private HealthCheckRequest result;
-
- private HealthCheckRequest PrepareBuilder() {
- if (resultIsReadOnly) {
- HealthCheckRequest original = result;
- result = new HealthCheckRequest();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override HealthCheckRequest MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Host.Length != 0) {
+ output.WriteRawTag(10);
+ output.WriteString(Host);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; }
+ if (Service.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Service);
}
+ }
- public override HealthCheckRequest DefaultInstanceForType {
- get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (Host.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Host);
}
-
- public override HealthCheckRequest BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (Service.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Service);
}
+ return size;
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is HealthCheckRequest) {
- return MergeFrom((HealthCheckRequest) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public void MergeFrom(HealthCheckRequest other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(HealthCheckRequest other) {
- if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasHost) {
- Host = other.Host;
- }
- if (other.HasService) {
- Service = other.Service;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ if (other.Host.Length != 0) {
+ Host = other.Host;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Service.Length != 0) {
+ Service = other.Service;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _healthCheckRequestFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ Host = input.ReadString();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 10: {
- result.hasHost = input.ReadString(ref result.host_);
- break;
- }
- case 18: {
- result.hasService = input.ReadString(ref result.service_);
- break;
- }
+ case 18: {
+ Service = input.ReadString();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasHost {
- get { return result.hasHost; }
- }
- public string Host {
- get { return result.Host; }
- set { SetHost(value); }
- }
- public Builder SetHost(string value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasHost = true;
- result.host_ = value;
- return this;
- }
- public Builder ClearHost() {
- PrepareBuilder();
- result.hasHost = false;
- result.host_ = "";
- return this;
- }
-
- public bool HasService {
- get { return result.hasService; }
- }
- public string Service {
- get { return result.Service; }
- set { SetService(value); }
}
- public Builder SetService(string value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasService = true;
- result.service_ = value;
- return this;
- }
- public Builder ClearService() {
- PrepareBuilder();
- result.hasService = false;
- result.service_ = "";
- return this;
- }
- }
- static HealthCheckRequest() {
- object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class HealthCheckResponse : pb::GeneratedMessage<HealthCheckResponse, HealthCheckResponse.Builder> {
- private HealthCheckResponse() { }
- private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly();
- private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" };
- private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 };
- public static HealthCheckResponse DefaultInstance {
- get { return defaultInstance; }
- }
+ public sealed partial class HealthCheckResponse : pb::IMessage<HealthCheckResponse> {
+ private static readonly pb::MessageParser<HealthCheckResponse> _parser = new pb::MessageParser<HealthCheckResponse>(() => new HealthCheckResponse());
+ public static pb::MessageParser<HealthCheckResponse> Parser { get { return _parser; } }
- public override HealthCheckResponse DefaultInstanceForType {
- get { return DefaultInstance; }
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[1]; }
}
- protected override HealthCheckResponse ThisMessage {
- get { return this; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; }
+ public HealthCheckResponse() {
+ OnConstruction();
}
- protected override pb::FieldAccess.FieldAccessorTable<HealthCheckResponse, HealthCheckResponse.Builder> InternalFieldAccessors {
- get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; }
- }
+ partial void OnConstruction();
- #region Nested types
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public static partial class Types {
- public enum ServingStatus {
- UNKNOWN = 0,
- SERVING = 1,
- NOT_SERVING = 2,
- }
+ public HealthCheckResponse(HealthCheckResponse other) : this() {
+ status_ = other.status_;
+ }
+ public HealthCheckResponse Clone() {
+ return new HealthCheckResponse(this);
}
- #endregion
public const int StatusFieldNumber = 1;
- private bool hasStatus;
private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
- public bool HasStatus {
- get { return hasStatus; }
- }
public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
get { return status_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ status_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- CalcSerializedSize();
- string[] field_names = _healthCheckResponseFieldNames;
- if (hasStatus) {
- output.WriteEnum(1, field_names[0], (int) Status, Status);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as HealthCheckResponse);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
- return CalcSerializedSize();
+ public bool Equals(HealthCheckResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
- }
-
- private int CalcSerializedSize() {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasStatus) {
- size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status);
+ if (ReferenceEquals(other, this)) {
+ return true;
}
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
- }
- public static HealthCheckResponse ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private HealthCheckResponse MakeReadOnly() {
- return this;
+ if (Status != other.Status) return false;
+ return true;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(HealthCheckResponse prototype) {
- return new Builder(prototype);
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode();
+ return hash;
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckResponse, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(HealthCheckResponse cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private HealthCheckResponse result;
-
- private HealthCheckResponse PrepareBuilder() {
- if (resultIsReadOnly) {
- HealthCheckResponse original = result;
- result = new HealthCheckResponse();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override HealthCheckResponse MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; }
- }
-
- public override HealthCheckResponse DefaultInstanceForType {
- get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; }
- }
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
- public override HealthCheckResponse BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ output.WriteRawTag(8);
+ output.WriteEnum((int) Status);
}
+ }
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is HealthCheckResponse) {
- return MergeFrom((HealthCheckResponse) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
}
+ return size;
+ }
- public override Builder MergeFrom(HealthCheckResponse other) {
- if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasStatus) {
- Status = other.Status;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
+ public void MergeFrom(HealthCheckResponse other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ if (other.Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
+ Status = other.Status;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _healthCheckResponseFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ status_ = (global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) input.ReadEnum();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- object unknown;
- if(input.ReadEnum(ref result.status_, out unknown)) {
- result.hasStatus = true;
- } else if(unknown is int) {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- unknownFields.MergeVarintField(1, (ulong)(int)unknown);
- }
- break;
- }
- }
- }
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
}
- return this;
}
+ }
-
- public bool HasStatus {
- get { return result.hasStatus; }
- }
- public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
- get { return result.Status; }
- set { SetStatus(value); }
- }
- public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) {
- PrepareBuilder();
- result.hasStatus = true;
- result.status_ = value;
- return this;
- }
- public Builder ClearStatus() {
- PrepareBuilder();
- result.hasStatus = false;
- result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
- return this;
+ #region Nested types
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Types {
+ public enum ServingStatus {
+ UNKNOWN = 0,
+ SERVING = 1,
+ NOT_SERVING = 2,
}
+
}
- static HealthCheckResponse() {
- object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
- }
+ #endregion
+
}
#endregion
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index 0dabc91f7c..da721ce5f6 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -12,8 +12,8 @@ namespace Grpc.Health.V1Alpha {
{
static readonly string __ServiceName = "grpc.health.v1alpha.Health";
- static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom);
- static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom);
+ static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckResponse.Parser.ParseFrom);
static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
MethodType.Unary,
@@ -22,6 +22,12 @@ namespace Grpc.Health.V1Alpha {
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.Services[0]; }
+ }
+
// client interface
public interface IHealthClient
{
diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
index 8c04b43a86..26c6445c35 100644
--- a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
@@ -105,8 +105,8 @@ namespace Grpc.HealthCheck
{
lock (myLock)
{
- var host = request.HasHost ? request.Host : "";
- var service = request.HasService ? request.Service : "";
+ var host = request.Host;
+ var service = request.Service;
HealthCheckResponse.Types.ServingStatus status;
if (!statusMap.TryGetValue(CreateKey(host, service), out status))
@@ -114,7 +114,7 @@ namespace Grpc.HealthCheck
// TODO(jtattermusch): returning specific status from server handler is not supported yet.
throw new RpcException(new Status(StatusCode.NotFound, ""));
}
- return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build());
+ return Task.FromResult(new HealthCheckResponse { Status = status });
}
}
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
index 094a30981e..cafff6123a 100644
--- a/src/csharp/Grpc.HealthCheck/packages.config
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-alpha4" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto
index 08df7e104e..01aa3fcf57 100644
--- a/src/csharp/Grpc.HealthCheck/proto/health.proto
+++ b/src/csharp/Grpc.HealthCheck/proto/health.proto
@@ -28,14 +28,14 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(jtattermusch): switch to proto3 once C# supports that.
-syntax = "proto2";
+syntax = "proto3";
package grpc.health.v1alpha;
option csharp_namespace = "Grpc.Health.V1Alpha";
message HealthCheckRequest {
- optional string host = 1;
- optional string service = 2;
+ string host = 1;
+ string service = 2;
}
message HealthCheckResponse {
@@ -44,7 +44,7 @@ message HealthCheckResponse {
SERVING = 1;
NOT_SERVING = 2;
}
- optional ServingStatus status = 1;
+ ServingStatus status = 1;
}
service Health {
diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs
index 7169ee2a4a..28c28c9afd 100644
--- a/src/csharp/Grpc.IntegrationTesting/Empty.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs
@@ -1,47 +1,34 @@
-// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT!
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: empty.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
-using pb = global::Google.ProtocolBuffers;
-using pbc = global::Google.ProtocolBuffers.Collections;
-using pbd = global::Google.ProtocolBuffers.Descriptors;
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
-namespace grpc.testing {
+namespace Grpc.Testing {
namespace Proto {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Empty {
- #region Extension registration
- public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
- }
- #endregion
- #region Static variables
- internal static pbd::MessageDescriptor internal__static_grpc_testing_Empty__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder> internal__static_grpc_testing_Empty__FieldAccessorTable;
- #endregion
#region Descriptor
- public static pbd::FileDescriptor Descriptor {
+ public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
- private static pbd::FileDescriptor descriptor;
+ private static pbr::FileDescriptor descriptor;
static Empty() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5"));
- pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
- descriptor = root;
- internal__static_grpc_testing_Empty__Descriptor = Descriptor.MessageTypes[0];
- internal__static_grpc_testing_Empty__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Empty, global::grpc.testing.Empty.Builder>(internal__static_grpc_testing_Empty__Descriptor,
- new string[] { });
- return null;
- };
- pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
- new pbd::FileDescriptor[] {
- }, assigner);
+ "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM="));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Empty), null, null, null, null)
+ }));
}
#endregion
@@ -49,230 +36,79 @@ namespace grpc.testing {
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Empty : pb::GeneratedMessage<Empty, Empty.Builder> {
- private Empty() { }
- private static readonly Empty defaultInstance = new Empty().MakeReadOnly();
- private static readonly string[] _emptyFieldNames = new string[] { };
- private static readonly uint[] _emptyFieldTags = new uint[] { };
- public static Empty DefaultInstance {
- get { return defaultInstance; }
- }
+ public sealed partial class Empty : pb::IMessage<Empty> {
+ private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty());
+ public static pb::MessageParser<Empty> Parser { get { return _parser; } }
- public override Empty DefaultInstanceForType {
- get { return DefaultInstance; }
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Proto.Empty.Descriptor.MessageTypes[0]; }
}
- protected override Empty ThisMessage {
- get { return this; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__Descriptor; }
+ public Empty() {
+ OnConstruction();
}
- protected override pb::FieldAccess.FieldAccessorTable<Empty, Empty.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__FieldAccessorTable; }
- }
+ partial void OnConstruction();
- public override bool IsInitialized {
- get {
- return true;
- }
+ public Empty(Empty other) : this() {
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _emptyFieldNames;
- UnknownFields.WriteTo(output);
+ public Empty Clone() {
+ return new Empty(this);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
+ public override bool Equals(object other) {
+ return Equals(other as Empty);
+ }
- size = 0;
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(Empty other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ return true;
}
- public static Empty ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Empty ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Empty ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Empty ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Empty ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Empty ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static Empty ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static Empty ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static Empty ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Empty ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private Empty MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(Empty prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<Empty, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(Empty cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private Empty result;
-
- private Empty PrepareBuilder() {
- if (resultIsReadOnly) {
- Empty original = result;
- result = new Empty();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override Empty MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.Empty.Descriptor; }
- }
-
- public override Empty DefaultInstanceForType {
- get { return global::grpc.testing.Empty.DefaultInstance; }
- }
-
- public override Empty BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
- }
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is Empty) {
- return MergeFrom((Empty) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
- }
+ public void WriteTo(pb::CodedOutputStream output) {
+ }
- public override Builder MergeFrom(Empty other) {
- if (other == global::grpc.testing.Empty.DefaultInstance) return this;
- PrepareBuilder();
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
+ public int CalculateSize() {
+ int size = 0;
+ return size;
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ public void MergeFrom(Empty other) {
+ if (other == null) {
+ return;
}
+ }
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_emptyFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _emptyFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
- }
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- }
- }
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
}
- return this;
}
-
- }
- static Empty() {
- object.ReferenceEquals(global::grpc.testing.Proto.Empty.Descriptor, null);
}
+
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 2020a76d39..a0bcf431f7 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -42,6 +42,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
</Reference>
+ <Reference Include="CommandLine">
+ <HintPath>..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
+ </Reference>
<Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
@@ -54,6 +57,10 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
</Reference>
+ <Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll</HintPath>
+ </Reference>
<Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
@@ -74,22 +81,11 @@
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
- <Reference Include="Google.ProtocolBuffers">
- <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
- </Reference>
<Reference Include="System.Interactive.Async">
<HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.Http" />
- <Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
- </Reference>
- <Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
- </Reference>
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
@@ -106,6 +102,7 @@
<Compile Include="TestCredentials.cs" />
<Compile Include="TestGrpc.cs" />
<Compile Include="SslCredentialsTest.cs" />
+ <Compile Include="Test.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 24c22273fb..0884c6ea60 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -37,34 +37,62 @@ using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+using CommandLine;
using Google.Apis.Auth.OAuth2;
-using Google.ProtocolBuffers;
-
-using grpc.testing;
+using Google.Protobuf;
using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
-
+using Grpc.Testing;
using NUnit.Framework;
+using CommandLine.Text;
+using System.IO;
namespace Grpc.IntegrationTesting
{
public class InteropClient
{
- private const string ServiceAccountUser = "155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk@developer.gserviceaccount.com";
- private const string ComputeEngineUser = "155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com";
- private const string AuthScope = "https://www.googleapis.com/auth/xapi.zoo";
- private const string AuthScopeResponse = "xapi.zoo";
-
private class ClientOptions
{
- public bool help;
- public string serverHost = "127.0.0.1";
- public string serverHostOverride = TestCredentials.DefaultHostOverride;
- public int? serverPort;
- public string testCase = "large_unary";
- public bool useTls;
- public bool useTestCa;
+ [Option("server_host", DefaultValue = "127.0.0.1")]
+ public string ServerHost { get; set; }
+
+ [Option("server_host_override", DefaultValue = TestCredentials.DefaultHostOverride)]
+ public string ServerHostOverride { get; set; }
+
+ [Option("server_port", Required = true)]
+ public int ServerPort { get; set; }
+
+ [Option("test_case", DefaultValue = "large_unary")]
+ public string TestCase { get; set; }
+
+ [Option("use_tls")]
+ public bool UseTls { get; set; }
+
+ [Option("use_test_ca")]
+ public bool UseTestCa { get; set; }
+
+ [Option("default_service_account", Required = false)]
+ public string DefaultServiceAccount { get; set; }
+
+ [Option("oauth_scope", Required = false)]
+ public string OAuthScope { get; set; }
+
+ [Option("service_account_key_file", Required = false)]
+ public string ServiceAccountKeyFile { get; set; }
+
+ [HelpOption]
+ public string GetUsage()
+ {
+ var help = new HelpText
+ {
+ Heading = "gRPC C# interop testing client",
+ AddDashesToOption = true
+ };
+ help.AddPreOptionsLine("Usage:");
+ help.AddOptions(this);
+ return help;
+ }
}
ClientOptions options;
@@ -76,26 +104,9 @@ namespace Grpc.IntegrationTesting
public static void Run(string[] args)
{
- Console.WriteLine("gRPC C# interop testing client");
- ClientOptions options = ParseArguments(args);
-
- if (options.serverHost == null || !options.serverPort.HasValue || options.testCase == null)
- {
- Console.WriteLine("Missing required argument.");
- Console.WriteLine();
- options.help = true;
- }
-
- if (options.help)
+ var options = new ClientOptions();
+ if (!Parser.Default.ParseArguments(args, options))
{
- Console.WriteLine("Usage:");
- Console.WriteLine(" --server_host=HOSTNAME");
- Console.WriteLine(" --server_host_override=HOSTNAME");
- Console.WriteLine(" --server_port=PORT");
- Console.WriteLine(" --test_case=TESTCASE");
- Console.WriteLine(" --use_tls=BOOLEAN");
- Console.WriteLine(" --use_test_ca=BOOLEAN");
- Console.WriteLine();
Environment.Exit(1);
}
@@ -105,30 +116,27 @@ namespace Grpc.IntegrationTesting
private async Task Run()
{
- Credentials credentials = null;
- if (options.useTls)
- {
- credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa);
- }
-
+ var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure;
+
List<ChannelOption> channelOptions = null;
- if (!string.IsNullOrEmpty(options.serverHostOverride))
+ if (!string.IsNullOrEmpty(options.ServerHostOverride))
{
channelOptions = new List<ChannelOption>
{
- new ChannelOption(ChannelOptions.SslTargetNameOverride, options.serverHostOverride)
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride)
};
}
-
- var channel = new Channel(options.serverHost, options.serverPort.Value, credentials, channelOptions);
+ Console.WriteLine(options.ServerHost);
+ Console.WriteLine(options.ServerPort);
+ var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions);
TestService.TestServiceClient client = new TestService.TestServiceClient(channel);
- await RunTestCaseAsync(options.testCase, client);
+ await RunTestCaseAsync(client, options);
channel.ShutdownAsync().Wait();
}
- private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client)
+ private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options)
{
- switch (testCase)
+ switch (options.TestCase)
{
case "empty_unary":
RunEmptyUnary(client);
@@ -148,20 +156,17 @@ namespace Grpc.IntegrationTesting
case "empty_stream":
await RunEmptyStreamAsync(client);
break;
- case "service_account_creds":
- await RunServiceAccountCredsAsync(client);
- break;
case "compute_engine_creds":
- await RunComputeEngineCredsAsync(client);
+ await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "jwt_token_creds":
- await RunJwtTokenCredsAsync(client);
+ await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount);
break;
case "oauth2_auth_token":
- await RunOAuth2AuthTokenAsync(client);
+ await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "per_rpc_creds":
- await RunPerRpcCredsAsync(client);
+ await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "cancel_after_begin":
await RunCancelAfterBeginAsync(client);
@@ -176,14 +181,14 @@ namespace Grpc.IntegrationTesting
RunBenchmarkEmptyUnary(client);
break;
default:
- throw new ArgumentException("Unknown test case " + testCase);
+ throw new ArgumentException("Unknown test case " + options.TestCase);
}
}
public static void RunEmptyUnary(TestService.ITestServiceClient client)
{
Console.WriteLine("running empty_unary");
- var response = client.EmptyCall(Empty.DefaultInstance);
+ var response = client.EmptyCall(new Empty());
Assert.IsNotNull(response);
Console.WriteLine("Passed!");
}
@@ -191,11 +196,12 @@ namespace Grpc.IntegrationTesting
public static void RunLargeUnary(TestService.ITestServiceClient client)
{
Console.WriteLine("running large_unary");
- var request = SimpleRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .SetResponseSize(314159)
- .SetPayload(CreateZerosPayload(271828))
- .Build();
+ var request = new SimpleRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828)
+ };
var response = client.UnaryCall(request);
@@ -208,7 +214,7 @@ namespace Grpc.IntegrationTesting
{
Console.WriteLine("running client_streaming");
- var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build());
+ var bodySizes = new List<int> { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) });
using (var call = client.StreamingInputCall())
{
@@ -226,11 +232,11 @@ namespace Grpc.IntegrationTesting
var bodySizes = new List<int> { 31415, 9, 2653, 58979 };
- var request = StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddRangeResponseParameters(bodySizes.ConvertAll(
- (size) => ResponseParameters.CreateBuilder().SetSize(size).Build()))
- .Build();
+ var request = new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) }
+ };
using (var call = client.StreamingOutputCall(request))
{
@@ -250,37 +256,45 @@ namespace Grpc.IntegrationTesting
using (var call = client.FullDuplexCall())
{
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
- .SetPayload(CreateZerosPayload(27182)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 31415 } },
+ Payload = CreateZerosPayload(27182)
+ });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9))
- .SetPayload(CreateZerosPayload(8)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 9 } },
+ Payload = CreateZerosPayload(8)
+ });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653))
- .SetPayload(CreateZerosPayload(1828)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 2653 } },
+ Payload = CreateZerosPayload(1828)
+ });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length);
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979))
- .SetPayload(CreateZerosPayload(45904)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 58979 } },
+ Payload = CreateZerosPayload(45904)
+ });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
@@ -306,117 +320,94 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunServiceAccountCredsAsync(TestService.TestServiceClient client)
- {
- Console.WriteLine("running service_account_creds");
- var credential = await GoogleCredential.GetApplicationDefaultAsync();
- credential = credential.CreateScoped(new[] { AuthScope });
- client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
-
- var request = SimpleRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .SetResponseSize(314159)
- .SetPayload(CreateZerosPayload(271828))
- .SetFillUsername(true)
- .SetFillOauthScope(true)
- .Build();
-
- var response = client.UnaryCall(request);
-
- Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
- Assert.AreEqual(314159, response.Payload.Body.Length);
- Assert.AreEqual(AuthScopeResponse, response.OauthScope);
- Assert.AreEqual(ServiceAccountUser, response.Username);
- Console.WriteLine("Passed!");
- }
-
- public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client)
+ public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running compute_engine_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(credential.IsCreateScopedRequired);
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
- var request = SimpleRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .SetResponseSize(314159)
- .SetPayload(CreateZerosPayload(271828))
- .SetFillUsername(true)
- .SetFillOauthScope(true)
- .Build();
+ var request = new SimpleRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828),
+ FillUsername = true,
+ FillOauthScope = true
+ };
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
- Assert.AreEqual(AuthScopeResponse, response.OauthScope);
- Assert.AreEqual(ComputeEngineUser, response.Username);
+ Assert.False(string.IsNullOrEmpty(response.OauthScope));
+ Assert.True(oauthScope.Contains(response.OauthScope));
+ Assert.AreEqual(defaultServiceAccount, response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client)
+ public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount)
{
Console.WriteLine("running jwt_token_creds");
var credential = await GoogleCredential.GetApplicationDefaultAsync();
- // check this a credential with scope support, but don't add the scope.
Assert.IsTrue(credential.IsCreateScopedRequired);
client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
- var request = SimpleRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .SetResponseSize(314159)
- .SetPayload(CreateZerosPayload(271828))
- .SetFillUsername(true)
- .SetFillOauthScope(true)
- .Build();
+ var request = new SimpleRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseSize = 314159,
+ Payload = CreateZerosPayload(271828),
+ FillUsername = true,
+ };
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
- Assert.AreEqual(ServiceAccountUser, response.Username);
+ Assert.AreEqual(defaultServiceAccount, response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client)
+ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running oauth2_auth_token");
- ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
+ ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
- var request = SimpleRequest.CreateBuilder()
- .SetFillUsername(true)
- .SetFillOauthScope(true)
- .Build();
+ var request = new SimpleRequest
+ {
+ FillUsername = true,
+ FillOauthScope = true
+ };
var response = client.UnaryCall(request);
- Assert.AreEqual(AuthScopeResponse, response.OauthScope);
- Assert.AreEqual(ServiceAccountUser, response.Username);
+ Assert.False(string.IsNullOrEmpty(response.OauthScope));
+ Assert.True(oauthScope.Contains(response.OauthScope));
+ Assert.AreEqual(defaultServiceAccount, response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client)
+ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running per_rpc_creds");
+ ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
+ string accessToken = await credential.GetAccessTokenForRequestAsync();
+ var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken);
- ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { AuthScope });
- string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
-
- var request = SimpleRequest.CreateBuilder()
- .SetFillUsername(true)
- .SetFillOauthScope(true)
- .Build();
+ var request = new SimpleRequest
+ {
+ FillUsername = true,
+ };
var headers = new Metadata();
headerInterceptor(null, "", headers);
var response = client.UnaryCall(request, headers: headers);
- Assert.AreEqual(AuthScopeResponse, response.OauthScope);
- Assert.AreEqual(ServiceAccountUser, response.Username);
+ Assert.AreEqual(defaultServiceAccount, response.Username);
Console.WriteLine("Passed!");
}
@@ -444,10 +435,12 @@ namespace Grpc.IntegrationTesting
var cts = new CancellationTokenSource();
using (var call = client.FullDuplexCall(cancellationToken: cts.Token))
{
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetResponseType(PayloadType.COMPRESSABLE)
- .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415))
- .SetPayload(CreateZerosPayload(27182)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest
+ {
+ ResponseType = PayloadType.COMPRESSABLE,
+ ResponseParameters = { new ResponseParameters { Size = 31415 } },
+ Payload = CreateZerosPayload(27182)
+ });
Assert.IsTrue(await call.ResponseStream.MoveNext());
Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type);
@@ -470,8 +463,7 @@ namespace Grpc.IntegrationTesting
{
try
{
- await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder()
- .SetPayload(CreateZerosPayload(27182)).Build());
+ await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) });
}
catch (InvalidOperationException)
{
@@ -488,75 +480,12 @@ namespace Grpc.IntegrationTesting
public static void RunBenchmarkEmptyUnary(TestService.ITestServiceClient client)
{
BenchmarkUtil.RunBenchmark(10000, 10000,
- () => { client.EmptyCall(Empty.DefaultInstance); });
+ () => { client.EmptyCall(new Empty()); });
}
private static Payload CreateZerosPayload(int size)
{
- return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build();
- }
-
- private static ClientOptions ParseArguments(string[] args)
- {
- var options = new ClientOptions();
- foreach (string arg in args)
- {
- ParseArgument(arg, options);
- if (options.help)
- {
- break;
- }
- }
- return options;
- }
-
- private static void ParseArgument(string arg, ClientOptions options)
- {
- Match match;
- match = Regex.Match(arg, "--server_host=(.*)");
- if (match.Success)
- {
- options.serverHost = match.Groups[1].Value.Trim();
- return;
- }
-
- match = Regex.Match(arg, "--server_host_override=(.*)");
- if (match.Success)
- {
- options.serverHostOverride = match.Groups[1].Value.Trim();
- return;
- }
-
- match = Regex.Match(arg, "--server_port=(.*)");
- if (match.Success)
- {
- options.serverPort = int.Parse(match.Groups[1].Value.Trim());
- return;
- }
-
- match = Regex.Match(arg, "--test_case=(.*)");
- if (match.Success)
- {
- options.testCase = match.Groups[1].Value.Trim();
- return;
- }
-
- match = Regex.Match(arg, "--use_tls=(.*)");
- if (match.Success)
- {
- options.useTls = bool.Parse(match.Groups[1].Value.Trim());
- return;
- }
-
- match = Regex.Match(arg, "--use_test_ca=(.*)");
- if (match.Success)
- {
- options.useTestCa = bool.Parse(match.Groups[1].Value.Trim());
- return;
- }
-
- Console.WriteLine(string.Format("Unrecognized argument \"{0}\"", arg));
- options.help = true;
+ return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index f3158aeb45..7bc17a207f 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -36,9 +36,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
+using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 0cc8b2cde1..513f8722d6 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -37,10 +37,12 @@ using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Google.ProtocolBuffers;
-using grpc.testing;
+
+using CommandLine;
+using CommandLine.Text;
using Grpc.Core;
using Grpc.Core.Utils;
+using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -49,9 +51,24 @@ namespace Grpc.IntegrationTesting
{
private class ServerOptions
{
- public bool help;
- public int? port = 8070;
- public bool useTls;
+ [Option("port", DefaultValue = 8070)]
+ public int Port { get; set; }
+
+ [Option("use_tls")]
+ public bool UseTls { get; set; }
+
+ [HelpOption]
+ public string GetUsage()
+ {
+ var help = new HelpText
+ {
+ Heading = "gRPC C# interop testing server",
+ AddDashesToOption = true
+ };
+ help.AddPreOptionsLine("Usage:");
+ help.AddOptions(this);
+ return help;
+ }
}
ServerOptions options;
@@ -63,22 +80,9 @@ namespace Grpc.IntegrationTesting
public static void Run(string[] args)
{
- Console.WriteLine("gRPC C# interop testing server");
- ServerOptions options = ParseArguments(args);
-
- if (!options.port.HasValue)
- {
- Console.WriteLine("Missing required argument.");
- Console.WriteLine();
- options.help = true;
- }
-
- if (options.help)
+ var options = new ServerOptions();
+ if (!Parser.Default.ParseArguments(args, options))
{
- Console.WriteLine("Usage:");
- Console.WriteLine(" --port=PORT");
- Console.WriteLine(" --use_tls=BOOLEAN");
- Console.WriteLine();
Environment.Exit(1);
}
@@ -94,54 +98,19 @@ namespace Grpc.IntegrationTesting
};
string host = "0.0.0.0";
- int port = options.port.Value;
- if (options.useTls)
+ int port = options.Port;
+ if (options.UseTls)
{
server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}
else
{
- server.Ports.Add(host, options.port.Value, ServerCredentials.Insecure);
+ server.Ports.Add(host, options.Port, ServerCredentials.Insecure);
}
Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port));
server.Start();
server.ShutdownTask.Wait();
}
-
- private static ServerOptions ParseArguments(string[] args)
- {
- var options = new ServerOptions();
- foreach (string arg in args)
- {
- ParseArgument(arg, options);
- if (options.help)
- {
- break;
- }
- }
- return options;
- }
-
- private static void ParseArgument(string arg, ServerOptions options)
- {
- Match match;
- match = Regex.Match(arg, "--port=(.*)");
- if (match.Success)
- {
- options.port = int.Parse(match.Groups[1].Value.Trim());
- return;
- }
-
- match = Regex.Match(arg, "--use_tls=(.*)");
- if (match.Success)
- {
- options.useTls = bool.Parse(match.Groups[1].Value.Trim());
- return;
- }
-
- Console.WriteLine(string.Format("Unrecognized argument \"{0}\"", arg));
- options.help = true;
- }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index 386f377f08..a3cbb7d76e 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -1,106 +1,58 @@
-// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT!
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: messages.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
-using pb = global::Google.ProtocolBuffers;
-using pbc = global::Google.ProtocolBuffers.Collections;
-using pbd = global::Google.ProtocolBuffers.Descriptors;
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
-namespace grpc.testing {
+namespace Grpc.Testing {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Messages {
- #region Extension registration
- public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
- }
- #endregion
- #region Static variables
- internal static pbd::MessageDescriptor internal__static_grpc_testing_Payload__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Payload, global::grpc.testing.Payload.Builder> internal__static_grpc_testing_Payload__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_SimpleRequest__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleRequest.Builder> internal__static_grpc_testing_SimpleRequest__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_SimpleResponse__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.SimpleResponse, global::grpc.testing.SimpleResponse.Builder> internal__static_grpc_testing_SimpleResponse__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingInputCallRequest__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallRequest.Builder> internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingInputCallResponse__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingInputCallResponse, global::grpc.testing.StreamingInputCallResponse.Builder> internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_ResponseParameters__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.ResponseParameters, global::grpc.testing.ResponseParameters.Builder> internal__static_grpc_testing_ResponseParameters__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallRequest.Builder> internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable;
- internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor;
- internal static pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingOutputCallResponse, global::grpc.testing.StreamingOutputCallResponse.Builder> internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable;
- #endregion
#region Descriptor
- public static pbd::FileDescriptor Descriptor {
+ public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
- private static pbd::FileDescriptor descriptor;
+ private static pbr::FileDescriptor descriptor;
static Messages() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE",
- "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5",
- "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB",
- "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6",
- "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
- "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl",
- "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
- "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
- "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
- "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
- "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
- "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
- "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
- "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
- "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
- "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
- "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0",
- "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
- "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V",
- "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC"));
- pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
- descriptor = root;
- internal__static_grpc_testing_Payload__Descriptor = Descriptor.MessageTypes[0];
- internal__static_grpc_testing_Payload__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.Payload, global::grpc.testing.Payload.Builder>(internal__static_grpc_testing_Payload__Descriptor,
- new string[] { "Type", "Body", });
- internal__static_grpc_testing_SimpleRequest__Descriptor = Descriptor.MessageTypes[1];
- internal__static_grpc_testing_SimpleRequest__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleRequest.Builder>(internal__static_grpc_testing_SimpleRequest__Descriptor,
- new string[] { "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", });
- internal__static_grpc_testing_SimpleResponse__Descriptor = Descriptor.MessageTypes[2];
- internal__static_grpc_testing_SimpleResponse__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.SimpleResponse, global::grpc.testing.SimpleResponse.Builder>(internal__static_grpc_testing_SimpleResponse__Descriptor,
- new string[] { "Payload", "Username", "OauthScope", });
- internal__static_grpc_testing_StreamingInputCallRequest__Descriptor = Descriptor.MessageTypes[3];
- internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallRequest.Builder>(internal__static_grpc_testing_StreamingInputCallRequest__Descriptor,
- new string[] { "Payload", });
- internal__static_grpc_testing_StreamingInputCallResponse__Descriptor = Descriptor.MessageTypes[4];
- internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingInputCallResponse, global::grpc.testing.StreamingInputCallResponse.Builder>(internal__static_grpc_testing_StreamingInputCallResponse__Descriptor,
- new string[] { "AggregatedPayloadSize", });
- internal__static_grpc_testing_ResponseParameters__Descriptor = Descriptor.MessageTypes[5];
- internal__static_grpc_testing_ResponseParameters__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.ResponseParameters, global::grpc.testing.ResponseParameters.Builder>(internal__static_grpc_testing_ResponseParameters__Descriptor,
- new string[] { "Size", "IntervalUs", });
- internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor = Descriptor.MessageTypes[6];
- internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallRequest.Builder>(internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor,
- new string[] { "ResponseType", "ResponseParameters", "Payload", });
- internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor = Descriptor.MessageTypes[7];
- internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable =
- new pb::FieldAccess.FieldAccessorTable<global::grpc.testing.StreamingOutputCallResponse, global::grpc.testing.StreamingOutputCallResponse.Builder>(internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor,
- new string[] { "Payload", });
- return null;
- };
- pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
- new pbd::FileDescriptor[] {
- }, assigner);
+ "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE",
+ "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5",
+ "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB",
+ "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6",
+ "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
+ "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl",
+ "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
+ "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
+ "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
+ "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
+ "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
+ "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
+ "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
+ "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
+ "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
+ "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
+ "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0",
+ "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
+ "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V",
+ "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM="));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { },
+ new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null)
+ }));
}
#endregion
@@ -116,2772 +68,1101 @@ namespace grpc.testing {
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Payload : pb::GeneratedMessage<Payload, Payload.Builder> {
- private Payload() { }
- private static readonly Payload defaultInstance = new Payload().MakeReadOnly();
- private static readonly string[] _payloadFieldNames = new string[] { "body", "type" };
- private static readonly uint[] _payloadFieldTags = new uint[] { 18, 8 };
- public static Payload DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class Payload : pb::IMessage<Payload> {
+ private static readonly pb::MessageParser<Payload> _parser = new pb::MessageParser<Payload>(() => new Payload());
+ public static pb::MessageParser<Payload> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[0]; }
}
- public override Payload DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override Payload ThisMessage {
- get { return this; }
+ public Payload() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_Payload__Descriptor; }
+ partial void OnConstruction();
+
+ public Payload(Payload other) : this() {
+ type_ = other.type_;
+ body_ = other.body_;
}
- protected override pb::FieldAccess.FieldAccessorTable<Payload, Payload.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_Payload__FieldAccessorTable; }
+ public Payload Clone() {
+ return new Payload(this);
}
public const int TypeFieldNumber = 1;
- private bool hasType;
- private global::grpc.testing.PayloadType type_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- public bool HasType {
- get { return hasType; }
- }
- public global::grpc.testing.PayloadType Type {
+ private global::Grpc.Testing.PayloadType type_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ public global::Grpc.Testing.PayloadType Type {
get { return type_; }
+ set {
+ type_ = value;
+ }
}
public const int BodyFieldNumber = 2;
- private bool hasBody;
private pb::ByteString body_ = pb::ByteString.Empty;
- public bool HasBody {
- get { return hasBody; }
- }
public pb::ByteString Body {
get { return body_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ body_ = pb::Preconditions.CheckNotNull(value, "value");
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _payloadFieldNames;
- if (hasType) {
- output.WriteEnum(1, field_names[1], (int) Type, Type);
- }
- if (hasBody) {
- output.WriteBytes(2, field_names[0], Body);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as Payload);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasType) {
- size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Type);
- }
- if (hasBody) {
- size += pb::CodedOutputStream.ComputeBytesSize(2, Body);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(Payload other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Type != other.Type) return false;
+ if (Body != other.Body) return false;
+ return true;
}
- public static Payload ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Payload ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Payload ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static Payload ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static Payload ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Payload ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static Payload ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static Payload ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static Payload ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static Payload ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private Payload MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= Type.GetHashCode();
+ if (Body.Length != 0) hash ^= Body.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(Payload prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<Payload, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(Payload cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private Payload result;
-
- private Payload PrepareBuilder() {
- if (resultIsReadOnly) {
- Payload original = result;
- result = new Payload();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ output.WriteRawTag(8);
+ output.WriteEnum((int) Type);
}
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override Payload MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
+ if (Body.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteBytes(Body);
}
+ }
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.Payload.Descriptor; }
+ if (Body.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeBytesSize(Body);
}
+ return size;
+ }
- public override Payload DefaultInstanceForType {
- get { return global::grpc.testing.Payload.DefaultInstance; }
+ public void MergeFrom(Payload other) {
+ if (other == null) {
+ return;
}
-
- public override Payload BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (other.Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ Type = other.Type;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is Payload) {
- return MergeFrom((Payload) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ if (other.Body.Length != 0) {
+ Body = other.Body;
}
+ }
- public override Builder MergeFrom(Payload other) {
- if (other == global::grpc.testing.Payload.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasType) {
- Type = other.Type;
- }
- if (other.HasBody) {
- Body = other.Body;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_payloadFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _payloadFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ type_ = (global::Grpc.Testing.PayloadType) input.ReadEnum();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- object unknown;
- if(input.ReadEnum(ref result.type_, out unknown)) {
- result.hasType = true;
- } else if(unknown is int) {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- unknownFields.MergeVarintField(1, (ulong)(int)unknown);
- }
- break;
- }
- case 18: {
- result.hasBody = input.ReadBytes(ref result.body_);
- break;
- }
+ case 18: {
+ Body = input.ReadBytes();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasType {
- get { return result.hasType; }
- }
- public global::grpc.testing.PayloadType Type {
- get { return result.Type; }
- set { SetType(value); }
- }
- public Builder SetType(global::grpc.testing.PayloadType value) {
- PrepareBuilder();
- result.hasType = true;
- result.type_ = value;
- return this;
- }
- public Builder ClearType() {
- PrepareBuilder();
- result.hasType = false;
- result.type_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- return this;
- }
-
- public bool HasBody {
- get { return result.hasBody; }
- }
- public pb::ByteString Body {
- get { return result.Body; }
- set { SetBody(value); }
}
- public Builder SetBody(pb::ByteString value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasBody = true;
- result.body_ = value;
- return this;
- }
- public Builder ClearBody() {
- PrepareBuilder();
- result.hasBody = false;
- result.body_ = pb::ByteString.Empty;
- return this;
- }
- }
- static Payload() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class SimpleRequest : pb::GeneratedMessage<SimpleRequest, SimpleRequest.Builder> {
- private SimpleRequest() { }
- private static readonly SimpleRequest defaultInstance = new SimpleRequest().MakeReadOnly();
- private static readonly string[] _simpleRequestFieldNames = new string[] { "fill_oauth_scope", "fill_username", "payload", "response_size", "response_type" };
- private static readonly uint[] _simpleRequestFieldTags = new uint[] { 40, 32, 26, 16, 8 };
- public static SimpleRequest DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class SimpleRequest : pb::IMessage<SimpleRequest> {
+ private static readonly pb::MessageParser<SimpleRequest> _parser = new pb::MessageParser<SimpleRequest>(() => new SimpleRequest());
+ public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
}
- public override SimpleRequest DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override SimpleRequest ThisMessage {
- get { return this; }
+ public SimpleRequest() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleRequest__Descriptor; }
+ partial void OnConstruction();
+
+ public SimpleRequest(SimpleRequest other) : this() {
+ responseType_ = other.responseType_;
+ responseSize_ = other.responseSize_;
+ Payload = other.payload_ != null ? other.Payload.Clone() : null;
+ fillUsername_ = other.fillUsername_;
+ fillOauthScope_ = other.fillOauthScope_;
}
- protected override pb::FieldAccess.FieldAccessorTable<SimpleRequest, SimpleRequest.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleRequest__FieldAccessorTable; }
+ public SimpleRequest Clone() {
+ return new SimpleRequest(this);
}
public const int ResponseTypeFieldNumber = 1;
- private bool hasResponseType;
- private global::grpc.testing.PayloadType responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- public bool HasResponseType {
- get { return hasResponseType; }
- }
- public global::grpc.testing.PayloadType ResponseType {
+ private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ public global::Grpc.Testing.PayloadType ResponseType {
get { return responseType_; }
+ set {
+ responseType_ = value;
+ }
}
public const int ResponseSizeFieldNumber = 2;
- private bool hasResponseSize;
private int responseSize_;
- public bool HasResponseSize {
- get { return hasResponseSize; }
- }
public int ResponseSize {
get { return responseSize_; }
+ set {
+ responseSize_ = value;
+ }
}
public const int PayloadFieldNumber = 3;
- private bool hasPayload;
- private global::grpc.testing.Payload payload_;
- public bool HasPayload {
- get { return hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; }
+ private global::Grpc.Testing.Payload payload_;
+ public global::Grpc.Testing.Payload Payload {
+ get { return payload_; }
+ set {
+ payload_ = value;
+ }
}
public const int FillUsernameFieldNumber = 4;
- private bool hasFillUsername;
private bool fillUsername_;
- public bool HasFillUsername {
- get { return hasFillUsername; }
- }
public bool FillUsername {
get { return fillUsername_; }
+ set {
+ fillUsername_ = value;
+ }
}
public const int FillOauthScopeFieldNumber = 5;
- private bool hasFillOauthScope;
private bool fillOauthScope_;
- public bool HasFillOauthScope {
- get { return hasFillOauthScope; }
- }
public bool FillOauthScope {
get { return fillOauthScope_; }
+ set {
+ fillOauthScope_ = value;
+ }
}
- public override bool IsInitialized {
- get {
- return true;
- }
+ public override bool Equals(object other) {
+ return Equals(other as SimpleRequest);
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _simpleRequestFieldNames;
- if (hasResponseType) {
- output.WriteEnum(1, field_names[4], (int) ResponseType, ResponseType);
- }
- if (hasResponseSize) {
- output.WriteInt32(2, field_names[3], ResponseSize);
- }
- if (hasPayload) {
- output.WriteMessage(3, field_names[2], Payload);
- }
- if (hasFillUsername) {
- output.WriteBool(4, field_names[1], FillUsername);
+ public bool Equals(SimpleRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
- if (hasFillOauthScope) {
- output.WriteBool(5, field_names[0], FillOauthScope);
+ if (ReferenceEquals(other, this)) {
+ return true;
}
- UnknownFields.WriteTo(output);
+ if (ResponseType != other.ResponseType) return false;
+ if (ResponseSize != other.ResponseSize) return false;
+ if (!object.Equals(Payload, other.Payload)) return false;
+ if (FillUsername != other.FillUsername) return false;
+ if (FillOauthScope != other.FillOauthScope) return false;
+ return true;
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasResponseType) {
- size += pb::CodedOutputStream.ComputeEnumSize(1, (int) ResponseType);
- }
- if (hasResponseSize) {
- size += pb::CodedOutputStream.ComputeInt32Size(2, ResponseSize);
- }
- if (hasPayload) {
- size += pb::CodedOutputStream.ComputeMessageSize(3, Payload);
- }
- if (hasFillUsername) {
- size += pb::CodedOutputStream.ComputeBoolSize(4, FillUsername);
- }
- if (hasFillOauthScope) {
- size += pb::CodedOutputStream.ComputeBoolSize(5, FillOauthScope);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
- }
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
+ if (ResponseSize != 0) hash ^= ResponseSize.GetHashCode();
+ if (payload_ != null) hash ^= Payload.GetHashCode();
+ if (FillUsername != false) hash ^= FillUsername.GetHashCode();
+ if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
+ return hash;
}
- public static SimpleRequest ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static SimpleRequest ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static SimpleRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static SimpleRequest ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static SimpleRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private SimpleRequest MakeReadOnly() {
- return this;
- }
-
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(SimpleRequest prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<SimpleRequest, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ output.WriteRawTag(8);
+ output.WriteEnum((int) ResponseType);
}
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
+ if (ResponseSize != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(ResponseSize);
}
- internal Builder(SimpleRequest cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
+ if (payload_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(Payload);
}
-
- private bool resultIsReadOnly;
- private SimpleRequest result;
-
- private SimpleRequest PrepareBuilder() {
- if (resultIsReadOnly) {
- SimpleRequest original = result;
- result = new SimpleRequest();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
+ if (FillUsername != false) {
+ output.WriteRawTag(32);
+ output.WriteBool(FillUsername);
}
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
+ if (FillOauthScope != false) {
+ output.WriteRawTag(40);
+ output.WriteBool(FillOauthScope);
}
+ }
- protected override SimpleRequest MessageBeingBuilt {
- get { return PrepareBuilder(); }
+ public int CalculateSize() {
+ int size = 0;
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType);
}
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
+ if (ResponseSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(ResponseSize);
}
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ if (payload_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.SimpleRequest.Descriptor; }
+ if (FillUsername != false) {
+ size += 1 + 1;
}
-
- public override SimpleRequest DefaultInstanceForType {
- get { return global::grpc.testing.SimpleRequest.DefaultInstance; }
+ if (FillOauthScope != false) {
+ size += 1 + 1;
}
+ return size;
+ }
- public override SimpleRequest BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void MergeFrom(SimpleRequest other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is SimpleRequest) {
- return MergeFrom((SimpleRequest) other);
- } else {
- base.MergeFrom(other);
- return this;
+ if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ ResponseType = other.ResponseType;
+ }
+ if (other.ResponseSize != 0) {
+ ResponseSize = other.ResponseSize;
+ }
+ if (other.payload_ != null) {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ Payload.MergeFrom(other.Payload);
+ }
+ if (other.FillUsername != false) {
+ FillUsername = other.FillUsername;
}
+ if (other.FillOauthScope != false) {
+ FillOauthScope = other.FillOauthScope;
+ }
+ }
- public override Builder MergeFrom(SimpleRequest other) {
- if (other == global::grpc.testing.SimpleRequest.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasResponseType) {
- ResponseType = other.ResponseType;
- }
- if (other.HasResponseSize) {
- ResponseSize = other.ResponseSize;
- }
- if (other.HasPayload) {
- MergePayload(other.Payload);
- }
- if (other.HasFillUsername) {
- FillUsername = other.FillUsername;
- }
- if (other.HasFillOauthScope) {
- FillOauthScope = other.FillOauthScope;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_simpleRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _simpleRequestFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- object unknown;
- if(input.ReadEnum(ref result.responseType_, out unknown)) {
- result.hasResponseType = true;
- } else if(unknown is int) {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- unknownFields.MergeVarintField(1, (ulong)(int)unknown);
- }
- break;
- }
- case 16: {
- result.hasResponseSize = input.ReadInt32(ref result.responseSize_);
- break;
- }
- case 26: {
- global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder();
- if (result.hasPayload) {
- subBuilder.MergeFrom(Payload);
- }
- input.ReadMessage(subBuilder, extensionRegistry);
- Payload = subBuilder.BuildPartial();
- break;
- }
- case 32: {
- result.hasFillUsername = input.ReadBool(ref result.fillUsername_);
- break;
- }
- case 40: {
- result.hasFillOauthScope = input.ReadBool(ref result.fillOauthScope_);
- break;
+ case 16: {
+ ResponseSize = input.ReadInt32();
+ break;
+ }
+ case 26: {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ input.ReadMessage(payload_);
+ break;
+ }
+ case 32: {
+ FillUsername = input.ReadBool();
+ break;
+ }
+ case 40: {
+ FillOauthScope = input.ReadBool();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasResponseType {
- get { return result.hasResponseType; }
- }
- public global::grpc.testing.PayloadType ResponseType {
- get { return result.ResponseType; }
- set { SetResponseType(value); }
- }
- public Builder SetResponseType(global::grpc.testing.PayloadType value) {
- PrepareBuilder();
- result.hasResponseType = true;
- result.responseType_ = value;
- return this;
- }
- public Builder ClearResponseType() {
- PrepareBuilder();
- result.hasResponseType = false;
- result.responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- return this;
- }
-
- public bool HasResponseSize {
- get { return result.hasResponseSize; }
- }
- public int ResponseSize {
- get { return result.ResponseSize; }
- set { SetResponseSize(value); }
- }
- public Builder SetResponseSize(int value) {
- PrepareBuilder();
- result.hasResponseSize = true;
- result.responseSize_ = value;
- return this;
- }
- public Builder ClearResponseSize() {
- PrepareBuilder();
- result.hasResponseSize = false;
- result.responseSize_ = 0;
- return this;
- }
-
- public bool HasPayload {
- get { return result.hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return result.Payload; }
- set { SetPayload(value); }
- }
- public Builder SetPayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = value;
- return this;
- }
- public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = builderForValue.Build();
- return this;
- }
- public Builder MergePayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- if (result.hasPayload &&
- result.payload_ != global::grpc.testing.Payload.DefaultInstance) {
- result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial();
- } else {
- result.payload_ = value;
- }
- result.hasPayload = true;
- return this;
- }
- public Builder ClearPayload() {
- PrepareBuilder();
- result.hasPayload = false;
- result.payload_ = null;
- return this;
- }
-
- public bool HasFillUsername {
- get { return result.hasFillUsername; }
- }
- public bool FillUsername {
- get { return result.FillUsername; }
- set { SetFillUsername(value); }
- }
- public Builder SetFillUsername(bool value) {
- PrepareBuilder();
- result.hasFillUsername = true;
- result.fillUsername_ = value;
- return this;
- }
- public Builder ClearFillUsername() {
- PrepareBuilder();
- result.hasFillUsername = false;
- result.fillUsername_ = false;
- return this;
- }
-
- public bool HasFillOauthScope {
- get { return result.hasFillOauthScope; }
- }
- public bool FillOauthScope {
- get { return result.FillOauthScope; }
- set { SetFillOauthScope(value); }
- }
- public Builder SetFillOauthScope(bool value) {
- PrepareBuilder();
- result.hasFillOauthScope = true;
- result.fillOauthScope_ = value;
- return this;
- }
- public Builder ClearFillOauthScope() {
- PrepareBuilder();
- result.hasFillOauthScope = false;
- result.fillOauthScope_ = false;
- return this;
}
}
- static SimpleRequest() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
- }
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class SimpleResponse : pb::GeneratedMessage<SimpleResponse, SimpleResponse.Builder> {
- private SimpleResponse() { }
- private static readonly SimpleResponse defaultInstance = new SimpleResponse().MakeReadOnly();
- private static readonly string[] _simpleResponseFieldNames = new string[] { "oauth_scope", "payload", "username" };
- private static readonly uint[] _simpleResponseFieldTags = new uint[] { 26, 10, 18 };
- public static SimpleResponse DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class SimpleResponse : pb::IMessage<SimpleResponse> {
+ private static readonly pb::MessageParser<SimpleResponse> _parser = new pb::MessageParser<SimpleResponse>(() => new SimpleResponse());
+ public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
}
- public override SimpleResponse DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override SimpleResponse ThisMessage {
- get { return this; }
+ public SimpleResponse() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleResponse__Descriptor; }
+ partial void OnConstruction();
+
+ public SimpleResponse(SimpleResponse other) : this() {
+ Payload = other.payload_ != null ? other.Payload.Clone() : null;
+ username_ = other.username_;
+ oauthScope_ = other.oauthScope_;
}
- protected override pb::FieldAccess.FieldAccessorTable<SimpleResponse, SimpleResponse.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleResponse__FieldAccessorTable; }
+ public SimpleResponse Clone() {
+ return new SimpleResponse(this);
}
public const int PayloadFieldNumber = 1;
- private bool hasPayload;
- private global::grpc.testing.Payload payload_;
- public bool HasPayload {
- get { return hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; }
+ private global::Grpc.Testing.Payload payload_;
+ public global::Grpc.Testing.Payload Payload {
+ get { return payload_; }
+ set {
+ payload_ = value;
+ }
}
public const int UsernameFieldNumber = 2;
- private bool hasUsername;
private string username_ = "";
- public bool HasUsername {
- get { return hasUsername; }
- }
public string Username {
get { return username_; }
+ set {
+ username_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
}
public const int OauthScopeFieldNumber = 3;
- private bool hasOauthScope;
private string oauthScope_ = "";
- public bool HasOauthScope {
- get { return hasOauthScope; }
- }
public string OauthScope {
get { return oauthScope_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ oauthScope_ = pb::Preconditions.CheckNotNull(value, "value");
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _simpleResponseFieldNames;
- if (hasPayload) {
- output.WriteMessage(1, field_names[1], Payload);
- }
- if (hasUsername) {
- output.WriteString(2, field_names[2], Username);
- }
- if (hasOauthScope) {
- output.WriteString(3, field_names[0], OauthScope);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as SimpleResponse);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasPayload) {
- size += pb::CodedOutputStream.ComputeMessageSize(1, Payload);
- }
- if (hasUsername) {
- size += pb::CodedOutputStream.ComputeStringSize(2, Username);
- }
- if (hasOauthScope) {
- size += pb::CodedOutputStream.ComputeStringSize(3, OauthScope);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(SimpleResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!object.Equals(Payload, other.Payload)) return false;
+ if (Username != other.Username) return false;
+ if (OauthScope != other.OauthScope) return false;
+ return true;
}
- public static SimpleResponse ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static SimpleResponse ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static SimpleResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static SimpleResponse ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static SimpleResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private SimpleResponse MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (payload_ != null) hash ^= Payload.GetHashCode();
+ if (Username.Length != 0) hash ^= Username.GetHashCode();
+ if (OauthScope.Length != 0) hash ^= OauthScope.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(SimpleResponse prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<SimpleResponse, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (payload_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Payload);
}
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
+ if (Username.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Username);
}
- internal Builder(SimpleResponse cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
+ if (OauthScope.Length != 0) {
+ output.WriteRawTag(26);
+ output.WriteString(OauthScope);
}
+ }
- private bool resultIsReadOnly;
- private SimpleResponse result;
-
- private SimpleResponse PrepareBuilder() {
- if (resultIsReadOnly) {
- SimpleResponse original = result;
- result = new SimpleResponse();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
+ public int CalculateSize() {
+ int size = 0;
+ if (payload_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
+ if (Username.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Username);
}
-
- protected override SimpleResponse MessageBeingBuilt {
- get { return PrepareBuilder(); }
+ if (OauthScope.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(OauthScope);
}
+ return size;
+ }
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
+ public void MergeFrom(SimpleResponse other) {
+ if (other == null) {
+ return;
}
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
+ if (other.payload_ != null) {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ Payload.MergeFrom(other.Payload);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.SimpleResponse.Descriptor; }
- }
-
- public override SimpleResponse DefaultInstanceForType {
- get { return global::grpc.testing.SimpleResponse.DefaultInstance; }
+ if (other.Username.Length != 0) {
+ Username = other.Username;
}
-
- public override SimpleResponse BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
- }
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is SimpleResponse) {
- return MergeFrom((SimpleResponse) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ if (other.OauthScope.Length != 0) {
+ OauthScope = other.OauthScope;
}
+ }
- public override Builder MergeFrom(SimpleResponse other) {
- if (other == global::grpc.testing.SimpleResponse.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasPayload) {
- MergePayload(other.Payload);
- }
- if (other.HasUsername) {
- Username = other.Username;
- }
- if (other.HasOauthScope) {
- OauthScope = other.OauthScope;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_simpleResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _simpleResponseFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ input.ReadMessage(payload_);
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 10: {
- global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder();
- if (result.hasPayload) {
- subBuilder.MergeFrom(Payload);
- }
- input.ReadMessage(subBuilder, extensionRegistry);
- Payload = subBuilder.BuildPartial();
- break;
- }
- case 18: {
- result.hasUsername = input.ReadString(ref result.username_);
- break;
- }
- case 26: {
- result.hasOauthScope = input.ReadString(ref result.oauthScope_);
- break;
- }
+ case 18: {
+ Username = input.ReadString();
+ break;
+ }
+ case 26: {
+ OauthScope = input.ReadString();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasPayload {
- get { return result.hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return result.Payload; }
- set { SetPayload(value); }
- }
- public Builder SetPayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = value;
- return this;
- }
- public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = builderForValue.Build();
- return this;
- }
- public Builder MergePayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- if (result.hasPayload &&
- result.payload_ != global::grpc.testing.Payload.DefaultInstance) {
- result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial();
- } else {
- result.payload_ = value;
- }
- result.hasPayload = true;
- return this;
- }
- public Builder ClearPayload() {
- PrepareBuilder();
- result.hasPayload = false;
- result.payload_ = null;
- return this;
- }
-
- public bool HasUsername {
- get { return result.hasUsername; }
- }
- public string Username {
- get { return result.Username; }
- set { SetUsername(value); }
- }
- public Builder SetUsername(string value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasUsername = true;
- result.username_ = value;
- return this;
- }
- public Builder ClearUsername() {
- PrepareBuilder();
- result.hasUsername = false;
- result.username_ = "";
- return this;
- }
-
- public bool HasOauthScope {
- get { return result.hasOauthScope; }
- }
- public string OauthScope {
- get { return result.OauthScope; }
- set { SetOauthScope(value); }
- }
- public Builder SetOauthScope(string value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasOauthScope = true;
- result.oauthScope_ = value;
- return this;
- }
- public Builder ClearOauthScope() {
- PrepareBuilder();
- result.hasOauthScope = false;
- result.oauthScope_ = "";
- return this;
}
}
- static SimpleResponse() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
- }
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class StreamingInputCallRequest : pb::GeneratedMessage<StreamingInputCallRequest, StreamingInputCallRequest.Builder> {
- private StreamingInputCallRequest() { }
- private static readonly StreamingInputCallRequest defaultInstance = new StreamingInputCallRequest().MakeReadOnly();
- private static readonly string[] _streamingInputCallRequestFieldNames = new string[] { "payload" };
- private static readonly uint[] _streamingInputCallRequestFieldTags = new uint[] { 10 };
- public static StreamingInputCallRequest DefaultInstance {
- get { return defaultInstance; }
- }
+ public sealed partial class StreamingInputCallRequest : pb::IMessage<StreamingInputCallRequest> {
+ private static readonly pb::MessageParser<StreamingInputCallRequest> _parser = new pb::MessageParser<StreamingInputCallRequest>(() => new StreamingInputCallRequest());
+ public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
- public override StreamingInputCallRequest DefaultInstanceForType {
- get { return DefaultInstance; }
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
}
- protected override StreamingInputCallRequest ThisMessage {
- get { return this; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallRequest__Descriptor; }
+ public StreamingInputCallRequest() {
+ OnConstruction();
}
- protected override pb::FieldAccess.FieldAccessorTable<StreamingInputCallRequest, StreamingInputCallRequest.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable; }
- }
+ partial void OnConstruction();
- public const int PayloadFieldNumber = 1;
- private bool hasPayload;
- private global::grpc.testing.Payload payload_;
- public bool HasPayload {
- get { return hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; }
+ public StreamingInputCallRequest(StreamingInputCallRequest other) : this() {
+ Payload = other.payload_ != null ? other.Payload.Clone() : null;
}
- public override bool IsInitialized {
- get {
- return true;
- }
+ public StreamingInputCallRequest Clone() {
+ return new StreamingInputCallRequest(this);
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _streamingInputCallRequestFieldNames;
- if (hasPayload) {
- output.WriteMessage(1, field_names[0], Payload);
+ public const int PayloadFieldNumber = 1;
+ private global::Grpc.Testing.Payload payload_;
+ public global::Grpc.Testing.Payload Payload {
+ get { return payload_; }
+ set {
+ payload_ = value;
}
- UnknownFields.WriteTo(output);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
+ public override bool Equals(object other) {
+ return Equals(other as StreamingInputCallRequest);
+ }
- size = 0;
- if (hasPayload) {
- size += pb::CodedOutputStream.ComputeMessageSize(1, Payload);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(StreamingInputCallRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ if (!object.Equals(Payload, other.Payload)) return false;
+ return true;
}
- public static StreamingInputCallRequest ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static StreamingInputCallRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingInputCallRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private StreamingInputCallRequest MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (payload_ != null) hash ^= Payload.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(StreamingInputCallRequest prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<StreamingInputCallRequest, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(StreamingInputCallRequest cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private StreamingInputCallRequest result;
-
- private StreamingInputCallRequest PrepareBuilder() {
- if (resultIsReadOnly) {
- StreamingInputCallRequest original = result;
- result = new StreamingInputCallRequest();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override StreamingInputCallRequest MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.StreamingInputCallRequest.Descriptor; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (payload_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Payload);
}
+ }
- public override StreamingInputCallRequest DefaultInstanceForType {
- get { return global::grpc.testing.StreamingInputCallRequest.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (payload_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ return size;
+ }
- public override StreamingInputCallRequest BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void MergeFrom(StreamingInputCallRequest other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is StreamingInputCallRequest) {
- return MergeFrom((StreamingInputCallRequest) other);
- } else {
- base.MergeFrom(other);
- return this;
+ if (other.payload_ != null) {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ Payload.MergeFrom(other.Payload);
}
+ }
- public override Builder MergeFrom(StreamingInputCallRequest other) {
- if (other == global::grpc.testing.StreamingInputCallRequest.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasPayload) {
- MergePayload(other.Payload);
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_streamingInputCallRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _streamingInputCallRequestFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ input.ReadMessage(payload_);
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 10: {
- global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder();
- if (result.hasPayload) {
- subBuilder.MergeFrom(Payload);
- }
- input.ReadMessage(subBuilder, extensionRegistry);
- Payload = subBuilder.BuildPartial();
- break;
- }
- }
- }
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasPayload {
- get { return result.hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return result.Payload; }
- set { SetPayload(value); }
- }
- public Builder SetPayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = value;
- return this;
- }
- public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = builderForValue.Build();
- return this;
- }
- public Builder MergePayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- if (result.hasPayload &&
- result.payload_ != global::grpc.testing.Payload.DefaultInstance) {
- result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial();
- } else {
- result.payload_ = value;
}
- result.hasPayload = true;
- return this;
}
- public Builder ClearPayload() {
- PrepareBuilder();
- result.hasPayload = false;
- result.payload_ = null;
- return this;
- }
- }
- static StreamingInputCallRequest() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class StreamingInputCallResponse : pb::GeneratedMessage<StreamingInputCallResponse, StreamingInputCallResponse.Builder> {
- private StreamingInputCallResponse() { }
- private static readonly StreamingInputCallResponse defaultInstance = new StreamingInputCallResponse().MakeReadOnly();
- private static readonly string[] _streamingInputCallResponseFieldNames = new string[] { "aggregated_payload_size" };
- private static readonly uint[] _streamingInputCallResponseFieldTags = new uint[] { 8 };
- public static StreamingInputCallResponse DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class StreamingInputCallResponse : pb::IMessage<StreamingInputCallResponse> {
+ private static readonly pb::MessageParser<StreamingInputCallResponse> _parser = new pb::MessageParser<StreamingInputCallResponse>(() => new StreamingInputCallResponse());
+ public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
}
- public override StreamingInputCallResponse DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override StreamingInputCallResponse ThisMessage {
- get { return this; }
+ public StreamingInputCallResponse() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallResponse__Descriptor; }
+ partial void OnConstruction();
+
+ public StreamingInputCallResponse(StreamingInputCallResponse other) : this() {
+ aggregatedPayloadSize_ = other.aggregatedPayloadSize_;
}
- protected override pb::FieldAccess.FieldAccessorTable<StreamingInputCallResponse, StreamingInputCallResponse.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable; }
+ public StreamingInputCallResponse Clone() {
+ return new StreamingInputCallResponse(this);
}
public const int AggregatedPayloadSizeFieldNumber = 1;
- private bool hasAggregatedPayloadSize;
private int aggregatedPayloadSize_;
- public bool HasAggregatedPayloadSize {
- get { return hasAggregatedPayloadSize; }
- }
public int AggregatedPayloadSize {
get { return aggregatedPayloadSize_; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ set {
+ aggregatedPayloadSize_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _streamingInputCallResponseFieldNames;
- if (hasAggregatedPayloadSize) {
- output.WriteInt32(1, field_names[0], AggregatedPayloadSize);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as StreamingInputCallResponse);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasAggregatedPayloadSize) {
- size += pb::CodedOutputStream.ComputeInt32Size(1, AggregatedPayloadSize);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(StreamingInputCallResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ if (AggregatedPayloadSize != other.AggregatedPayloadSize) return false;
+ return true;
}
- public static StreamingInputCallResponse ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static StreamingInputCallResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingInputCallResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private StreamingInputCallResponse MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (AggregatedPayloadSize != 0) hash ^= AggregatedPayloadSize.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(StreamingInputCallResponse prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<StreamingInputCallResponse, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(StreamingInputCallResponse cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private StreamingInputCallResponse result;
-
- private StreamingInputCallResponse PrepareBuilder() {
- if (resultIsReadOnly) {
- StreamingInputCallResponse original = result;
- result = new StreamingInputCallResponse();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override StreamingInputCallResponse MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.StreamingInputCallResponse.Descriptor; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (AggregatedPayloadSize != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(AggregatedPayloadSize);
}
+ }
- public override StreamingInputCallResponse DefaultInstanceForType {
- get { return global::grpc.testing.StreamingInputCallResponse.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (AggregatedPayloadSize != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(AggregatedPayloadSize);
}
+ return size;
+ }
- public override StreamingInputCallResponse BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void MergeFrom(StreamingInputCallResponse other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is StreamingInputCallResponse) {
- return MergeFrom((StreamingInputCallResponse) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ if (other.AggregatedPayloadSize != 0) {
+ AggregatedPayloadSize = other.AggregatedPayloadSize;
}
+ }
- public override Builder MergeFrom(StreamingInputCallResponse other) {
- if (other == global::grpc.testing.StreamingInputCallResponse.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasAggregatedPayloadSize) {
- AggregatedPayloadSize = other.AggregatedPayloadSize;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_streamingInputCallResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _streamingInputCallResponseFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
- }
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasAggregatedPayloadSize = input.ReadInt32(ref result.aggregatedPayloadSize_);
- break;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ AggregatedPayloadSize = input.ReadInt32();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasAggregatedPayloadSize {
- get { return result.hasAggregatedPayloadSize; }
- }
- public int AggregatedPayloadSize {
- get { return result.AggregatedPayloadSize; }
- set { SetAggregatedPayloadSize(value); }
- }
- public Builder SetAggregatedPayloadSize(int value) {
- PrepareBuilder();
- result.hasAggregatedPayloadSize = true;
- result.aggregatedPayloadSize_ = value;
- return this;
}
- public Builder ClearAggregatedPayloadSize() {
- PrepareBuilder();
- result.hasAggregatedPayloadSize = false;
- result.aggregatedPayloadSize_ = 0;
- return this;
- }
- }
- static StreamingInputCallResponse() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class ResponseParameters : pb::GeneratedMessage<ResponseParameters, ResponseParameters.Builder> {
- private ResponseParameters() { }
- private static readonly ResponseParameters defaultInstance = new ResponseParameters().MakeReadOnly();
- private static readonly string[] _responseParametersFieldNames = new string[] { "interval_us", "size" };
- private static readonly uint[] _responseParametersFieldTags = new uint[] { 16, 8 };
- public static ResponseParameters DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class ResponseParameters : pb::IMessage<ResponseParameters> {
+ private static readonly pb::MessageParser<ResponseParameters> _parser = new pb::MessageParser<ResponseParameters>(() => new ResponseParameters());
+ public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
}
- public override ResponseParameters DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override ResponseParameters ThisMessage {
- get { return this; }
+ public ResponseParameters() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_ResponseParameters__Descriptor; }
+ partial void OnConstruction();
+
+ public ResponseParameters(ResponseParameters other) : this() {
+ size_ = other.size_;
+ intervalUs_ = other.intervalUs_;
}
- protected override pb::FieldAccess.FieldAccessorTable<ResponseParameters, ResponseParameters.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_ResponseParameters__FieldAccessorTable; }
+ public ResponseParameters Clone() {
+ return new ResponseParameters(this);
}
public const int SizeFieldNumber = 1;
- private bool hasSize;
private int size_;
- public bool HasSize {
- get { return hasSize; }
- }
public int Size {
get { return size_; }
+ set {
+ size_ = value;
+ }
}
public const int IntervalUsFieldNumber = 2;
- private bool hasIntervalUs;
private int intervalUs_;
- public bool HasIntervalUs {
- get { return hasIntervalUs; }
- }
public int IntervalUs {
get { return intervalUs_; }
+ set {
+ intervalUs_ = value;
+ }
}
- public override bool IsInitialized {
- get {
- return true;
- }
+ public override bool Equals(object other) {
+ return Equals(other as ResponseParameters);
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _responseParametersFieldNames;
- if (hasSize) {
- output.WriteInt32(1, field_names[1], Size);
+ public bool Equals(ResponseParameters other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
}
- if (hasIntervalUs) {
- output.WriteInt32(2, field_names[0], IntervalUs);
+ if (ReferenceEquals(other, this)) {
+ return true;
}
- UnknownFields.WriteTo(output);
+ if (Size != other.Size) return false;
+ if (IntervalUs != other.IntervalUs) return false;
+ return true;
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasSize) {
- size += pb::CodedOutputStream.ComputeInt32Size(1, Size);
- }
- if (hasIntervalUs) {
- size += pb::CodedOutputStream.ComputeInt32Size(2, IntervalUs);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
- }
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Size != 0) hash ^= Size.GetHashCode();
+ if (IntervalUs != 0) hash ^= IntervalUs.GetHashCode();
+ return hash;
}
- public static ResponseParameters ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static ResponseParameters ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static ResponseParameters ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static ResponseParameters ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static ResponseParameters ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static ResponseParameters ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static ResponseParameters ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static ResponseParameters ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static ResponseParameters ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- public static ResponseParameters ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private ResponseParameters MakeReadOnly() {
- return this;
- }
-
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(ResponseParameters prototype) {
- return new Builder(prototype);
- }
-
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<ResponseParameters, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(ResponseParameters cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
- private bool resultIsReadOnly;
- private ResponseParameters result;
-
- private ResponseParameters PrepareBuilder() {
- if (resultIsReadOnly) {
- ResponseParameters original = result;
- result = new ResponseParameters();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Size != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(Size);
}
-
- protected override ResponseParameters MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
+ if (IntervalUs != 0) {
+ output.WriteRawTag(16);
+ output.WriteInt32(IntervalUs);
}
+ }
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (Size != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Size);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.ResponseParameters.Descriptor; }
+ if (IntervalUs != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(IntervalUs);
}
+ return size;
+ }
- public override ResponseParameters DefaultInstanceForType {
- get { return global::grpc.testing.ResponseParameters.DefaultInstance; }
+ public void MergeFrom(ResponseParameters other) {
+ if (other == null) {
+ return;
}
-
- public override ResponseParameters BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (other.Size != 0) {
+ Size = other.Size;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is ResponseParameters) {
- return MergeFrom((ResponseParameters) other);
- } else {
- base.MergeFrom(other);
- return this;
- }
+ if (other.IntervalUs != 0) {
+ IntervalUs = other.IntervalUs;
}
+ }
- public override Builder MergeFrom(ResponseParameters other) {
- if (other == global::grpc.testing.ResponseParameters.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasSize) {
- Size = other.Size;
- }
- if (other.HasIntervalUs) {
- IntervalUs = other.IntervalUs;
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_responseParametersFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _responseParametersFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Size = input.ReadInt32();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- result.hasSize = input.ReadInt32(ref result.size_);
- break;
- }
- case 16: {
- result.hasIntervalUs = input.ReadInt32(ref result.intervalUs_);
- break;
- }
+ case 16: {
+ IntervalUs = input.ReadInt32();
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasSize {
- get { return result.hasSize; }
- }
- public int Size {
- get { return result.Size; }
- set { SetSize(value); }
- }
- public Builder SetSize(int value) {
- PrepareBuilder();
- result.hasSize = true;
- result.size_ = value;
- return this;
- }
- public Builder ClearSize() {
- PrepareBuilder();
- result.hasSize = false;
- result.size_ = 0;
- return this;
- }
-
- public bool HasIntervalUs {
- get { return result.hasIntervalUs; }
}
- public int IntervalUs {
- get { return result.IntervalUs; }
- set { SetIntervalUs(value); }
- }
- public Builder SetIntervalUs(int value) {
- PrepareBuilder();
- result.hasIntervalUs = true;
- result.intervalUs_ = value;
- return this;
- }
- public Builder ClearIntervalUs() {
- PrepareBuilder();
- result.hasIntervalUs = false;
- result.intervalUs_ = 0;
- return this;
- }
- }
- static ResponseParameters() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
}
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class StreamingOutputCallRequest : pb::GeneratedMessage<StreamingOutputCallRequest, StreamingOutputCallRequest.Builder> {
- private StreamingOutputCallRequest() { }
- private static readonly StreamingOutputCallRequest defaultInstance = new StreamingOutputCallRequest().MakeReadOnly();
- private static readonly string[] _streamingOutputCallRequestFieldNames = new string[] { "payload", "response_parameters", "response_type" };
- private static readonly uint[] _streamingOutputCallRequestFieldTags = new uint[] { 26, 18, 8 };
- public static StreamingOutputCallRequest DefaultInstance {
- get { return defaultInstance; }
+ public sealed partial class StreamingOutputCallRequest : pb::IMessage<StreamingOutputCallRequest> {
+ private static readonly pb::MessageParser<StreamingOutputCallRequest> _parser = new pb::MessageParser<StreamingOutputCallRequest>(() => new StreamingOutputCallRequest());
+ public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
}
- public override StreamingOutputCallRequest DefaultInstanceForType {
- get { return DefaultInstance; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- protected override StreamingOutputCallRequest ThisMessage {
- get { return this; }
+ public StreamingOutputCallRequest() {
+ OnConstruction();
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor; }
+ partial void OnConstruction();
+
+ public StreamingOutputCallRequest(StreamingOutputCallRequest other) : this() {
+ responseType_ = other.responseType_;
+ responseParameters_ = other.responseParameters_.Clone();
+ Payload = other.payload_ != null ? other.Payload.Clone() : null;
}
- protected override pb::FieldAccess.FieldAccessorTable<StreamingOutputCallRequest, StreamingOutputCallRequest.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable; }
+ public StreamingOutputCallRequest Clone() {
+ return new StreamingOutputCallRequest(this);
}
public const int ResponseTypeFieldNumber = 1;
- private bool hasResponseType;
- private global::grpc.testing.PayloadType responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- public bool HasResponseType {
- get { return hasResponseType; }
- }
- public global::grpc.testing.PayloadType ResponseType {
+ private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE;
+ public global::Grpc.Testing.PayloadType ResponseType {
get { return responseType_; }
+ set {
+ responseType_ = value;
+ }
}
public const int ResponseParametersFieldNumber = 2;
- private pbc::PopsicleList<global::grpc.testing.ResponseParameters> responseParameters_ = new pbc::PopsicleList<global::grpc.testing.ResponseParameters>();
- public scg::IList<global::grpc.testing.ResponseParameters> ResponseParametersList {
+ private static readonly pb::FieldCodec<global::Grpc.Testing.ResponseParameters> _repeated_responseParameters_codec
+ = pb::FieldCodec.ForMessage(18, global::Grpc.Testing.ResponseParameters.Parser);
+ private readonly pbc::RepeatedField<global::Grpc.Testing.ResponseParameters> responseParameters_ = new pbc::RepeatedField<global::Grpc.Testing.ResponseParameters>();
+ public pbc::RepeatedField<global::Grpc.Testing.ResponseParameters> ResponseParameters {
get { return responseParameters_; }
}
- public int ResponseParametersCount {
- get { return responseParameters_.Count; }
- }
- public global::grpc.testing.ResponseParameters GetResponseParameters(int index) {
- return responseParameters_[index];
- }
public const int PayloadFieldNumber = 3;
- private bool hasPayload;
- private global::grpc.testing.Payload payload_;
- public bool HasPayload {
- get { return hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; }
- }
-
- public override bool IsInitialized {
- get {
- return true;
+ private global::Grpc.Testing.Payload payload_;
+ public global::Grpc.Testing.Payload Payload {
+ get { return payload_; }
+ set {
+ payload_ = value;
}
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _streamingOutputCallRequestFieldNames;
- if (hasResponseType) {
- output.WriteEnum(1, field_names[2], (int) ResponseType, ResponseType);
- }
- if (responseParameters_.Count > 0) {
- output.WriteMessageArray(2, field_names[1], responseParameters_);
- }
- if (hasPayload) {
- output.WriteMessage(3, field_names[0], Payload);
- }
- UnknownFields.WriteTo(output);
+ public override bool Equals(object other) {
+ return Equals(other as StreamingOutputCallRequest);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
-
- size = 0;
- if (hasResponseType) {
- size += pb::CodedOutputStream.ComputeEnumSize(1, (int) ResponseType);
- }
- foreach (global::grpc.testing.ResponseParameters element in ResponseParametersList) {
- size += pb::CodedOutputStream.ComputeMessageSize(2, element);
- }
- if (hasPayload) {
- size += pb::CodedOutputStream.ComputeMessageSize(3, Payload);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(StreamingOutputCallRequest other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ if (ResponseType != other.ResponseType) return false;
+ if(!responseParameters_.Equals(other.responseParameters_)) return false;
+ if (!object.Equals(Payload, other.Payload)) return false;
+ return true;
}
- public static StreamingOutputCallRequest ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingOutputCallRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private StreamingOutputCallRequest MakeReadOnly() {
- responseParameters_.MakeReadOnly();
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
+ hash ^= responseParameters_.GetHashCode();
+ if (payload_ != null) hash ^= Payload.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(StreamingOutputCallRequest prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<StreamingOutputCallRequest, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(StreamingOutputCallRequest cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private StreamingOutputCallRequest result;
-
- private StreamingOutputCallRequest PrepareBuilder() {
- if (resultIsReadOnly) {
- StreamingOutputCallRequest original = result;
- result = new StreamingOutputCallRequest();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ output.WriteRawTag(8);
+ output.WriteEnum((int) ResponseType);
}
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override StreamingOutputCallRequest MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
+ responseParameters_.WriteTo(output, _repeated_responseParameters_codec);
+ if (payload_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(Payload);
}
+ }
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
+ public int CalculateSize() {
+ int size = 0;
+ if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType);
}
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.StreamingOutputCallRequest.Descriptor; }
+ size += responseParameters_.CalculateSize(_repeated_responseParameters_codec);
+ if (payload_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ return size;
+ }
- public override StreamingOutputCallRequest DefaultInstanceForType {
- get { return global::grpc.testing.StreamingOutputCallRequest.DefaultInstance; }
+ public void MergeFrom(StreamingOutputCallRequest other) {
+ if (other == null) {
+ return;
}
-
- public override StreamingOutputCallRequest BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) {
+ ResponseType = other.ResponseType;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is StreamingOutputCallRequest) {
- return MergeFrom((StreamingOutputCallRequest) other);
- } else {
- base.MergeFrom(other);
- return this;
+ responseParameters_.Add(other.responseParameters_);
+ if (other.payload_ != null) {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ Payload.MergeFrom(other.Payload);
}
+ }
- public override Builder MergeFrom(StreamingOutputCallRequest other) {
- if (other == global::grpc.testing.StreamingOutputCallRequest.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasResponseType) {
- ResponseType = other.ResponseType;
- }
- if (other.responseParameters_.Count != 0) {
- result.responseParameters_.Add(other.responseParameters_);
- }
- if (other.HasPayload) {
- MergePayload(other.Payload);
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_streamingOutputCallRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _streamingOutputCallRequestFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum();
+ break;
}
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 8: {
- object unknown;
- if(input.ReadEnum(ref result.responseType_, out unknown)) {
- result.hasResponseType = true;
- } else if(unknown is int) {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- unknownFields.MergeVarintField(1, (ulong)(int)unknown);
- }
- break;
- }
- case 18: {
- input.ReadMessageArray(tag, field_name, result.responseParameters_, global::grpc.testing.ResponseParameters.DefaultInstance, extensionRegistry);
- break;
- }
- case 26: {
- global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder();
- if (result.hasPayload) {
- subBuilder.MergeFrom(Payload);
- }
- input.ReadMessage(subBuilder, extensionRegistry);
- Payload = subBuilder.BuildPartial();
- break;
+ case 18: {
+ responseParameters_.AddEntriesFrom(input, _repeated_responseParameters_codec);
+ break;
+ }
+ case 26: {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ input.ReadMessage(payload_);
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasResponseType {
- get { return result.hasResponseType; }
- }
- public global::grpc.testing.PayloadType ResponseType {
- get { return result.ResponseType; }
- set { SetResponseType(value); }
- }
- public Builder SetResponseType(global::grpc.testing.PayloadType value) {
- PrepareBuilder();
- result.hasResponseType = true;
- result.responseType_ = value;
- return this;
- }
- public Builder ClearResponseType() {
- PrepareBuilder();
- result.hasResponseType = false;
- result.responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE;
- return this;
- }
-
- public pbc::IPopsicleList<global::grpc.testing.ResponseParameters> ResponseParametersList {
- get { return PrepareBuilder().responseParameters_; }
- }
- public int ResponseParametersCount {
- get { return result.ResponseParametersCount; }
- }
- public global::grpc.testing.ResponseParameters GetResponseParameters(int index) {
- return result.GetResponseParameters(index);
- }
- public Builder SetResponseParameters(int index, global::grpc.testing.ResponseParameters value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.responseParameters_[index] = value;
- return this;
- }
- public Builder SetResponseParameters(int index, global::grpc.testing.ResponseParameters.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.responseParameters_[index] = builderForValue.Build();
- return this;
- }
- public Builder AddResponseParameters(global::grpc.testing.ResponseParameters value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.responseParameters_.Add(value);
- return this;
- }
- public Builder AddResponseParameters(global::grpc.testing.ResponseParameters.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.responseParameters_.Add(builderForValue.Build());
- return this;
- }
- public Builder AddRangeResponseParameters(scg::IEnumerable<global::grpc.testing.ResponseParameters> values) {
- PrepareBuilder();
- result.responseParameters_.Add(values);
- return this;
- }
- public Builder ClearResponseParameters() {
- PrepareBuilder();
- result.responseParameters_.Clear();
- return this;
- }
-
- public bool HasPayload {
- get { return result.hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return result.Payload; }
- set { SetPayload(value); }
- }
- public Builder SetPayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = value;
- return this;
- }
- public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = builderForValue.Build();
- return this;
- }
- public Builder MergePayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- if (result.hasPayload &&
- result.payload_ != global::grpc.testing.Payload.DefaultInstance) {
- result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial();
- } else {
- result.payload_ = value;
- }
- result.hasPayload = true;
- return this;
- }
- public Builder ClearPayload() {
- PrepareBuilder();
- result.hasPayload = false;
- result.payload_ = null;
- return this;
}
}
- static StreamingOutputCallRequest() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
- }
+
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class StreamingOutputCallResponse : pb::GeneratedMessage<StreamingOutputCallResponse, StreamingOutputCallResponse.Builder> {
- private StreamingOutputCallResponse() { }
- private static readonly StreamingOutputCallResponse defaultInstance = new StreamingOutputCallResponse().MakeReadOnly();
- private static readonly string[] _streamingOutputCallResponseFieldNames = new string[] { "payload" };
- private static readonly uint[] _streamingOutputCallResponseFieldTags = new uint[] { 10 };
- public static StreamingOutputCallResponse DefaultInstance {
- get { return defaultInstance; }
- }
+ public sealed partial class StreamingOutputCallResponse : pb::IMessage<StreamingOutputCallResponse> {
+ private static readonly pb::MessageParser<StreamingOutputCallResponse> _parser = new pb::MessageParser<StreamingOutputCallResponse>(() => new StreamingOutputCallResponse());
+ public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
- public override StreamingOutputCallResponse DefaultInstanceForType {
- get { return DefaultInstance; }
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
}
- protected override StreamingOutputCallResponse ThisMessage {
- get { return this; }
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
}
- public static pbd::MessageDescriptor Descriptor {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor; }
+ public StreamingOutputCallResponse() {
+ OnConstruction();
}
- protected override pb::FieldAccess.FieldAccessorTable<StreamingOutputCallResponse, StreamingOutputCallResponse.Builder> InternalFieldAccessors {
- get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable; }
- }
+ partial void OnConstruction();
- public const int PayloadFieldNumber = 1;
- private bool hasPayload;
- private global::grpc.testing.Payload payload_;
- public bool HasPayload {
- get { return hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; }
+ public StreamingOutputCallResponse(StreamingOutputCallResponse other) : this() {
+ Payload = other.payload_ != null ? other.Payload.Clone() : null;
}
- public override bool IsInitialized {
- get {
- return true;
- }
+ public StreamingOutputCallResponse Clone() {
+ return new StreamingOutputCallResponse(this);
}
- public override void WriteTo(pb::ICodedOutputStream output) {
- int size = SerializedSize;
- string[] field_names = _streamingOutputCallResponseFieldNames;
- if (hasPayload) {
- output.WriteMessage(1, field_names[0], Payload);
+ public const int PayloadFieldNumber = 1;
+ private global::Grpc.Testing.Payload payload_;
+ public global::Grpc.Testing.Payload Payload {
+ get { return payload_; }
+ set {
+ payload_ = value;
}
- UnknownFields.WriteTo(output);
}
- private int memoizedSerializedSize = -1;
- public override int SerializedSize {
- get {
- int size = memoizedSerializedSize;
- if (size != -1) return size;
+ public override bool Equals(object other) {
+ return Equals(other as StreamingOutputCallResponse);
+ }
- size = 0;
- if (hasPayload) {
- size += pb::CodedOutputStream.ComputeMessageSize(1, Payload);
- }
- size += UnknownFields.SerializedSize;
- memoizedSerializedSize = size;
- return size;
+ public bool Equals(StreamingOutputCallResponse other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
}
+ if (!object.Equals(Payload, other.Payload)) return false;
+ return true;
}
- public static StreamingOutputCallResponse ParseFrom(pb::ByteString data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(byte[] data) {
- return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(global::System.IO.Stream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseDelimitedFrom(global::System.IO.Stream input) {
- return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
- return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(pb::ICodedInputStream input) {
- return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
- }
- public static StreamingOutputCallResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
- }
- private StreamingOutputCallResponse MakeReadOnly() {
- return this;
+ public override int GetHashCode() {
+ int hash = 1;
+ if (payload_ != null) hash ^= Payload.GetHashCode();
+ return hash;
}
- public static Builder CreateBuilder() { return new Builder(); }
- public override Builder ToBuilder() { return CreateBuilder(this); }
- public override Builder CreateBuilderForType() { return new Builder(); }
- public static Builder CreateBuilder(StreamingOutputCallResponse prototype) {
- return new Builder(prototype);
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
}
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- public sealed partial class Builder : pb::GeneratedBuilder<StreamingOutputCallResponse, Builder> {
- protected override Builder ThisBuilder {
- get { return this; }
- }
- public Builder() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- }
- internal Builder(StreamingOutputCallResponse cloneFrom) {
- result = cloneFrom;
- resultIsReadOnly = true;
- }
-
- private bool resultIsReadOnly;
- private StreamingOutputCallResponse result;
-
- private StreamingOutputCallResponse PrepareBuilder() {
- if (resultIsReadOnly) {
- StreamingOutputCallResponse original = result;
- result = new StreamingOutputCallResponse();
- resultIsReadOnly = false;
- MergeFrom(original);
- }
- return result;
- }
-
- public override bool IsInitialized {
- get { return result.IsInitialized; }
- }
-
- protected override StreamingOutputCallResponse MessageBeingBuilt {
- get { return PrepareBuilder(); }
- }
-
- public override Builder Clear() {
- result = DefaultInstance;
- resultIsReadOnly = true;
- return this;
- }
-
- public override Builder Clone() {
- if (resultIsReadOnly) {
- return new Builder(result);
- } else {
- return new Builder().MergeFrom(result);
- }
- }
-
- public override pbd::MessageDescriptor DescriptorForType {
- get { return global::grpc.testing.StreamingOutputCallResponse.Descriptor; }
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (payload_ != null) {
+ output.WriteRawTag(10);
+ output.WriteMessage(Payload);
}
+ }
- public override StreamingOutputCallResponse DefaultInstanceForType {
- get { return global::grpc.testing.StreamingOutputCallResponse.DefaultInstance; }
+ public int CalculateSize() {
+ int size = 0;
+ if (payload_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ return size;
+ }
- public override StreamingOutputCallResponse BuildPartial() {
- if (resultIsReadOnly) {
- return result;
- }
- resultIsReadOnly = true;
- return result.MakeReadOnly();
+ public void MergeFrom(StreamingOutputCallResponse other) {
+ if (other == null) {
+ return;
}
-
- public override Builder MergeFrom(pb::IMessage other) {
- if (other is StreamingOutputCallResponse) {
- return MergeFrom((StreamingOutputCallResponse) other);
- } else {
- base.MergeFrom(other);
- return this;
+ if (other.payload_ != null) {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ Payload.MergeFrom(other.Payload);
}
+ }
- public override Builder MergeFrom(StreamingOutputCallResponse other) {
- if (other == global::grpc.testing.StreamingOutputCallResponse.DefaultInstance) return this;
- PrepareBuilder();
- if (other.HasPayload) {
- MergePayload(other.Payload);
- }
- this.MergeUnknownFields(other.UnknownFields);
- return this;
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input) {
- return MergeFrom(input, pb::ExtensionRegistry.Empty);
- }
-
- public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
- PrepareBuilder();
- pb::UnknownFieldSet.Builder unknownFields = null;
- uint tag;
- string field_name;
- while (input.ReadTag(out tag, out field_name)) {
- if(tag == 0 && field_name != null) {
- int field_ordinal = global::System.Array.BinarySearch(_streamingOutputCallResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
- if(field_ordinal >= 0)
- tag = _streamingOutputCallResponseFieldTags[field_ordinal];
- else {
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- continue;
- }
- }
- switch (tag) {
- case 0: {
- throw pb::InvalidProtocolBufferException.InvalidTag();
- }
- default: {
- if (pb::WireFormat.IsEndGroupTag(tag)) {
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
- if (unknownFields == null) {
- unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
- }
- ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
- break;
- }
- case 10: {
- global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder();
- if (result.hasPayload) {
- subBuilder.MergeFrom(Payload);
- }
- input.ReadMessage(subBuilder, extensionRegistry);
- Payload = subBuilder.BuildPartial();
- break;
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 10: {
+ if (payload_ == null) {
+ payload_ = new global::Grpc.Testing.Payload();
}
+ input.ReadMessage(payload_);
+ break;
}
}
-
- if (unknownFields != null) {
- this.UnknownFields = unknownFields.Build();
- }
- return this;
- }
-
-
- public bool HasPayload {
- get { return result.hasPayload; }
- }
- public global::grpc.testing.Payload Payload {
- get { return result.Payload; }
- set { SetPayload(value); }
- }
- public Builder SetPayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = value;
- return this;
- }
- public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) {
- pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
- PrepareBuilder();
- result.hasPayload = true;
- result.payload_ = builderForValue.Build();
- return this;
- }
- public Builder MergePayload(global::grpc.testing.Payload value) {
- pb::ThrowHelper.ThrowIfNull(value, "value");
- PrepareBuilder();
- if (result.hasPayload &&
- result.payload_ != global::grpc.testing.Payload.DefaultInstance) {
- result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial();
- } else {
- result.payload_ = value;
- }
- result.hasPayload = true;
- return this;
- }
- public Builder ClearPayload() {
- PrepareBuilder();
- result.hasPayload = false;
- result.payload_ = null;
- return this;
}
}
- static StreamingOutputCallResponse() {
- object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null);
- }
+
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
index 842795374f..37b2518c21 100644
--- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
@@ -37,9 +37,9 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
+using Grpc.Testing;
using NUnit.Framework;
namespace Grpc.IntegrationTesting
@@ -92,7 +92,7 @@ namespace Grpc.IntegrationTesting
[Test]
public void AuthenticatedClientAndServer()
{
- var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build());
+ var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
Assert.AreEqual(10, response.Payload.Body.Length);
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs
new file mode 100644
index 0000000000..466ec57d3d
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/Test.cs
@@ -0,0 +1,48 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: test.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.Protobuf;
+using pbc = global::Google.Protobuf.Collections;
+using pbr = global::Google.Protobuf.Reflection;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Testing {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Test {
+
+ #region Descriptor
+ public static pbr::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbr::FileDescriptor descriptor;
+
+ static Test() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz",
+ "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw",
+ "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5",
+ "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0",
+ "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n",
+ "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj",
+ "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry",
+ "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0",
+ "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs",
+ "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T",
+ "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl",
+ "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs",
+ "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku",
+ "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi",
+ "BnByb3RvMw=="));
+ descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, },
+ new pbr::GeneratedCodeInfo(null, null));
+ }
+ #endregion
+
+ }
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
index da0b7fb910..7a48d6e92e 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -37,8 +37,6 @@ using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Google.ProtocolBuffers;
-using grpc.testing;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 697acb53d8..f63e148475 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -7,91 +7,97 @@ using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
-namespace grpc.testing {
+namespace Grpc.Testing {
public static class TestService
{
static readonly string __ServiceName = "grpc.testing.TestService";
- static readonly Marshaller<global::grpc.testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.Empty.ParseFrom);
- static readonly Marshaller<global::grpc.testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.SimpleRequest.ParseFrom);
- static readonly Marshaller<global::grpc.testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.SimpleResponse.ParseFrom);
- static readonly Marshaller<global::grpc.testing.StreamingOutputCallRequest> __Marshaller_StreamingOutputCallRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingOutputCallRequest.ParseFrom);
- static readonly Marshaller<global::grpc.testing.StreamingOutputCallResponse> __Marshaller_StreamingOutputCallResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingOutputCallResponse.ParseFrom);
- static readonly Marshaller<global::grpc.testing.StreamingInputCallRequest> __Marshaller_StreamingInputCallRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingInputCallRequest.ParseFrom);
- static readonly Marshaller<global::grpc.testing.StreamingInputCallResponse> __Marshaller_StreamingInputCallResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingInputCallResponse.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.SimpleRequest> __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.SimpleResponse> __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.StreamingOutputCallRequest> __Marshaller_StreamingOutputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.StreamingOutputCallResponse> __Marshaller_StreamingOutputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.StreamingInputCallRequest> __Marshaller_StreamingInputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.StreamingInputCallResponse> __Marshaller_StreamingInputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom);
- static readonly Method<global::grpc.testing.Empty, global::grpc.testing.Empty> __Method_EmptyCall = new Method<global::grpc.testing.Empty, global::grpc.testing.Empty>(
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_EmptyCall = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
MethodType.Unary,
__ServiceName,
"EmptyCall",
__Marshaller_Empty,
__Marshaller_Empty);
- static readonly Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse> __Method_UnaryCall = new Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse>(
+ static readonly Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> __Method_UnaryCall = new Method<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse>(
MethodType.Unary,
__ServiceName,
"UnaryCall",
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
- static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
+ static readonly Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
MethodType.ServerStreaming,
__ServiceName,
"StreamingOutputCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
- static readonly Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> __Method_StreamingInputCall = new Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse>(
+ static readonly Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> __Method_StreamingInputCall = new Method<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse>(
MethodType.ClientStreaming,
__ServiceName,
"StreamingInputCall",
__Marshaller_StreamingInputCallRequest,
__Marshaller_StreamingInputCallResponse);
- static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
+ static readonly Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
__ServiceName,
"FullDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
- static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
+ static readonly Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new Method<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
__ServiceName,
"HalfDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Test.Descriptor.Services[0]; }
+ }
+
// client interface
public interface ITestServiceClient
{
- global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options);
- AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options);
- global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options);
- AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options);
- AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options);
- AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
- AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
+ global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+ AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
+ AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
+ AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
+ AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
// server-side interface
public interface ITestService
{
- Task<global::grpc.testing.Empty> EmptyCall(global::grpc.testing.Empty request, ServerCallContext context);
- Task<global::grpc.testing.SimpleResponse> UnaryCall(global::grpc.testing.SimpleRequest request, ServerCallContext context);
- Task StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, IServerStreamWriter<global::grpc.testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- Task<global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::grpc.testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
- Task FullDuplexCall(IAsyncStreamReader<global::grpc.testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::grpc.testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
- Task HalfDuplexCall(IAsyncStreamReader<global::grpc.testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::grpc.testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+ Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
+ Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+ Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
}
// client stub
@@ -100,82 +106,82 @@ namespace grpc.testing {
public TestServiceClient(Channel channel) : base(channel)
{
}
- public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
- public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options)
+ public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_EmptyCall, options);
return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options)
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_EmptyCall, options);
return Calls.AsyncUnaryCall(call, request);
}
- public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
- public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options)
+ public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
var call = CreateCall(__Method_UnaryCall, options);
return Calls.BlockingUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
- public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options)
+ public AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
{
var call = CreateCall(__Method_UnaryCall, options);
return Calls.AsyncUnaryCall(call, request);
}
- public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncServerStreamingCall(call, request);
}
- public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options)
+ public AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
{
var call = CreateCall(__Method_StreamingOutputCall, options);
return Calls.AsyncServerStreamingCall(call, request);
}
- public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncClientStreamingCall(call);
}
- public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
+ public AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
{
var call = CreateCall(__Method_StreamingInputCall, options);
return Calls.AsyncClientStreamingCall(call);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
{
var call = CreateCall(__Method_FullDuplexCall, options);
return Calls.AsyncDuplexStreamingCall(call);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
- public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
+ public AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
{
var call = CreateCall(__Method_HalfDuplexCall, options);
return Calls.AsyncDuplexStreamingCall(call);
diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
index ceebd5dd8c..c5bfcf08c0 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs
@@ -35,11 +35,11 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using Google.ProtocolBuffers;
+using Google.Protobuf;
using Grpc.Core;
using Grpc.Core.Utils;
-namespace grpc.testing
+namespace Grpc.Testing
{
/// <summary>
/// Implementation of TestService server
@@ -48,22 +48,20 @@ namespace grpc.testing
{
public Task<Empty> EmptyCall(Empty request, ServerCallContext context)
{
- return Task.FromResult(Empty.DefaultInstance);
+ return Task.FromResult(new Empty());
}
public Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{
- var response = SimpleResponse.CreateBuilder()
- .SetPayload(CreateZerosPayload(request.ResponseSize)).Build();
+ var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) };
return Task.FromResult(response);
}
public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
- foreach (var responseParam in request.ResponseParametersList)
+ foreach (var responseParam in request.ResponseParameters)
{
- var response = StreamingOutputCallResponse.CreateBuilder()
- .SetPayload(CreateZerosPayload(responseParam.Size)).Build();
+ var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) };
await responseStream.WriteAsync(response);
}
}
@@ -75,17 +73,16 @@ namespace grpc.testing
{
sum += request.Payload.Body.Length;
});
- return StreamingInputCallResponse.CreateBuilder().SetAggregatedPayloadSize(sum).Build();
+ return new StreamingInputCallResponse { AggregatedPayloadSize = sum };
}
public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream, ServerCallContext context)
{
await requestStream.ForEachAsync(async request =>
{
- foreach (var responseParam in request.ResponseParametersList)
+ foreach (var responseParam in request.ResponseParameters)
{
- var response = StreamingOutputCallResponse.CreateBuilder()
- .SetPayload(CreateZerosPayload(responseParam.Size)).Build();
+ var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) };
await responseStream.WriteAsync(response);
}
});
@@ -98,7 +95,7 @@ namespace grpc.testing
private static Payload CreateZerosPayload(int size)
{
- return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build();
+ return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 0867b091b9..bdb3dadf44 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,8 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="CommandLineParser" version="1.9.71" targetFramework="net45" />
<package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
<package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Protobuf" version="3.0.0-alpha4" targetFramework="net45" />
<package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
<package id="Ix-Async" version="1.2.3" targetFramework="net45" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
index 4295a0a960..6d0eb937d6 100644
--- a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
+++ b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
@@ -28,7 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-syntax = "proto2";
+syntax = "proto3";
package grpc.testing;
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
index 65a8140465..7df85e3c13 100644
--- a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
+++ b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
@@ -30,7 +30,7 @@
// Message definitions to be used by integration test service definitions.
-syntax = "proto2";
+syntax = "proto3";
package grpc.testing;
@@ -49,46 +49,46 @@ enum PayloadType {
// A block of data, to simply increase gRPC message size.
message Payload {
// The type of data in body.
- optional PayloadType type = 1;
+ PayloadType type = 1;
// Primary contents of payload.
- optional bytes body = 2;
+ bytes body = 2;
}
// Unary request.
message SimpleRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, server randomly chooses one from other formats.
- optional PayloadType response_type = 1;
+ PayloadType response_type = 1;
// Desired payload size in the response from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
- optional int32 response_size = 2;
+ int32 response_size = 2;
// Optional input payload sent along with the request.
- optional Payload payload = 3;
+ Payload payload = 3;
// Whether SimpleResponse should include username.
- optional bool fill_username = 4;
+ bool fill_username = 4;
// Whether SimpleResponse should include OAuth scope.
- optional bool fill_oauth_scope = 5;
+ bool fill_oauth_scope = 5;
}
// Unary response, as configured by the request.
message SimpleResponse {
// Payload to increase message size.
- optional Payload payload = 1;
+ Payload payload = 1;
// The user the request came from, for verifying authentication was
// successful when the client expected it.
- optional string username = 2;
+ string username = 2;
// OAuth scope.
- optional string oauth_scope = 3;
+ string oauth_scope = 3;
}
// Client-streaming request.
message StreamingInputCallRequest {
// Optional input payload sent along with the request.
- optional Payload payload = 1;
+ Payload payload = 1;
// Not expecting any payload from the response.
}
@@ -96,18 +96,18 @@ message StreamingInputCallRequest {
// Client-streaming response.
message StreamingInputCallResponse {
// Aggregated size of payloads received from the client.
- optional int32 aggregated_payload_size = 1;
+ int32 aggregated_payload_size = 1;
}
// Configuration for a particular response.
message ResponseParameters {
// Desired payload sizes in responses from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
- optional int32 size = 1;
+ int32 size = 1;
// Desired interval between consecutive responses in the response stream in
// microseconds.
- optional int32 interval_us = 2;
+ int32 interval_us = 2;
}
// Server-streaming request.
@@ -116,17 +116,17 @@ message StreamingOutputCallRequest {
// If response_type is RANDOM, the payload from each response in the stream
// might be of different types. This is to simulate a mixed type of payload
// stream.
- optional PayloadType response_type = 1;
+ PayloadType response_type = 1;
// Configuration for each expected response message.
repeated ResponseParameters response_parameters = 2;
// Optional input payload sent along with the request.
- optional Payload payload = 3;
+ Payload payload = 3;
}
// Server-streaming response, as configured by the request and parameters.
message StreamingOutputCallResponse {
// Payload to increase response size.
- optional Payload payload = 1;
+ Payload payload = 1;
}
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/test.proto b/src/csharp/Grpc.IntegrationTesting/proto/test.proto
index 927a3a83aa..f9e0d2a039 100644
--- a/src/csharp/Grpc.IntegrationTesting/proto/test.proto
+++ b/src/csharp/Grpc.IntegrationTesting/proto/test.proto
@@ -30,7 +30,7 @@
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
-syntax = "proto2";
+syntax = "proto3";
import "empty.proto";
import "messages.proto";
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
index eabf5dc7db..48a7b1f3af 100644
--- a/src/csharp/Grpc.Tools.nuspec
+++ b/src/csharp/Grpc.Tools.nuspec
@@ -4,19 +4,18 @@
<id>Grpc.Tools</id>
<title>gRPC C# Tools</title>
<summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
- <description>Precompiled Windows binaries for generating protocol buffer messages and gRPC client/server code</description>
+ <description>Precompiled Windows binary for generating gRPC client/server code</description>
<version>$version$</version>
<authors>Google Inc.</authors>
<owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
- <releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$</releaseNotes>
+ <releaseNotes>grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
</metadata>
<files>
- <file src="protoc.exe" target="tools" />
- <file src="grpc_csharp_plugin.exe" target="tools" />
+ <file src="..\..\vsprojects\Release\grpc_csharp_plugin.exe" target="tools" />
</files>
</package>
diff --git a/src/csharp/README.md b/src/csharp/README.md
index bb5e165986..3fbc1c5f05 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -19,7 +19,7 @@ Usage: Windows
That will also pull all the transitive dependencies (including the native libraries that
gRPC C# is internally using).
-- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
+- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp.
Usage: Linux (Mono)
--------------
@@ -50,7 +50,7 @@ Usage: Linux (Mono)
- Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages).
-- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
+- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp.
Usage: MacOS (Mono)
--------------
@@ -73,7 +73,7 @@ Usage: MacOS (Mono)
- *You will be able to build your project in Xamarin Studio, but to run or test it,
you will need to run it under 64-bit version of Mono.*
-- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp.
+- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp.
Building: Windows
-----------------
@@ -158,3 +158,20 @@ Contents
An example client that sends some requests to math server.
- Grpc.IntegrationTesting:
Cross-language gRPC implementation testing (interop testing).
+
+Troubleshooting
+---------------
+
+### Problem: Unable to load DLL 'grpc_csharp_ext.dll'
+
+Internally, gRPC C# uses a native library written in C (gRPC C core) and invokes its functionality via P/Invoke. `grpc_csharp_ext` library is a native extension library that facilitates this by wrapping some C core API into a form that's more digestible for P/Invoke. If you get the above error, it means that the native dependencies could not be located by the C# runtime (or they are incompatible with the current runtime, so they could not be loaded). The solution to this is environment specific.
+
+- If you are developing on Windows in Visual Studio, the `grpc_csharp_ext.dll` that is shipped by gRPC nuget packages should be automatically copied to your build destination folder once you build. By adjusting project properties in your VS project file, you can influence which exact configuration of `grpc_csharp_ext.dll` will be used (based on VS version, bitness, debug/release configuration).
+
+- If you are running your application that is using gRPC on Windows machine that doesn't have Visual Studio installed, you might need to install [Visual C++ 2013 redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=40784) that contains some system .dll libraries that `grpc_csharp_ext.dll` depends on (see #905 for more details).
+
+- On Linux (or Docker), you need to first install gRPC C core and `libgrpc_csharp_ext.so` shared libraries. Currently, the libraries can be installed by `make install_grpc_csharp_ext` or using Linuxbrew (a Debian package is coming soon). Installation on a machine where your application is going to be deployed is no different.
+
+- On Mac, you need to first install gRPC C core and `libgrpc_csharp_ext.dylib` shared libraries using Homebrew. See above for installation instruction. Installation on a machine where your application is going to be deployed is no different.
+
+- Possible cause for the problem is that the `grpc_csharp_ext` library is installed, but it has different bitness (32/64bit) than your C# runtime (in case you are using mono) or C# application.
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 8a11d01430..ea2206e760 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,8 +1,12 @@
@rem Builds gRPC NuGet packages
@rem Current package versions
-set VERSION=0.6.1
-set CORE_VERSION=0.10.1
+set VERSION=0.7.0
+set CORE_VERSION=0.11.0
+set PROTOBUF_VERSION=3.0.0-alpha4
+
+@rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
+set VERSION_WITH_BETA=0.7.0-beta
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
@@ -14,10 +18,12 @@ endlocal
@call buildall.bat BUILD_SIGNED || goto :error
+@call ..\..\vsprojects\build_plugins.bat || goto :error
+
%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
-%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% || goto :error
+%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 489e219c49..70c0fbcc50 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -837,11 +837,11 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs,
if (key_cert_pair_cert_chain || key_cert_pair_private_key) {
key_cert_pair.cert_chain = key_cert_pair_cert_chain;
key_cert_pair.private_key = key_cert_pair_private_key;
- return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair);
+ return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL);
} else {
GPR_ASSERT(!key_cert_pair_cert_chain);
GPR_ASSERT(!key_cert_pair_private_key);
- return grpc_ssl_credentials_create(pem_root_certs, NULL);
+ return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL);
}
}
@@ -852,7 +852,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *cre
GPR_EXPORT grpc_channel *GPR_CALLTYPE
grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target,
const grpc_channel_args *args) {
- return grpc_secure_channel_create(creds, target, args);
+ return grpc_secure_channel_create(creds, target, args, NULL);
}
GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE
@@ -876,7 +876,7 @@ grpcsharp_ssl_server_credentials_create(
}
creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
num_key_cert_pairs,
- force_client_auth);
+ force_client_auth, NULL);
gpr_free(key_cert_pairs);
return creds;
}
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index 7c3ba70922..a17f45b587 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -38,11 +38,11 @@ EXAMPLES_DIR=Grpc.Examples
INTEROP_DIR=Grpc.IntegrationTesting
HEALTHCHECK_DIR=Grpc.HealthCheck
-$PROTOC --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \
+$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
-$PROTOC --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \
- -I $INTEROP_DIR/proto $INTEROP_DIR/proto/test.proto
+$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
+ -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto
-$PROTOC --plugin=$PLUGIN --grpc_out=$HEALTHCHECK_DIR \
+$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
diff --git a/src/node/README.md b/src/node/README.md
index b6411537c7..7719d08290 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -1,7 +1,7 @@
# Node.js gRPC Library
## Status
-Alpha : Ready for early adopters
+Beta
## PREREQUISITES
- `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
@@ -11,10 +11,10 @@ Alpha : Ready for early adopters
**Linux (Debian):**
-Add [Debian unstable][] to your `sources.list` file. Example:
+Add [Debian jessie-backports][] to your `sources.list` file. Example:
```sh
-echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+echo "deb http://http.debian.net/debian jessie-backports main" | \
sudo tee -a /etc/apt/sources.list
```
@@ -113,4 +113,4 @@ An object with factory methods for creating credential objects for servers.
[homebrew]:http://brew.sh
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
-[Debian unstable]:https://www.debian.org/releases/sid/
+[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/node/examples/route_guide.proto b/src/node/examples/route_guide.proto
deleted file mode 100644
index fceb632a97..0000000000
--- a/src/node/examples/route_guide.proto
+++ /dev/null
@@ -1,120 +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";
-
-option java_package = "io.grpc.examples";
-
-package examples;
-
-// Interface exported by the server.
-service RouteGuide {
- // A simple RPC.
- //
- // Obtains the feature at a given position.
- rpc GetFeature(Point) returns (Feature) {}
-
- // A server-to-client streaming RPC.
- //
- // Obtains the Features available within the given Rectangle. Results are
- // streamed rather than returned at once (e.g. in a response message with a
- // repeated field), as the rectangle may cover a large area and contain a
- // huge number of features.
- rpc ListFeatures(Rectangle) returns (stream Feature) {}
-
- // A client-to-server streaming RPC.
- //
- // Accepts a stream of Points on a route being traversed, returning a
- // RouteSummary when traversal is completed.
- rpc RecordRoute(stream Point) returns (RouteSummary) {}
-
- // A Bidirectional streaming RPC.
- //
- // Accepts a stream of RouteNotes sent while a route is being traversed,
- // while receiving other RouteNotes (e.g. from other users).
- rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
-}
-
-// Points are represented as latitude-longitude pairs in the E7 representation
-// (degrees multiplied by 10**7 and rounded to the nearest integer).
-// Latitudes should be in the range +/- 90 degrees and longitude should be in
-// the range +/- 180 degrees (inclusive).
-message Point {
- int32 latitude = 1;
- int32 longitude = 2;
-}
-
-// A latitude-longitude rectangle, represented as two diagonally opposite
-// points "lo" and "hi".
-message Rectangle {
- // One corner of the rectangle.
- Point lo = 1;
-
- // The other corner of the rectangle.
- Point hi = 2;
-}
-
-// A feature names something at a given point.
-//
-// If a feature could not be named, the name is empty.
-message Feature {
- // The name of the feature.
- string name = 1;
-
- // The point where the feature is detected.
- Point location = 2;
-}
-
-// A RouteNote is a message sent while at a given point.
-message RouteNote {
- // The location from which the message is sent.
- Point location = 1;
-
- // The message to be sent.
- string message = 2;
-}
-
-// A RouteSummary is received in response to a RecordRoute rpc.
-//
-// It contains the number of individual points received, the number of
-// detected features, and the total distance covered as the cumulative sum of
-// the distance between each point.
-message RouteSummary {
- // The number of points received.
- int32 point_count = 1;
-
- // The number of known features passed while traversing the route.
- int32 feature_count = 2;
-
- // The distance covered in metres.
- int32 distance = 3;
-
- // The duration of the traversal in seconds.
- int32 elapsed_time = 4;
-}
diff --git a/src/node/examples/route_guide_client.js b/src/node/examples/route_guide_client.js
deleted file mode 100644
index 647f3ffaba..0000000000
--- a/src/node/examples/route_guide_client.js
+++ /dev/null
@@ -1,240 +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 async = require('async');
-var fs = require('fs');
-var parseArgs = require('minimist');
-var path = require('path');
-var _ = require('lodash');
-var grpc = require('..');
-var examples = grpc.load(__dirname + '/route_guide.proto').examples;
-var client = new examples.RouteGuide('localhost:50051',
- grpc.Credentials.createInsecure());
-
-var COORD_FACTOR = 1e7;
-
-/**
- * Run the getFeature demo. Calls getFeature with a point known to have a
- * feature and a point known not to have a feature.
- * @param {function} callback Called when this demo is complete
- */
-function runGetFeature(callback) {
- var next = _.after(2, callback);
- function featureCallback(error, feature) {
- if (error) {
- callback(error);
- }
- if (feature.name === '') {
- console.log('Found no feature at ' +
- feature.location.latitude/COORD_FACTOR + ', ' +
- feature.location.longitude/COORD_FACTOR);
- } else {
- console.log('Found feature called "' + feature.name + '" at ' +
- feature.location.latitude/COORD_FACTOR + ', ' +
- feature.location.longitude/COORD_FACTOR);
- }
- next();
- }
- var point1 = {
- latitude: 409146138,
- longitude: -746188906
- };
- var point2 = {
- latitude: 0,
- longitude: 0
- };
- client.getFeature(point1, featureCallback);
- client.getFeature(point2, featureCallback);
-}
-
-/**
- * Run the listFeatures demo. Calls listFeatures with a rectangle containing all
- * of the features in the pre-generated database. Prints each response as it
- * comes in.
- * @param {function} callback Called when this demo is complete
- */
-function runListFeatures(callback) {
- var rectangle = {
- lo: {
- latitude: 400000000,
- longitude: -750000000
- },
- hi: {
- latitude: 420000000,
- longitude: -730000000
- }
- };
- console.log('Looking for features between 40, -75 and 42, -73');
- var call = client.listFeatures(rectangle);
- call.on('data', function(feature) {
- console.log('Found feature called "' + feature.name + '" at ' +
- feature.location.latitude/COORD_FACTOR + ', ' +
- feature.location.longitude/COORD_FACTOR);
- });
- call.on('end', callback);
-}
-
-/**
- * Run the recordRoute demo. Sends several randomly chosen points from the
- * pre-generated feature database with a variable delay in between. Prints the
- * statistics when they are sent from the server.
- * @param {function} callback Called when this demo is complete
- */
-function runRecordRoute(callback) {
- var argv = parseArgs(process.argv, {
- string: 'db_path'
- });
- fs.readFile(path.resolve(argv.db_path), function(err, data) {
- if (err) {
- callback(err);
- }
- var feature_list = JSON.parse(data);
-
- var num_points = 10;
- var call = client.recordRoute(function(error, stats) {
- if (error) {
- callback(error);
- }
- console.log('Finished trip with', stats.point_count, 'points');
- console.log('Passed', stats.feature_count, 'features');
- console.log('Travelled', stats.distance, 'meters');
- console.log('It took', stats.elapsed_time, 'seconds');
- callback();
- });
- /**
- * Constructs a function that asynchronously sends the given point and then
- * delays sending its callback
- * @param {number} lat The latitude to send
- * @param {number} lng The longitude to send
- * @return {function(function)} The function that sends the point
- */
- function pointSender(lat, lng) {
- /**
- * Sends the point, then calls the callback after a delay
- * @param {function} callback Called when complete
- */
- return function(callback) {
- console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
- lng/COORD_FACTOR);
- call.write({
- latitude: lat,
- longitude: lng
- });
- _.delay(callback, _.random(500, 1500));
- };
- }
- var point_senders = [];
- for (var i = 0; i < num_points; i++) {
- var rand_point = feature_list[_.random(0, feature_list.length - 1)];
- point_senders[i] = pointSender(rand_point.location.latitude,
- rand_point.location.longitude);
- }
- async.series(point_senders, function() {
- call.end();
- });
- });
-}
-
-/**
- * Run the routeChat demo. Send some chat messages, and print any chat messages
- * that are sent from the server.
- * @param {function} callback Called when the demo is complete
- */
-function runRouteChat(callback) {
- var call = client.routeChat();
- call.on('data', function(note) {
- console.log('Got message "' + note.message + '" at ' +
- note.location.latitude + ', ' + note.location.longitude);
- });
-
- call.on('end', callback);
-
- var notes = [{
- location: {
- latitude: 0,
- longitude: 0
- },
- message: 'First message'
- }, {
- location: {
- latitude: 0,
- longitude: 1
- },
- message: 'Second message'
- }, {
- location: {
- latitude: 1,
- longitude: 0
- },
- message: 'Third message'
- }, {
- location: {
- latitude: 0,
- longitude: 0
- },
- message: 'Fourth message'
- }];
- for (var i = 0; i < notes.length; i++) {
- var note = notes[i];
- console.log('Sending message "' + note.message + '" at ' +
- note.location.latitude + ', ' + note.location.longitude);
- call.write(note);
- }
- call.end();
-}
-
-/**
- * Run all of the demos in order
- */
-function main() {
- async.series([
- runGetFeature,
- runListFeatures,
- runRecordRoute,
- runRouteChat
- ]);
-}
-
-if (require.main === module) {
- main();
-}
-
-exports.runGetFeature = runGetFeature;
-
-exports.runListFeatures = runListFeatures;
-
-exports.runRecordRoute = runRecordRoute;
-
-exports.runRouteChat = runRouteChat;
diff --git a/src/node/examples/route_guide_db.json b/src/node/examples/route_guide_db.json
deleted file mode 100644
index 9d6a980ab7..0000000000
--- a/src/node/examples/route_guide_db.json
+++ /dev/null
@@ -1,601 +0,0 @@
-[{
- "location": {
- "latitude": 407838351,
- "longitude": -746143763
- },
- "name": "Patriots Path, Mendham, NJ 07945, USA"
-}, {
- "location": {
- "latitude": 408122808,
- "longitude": -743999179
- },
- "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
-}, {
- "location": {
- "latitude": 413628156,
- "longitude": -749015468
- },
- "name": "U.S. 6, Shohola, PA 18458, USA"
-}, {
- "location": {
- "latitude": 419999544,
- "longitude": -740371136
- },
- "name": "5 Conners Road, Kingston, NY 12401, USA"
-}, {
- "location": {
- "latitude": 414008389,
- "longitude": -743951297
- },
- "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
-}, {
- "location": {
- "latitude": 419611318,
- "longitude": -746524769
- },
- "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
-}, {
- "location": {
- "latitude": 406109563,
- "longitude": -742186778
- },
- "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
-}, {
- "location": {
- "latitude": 416802456,
- "longitude": -742370183
- },
- "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
-}, {
- "location": {
- "latitude": 412950425,
- "longitude": -741077389
- },
- "name": "Bailey Turn Road, Harriman, NY 10926, USA"
-}, {
- "location": {
- "latitude": 412144655,
- "longitude": -743949739
- },
- "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
-}, {
- "location": {
- "latitude": 415736605,
- "longitude": -742847522
- },
- "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
-}, {
- "location": {
- "latitude": 413843930,
- "longitude": -740501726
- },
- "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
-}, {
- "location": {
- "latitude": 410873075,
- "longitude": -744459023
- },
- "name": "Clinton Road, West Milford, NJ 07480, USA"
-}, {
- "location": {
- "latitude": 412346009,
- "longitude": -744026814
- },
- "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
-}, {
- "location": {
- "latitude": 402948455,
- "longitude": -747903913
- },
- "name": "3 Drake Lane, Pennington, NJ 08534, USA"
-}, {
- "location": {
- "latitude": 406337092,
- "longitude": -740122226
- },
- "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
-}, {
- "location": {
- "latitude": 406421967,
- "longitude": -747727624
- },
- "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
-}, {
- "location": {
- "latitude": 416318082,
- "longitude": -749677716
- },
- "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
-}, {
- "location": {
- "latitude": 415301720,
- "longitude": -748416257
- },
- "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
-}, {
- "location": {
- "latitude": 402647019,
- "longitude": -747071791
- },
- "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
-}, {
- "location": {
- "latitude": 412567807,
- "longitude": -741058078
- },
- "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
-}, {
- "location": {
- "latitude": 416855156,
- "longitude": -744420597
- },
- "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
-}, {
- "location": {
- "latitude": 404663628,
- "longitude": -744820157
- },
- "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
-}, {
- "location": {
- "latitude": 407113723,
- "longitude": -749746483
- },
- "name": ""
-}, {
- "location": {
- "latitude": 402133926,
- "longitude": -743613249
- },
- "name": ""
-}, {
- "location": {
- "latitude": 400273442,
- "longitude": -741220915
- },
- "name": ""
-}, {
- "location": {
- "latitude": 411236786,
- "longitude": -744070769
- },
- "name": ""
-}, {
- "location": {
- "latitude": 411633782,
- "longitude": -746784970
- },
- "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
-}, {
- "location": {
- "latitude": 415830701,
- "longitude": -742952812
- },
- "name": ""
-}, {
- "location": {
- "latitude": 413447164,
- "longitude": -748712898
- },
- "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
-}, {
- "location": {
- "latitude": 405047245,
- "longitude": -749800722
- },
- "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
-}, {
- "location": {
- "latitude": 418858923,
- "longitude": -746156790
- },
- "name": ""
-}, {
- "location": {
- "latitude": 417951888,
- "longitude": -748484944
- },
- "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
-}, {
- "location": {
- "latitude": 407033786,
- "longitude": -743977337
- },
- "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
-}, {
- "location": {
- "latitude": 417548014,
- "longitude": -740075041
- },
- "name": ""
-}, {
- "location": {
- "latitude": 410395868,
- "longitude": -744972325
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404615353,
- "longitude": -745129803
- },
- "name": ""
-}, {
- "location": {
- "latitude": 406589790,
- "longitude": -743560121
- },
- "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
-}, {
- "location": {
- "latitude": 414653148,
- "longitude": -740477477
- },
- "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
-}, {
- "location": {
- "latitude": 405957808,
- "longitude": -743255336
- },
- "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
-}, {
- "location": {
- "latitude": 411733589,
- "longitude": -741648093
- },
- "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
-}, {
- "location": {
- "latitude": 412676291,
- "longitude": -742606606
- },
- "name": "1270 Lakes Road, Monroe, NY 10950, USA"
-}, {
- "location": {
- "latitude": 409224445,
- "longitude": -748286738
- },
- "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
-}, {
- "location": {
- "latitude": 406523420,
- "longitude": -742135517
- },
- "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
-}, {
- "location": {
- "latitude": 401827388,
- "longitude": -740294537
- },
- "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
-}, {
- "location": {
- "latitude": 410564152,
- "longitude": -743685054
- },
- "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
-}, {
- "location": {
- "latitude": 408472324,
- "longitude": -740726046
- },
- "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
-}, {
- "location": {
- "latitude": 412452168,
- "longitude": -740214052
- },
- "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
-}, {
- "location": {
- "latitude": 409146138,
- "longitude": -746188906
- },
- "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
-}, {
- "location": {
- "latitude": 404701380,
- "longitude": -744781745
- },
- "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
-}, {
- "location": {
- "latitude": 409642566,
- "longitude": -746017679
- },
- "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
-}, {
- "location": {
- "latitude": 408031728,
- "longitude": -748645385
- },
- "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
-}, {
- "location": {
- "latitude": 413700272,
- "longitude": -742135189
- },
- "name": "367 Prospect Road, Chester, NY 10918, USA"
-}, {
- "location": {
- "latitude": 404310607,
- "longitude": -740282632
- },
- "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
-}, {
- "location": {
- "latitude": 409319800,
- "longitude": -746201391
- },
- "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
-}, {
- "location": {
- "latitude": 406685311,
- "longitude": -742108603
- },
- "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
-}, {
- "location": {
- "latitude": 419018117,
- "longitude": -749142781
- },
- "name": "43 Dreher Road, Roscoe, NY 12776, USA"
-}, {
- "location": {
- "latitude": 412856162,
- "longitude": -745148837
- },
- "name": "Swan Street, Pine Island, NY 10969, USA"
-}, {
- "location": {
- "latitude": 416560744,
- "longitude": -746721964
- },
- "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
-}, {
- "location": {
- "latitude": 405314270,
- "longitude": -749836354
- },
- "name": ""
-}, {
- "location": {
- "latitude": 414219548,
- "longitude": -743327440
- },
- "name": ""
-}, {
- "location": {
- "latitude": 415534177,
- "longitude": -742900616
- },
- "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
-}, {
- "location": {
- "latitude": 406898530,
- "longitude": -749127080
- },
- "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
-}, {
- "location": {
- "latitude": 407586880,
- "longitude": -741670168
- },
- "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
-}, {
- "location": {
- "latitude": 400106455,
- "longitude": -742870190
- },
- "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
-}, {
- "location": {
- "latitude": 400066188,
- "longitude": -746793294
- },
- "name": ""
-}, {
- "location": {
- "latitude": 418803880,
- "longitude": -744102673
- },
- "name": "40 Mountain Road, Napanoch, NY 12458, USA"
-}, {
- "location": {
- "latitude": 414204288,
- "longitude": -747895140
- },
- "name": ""
-}, {
- "location": {
- "latitude": 414777405,
- "longitude": -740615601
- },
- "name": ""
-}, {
- "location": {
- "latitude": 415464475,
- "longitude": -747175374
- },
- "name": "48 North Road, Forestburgh, NY 12777, USA"
-}, {
- "location": {
- "latitude": 404062378,
- "longitude": -746376177
- },
- "name": ""
-}, {
- "location": {
- "latitude": 405688272,
- "longitude": -749285130
- },
- "name": ""
-}, {
- "location": {
- "latitude": 400342070,
- "longitude": -748788996
- },
- "name": ""
-}, {
- "location": {
- "latitude": 401809022,
- "longitude": -744157964
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404226644,
- "longitude": -740517141
- },
- "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
-}, {
- "location": {
- "latitude": 410322033,
- "longitude": -747871659
- },
- "name": ""
-}, {
- "location": {
- "latitude": 407100674,
- "longitude": -747742727
- },
- "name": ""
-}, {
- "location": {
- "latitude": 418811433,
- "longitude": -741718005
- },
- "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
-}, {
- "location": {
- "latitude": 415034302,
- "longitude": -743850945
- },
- "name": ""
-}, {
- "location": {
- "latitude": 411349992,
- "longitude": -743694161
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404839914,
- "longitude": -744759616
- },
- "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
-}, {
- "location": {
- "latitude": 414638017,
- "longitude": -745957854
- },
- "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
-}, {
- "location": {
- "latitude": 412127800,
- "longitude": -740173578
- },
- "name": ""
-}, {
- "location": {
- "latitude": 401263460,
- "longitude": -747964303
- },
- "name": ""
-}, {
- "location": {
- "latitude": 412843391,
- "longitude": -749086026
- },
- "name": ""
-}, {
- "location": {
- "latitude": 418512773,
- "longitude": -743067823
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404318328,
- "longitude": -740835638
- },
- "name": "42-102 Main Street, Belford, NJ 07718, USA"
-}, {
- "location": {
- "latitude": 419020746,
- "longitude": -741172328
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404080723,
- "longitude": -746119569
- },
- "name": ""
-}, {
- "location": {
- "latitude": 401012643,
- "longitude": -744035134
- },
- "name": ""
-}, {
- "location": {
- "latitude": 404306372,
- "longitude": -741079661
- },
- "name": ""
-}, {
- "location": {
- "latitude": 403966326,
- "longitude": -748519297
- },
- "name": ""
-}, {
- "location": {
- "latitude": 405002031,
- "longitude": -748407866
- },
- "name": ""
-}, {
- "location": {
- "latitude": 409532885,
- "longitude": -742200683
- },
- "name": ""
-}, {
- "location": {
- "latitude": 416851321,
- "longitude": -742674555
- },
- "name": ""
-}, {
- "location": {
- "latitude": 406411633,
- "longitude": -741722051
- },
- "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
-}, {
- "location": {
- "latitude": 413069058,
- "longitude": -744597778
- },
- "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
-}, {
- "location": {
- "latitude": 418465462,
- "longitude": -746859398
- },
- "name": ""
-}, {
- "location": {
- "latitude": 411733222,
- "longitude": -744228360
- },
- "name": ""
-}, {
- "location": {
- "latitude": 410248224,
- "longitude": -747127767
- },
- "name": "3 Hasta Way, Newton, NJ 07860, USA"
-}]
diff --git a/src/node/examples/route_guide_server.js b/src/node/examples/route_guide_server.js
deleted file mode 100644
index 465b32f54f..0000000000
--- a/src/node/examples/route_guide_server.js
+++ /dev/null
@@ -1,255 +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 fs = require('fs');
-var parseArgs = require('minimist');
-var path = require('path');
-var _ = require('lodash');
-var grpc = require('..');
-var examples = grpc.load(__dirname + '/route_guide.proto').examples;
-
-var COORD_FACTOR = 1e7;
-
-/**
- * For simplicity, a point is a record type that looks like
- * {latitude: number, longitude: number}, and a feature is a record type that
- * looks like {name: string, location: point}. feature objects with name===''
- * are points with no feature.
- */
-
-/**
- * List of feature objects at points that have been requested so far.
- */
-var feature_list = [];
-
-/**
- * Get a feature object at the given point.
- * @param {point} point The point to check
- * @return {feature} The feature object at the point. Note that an empty name
- * indicates no feature
- */
-function checkFeature(point) {
- var feature;
- // Check if there is already a feature object for the given point
- for (var i = 0; i < feature_list.length; i++) {
- feature = feature_list[i];
- if (feature.location.latitude === point.latitude &&
- feature.location.longitude === point.longitude) {
- return feature;
- }
- }
- var name = '';
- feature = {
- name: name,
- location: point
- };
- return feature;
-}
-
-/**
- * getFeature request handler. Gets a request with a point, and responds with a
- * feature object indicating whether there is a feature at that point.
- * @param {EventEmitter} call Call object for the handler to process
- * @param {function(Error, feature)} callback Response callback
- */
-function getFeature(call, callback) {
- callback(null, checkFeature(call.request));
-}
-
-/**
- * listFeatures request handler. Gets a request with two points, and responds
- * with a stream of all features in the bounding box defined by those points.
- * @param {Writable} call Writable stream for responses with an additional
- * request property for the request value.
- */
-function listFeatures(call) {
- var lo = call.request.lo;
- var hi = call.request.hi;
- var left = _.min([lo.longitude, hi.longitude]);
- var right = _.max([lo.longitude, hi.longitude]);
- var top = _.max([lo.latitude, hi.latitude]);
- var bottom = _.min([lo.latitude, hi.latitude]);
- // For each feature, check if it is in the given bounding box
- _.each(feature_list, function(feature) {
- if (feature.name === '') {
- return;
- }
- if (feature.location.longitude >= left &&
- feature.location.longitude <= right &&
- feature.location.latitude >= bottom &&
- feature.location.latitude <= top) {
- call.write(feature);
- }
- });
- call.end();
-}
-
-/**
- * Calculate the distance between two points using the "haversine" formula.
- * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
- * @param start The starting point
- * @param end The end point
- * @return The distance between the points in meters
- */
-function getDistance(start, end) {
- function toRadians(num) {
- return num * Math.PI / 180;
- }
- var lat1 = start.latitude / COORD_FACTOR;
- var lat2 = end.latitude / COORD_FACTOR;
- var lon1 = start.longitude / COORD_FACTOR;
- var lon2 = end.longitude / COORD_FACTOR;
- var R = 6371000; // metres
- var φ1 = toRadians(lat1);
- var φ2 = toRadians(lat2);
- var Δφ = toRadians(lat2-lat1);
- var Δλ = toRadians(lon2-lon1);
-
- var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
- Math.cos(φ1) * Math.cos(φ2) *
- Math.sin(Δλ/2) * Math.sin(Δλ/2);
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
-
- return R * c;
-}
-
-/**
- * recordRoute handler. Gets a stream of points, and responds with statistics
- * about the "trip": number of points, number of known features visited, total
- * distance traveled, and total time spent.
- * @param {Readable} call The request point stream.
- * @param {function(Error, routeSummary)} callback The callback to pass the
- * response to
- */
-function recordRoute(call, callback) {
- var point_count = 0;
- var feature_count = 0;
- var distance = 0;
- var previous = null;
- // Start a timer
- var start_time = process.hrtime();
- call.on('data', function(point) {
- point_count += 1;
- if (checkFeature(point).name !== '') {
- feature_count += 1;
- }
- /* For each point after the first, add the incremental distance from the
- * previous point to the total distance value */
- if (previous !== null) {
- distance += getDistance(previous, point);
- }
- previous = point;
- });
- call.on('end', function() {
- callback(null, {
- point_count: point_count,
- feature_count: feature_count,
- // Cast the distance to an integer
- distance: Math.floor(distance),
- // End the timer
- elapsed_time: process.hrtime(start_time)[0]
- });
- });
-}
-
-var route_notes = {};
-
-/**
- * Turn the point into a dictionary key.
- * @param {point} point The point to use
- * @return {string} The key for an object
- */
-function pointKey(point) {
- return point.latitude + ' ' + point.longitude;
-}
-
-/**
- * routeChat handler. Receives a stream of message/location pairs, and responds
- * with a stream of all previous messages at each of those locations.
- * @param {Duplex} call The stream for incoming and outgoing messages
- */
-function routeChat(call) {
- call.on('data', function(note) {
- var key = pointKey(note.location);
- /* For each note sent, respond with all previous notes that correspond to
- * the same point */
- if (route_notes.hasOwnProperty(key)) {
- _.each(route_notes[key], function(note) {
- call.write(note);
- });
- } else {
- route_notes[key] = [];
- }
- // Then add the new note to the list
- route_notes[key].push(JSON.parse(JSON.stringify(note)));
- });
- call.on('end', function() {
- call.end();
- });
-}
-
-/**
- * Get a new server with the handler functions in this file bound to the methods
- * it serves.
- * @return {Server} The new server object
- */
-function getServer() {
- var server = new grpc.Server();
- server.addProtoService(examples.RouteGuide.service, {
- getFeature: getFeature,
- listFeatures: listFeatures,
- recordRoute: recordRoute,
- routeChat: routeChat
- });
- return server;
-}
-
-if (require.main === module) {
- // If this is run as a script, start a server on an unused port
- var routeServer = getServer();
- routeServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
- var argv = parseArgs(process.argv, {
- string: 'db_path'
- });
- fs.readFile(path.resolve(argv.db_path), function(err, data) {
- if (err) {
- throw err;
- }
- feature_list = JSON.parse(data);
- routeServer.start();
- });
-}
-
-exports.getServer = getServer;
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 18858fa334..560869e6fa 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -111,17 +111,19 @@ bool CreateMetadataArray(Handle<Object> metadata, grpc_metadata_array *array,
NanAssignPersistent(*handle, value);
resources->handles.push_back(unique_ptr<PersistentHolder>(
new PersistentHolder(handle)));
- continue;
+ } else {
+ return false;
}
- }
- if (value->IsString()) {
- Handle<String> string_value = value->ToString();
- NanUtf8String *utf8_value = new NanUtf8String(string_value);
- resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
- current->value = **utf8_value;
- current->value_length = string_value->Length();
} else {
- return false;
+ if (value->IsString()) {
+ Handle<String> string_value = value->ToString();
+ NanUtf8String *utf8_value = new NanUtf8String(string_value);
+ resources->strings.push_back(unique_ptr<NanUtf8String>(utf8_value));
+ current->value = **utf8_value;
+ current->value_length = string_value->Length();
+ } else {
+ return false;
+ }
}
array->count += 1;
}
@@ -156,8 +158,7 @@ Handle<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
}
if (EndsWith(elem->key, "-bin")) {
array->Set(index_map[elem->key],
- MakeFastBuffer(
- NanNewBufferHandle(elem->value, elem->value_length)));
+ NanNewBufferHandle(elem->value, elem->value_length));
} else {
array->Set(index_map[elem->key], NanNew(elem->value));
}
@@ -460,6 +461,9 @@ void Call::Init(Handle<Object> exports) {
NanNew<FunctionTemplate>(StartBatch)->GetFunction());
NanSetPrototypeTemplate(tpl, "cancel",
NanNew<FunctionTemplate>(Cancel)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "cancelWithStatus",
+ NanNew<FunctionTemplate>(CancelWithStatus)->GetFunction());
NanSetPrototypeTemplate(tpl, "getPeer",
NanNew<FunctionTemplate>(GetPeer)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
@@ -642,6 +646,26 @@ NAN_METHOD(Call::Cancel) {
NanReturnUndefined();
}
+NAN_METHOD(Call::CancelWithStatus) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("cancel can only be called on Call objects");
+ }
+ if (!args[0]->IsUint32()) {
+ return NanThrowTypeError(
+ "cancelWithStatus's first argument must be a status code");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError(
+ "cancelWithStatus's second argument must be a string");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_status_code code = static_cast<grpc_status_code>(args[0]->Uint32Value());
+ NanUtf8String details(args[0]);
+ grpc_call_cancel_with_status(call->wrapped_call, code, *details, NULL);
+ NanReturnUndefined();
+}
+
NAN_METHOD(Call::GetPeer) {
NanScope();
if (!HasInstance(args.This())) {
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index ef6e5fcd21..89f81dcf4d 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -133,6 +133,7 @@ class Call : public ::node::ObjectWrap {
static NAN_METHOD(New);
static NAN_METHOD(StartBatch);
static NAN_METHOD(Cancel);
+ static NAN_METHOD(CancelWithStatus);
static NAN_METHOD(GetPeer);
static NanCallback *constructor;
// Used for typechecking instances of this javascript class
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index a61c830099..9aed96bbf5 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -161,7 +161,7 @@ NAN_METHOD(Channel::New) {
NULL);
} else {
wrapped_channel =
- grpc_secure_channel_create(creds, *host, channel_args_ptr);
+ grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL);
}
if (channel_args_ptr != NULL) {
free(channel_args_ptr->args);
diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
index 21d61f1a7f..c3b04dcea7 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/credentials.cc
@@ -156,7 +156,8 @@ NAN_METHOD(Credentials::CreateSsl) {
"createSSl's third argument must be a Buffer if provided");
}
grpc_credentials *creds = grpc_ssl_credentials_create(
- root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair);
+ root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair,
+ NULL);
if (creds == NULL) {
NanReturnNull();
}
@@ -176,7 +177,7 @@ NAN_METHOD(Credentials::CreateComposite) {
Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
grpc_credentials *creds = grpc_composite_credentials_create(
- creds1->wrapped_credentials, creds2->wrapped_credentials);
+ creds1->wrapped_credentials, creds2->wrapped_credentials, NULL);
if (creds == NULL) {
NanReturnNull();
}
@@ -185,7 +186,7 @@ NAN_METHOD(Credentials::CreateComposite) {
NAN_METHOD(Credentials::CreateGce) {
NanScope();
- grpc_credentials *creds = grpc_compute_engine_credentials_create();
+ grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL);
if (creds == NULL) {
NanReturnNull();
}
@@ -202,8 +203,8 @@ NAN_METHOD(Credentials::CreateIam) {
}
NanUtf8String auth_token(args[0]);
NanUtf8String auth_selector(args[1]);
- grpc_credentials *creds = grpc_iam_credentials_create(*auth_token,
- *auth_selector);
+ grpc_credentials *creds =
+ grpc_google_iam_credentials_create(*auth_token, *auth_selector, NULL);
if (creds == NULL) {
NanReturnNull();
}
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index 01217bce79..32a8ff55b1 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -120,7 +120,7 @@ Server::Server(grpc_server *server) : wrapped_server(server) {
Server::~Server() {
this->ShutdownServer();
grpc_completion_queue_shutdown(this->shutdown_queue);
- grpc_server_destroy(wrapped_server);
+ grpc_server_destroy(this->wrapped_server);
grpc_completion_queue_destroy(this->shutdown_queue);
}
@@ -139,8 +139,11 @@ void Server::Init(Handle<Object> exports) {
NanSetPrototypeTemplate(tpl, "start",
NanNew<FunctionTemplate>(Start)->GetFunction());
- NanSetPrototypeTemplate(tpl, "shutdown",
- NanNew<FunctionTemplate>(Shutdown)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "tryShutdown",
+ NanNew<FunctionTemplate>(TryShutdown)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "forceShutdown",
+ NanNew<FunctionTemplate>(ForceShutdown)->GetFunction());
NanAssignPersistent(fun_tpl, tpl);
Handle<Function> ctr = tpl->GetFunction();
@@ -153,14 +156,12 @@ bool Server::HasInstance(Handle<Value> val) {
}
void Server::ShutdownServer() {
- if (this->wrapped_server != NULL) {
- grpc_server_shutdown_and_notify(this->wrapped_server,
- this->shutdown_queue,
- NULL);
- grpc_completion_queue_pluck(this->shutdown_queue, NULL,
- gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- this->wrapped_server = NULL;
- }
+ grpc_server_shutdown_and_notify(this->wrapped_server,
+ this->shutdown_queue,
+ NULL);
+ grpc_server_cancel_all_calls(this->wrapped_server);
+ grpc_completion_queue_pluck(this->shutdown_queue, NULL,
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
}
NAN_METHOD(Server::New) {
@@ -222,9 +223,6 @@ NAN_METHOD(Server::RequestCall) {
return NanThrowTypeError("requestCall can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
- if (server->wrapped_server == NULL) {
- return NanThrowError("requestCall cannot be called on a shut down Server");
- }
NewCallOp *op = new NewCallOp();
unique_ptr<OpVec> ops(new OpVec());
ops->push_back(unique_ptr<Op>(op));
@@ -256,10 +254,6 @@ NAN_METHOD(Server::AddHttp2Port) {
"addHttp2Port's second argument must be ServerCredentials");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
- if (server->wrapped_server == NULL) {
- return NanThrowError(
- "addHttp2Port cannot be called on a shut down Server");
- }
ServerCredentials *creds_object = ObjectWrap::Unwrap<ServerCredentials>(
args[1]->ToObject());
grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials();
@@ -281,21 +275,30 @@ NAN_METHOD(Server::Start) {
return NanThrowTypeError("start can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
- if (server->wrapped_server == NULL) {
- return NanThrowError("start cannot be called on a shut down Server");
- }
grpc_server_start(server->wrapped_server);
NanReturnUndefined();
}
-NAN_METHOD(ShutdownCallback) {
+NAN_METHOD(Server::TryShutdown) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("tryShutdown can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ unique_ptr<OpVec> ops(new OpVec());
+ grpc_server_shutdown_and_notify(
+ server->wrapped_server,
+ CompletionQueueAsyncWorker::GetQueue(),
+ new struct tag(new NanCallback(args[0].As<Function>()), ops.release(),
+ shared_ptr<Resources>(nullptr)));
+ CompletionQueueAsyncWorker::Next();
NanReturnUndefined();
}
-NAN_METHOD(Server::Shutdown) {
+NAN_METHOD(Server::ForceShutdown) {
NanScope();
if (!HasInstance(args.This())) {
- return NanThrowTypeError("shutdown can only be called on a Server");
+ return NanThrowTypeError("forceShutdown can only be called on a Server");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
server->ShutdownServer();
diff --git a/src/node/ext/server.h b/src/node/ext/server.h
index faab7e3418..e7d5c3fb11 100644
--- a/src/node/ext/server.h
+++ b/src/node/ext/server.h
@@ -67,7 +67,8 @@ class Server : public ::node::ObjectWrap {
static NAN_METHOD(RequestCall);
static NAN_METHOD(AddHttp2Port);
static NAN_METHOD(Start);
- static NAN_METHOD(Shutdown);
+ static NAN_METHOD(TryShutdown);
+ static NAN_METHOD(ForceShutdown);
static NanCallback *constructor;
static v8::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index 6e17197e16..b1201eb664 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -178,11 +178,8 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
key_cert_pairs[i].cert_chain = ::node::Buffer::Data(
pair_obj->Get(cert_key));
}
- grpc_server_credentials *creds =
- grpc_ssl_server_credentials_create(root_certs,
- key_cert_pairs,
- key_cert_pair_count,
- force_client_auth);
+ grpc_server_credentials *creds = grpc_ssl_server_credentials_create(
+ root_certs, key_cert_pairs, key_cert_pair_count, force_client_auth, NULL);
delete key_cert_pairs;
if (creds == NULL) {
NanReturnNull();
diff --git a/src/node/index.js b/src/node/index.js
index 889b0ac0e9..02b73f66ee 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -41,6 +41,8 @@ var client = require('./src/client.js');
var server = require('./src/server.js');
+var Metadata = require('./src/metadata.js');
+
var grpc = require('bindings')('grpc');
/**
@@ -107,18 +109,12 @@ exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) {
* @param {function(Error, Object)} callback
*/
return function updateMetadata(authURI, metadata, callback) {
- metadata = _.clone(metadata);
- if (metadata.Authorization) {
- metadata.Authorization = _.clone(metadata.Authorization);
- } else {
- metadata.Authorization = [];
- }
credential.getRequestMetadata(authURI, function(err, header) {
if (err) {
callback(err);
return;
}
- metadata.Authorization.push(header.Authorization);
+ metadata.add('authorization', header.Authorization);
callback(null, metadata);
});
};
@@ -130,6 +126,11 @@ exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) {
exports.Server = server.Server;
/**
+ * @see module:src/metadata
+ */
+exports.Metadata = Metadata;
+
+/**
* Status name to code number mapping
*/
exports.status = grpc.status;
@@ -163,3 +164,13 @@ exports.ServerCredentials = grpc.ServerCredentials;
* @see module:src/client.makeClientConstructor
*/
exports.makeGenericClientConstructor = client.makeClientConstructor;
+
+/**
+ * @see module:src/client.getClientChannel
+ */
+exports.getClientChannel = client.getClientChannel;
+
+/**
+ * @see module:src/client.waitForClientReady
+ */
+exports.waitForClientReady = client.waitForClientReady;
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 612dcf01f6..215d42121c 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -44,7 +44,7 @@ var assert = require('assert');
var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo';
var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
-var AUTH_USER = ('155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk' +
+var AUTH_USER = ('155450119199-vefjjaekcc6cmsd5914v6lqufunmh9ue' +
'@developer.gserviceaccount.com');
var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
'@developer.gserviceaccount.com');
@@ -285,7 +285,7 @@ function authTest(expected_user, scope, client, done) {
if (credential.createScopedRequired() && scope) {
credential = credential.createScoped(scope);
}
- client.updateMetadata = grpc.getGoogleAuthDelegate(credential);
+ client.$updateMetadata = grpc.getGoogleAuthDelegate(credential);
var arg = {
response_type: 'COMPRESSABLE',
response_size: 314159,
@@ -321,13 +321,7 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) {
credential.getAccessToken(function(err, token) {
assert.ifError(err);
var updateMetadata = function(authURI, metadata, callback) {
- metadata = _.clone(metadata);
- if (metadata.Authorization) {
- metadata.Authorization = _.clone(metadata.Authorization);
- } else {
- metadata.Authorization = [];
- }
- metadata.Authorization.push('Bearer ' + token);
+ metadata.add('authorization', 'Bearer ' + token);
callback(null, metadata);
};
var makeTestCall = function(error, client_metadata) {
@@ -342,10 +336,10 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) {
}, client_metadata);
};
if (per_rpc) {
- updateMetadata('', {}, makeTestCall);
+ updateMetadata('', new grpc.Metadata(), makeTestCall);
} else {
- client.updateMetadata = updateMetadata;
- makeTestCall(null, {});
+ client.$updateMetadata = updateMetadata;
+ makeTestCall(null, new grpc.Metadata());
}
});
});
diff --git a/src/node/package.json b/src/node/package.json
index 756d41b0af..bb8987cc0d 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.10.0",
+ "version": "0.11.0",
"author": "Google Inc.",
"description": "gRPC Library for Node",
"homepage": "http://www.grpc.io/",
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 7b7eae51d2..7f510231b3 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -32,7 +32,7 @@
*/
/**
- * Server module
+ * Client module
* @module
*/
@@ -42,7 +42,9 @@ var _ = require('lodash');
var grpc = require('bindings')('grpc.node');
-var common = require('./common.js');
+var common = require('./common');
+
+var Metadata = require('./metadata');
var EventEmitter = require('events').EventEmitter;
@@ -140,7 +142,14 @@ function _read(size) {
return;
}
var data = event.read;
- if (self.push(self.deserialize(data)) && data !== null) {
+ var deserialized;
+ try {
+ deserialized = self.deserialize(data);
+ } catch (e) {
+ self.call.cancelWithStatus(grpc.status.INTERNAL,
+ 'Failed to parse server response');
+ }
+ if (self.push(deserialized) && data !== null) {
var read_batch = {};
read_batch[grpc.opType.RECV_MESSAGE] = true;
self.call.startBatch(read_batch, readCallback);
@@ -254,17 +263,18 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
* serialize
* @param {function(?Error, value=)} callback The callback to for when the
* response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
- * call
+ * @param {Metadata=} metadata Metadata to add to the call
* @param {Object=} options Options map
* @return {EventEmitter} An event emitter for stream related events
*/
function makeUnaryRequest(argument, callback, metadata, options) {
/* jshint validthis: true */
var emitter = new EventEmitter();
- var call = getCall(this.channel, method, options);
+ var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) {
- metadata = {};
+ metadata = new Metadata();
+ } else {
+ metadata = metadata.clone();
}
emitter.cancel = function cancel() {
call.cancel();
@@ -272,7 +282,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
emitter.getPeer = function getPeer() {
return call.getPeer();
};
- this.updateMetadata(this.auth_uri, metadata, function(error, metadata) {
+ this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) {
call.cancel();
callback(error);
@@ -283,29 +293,48 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
if (options) {
message.grpcWriteFlags = options.flags;
}
- client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
client_batch[grpc.opType.SEND_MESSAGE] = message;
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
client_batch[grpc.opType.RECV_MESSAGE] = true;
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(client_batch, function(err, response) {
- emitter.emit('status', response.status);
- if (response.status.code !== grpc.status.OK) {
- var error = new Error(response.status.details);
- error.code = response.status.code;
- error.metadata = response.status.metadata;
- callback(error);
- return;
- } else {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ var status = response.status;
+ var error;
+ var deserialized;
+ if (status.code === grpc.status.OK) {
if (err) {
// Got a batch error, but OK status. Something went wrong
callback(err);
return;
+ } else {
+ try {
+ deserialized = deserialize(response.read);
+ } catch (e) {
+ /* Change status to indicate bad server response. This will result
+ * in passing an error to the callback */
+ status = {
+ code: grpc.status.INTERNAL,
+ details: 'Failed to parse server response'
+ };
+ }
}
}
- emitter.emit('metadata', response.metadata);
- callback(null, deserialize(response.read));
+ if (status.code !== grpc.status.OK) {
+ error = new Error(response.status.details);
+ error.code = status.code;
+ error.metadata = status.metadata;
+ callback(error);
+ } else {
+ callback(null, deserialized);
+ }
+ emitter.emit('status', status);
+ emitter.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
});
});
return emitter;
@@ -328,26 +357,29 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
* @this {Client} Client object. Must have a channel member.
* @param {function(?Error, value=)} callback The callback to for when the
* response is received
- * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
* call
* @param {Object=} options Options map
* @return {EventEmitter} An event emitter for stream related events
*/
function makeClientStreamRequest(callback, metadata, options) {
/* jshint validthis: true */
- var call = getCall(this.channel, method, options);
+ var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) {
- metadata = {};
+ metadata = new Metadata();
+ } else {
+ metadata = metadata.clone();
}
var stream = new ClientWritableStream(call, serialize);
- this.updateMetadata(this.auth_uri, metadata, function(error, metadata) {
+ this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) {
call.cancel();
callback(error);
return;
}
var metadata_batch = {};
- metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
call.startBatch(metadata_batch, function(err, response) {
if (err) {
@@ -355,27 +387,45 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
// in the other batch.
return;
}
- stream.emit('metadata', response.metadata);
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
});
var client_batch = {};
client_batch[grpc.opType.RECV_MESSAGE] = true;
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(client_batch, function(err, response) {
- stream.emit('status', response.status);
- if (response.status.code !== grpc.status.OK) {
- var error = new Error(response.status.details);
- error.code = response.status.code;
- error.metadata = response.status.metadata;
- callback(error);
- return;
- } else {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ var status = response.status;
+ var error;
+ var deserialized;
+ if (status.code === grpc.status.OK) {
if (err) {
// Got a batch error, but OK status. Something went wrong
callback(err);
return;
+ } else {
+ try {
+ deserialized = deserialize(response.read);
+ } catch (e) {
+ /* Change status to indicate bad server response. This will result
+ * in passing an error to the callback */
+ status = {
+ code: grpc.status.INTERNAL,
+ details: 'Failed to parse server response'
+ };
+ }
}
}
- callback(null, deserialize(response.read));
+ if (status.code !== grpc.status.OK) {
+ error = new Error(response.status.details);
+ error.code = status.code;
+ error.metadata = status.metadata;
+ callback(error);
+ } else {
+ callback(null, deserialized);
+ }
+ stream.emit('status', status);
});
});
return stream;
@@ -398,19 +448,21 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
* @this {SurfaceClient} Client object. Must have a channel member.
* @param {*} argument The argument to the call. Should be serializable with
* serialize
- * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
* call
* @param {Object} options Options map
* @return {EventEmitter} An event emitter for stream related events
*/
function makeServerStreamRequest(argument, metadata, options) {
/* jshint validthis: true */
- var call = getCall(this.channel, method, options);
+ var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) {
- metadata = {};
+ metadata = new Metadata();
+ } else {
+ metadata = metadata.clone();
}
var stream = new ClientReadableStream(call, deserialize);
- this.updateMetadata(this.auth_uri, metadata, function(error, metadata) {
+ this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) {
call.cancel();
stream.emit('error', error);
@@ -421,7 +473,8 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
if (options) {
message.grpcWriteFlags = options.flags;
}
- start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
start_batch[grpc.opType.SEND_MESSAGE] = message;
start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
@@ -431,11 +484,14 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
// in the other batch.
return;
}
- stream.emit('metadata', response.metadata);
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
});
var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
@@ -470,26 +526,29 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
/**
* Make a bidirectional stream request with this method on the given channel.
* @this {SurfaceClient} Client object. Must have a channel member.
- * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * @param {Metadata=} metadata Array of metadata key/value pairs to add to the
* call
* @param {Options} options Options map
* @return {EventEmitter} An event emitter for stream related events
*/
function makeBidiStreamRequest(metadata, options) {
/* jshint validthis: true */
- var call = getCall(this.channel, method, options);
+ var call = getCall(this.$channel, method, options);
if (metadata === null || metadata === undefined) {
- metadata = {};
+ metadata = new Metadata();
+ } else {
+ metadata = metadata.clone();
}
var stream = new ClientDuplexStream(call, serialize, deserialize);
- this.updateMetadata(this.auth_uri, metadata, function(error, metadata) {
+ this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
if (error) {
call.cancel();
stream.emit('error', error);
return;
}
var start_batch = {};
- start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
call.startBatch(start_batch, function(err, response) {
if (err) {
@@ -497,11 +556,14 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
// in the other batch.
return;
}
- stream.emit('metadata', response.metadata);
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
});
var status_batch = {};
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
call.startBatch(status_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
@@ -569,45 +631,21 @@ exports.makeClientConstructor = function(methods, serviceName) {
options = {};
}
options['grpc.primary_user_agent'] = 'grpc-node/' + version;
- this.channel = new grpc.Channel(address, credentials, options);
+ /* Private fields use $ as a prefix instead of _ because it is an invalid
+ * prefix of a method name */
+ this.$channel = new grpc.Channel(address, credentials, options);
// Remove the optional DNS scheme, trailing port, and trailing backslash
address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2');
- this.server_address = address;
- this.auth_uri = 'https://' + this.server_address + '/' + serviceName;
- this.updateMetadata = updateMetadata;
+ this.$server_address = address;
+ this.$auth_uri = 'https://' + this.$server_address + '/' + serviceName;
+ this.$updateMetadata = updateMetadata;
}
- /**
- * Wait for the client to be ready. The callback will be called when the
- * client has successfully connected to the server, and it will be called
- * with an error if the attempt to connect to the server has unrecoverablly
- * failed or if the deadline expires. This function will make the channel
- * start connecting if it has not already done so.
- * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
- * Infinity to wait forever.
- * @param {function(Error)} callback The callback to call when done attempting
- * to connect.
- */
- Client.prototype.$waitForReady = function(deadline, callback) {
- var self = this;
- var checkState = function(err) {
- if (err) {
- callback(new Error('Failed to connect before the deadline'));
- }
- var new_state = self.channel.getConnectivityState(true);
- if (new_state === grpc.connectivityState.READY) {
- callback();
- } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
- callback(new Error('Failed to connect to server'));
- } else {
- self.channel.watchConnectivityState(new_state, deadline, checkState);
- }
- };
- checkState();
- };
-
_.each(methods, function(attrs, name) {
var method_type;
+ if (_.startsWith(name, '$')) {
+ throw new Error('Method names cannot start with $');
+ }
if (attrs.requestStream) {
if (attrs.responseStream) {
method_type = 'bidi';
@@ -633,6 +671,44 @@ exports.makeClientConstructor = function(methods, serviceName) {
};
/**
+ * Return the underlying channel object for the specified client
+ * @param {Client} client
+ * @return {Channel} The channel
+ */
+exports.getClientChannel = function(client) {
+ return client.$channel;
+};
+
+/**
+ * Wait for the client to be ready. The callback will be called when the
+ * client has successfully connected to the server, and it will be called
+ * with an error if the attempt to connect to the server has unrecoverablly
+ * failed or if the deadline expires. This function will make the channel
+ * start connecting if it has not already done so.
+ * @param {Client} client The client to wait on
+ * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
+ * Infinity to wait forever.
+ * @param {function(Error)} callback The callback to call when done attempting
+ * to connect.
+ */
+exports.waitForClientReady = function(client, deadline, callback) {
+ var checkState = function(err) {
+ if (err) {
+ callback(new Error('Failed to connect before the deadline'));
+ }
+ var new_state = client.$channel.getConnectivityState(true);
+ if (new_state === grpc.connectivityState.READY) {
+ callback();
+ } else if (new_state === grpc.connectivityState.FATAL_FAILURE) {
+ callback(new Error('Failed to connect to server'));
+ } else {
+ client.$channel.watchConnectivityState(new_state, deadline, checkState);
+ }
+ };
+ checkState();
+};
+
+/**
* Creates a constructor for clients for the given service
* @param {ProtoBuf.Reflect.Service} service The service to generate a client
* for
diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js
new file mode 100644
index 0000000000..c1da70b197
--- /dev/null
+++ b/src/node/src/metadata.js
@@ -0,0 +1,181 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Metadata module
+ * @module
+ */
+
+'use strict';
+
+var _ = require('lodash');
+
+/**
+ * Class for storing metadata. Keys are normalized to lowercase ASCII.
+ * @constructor
+ */
+function Metadata() {
+ this._internal_repr = {};
+}
+
+function normalizeKey(key) {
+ if (!(/^[A-Za-z\d_-]+$/.test(key))) {
+ throw new Error('Metadata keys must be nonempty strings containing only ' +
+ 'alphanumeric characters and hyphens');
+ }
+ return key.toLowerCase();
+}
+
+function validate(key, value) {
+ if (_.endsWith(key, '-bin')) {
+ if (!(value instanceof Buffer)) {
+ throw new Error('keys that end with \'-bin\' must have Buffer values');
+ }
+ } else {
+ if (!_.isString(value)) {
+ throw new Error(
+ 'keys that don\'t end with \'-bin\' must have String values');
+ }
+ if (!(/^[\x20-\x7E]*$/.test(value))) {
+ throw new Error('Metadata string values can only contain printable ' +
+ 'ASCII characters and space');
+ }
+ }
+}
+
+/**
+ * Sets the given value for the given key, replacing any other values associated
+ * with that key. Normalizes the key.
+ * @param {String} key The key to set
+ * @param {String|Buffer} value The value to set. Must be a buffer if and only
+ * if the normalized key ends with '-bin'
+ */
+Metadata.prototype.set = function(key, value) {
+ key = normalizeKey(key);
+ validate(key, value);
+ this._internal_repr[key] = [value];
+};
+
+/**
+ * Adds the given value for the given key. Normalizes the key.
+ * @param {String} key The key to add to.
+ * @param {String|Buffer} value The value to add. Must be a buffer if and only
+ * if the normalized key ends with '-bin'
+ */
+Metadata.prototype.add = function(key, value) {
+ key = normalizeKey(key);
+ validate(key, value);
+ if (!this._internal_repr[key]) {
+ this._internal_repr[key] = [];
+ }
+ this._internal_repr[key].push(value);
+};
+
+/**
+ * Remove the given key and any associated values. Normalizes the key.
+ * @param {String} key The key to remove
+ */
+Metadata.prototype.remove = function(key) {
+ key = normalizeKey(key);
+ if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) {
+ delete this._internal_repr[key];
+ }
+};
+
+/**
+ * Gets a list of all values associated with the key. Normalizes the key.
+ * @param {String} key The key to get
+ * @return {Array.<String|Buffer>} The values associated with that key
+ */
+Metadata.prototype.get = function(key) {
+ key = normalizeKey(key);
+ if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) {
+ return this._internal_repr[key];
+ } else {
+ return [];
+ }
+};
+
+/**
+ * Get a map of each key to a single associated value. This reflects the most
+ * common way that people will want to see metadata.
+ * @return {Object.<String,String|Buffer>} A key/value mapping of the metadata
+ */
+Metadata.prototype.getMap = function() {
+ var result = {};
+ _.forOwn(this._internal_repr, function(values, key) {
+ if(values.length > 0) {
+ result[key] = values[0];
+ }
+ });
+ return result;
+};
+
+/**
+ * Clone the metadata object.
+ * @return {Metadata} The new cloned object
+ */
+Metadata.prototype.clone = function() {
+ var copy = new Metadata();
+ _.forOwn(this._internal_repr, function(value, key) {
+ copy._internal_repr[key] = _.clone(value);
+ });
+ return copy;
+};
+
+/**
+ * Gets the metadata in the format used by interal code. Intended for internal
+ * use only. API stability is not guaranteed.
+ * @private
+ * @return {Object.<String, Array.<String|Buffer>>} The metadata
+ */
+Metadata.prototype._getCoreRepresentation = function() {
+ return this._internal_repr;
+};
+
+/**
+ * Creates a Metadata object from a metadata map in the internal format.
+ * Intended for internal use only. API stability is not guaranteed.
+ * @private
+ * @param {Object.<String, Array.<String|Buffer>>} The metadata
+ * @return {Metadata} The new Metadata object
+ */
+Metadata._fromCoreRepresentation = function(metadata) {
+ var newMetadata = new Metadata();
+ if (metadata) {
+ newMetadata._internal_repr = _.cloneDeep(metadata);
+ }
+ return newMetadata;
+};
+
+module.exports = Metadata;
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 5037abae43..b6f162adf8 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -44,6 +44,8 @@ var grpc = require('bindings')('grpc.node');
var common = require('./common');
+var Metadata = require('./metadata');
+
var stream = require('stream');
var Readable = stream.Readable;
@@ -60,10 +62,10 @@ var EventEmitter = require('events').EventEmitter;
* @param {Object} error The error object
*/
function handleError(call, error) {
+ var statusMetadata = new Metadata();
var status = {
code: grpc.status.UNKNOWN,
- details: 'Unknown Error',
- metadata: {}
+ details: 'Unknown Error'
};
if (error.hasOwnProperty('message')) {
status.details = error.message;
@@ -75,11 +77,13 @@ function handleError(call, error) {
}
}
if (error.hasOwnProperty('metadata')) {
- status.metadata = error.metadata;
+ statusMetadata = error.metadata;
}
+ status.metadata = statusMetadata._getCoreRepresentation();
var error_batch = {};
if (!call.metadataSent) {
- error_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ error_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
}
error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
call.startBatch(error_batch, function(){});
@@ -114,22 +118,24 @@ function waitForCancel(call, emitter) {
* @param {*} value The value to respond with
* @param {function(*):Buffer=} serialize Serialization function for the
* response
- * @param {Object=} metadata Optional trailing metadata to send with status
+ * @param {Metadata=} metadata Optional trailing metadata to send with status
* @param {number=} flags Flags for modifying how the message is sent.
* Defaults to 0.
*/
function sendUnaryResponse(call, value, serialize, metadata, flags) {
var end_batch = {};
+ var statusMetadata = new Metadata();
var status = {
code: grpc.status.OK,
- details: 'OK',
- metadata: {}
+ details: 'OK'
};
if (metadata) {
- status.metadata = metadata;
+ statusMetadata = metadata;
}
+ status.metadata = statusMetadata._getCoreRepresentation();
if (!call.metadataSent) {
- end_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ end_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
call.metadataSent = true;
}
var message = serialize(value);
@@ -151,14 +157,19 @@ function setUpWritable(stream, serialize) {
stream.status = {
code : grpc.status.OK,
details : 'OK',
- metadata : {}
+ metadata : new Metadata()
};
stream.serialize = common.wrapIgnoreNull(serialize);
function sendStatus() {
var batch = {};
if (!stream.call.metadataSent) {
stream.call.metadataSent = true;
- batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
+ }
+
+ if (stream.status.metadata) {
+ stream.status.metadata = stream.status.metadata._getCoreRepresentation();
}
batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status;
stream.call.startBatch(batch, function(){});
@@ -173,7 +184,7 @@ function setUpWritable(stream, serialize) {
function setStatus(err) {
var code = grpc.status.UNKNOWN;
var details = 'Unknown Error';
- var metadata = {};
+ var metadata = new Metadata();
if (err.hasOwnProperty('message')) {
details = err.message;
}
@@ -203,7 +214,7 @@ function setUpWritable(stream, serialize) {
/**
* Override of Writable#end method that allows for sending metadata with a
* success status.
- * @param {Object=} metadata Metadata to send with the status
+ * @param {Metadata=} metadata Metadata to send with the status
*/
stream.end = function(metadata) {
if (metadata) {
@@ -266,7 +277,8 @@ function _write(chunk, encoding, callback) {
/* jshint validthis: true */
var batch = {};
if (!this.call.metadataSent) {
- batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
this.call.metadataSent = true;
}
var message = this.serialize(chunk);
@@ -289,15 +301,15 @@ ServerWritableStream.prototype._write = _write;
/**
* Send the initial metadata for a writable stream.
- * @param {Object<String, Array<(String|Buffer)>>} responseMetadata Metadata
- * to send
+ * @param {Metadata} responseMetadata Metadata to send
*/
function sendMetadata(responseMetadata) {
/* jshint validthis: true */
if (!this.call.metadataSent) {
this.call.metadataSent = true;
var batch = [];
- batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ responseMetadata._getCoreRepresentation();
this.call.startBatch(batch, function(err) {
if (err) {
this.emit('error', err);
@@ -422,7 +434,7 @@ ServerDuplexStream.prototype.getPeer = getPeer;
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Object} metadata Metadata from the client
+ * @param {Metadata} metadata Metadata from the client
*/
function handleUnary(call, handler, metadata) {
var emitter = new EventEmitter();
@@ -430,7 +442,8 @@ function handleUnary(call, handler, metadata) {
if (!call.metadataSent) {
call.metadataSent = true;
var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ responseMetadata._getCoreRepresentation();
call.startBatch(batch, function() {});
}
};
@@ -478,7 +491,7 @@ function handleUnary(call, handler, metadata) {
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Object} metadata Metadata from the client
+ * @param {Metadata} metadata Metadata from the client
*/
function handleServerStreaming(call, handler, metadata) {
var stream = new ServerWritableStream(call, handler.serialize);
@@ -507,7 +520,7 @@ function handleServerStreaming(call, handler, metadata) {
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Object} metadata Metadata from the client
+ * @param {Metadata} metadata Metadata from the client
*/
function handleClientStreaming(call, handler, metadata) {
var stream = new ServerReadableStream(call, handler.deserialize);
@@ -515,7 +528,8 @@ function handleClientStreaming(call, handler, metadata) {
if (!call.metadataSent) {
call.metadataSent = true;
var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] = responseMetadata;
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ responseMetadata._getCoreRepresentation();
call.startBatch(batch, function() {});
}
};
@@ -542,7 +556,7 @@ function handleClientStreaming(call, handler, metadata) {
* @access private
* @param {grpc.Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Object} metadata Metadata from the client
+ * @param {Metadata} metadata Metadata from the client
*/
function handleBidiStreaming(call, handler, metadata) {
var stream = new ServerDuplexStream(call, handler.serialize,
@@ -599,7 +613,7 @@ function Server(options) {
var details = event.new_call;
var call = details.call;
var method = details.method;
- var metadata = details.metadata;
+ var metadata = Metadata._fromCoreRepresentation(details.metadata);
if (method === null) {
return;
}
@@ -609,7 +623,8 @@ function Server(options) {
handler = handlers[method];
} else {
var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
code: grpc.status.UNIMPLEMENTED,
details: 'This method is not available on this server.',
@@ -623,11 +638,26 @@ function Server(options) {
}
server.requestCall(handleNewCall);
};
+
+ /**
+ * Gracefully shuts down the server. The server will stop receiving new calls,
+ * and any pending calls will complete. The callback will be called when all
+ * pending calls have completed and the server is fully shut down. This method
+ * is idempotent with itself and forceShutdown.
+ * @param {function()} callback The shutdown complete callback
+ */
+ this.tryShutdown = function(callback) {
+ server.tryShutdown(callback);
+ };
+
/**
- * Shuts down the server.
+ * Forcibly shuts down the server. The server will stop receiving new calls
+ * and cancel all pending calls. When it returns, the server has shut down.
+ * This method is idempotent with itself and tryShutdown, and it will trigger
+ * any outstanding tryShutdown callbacks.
*/
- this.shutdown = function() {
- server.shutdown();
+ this.forceShutdown = function() {
+ server.forceShutdown();
};
}
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index 8d0f20b074..e7f071bcd5 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -61,7 +61,7 @@ describe('call', function() {
channel = new grpc.Channel('localhost:' + port, insecureCreds);
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
describe('constructor', function() {
it('should reject anything less than 3 arguments', function() {
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 7574d98b8a..4b8da3bfb1 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -70,7 +70,7 @@ describe('end-to-end', function() {
channel = new grpc.Channel('localhost:' + port_num, insecureCreds);
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('should start and end a request without error', function(complete) {
var done = multiDone(complete, 2);
diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js
index 04959f5f55..9267bff7eb 100644
--- a/src/node/test/health_test.js
+++ b/src/node/test/health_test.js
@@ -57,7 +57,7 @@ describe('Health Checking', function() {
grpc.Credentials.createInsecure());
});
after(function() {
- healthServer.shutdown();
+ healthServer.forceShutdown();
});
it('should say an enabled service is SERVING', function(done) {
healthClient.check({service: ''}, function(err, response) {
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index 0a5eb29c0c..2ca07c1d50 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -51,7 +51,7 @@ describe('Interop tests', function() {
done();
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
// This depends on not using a binary stream
it('should pass empty_unary', function(done) {
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index ef01870a4c..80b0c5ff2a 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -59,7 +59,7 @@ describe('Math client', function() {
done();
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('should handle a single request', function(done) {
var arg = {dividend: 7, divisor: 4};
diff --git a/src/node/test/metadata_test.js b/src/node/test/metadata_test.js
new file mode 100644
index 0000000000..86383f1bad
--- /dev/null
+++ b/src/node/test/metadata_test.js
@@ -0,0 +1,193 @@
+/*
+ *
+ * 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 Metadata = require('../src/metadata.js');
+
+var assert = require('assert');
+
+describe('Metadata', function() {
+ var metadata;
+ beforeEach(function() {
+ metadata = new Metadata();
+ });
+ describe('#set', function() {
+ it('Only accepts string values for non "-bin" keys', function() {
+ assert.throws(function() {
+ metadata.set('key', new Buffer('value'));
+ });
+ assert.doesNotThrow(function() {
+ metadata.set('key', 'value');
+ });
+ });
+ it('Only accepts Buffer values for "-bin" keys', function() {
+ assert.throws(function() {
+ metadata.set('key-bin', 'value');
+ });
+ assert.doesNotThrow(function() {
+ metadata.set('key-bin', new Buffer('value'));
+ });
+ });
+ it('Rejects invalid keys', function() {
+ assert.throws(function() {
+ metadata.set('key$', 'value');
+ });
+ assert.throws(function() {
+ metadata.set('', 'value');
+ });
+ });
+ it('Rejects values with non-ASCII characters', function() {
+ assert.throws(function() {
+ metadata.set('key', 'résumé');
+ });
+ });
+ it('Saves values that can be retrieved', function() {
+ metadata.set('key', 'value');
+ assert.deepEqual(metadata.get('key'), ['value']);
+ });
+ it('Overwrites previous values', function() {
+ metadata.set('key', 'value1');
+ metadata.set('key', 'value2');
+ assert.deepEqual(metadata.get('key'), ['value2']);
+ });
+ it('Normalizes keys', function() {
+ metadata.set('Key', 'value1');
+ assert.deepEqual(metadata.get('key'), ['value1']);
+ metadata.set('KEY', 'value2');
+ assert.deepEqual(metadata.get('key'), ['value2']);
+ });
+ });
+ describe('#add', function() {
+ it('Only accepts string values for non "-bin" keys', function() {
+ assert.throws(function() {
+ metadata.add('key', new Buffer('value'));
+ });
+ assert.doesNotThrow(function() {
+ metadata.add('key', 'value');
+ });
+ });
+ it('Only accepts Buffer values for "-bin" keys', function() {
+ assert.throws(function() {
+ metadata.add('key-bin', 'value');
+ });
+ assert.doesNotThrow(function() {
+ metadata.add('key-bin', new Buffer('value'));
+ });
+ });
+ it('Rejects invalid keys', function() {
+ assert.throws(function() {
+ metadata.add('key$', 'value');
+ });
+ assert.throws(function() {
+ metadata.add('', 'value');
+ });
+ });
+ it('Saves values that can be retrieved', function() {
+ metadata.add('key', 'value');
+ assert.deepEqual(metadata.get('key'), ['value']);
+ });
+ it('Combines with previous values', function() {
+ metadata.add('key', 'value1');
+ metadata.add('key', 'value2');
+ assert.deepEqual(metadata.get('key'), ['value1', 'value2']);
+ });
+ it('Normalizes keys', function() {
+ metadata.add('Key', 'value1');
+ assert.deepEqual(metadata.get('key'), ['value1']);
+ metadata.add('KEY', 'value2');
+ assert.deepEqual(metadata.get('key'), ['value1', 'value2']);
+ });
+ });
+ describe('#remove', function() {
+ it('clears values from a key', function() {
+ metadata.add('key', 'value');
+ metadata.remove('key');
+ assert.deepEqual(metadata.get('key'), []);
+ });
+ it('Normalizes keys', function() {
+ metadata.add('key', 'value');
+ metadata.remove('KEY');
+ assert.deepEqual(metadata.get('key'), []);
+ });
+ });
+ describe('#get', function() {
+ beforeEach(function() {
+ metadata.add('key', 'value1');
+ metadata.add('key', 'value2');
+ metadata.add('key-bin', new Buffer('value'));
+ });
+ it('gets all values associated with a key', function() {
+ assert.deepEqual(metadata.get('key'), ['value1', 'value2']);
+ });
+ it('Normalizes keys', function() {
+ assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']);
+ });
+ it('returns an empty list for non-existent keys', function() {
+ assert.deepEqual(metadata.get('non-existent-key'), []);
+ });
+ it('returns Buffers for "-bin" keys', function() {
+ assert(metadata.get('key-bin')[0] instanceof Buffer);
+ });
+ });
+ describe('#getMap', function() {
+ it('gets a map of keys to values', function() {
+ metadata.add('key1', 'value1');
+ metadata.add('Key2', 'value2');
+ metadata.add('KEY3', 'value3');
+ assert.deepEqual(metadata.getMap(),
+ {key1: 'value1',
+ key2: 'value2',
+ key3: 'value3'});
+ });
+ });
+ describe('#clone', function() {
+ it('retains values from the original', function() {
+ metadata.add('key', 'value');
+ var copy = metadata.clone();
+ assert.deepEqual(copy.get('key'), ['value']);
+ });
+ it('Does not see newly added values', function() {
+ metadata.add('key', 'value1');
+ var copy = metadata.clone();
+ metadata.add('key', 'value2');
+ assert.deepEqual(copy.get('key'), ['value1']);
+ });
+ it('Does not add new values to the original', function() {
+ metadata.add('key', 'value1');
+ var copy = metadata.clone();
+ copy.add('key', 'value2');
+ assert.deepEqual(metadata.get('key'), ['value1']);
+ });
+ });
+});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 78bac8da29..1e69d52e58 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -92,7 +92,7 @@ describe('server', function() {
server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('should start without error', function() {
assert.doesNotThrow(function() {
@@ -100,4 +100,33 @@ describe('server', function() {
});
});
});
+ describe('shutdown', function() {
+ var server;
+ beforeEach(function() {
+ server = new grpc.Server();
+ server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure());
+ server.start();
+ });
+ afterEach(function() {
+ server.forceShutdown();
+ });
+ it('tryShutdown should shutdown successfully', function(done) {
+ server.tryShutdown(done);
+ });
+ it('forceShutdown should shutdown successfully', function() {
+ server.forceShutdown();
+ });
+ it('tryShutdown should be idempotent', function(done) {
+ server.tryShutdown(done);
+ server.tryShutdown(function() {});
+ });
+ it('forceShutdown should be idempotent', function() {
+ server.forceShutdown();
+ server.forceShutdown();
+ });
+ it('forceShutdown should trigger tryShutdown', function(done) {
+ server.tryShutdown(done);
+ server.forceShutdown();
+ });
+ });
});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index ec7ed87728..d917c7a171 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -104,7 +104,7 @@ describe('Server.prototype.addProtoService', function() {
server = new grpc.Server();
});
afterEach(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('Should succeed with a single service', function() {
assert.doesNotThrow(function() {
@@ -133,7 +133,25 @@ describe('Server.prototype.addProtoService', function() {
});
});
});
-describe('Client#$waitForReady', function() {
+describe('Client constructor building', function() {
+ var illegal_service_attrs = {
+ $method : {
+ path: '/illegal/$method',
+ requestStream: false,
+ responseStream: false,
+ requestSerialize: _.identity,
+ requestDeserialize: _.identity,
+ responseSerialize: _.identity,
+ responseDeserialize: _.identity
+ }
+ };
+ it('Should reject method names starting with $', function() {
+ assert.throws(function() {
+ grpc.makeGenericClientConstructor(illegal_service_attrs);
+ }, /\$/);
+ });
+});
+describe('waitForClientReady', function() {
var server;
var port;
var Client;
@@ -148,16 +166,16 @@ describe('Client#$waitForReady', function() {
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('should complete when called alone', function(done) {
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
done();
});
});
it('should complete when a call is initiated', function(done) {
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
done();
});
@@ -166,19 +184,19 @@ describe('Client#$waitForReady', function() {
});
it('should complete if called more than once', function(done) {
done = multiDone(done, 2);
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
done();
});
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
done();
});
});
it('should complete if called when already ready', function(done) {
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
- client.$waitForReady(Infinity, function(error) {
+ grpc.waitForClientReady(client, Infinity, function(error) {
assert.ifError(error);
done();
});
@@ -203,7 +221,7 @@ describe('Echo service', function() {
server.start();
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('should echo the recieved message directly', function(done) {
client.echo({value: 'test value', value2: 3}, function(error, response) {
@@ -248,7 +266,7 @@ describe('Generic client and server', function() {
grpc.Credentials.createInsecure());
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('Should respond with a capitalized string', function(done) {
client.capitalize('abc', function(err, response) {
@@ -262,6 +280,7 @@ describe('Generic client and server', function() {
describe('Echo metadata', function() {
var client;
var server;
+ var metadata;
before(function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
var test_service = test_proto.lookup('TestService');
@@ -294,42 +313,44 @@ describe('Echo metadata', function() {
var Client = surface_client.makeProtobufClientConstructor(test_service);
client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
server.start();
+ metadata = new grpc.Metadata();
+ metadata.set('key', 'value');
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('with unary call', function(done) {
var call = client.unary({}, function(err, data) {
assert.ifError(err);
- }, {key: ['value']});
+ }, metadata);
call.on('metadata', function(metadata) {
- assert.deepEqual(metadata.key, ['value']);
+ assert.deepEqual(metadata.get('key'), ['value']);
done();
});
});
it('with client stream call', function(done) {
var call = client.clientStream(function(err, data) {
assert.ifError(err);
- }, {key: ['value']});
+ }, metadata);
call.on('metadata', function(metadata) {
- assert.deepEqual(metadata.key, ['value']);
+ assert.deepEqual(metadata.get('key'), ['value']);
done();
});
call.end();
});
it('with server stream call', function(done) {
- var call = client.serverStream({}, {key: ['value']});
+ var call = client.serverStream({}, metadata);
call.on('data', function() {});
call.on('metadata', function(metadata) {
- assert.deepEqual(metadata.key, ['value']);
+ assert.deepEqual(metadata.get('key'), ['value']);
done();
});
});
it('with bidi stream call', function(done) {
- var call = client.bidiStream({key: ['value']});
+ var call = client.bidiStream(metadata);
call.on('data', function() {});
call.on('metadata', function(metadata) {
- assert.deepEqual(metadata.key, ['value']);
+ assert.deepEqual(metadata.get('key'), ['value']);
done();
});
call.end();
@@ -337,9 +358,10 @@ describe('Echo metadata', function() {
it('shows the correct user-agent string', function(done) {
var version = require('../package.json').version;
var call = client.unary({}, function(err, data) { assert.ifError(err); },
- {key: ['value']});
+ metadata);
call.on('metadata', function(metadata) {
- assert(_.startsWith(metadata['user-agent'], 'grpc-node/' + version));
+ assert(_.startsWith(metadata.get('user-agent')[0],
+ 'grpc-node/' + version));
done();
});
});
@@ -354,13 +376,15 @@ describe('Other conditions', function() {
var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
test_service = test_proto.lookup('TestService');
server = new grpc.Server();
+ var trailer_metadata = new grpc.Metadata();
+ trailer_metadata.add('trailer-present', 'yes');
server.addProtoService(test_service, {
unary: function(call, cb) {
var req = call.request;
if (req.error) {
- cb(new Error('Requested error'), null, {trailer_present: ['yes']});
+ cb(new Error('Requested error'), null, trailer_metadata);
} else {
- cb(null, {count: 1}, {trailer_present: ['yes']});
+ cb(null, {count: 1}, trailer_metadata);
}
},
clientStream: function(stream, cb){
@@ -369,14 +393,14 @@ describe('Other conditions', function() {
stream.on('data', function(data) {
if (data.error) {
errored = true;
- cb(new Error('Requested error'), null, {trailer_present: ['yes']});
+ cb(new Error('Requested error'), null, trailer_metadata);
} else {
count += 1;
}
});
stream.on('end', function() {
if (!errored) {
- cb(null, {count: count}, {trailer_present: ['yes']});
+ cb(null, {count: count}, trailer_metadata);
}
});
},
@@ -384,13 +408,13 @@ describe('Other conditions', function() {
var req = stream.request;
if (req.error) {
var err = new Error('Requested error');
- err.metadata = {trailer_present: ['yes']};
+ err.metadata = trailer_metadata;
stream.emit('error', err);
} else {
for (var i = 0; i < 5; i++) {
stream.write({count: i});
}
- stream.end({trailer_present: ['yes']});
+ stream.end(trailer_metadata);
}
},
bidiStream: function(stream) {
@@ -398,10 +422,8 @@ describe('Other conditions', function() {
stream.on('data', function(data) {
if (data.error) {
var err = new Error('Requested error');
- err.metadata = {
- trailer_present: ['yes'],
- count: ['' + count]
- };
+ err.metadata = trailer_metadata.clone();
+ err.metadata.add('count', '' + count);
stream.emit('error', err);
} else {
stream.write({count: count});
@@ -409,7 +431,7 @@ describe('Other conditions', function() {
}
});
stream.on('end', function() {
- stream.end({trailer_present: ['yes']});
+ stream.end(trailer_metadata);
});
}
});
@@ -419,10 +441,11 @@ describe('Other conditions', function() {
server.start();
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('channel.getTarget should be available', function() {
- assert.strictEqual(typeof client.channel.getTarget(), 'string');
+ assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(),
+ 'string');
});
describe('Server recieving bad input', function() {
var misbehavingClient;
@@ -510,7 +533,7 @@ describe('Other conditions', function() {
assert.ifError(err);
});
call.on('status', function(status) {
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -519,7 +542,7 @@ describe('Other conditions', function() {
assert(err);
});
call.on('status', function(status) {
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -531,7 +554,7 @@ describe('Other conditions', function() {
call.write({error: false});
call.end();
call.on('status', function(status) {
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -543,7 +566,7 @@ describe('Other conditions', function() {
call.write({error: true});
call.end();
call.on('status', function(status) {
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -552,7 +575,7 @@ describe('Other conditions', function() {
call.on('data', function(){});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -560,7 +583,7 @@ describe('Other conditions', function() {
var call = client.serverStream({error: true});
call.on('data', function(){});
call.on('error', function(error) {
- assert.deepEqual(error.metadata.trailer_present, ['yes']);
+ assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -572,7 +595,7 @@ describe('Other conditions', function() {
call.on('data', function(){});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
- assert.deepEqual(status.metadata.trailer_present, ['yes']);
+ assert.deepEqual(status.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -583,7 +606,7 @@ describe('Other conditions', function() {
call.end();
call.on('data', function(){});
call.on('error', function(error) {
- assert.deepEqual(error.metadata.trailer_present, ['yes']);
+ assert.deepEqual(error.metadata.get('trailer-present'), ['yes']);
done();
});
});
@@ -681,7 +704,7 @@ describe('Other conditions', function() {
});
afterEach(function() {
console.log('Shutting down server');
- proxy.shutdown();
+ proxy.forceShutdown();
});
describe('Cancellation', function() {
it('With a unary call', function(done) {
@@ -847,7 +870,7 @@ describe('Cancelling surface client', function() {
server.start();
});
after(function() {
- server.shutdown();
+ server.forceShutdown();
});
it('Should correctly cancel a unary call', function(done) {
var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 4eda499b1a..35f7e16af7 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -48,11 +48,112 @@
#import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h>
+#pragma mark gRPC errors
+
+// Domain of NSError objects produced by gRPC.
+extern NSString *const kGRPCErrorDomain;
+
+// gRPC error codes.
+// Note that a few of these are never produced by the gRPC libraries, but are of general utility for
+// server applications to produce.
+typedef NS_ENUM(NSUInteger, GRPCErrorCode) {
+ // The operation was cancelled (typically by the caller).
+ GRPCErrorCodeCancelled = 1,
+
+ // Unknown error. Errors raised by APIs that do not return enough error information may be
+ // converted to this error.
+ GRPCErrorCodeUnknown = 2,
+
+ // The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION.
+ // INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the
+ // server (e.g., a malformed file name).
+ GRPCErrorCodeInvalidArgument = 3,
+
+ // Deadline expired before operation could complete. For operations that change the state of the
+ // server, this error may be returned even if the operation has completed successfully. For
+ // example, a successful response from the server could have been delayed long enough for the
+ // deadline to expire.
+ GRPCErrorCodeDeadlineExceeded = 4,
+
+ // Some requested entity (e.g., file or directory) was not found.
+ GRPCErrorCodeNotFound = 5,
+
+ // Some entity that we attempted to create (e.g., file or directory) already exists.
+ GRPCErrorCodeAlreadyExists = 6,
+
+ // The caller does not have permission to execute the specified operation. PERMISSION_DENIED isn't
+ // used for rejections caused by exhausting some resource (RESOURCE_EXHAUSTED is used instead for
+ // those errors). PERMISSION_DENIED doesn't indicate a failure to identify the caller
+ // (UNAUTHENTICATED is used instead for those errors).
+ GRPCErrorCodePermissionDenied = 7,
+
+ // The request does not have valid authentication credentials for the operation (e.g. the caller's
+ // identity can't be verified).
+ GRPCErrorCodeUnauthenticated = 16,
+
+ // Some resource has been exhausted, perhaps a per-user quota.
+ GRPCErrorCodeResourceExhausted = 8,
+
+ // The RPC was rejected because the server is not in a state required for the procedure's
+ // execution. For example, a directory to be deleted may be non-empty, etc.
+ // The client should not retry until the server state has been explicitly fixed (e.g. by
+ // performing another RPC). The details depend on the service being called, and should be found in
+ // the NSError's userInfo.
+ GRPCErrorCodeFailedPrecondition = 9,
+
+ // The RPC was aborted, typically due to a concurrency issue like sequencer check failures,
+ // transaction aborts, etc. The client should retry at a higher-level (e.g., restarting a read-
+ // modify-write sequence).
+ GRPCErrorCodeAborted = 10,
+
+ // The RPC was attempted past the valid range. E.g., enumerating past the end of a list.
+ // Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state
+ // changes. For example, an RPC to get elements of a list will generate INVALID_ARGUMENT if asked
+ // to return the element at a negative index, but it will generate OUT_OF_RANGE if asked to return
+ // the element at an index past the current size of the list.
+ GRPCErrorCodeOutOfRange = 11,
+
+ // The procedure is not implemented or not supported/enabled in this server.
+ GRPCErrorCodeUnimplemented = 12,
+
+ // Internal error. Means some invariant expected by the server application or the gRPC library has
+ // been broken.
+ GRPCErrorCodeInternal = 13,
+
+ // The server is currently unavailable. This is most likely a transient condition and may be
+ // corrected by retrying with a backoff.
+ GRPCErrorCodeUnavailable = 14,
+
+ // Unrecoverable data loss or corruption.
+ GRPCErrorCodeDataLoss = 15,
+};
+
// Keys used in |NSError|'s |userInfo| dictionary to store the response headers and trailers sent by
// the server.
extern id const kGRPCHeadersKey;
extern id const kGRPCTrailersKey;
+#pragma mark GRPCCall
+
+// 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.
+// The keys of this container are the header names, which per the HTTP standard are case-
+// insensitive. They are stored in lowercase (which is how HTTP/2 mandates them on the wire), and
+// can only consist of ASCII characters.
+// 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
@@ -68,10 +169,8 @@ extern id const kGRPCTrailersKey;
//
// After the call is started, trying to modify this property is an error.
//
-// For convenience, the property is initialized to an empty NSMutableDictionary, and the setter
-// accepts (and copies) both mutable and immutable dictionaries.
-- (NSMutableDictionary *)requestHeaders; // nonatomic
-- (void)setRequestHeaders:(NSDictionary *)requestHeaders; // nonatomic, copy
+// The property is initialized to an empty NSMutableDictionary.
+@property(atomic, readonly) id<GRPCRequestHeaders> requestHeaders;
// This dictionary is populated with the HTTP headers received from the server. This happens before
// any response message is received from the server. It has the same structure as the request
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index ff5d1c5aaf..b6986bf59c 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -37,6 +37,7 @@
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
+#import "private/GRPCRequestHeaders.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h"
@@ -93,7 +94,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
// the response arrives.
GRPCCall *_retainSelf;
- NSMutableDictionary *_requestHeaders;
+ GRPCRequestHeaders *_requestHeaders;
}
@synthesize state = _state;
@@ -124,21 +125,11 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
_requestWriter = requestWriter;
- _requestHeaders = [NSMutableDictionary dictionary];
+ _requestHeaders = [[GRPCRequestHeaders alloc] initWithCall:self];
}
return self;
}
-#pragma mark Metadata
-
-- (NSMutableDictionary *)requestHeaders {
- return _requestHeaders;
-}
-
-- (void)setRequestHeaders:(NSDictionary *)requestHeaders {
- _requestHeaders = [NSMutableDictionary dictionaryWithDictionary:requestHeaders];
-}
-
#pragma mark Finish
- (void)finishWithError:(NSError *)errorOrNil {
@@ -230,10 +221,10 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
#pragma mark Send headers
-- (void)sendHeaders:(NSDictionary *)headers {
+- (void)sendHeaders:(id<GRPCRequestHeaders>)headers {
// TODO(jcanizales): Add error handlers for async failures
- [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc]
- initWithMetadata:headers ?: @{} handler:nil]]];
+ [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendMetadata alloc] initWithMetadata:headers
+ handler:nil]]];
}
#pragma mark GRXWriteable implementation
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index a7142d0f00..a8cd3a0e74 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -57,13 +57,16 @@
// Default initializer.
- (instancetype)initWithAddress:(NSString *)address {
+ if (!address) {
+ return nil;
+ }
// To provide a default port, we try to interpret the address. If it's just a host name without
// scheme and without port, we'll use port 443. If it has a scheme, we pass it untouched to the C
// gRPC library.
// TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched.
NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]];
- if (hostURL && !hostURL.port) {
+ if (hostURL.host && !hostURL.port) {
address = [hostURL.host stringByAppendingString:@":443"];
}
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
new file mode 100644
index 0000000000..1391b5725f
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#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;
+
+- (instancetype)initWithCall:(GRPCCall *)call;
+
+- (id)objectForKeyedSubscript:(NSString *)key;
+- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
+
+- (void)removeAllObjects;
+- (void)removeObjectForKey:(NSString *)key;
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
new file mode 100644
index 0000000000..761677ce50
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCRequestHeaders.m
@@ -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 "GRPCRequestHeaders.h"
+
+#import <Foundation/Foundation.h>
+
+#import "../GRPCCall.h"
+#import "NSDictionary+GRPC.h"
+
+// Used by the setter.
+static void CheckIsNonNilASCII(NSString *name, NSString* value) {
+ if (!value) {
+ [NSException raise:NSInvalidArgumentException format:@"%@ cannot be nil", name];
+ }
+ if (![value canBeConvertedToEncoding:NSASCIIStringEncoding]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"%@ %@ contains non-ASCII characters", name, value];
+ }
+}
+
+// Precondition: key isn't nil.
+static void CheckKeyValuePairIsValid(NSString *key, id value) {
+ if ([key hasSuffix:@"-bin"]) {
+ if (![value isKindOfClass:NSData.class]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Expected NSData value for header %@ ending in \"-bin\", "
+ @"instead got %@", key, value];
+ }
+ } else {
+ if (![value isKindOfClass:NSString.class]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Expected NSString value for header %@ not ending in \"-bin\", "
+ @"instead got %@", key, value];
+ }
+ CheckIsNonNilASCII(@"Text header value", (NSString *)value);
+ }
+}
+
+@implementation GRPCRequestHeaders {
+ __weak GRPCCall *_call;
+ NSMutableDictionary *_delegate;
+}
+
+- (instancetype)initWithCall:(GRPCCall *)call {
+ if ((self = [super init])) {
+ _call = call;
+ _delegate = [NSMutableDictionary dictionary];
+ }
+ return self;
+}
+
+- (void)checkCallIsNotStarted {
+ if (_call.state != GRXWriterStateNotStarted) {
+ [NSException raise:@"Invalid modification"
+ format:@"Cannot modify request headers after call is started"];
+ }
+}
+
+- (id)objectForKeyedSubscript:(NSString *)key {
+ return _delegate[key.lowercaseString];
+}
+
+- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key {
+ [self checkCallIsNotStarted];
+ CheckIsNonNilASCII(@"Header name", key);
+ key = key.lowercaseString;
+ CheckKeyValuePairIsValid(key, obj);
+ _delegate[key] = obj;
+}
+
+- (void)removeObjectForKey:(NSString *)key {
+ [self checkCallIsNotStarted];
+ [_delegate removeObjectForKey:key.lowercaseString];
+}
+
+- (void)removeAllObjects {
+ [self checkCallIsNotStarted];
+ [_delegate removeAllObjects];
+}
+
+- (NSUInteger)count {
+ return _delegate.count;
+}
+
+- (grpc_metadata *)grpc_metadataArray {
+ return _delegate.grpc_metadataArray;
+}
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
index 0a54804bb2..ce16655330 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
@@ -49,7 +49,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr)
// Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
return NULL;
}
- return grpc_ssl_credentials_create(contentInASCII.bytes, NULL);
+ return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
}
@implementation GRPCSecureChannel
@@ -101,8 +101,9 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr)
- (instancetype)initWithHost:(NSString *)host
credentials:(grpc_credentials *)credentials
args:(grpc_channel_args *)args {
- return (self =
- [super initWithChannel:grpc_secure_channel_create(credentials, host.UTF8String, args)]);
+ return (self = [super
+ initWithChannel:grpc_secure_channel_create(
+ credentials, host.UTF8String, args, NULL)]);
}
// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index da11cbb761..4ca2766147 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -35,6 +35,7 @@
#include <grpc/grpc.h>
#import "GRPCChannel.h"
+#import "GRPCRequestHeaders.h"
@interface GRPCOperation : NSObject
@property(nonatomic, readonly) grpc_op op;
@@ -44,7 +45,7 @@
@interface GRPCOpSendMetadata : GRPCOperation
-- (instancetype)initWithMetadata:(NSDictionary *)metadata
+- (instancetype)initWithMetadata:(GRPCRequestHeaders *)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 fe3d51da53..cea7c479e0 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:(NSDictionary *)metadata handler:(void (^)())handler {
+- (instancetype)initWithMetadata:(GRPCRequestHeaders *)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/GRPCClient/private/NSDictionary+GRPC.m b/src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
index 99c890e4ee..7477da7619 100644
--- a/src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
+++ b/src/objective-c/GRPCClient/private/NSDictionary+GRPC.m
@@ -40,8 +40,8 @@
@interface NSData (GRPCMetadata)
+ (instancetype)grpc_dataFromMetadataValue:(grpc_metadata *)metadata;
-// Fill a metadata object with the binary value in this NSData and the given key.
-- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key;
+// Fill a metadata object with the binary value in this NSData.
+- (void)grpc_initMetadata:(grpc_metadata *)metadata;
@end
@implementation NSData (GRPCMetadata)
@@ -50,9 +50,7 @@
return [self dataWithBytes:metadata->value length:metadata->value_length];
}
-- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key {
- // TODO(jcanizales): Encode Unicode chars as ASCII.
- metadata->key = [key stringByAppendingString:@"-bin"].UTF8String;
+- (void)grpc_initMetadata:(grpc_metadata *)metadata {
metadata->value = self.bytes;
metadata->value_length = self.length;
}
@@ -63,8 +61,8 @@
@interface NSString (GRPCMetadata)
+ (instancetype)grpc_stringFromMetadataValue:(grpc_metadata *)metadata;
-// Fill a metadata object with the textual value in this NSString and the given key.
-- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key;
+// Fill a metadata object with the textual value in this NSString.
+- (void)grpc_initMetadata:(grpc_metadata *)metadata;
@end
@implementation NSString (GRPCMetadata)
@@ -74,22 +72,8 @@
encoding:NSASCIIStringEncoding];
}
-- (void)grpc_initMetadata:(grpc_metadata *)metadata withKey:(NSString *)key {
- if ([key hasSuffix:@"-bin"]) {
- // Disallow this, as at best it will confuse the server. If the app really needs to send a
- // textual header with a name ending in "-bin", it can be done by removing the suffix and
- // encoding the NSString as a NSData object.
- //
- // Why raise an exception: In the most common case, the developer knows this won't happen in
- // their code, so the exception isn't triggered. In the rare cases when the developer can't
- // tell, it's easy enough to add a sanitizing filter before the header is set. There, the
- // developer can choose whether to drop such a header, or trim its name. Doing either ourselves,
- // silently, would be very unintuitive for the user.
- [NSException raise:NSInvalidArgumentException
- format:@"Metadata keys ending in '-bin' are reserved for NSData values."];
- }
- // TODO(jcanizales): Encode Unicode chars as ASCII.
- metadata->key = key.UTF8String;
+// Precondition: This object contains only ASCII characters.
+- (void)grpc_initMetadata:(grpc_metadata *)metadata {
metadata->value = self.UTF8String;
metadata->value_length = self.length;
}
@@ -105,8 +89,6 @@
+ (instancetype)grpc_dictionaryFromMetadata:(grpc_metadata *)entries count:(size_t)count {
NSMutableDictionary *metadata = [NSMutableDictionary dictionaryWithCapacity:count];
for (grpc_metadata *entry = entries; entry < entries + count; entry++) {
- // TODO(jcanizales): Verify in a C library test that it's converting header names to lower case
- // automatically.
NSString *name = [NSString stringWithCString:entry->key encoding:NSASCIIStringEncoding];
if (!name || metadata[name]) {
// Log if name is nil?
@@ -114,7 +96,6 @@
}
id value;
if ([name hasSuffix:@"-bin"]) {
- name = [name substringToIndex:name.length - 4];
value = [NSData grpc_dataFromMetadataValue:entry];
} else {
value = [NSString grpc_stringFromMetadataValue:entry];
@@ -124,19 +105,21 @@
return metadata;
}
+// Preconditions: All keys are ASCII strings. Keys ending in -bin have NSData values; the others
+// have NSString values.
- (grpc_metadata *)grpc_metadataArray {
grpc_metadata *metadata = gpr_malloc([self count] * sizeof(grpc_metadata));
- int i = 0;
- for (id key in self) {
+ grpc_metadata *current = metadata;
+ for (NSString* key in self) {
id value = self[key];
- grpc_metadata *current = &metadata[i];
- if ([value respondsToSelector:@selector(grpc_initMetadata:withKey:)]) {
- [value grpc_initMetadata:current withKey:key];
+ current->key = key.UTF8String;
+ if ([value respondsToSelector:@selector(grpc_initMetadata:)]) {
+ [value grpc_initMetadata:current];
} else {
[NSException raise:NSInvalidArgumentException
format:@"Metadata values must be NSString or NSData."];
}
- i += 1;
+ ++current;
}
return metadata;
}
diff --git a/src/objective-c/GRPCClient/private/NSError+GRPC.h b/src/objective-c/GRPCClient/private/NSError+GRPC.h
index e712791271..f4729dc8a1 100644
--- a/src/objective-c/GRPCClient/private/NSError+GRPC.h
+++ b/src/objective-c/GRPCClient/private/NSError+GRPC.h
@@ -34,29 +34,6 @@
#import <Foundation/Foundation.h>
#include <grpc/grpc.h>
-// TODO(jcanizales): Make the domain string public.
-extern NSString *const kGRPCErrorDomain;
-
-// TODO(jcanizales): Make this public and document each code.
-typedef NS_ENUM(NSInteger, GRPCErrorCode) {
- GRPCErrorCodeCancelled = 1,
- GRPCErrorCodeUnknown = 2,
- GRPCErrorCodeInvalidArgument = 3,
- GRPCErrorCodeDeadlineExceeded = 4,
- GRPCErrorCodeNotFound = 5,
- GRPCErrorCodeAlreadyExists = 6,
- GRPCErrorCodePermissionDenied = 7,
- GRPCErrorCodeUnauthenticated = 16,
- GRPCErrorCodeResourceExhausted = 8,
- GRPCErrorCodeFailedPrecondition = 9,
- GRPCErrorCodeAborted = 10,
- GRPCErrorCodeOutOfRange = 11,
- GRPCErrorCodeUnimplemented = 12,
- GRPCErrorCodeInternal = 13,
- GRPCErrorCodeUnavailable = 14,
- GRPCErrorCodeDataLoss = 15
-};
-
@interface NSError (GRPC)
// Returns nil if the status code is OK. Otherwise, a NSError whose code is one of |GRPCErrorCode|
// and whose domain is |kGRPCErrorDomain|.
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
index 889d71a308..9bf66f347a 100644
--- a/src/objective-c/ProtoRPC/ProtoRPC.m
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -37,6 +37,22 @@
#import <RxLibrary/GRXWriteable.h>
#import <RxLibrary/GRXWriter+Transformations.h>
+static NSError *ErrorForBadProto(id proto, Class expectedClass, NSError *parsingError) {
+ NSDictionary *info = @{
+ NSLocalizedDescriptionKey: @"Unable to parse response from the server",
+ NSLocalizedRecoverySuggestionErrorKey: @"If this RPC is idempotent, retry "
+ @"with exponential backoff. Otherwise, query the server status before "
+ @"retrying.",
+ NSUnderlyingErrorKey: parsingError,
+ @"Expected class": expectedClass,
+ @"Received value": proto,
+ };
+ // TODO(jcanizales): Use kGRPCErrorDomain and GRPCErrorCodeInternal when they're public.
+ return [NSError errorWithDomain:@"io.grpc"
+ code:13
+ userInfo:info];
+}
+
@implementation ProtoRPC {
id<GRXWriteable> _responseWriteable;
}
@@ -65,14 +81,25 @@
}
// A writer that serializes the proto messages to send.
GRXWriter *bytesWriter = [requestsWriter map:^id(GPBMessage *proto) {
- // TODO(jcanizales): Fail with an understandable error message if the requestsWriter isn't
- // sending GPBMessages.
+ if (![proto isKindOfClass:GPBMessage.class]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Request must be a proto message: %@", proto];
+ }
return [proto data];
}];
if ((self = [super initWithHost:host path:method.HTTPPath requestsWriter:bytesWriter])) {
+ __weak ProtoRPC *weakSelf = self;
+
// A writeable that parses the proto messages received.
_responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
- [responsesWriteable writeValue:[responseClass parseFromData:value error:NULL]];
+ // TODO(jcanizales): This is done in the main thread, and needs to happen in another thread.
+ NSError *error = nil;
+ id parsed = [responseClass parseFromData:value error:&error];
+ if (parsed) {
+ [responsesWriteable writeValue:parsed];
+ } else {
+ [weakSelf finishWithError:ErrorForBadProto(value, responseClass, error)];
+ }
} completionHandler:^(NSError *errorOrNil) {
[responsesWriteable writesFinishedWithError:errorOrNil];
}];
diff --git a/src/objective-c/README.md b/src/objective-c/README.md
index e997b76d14..6c27657def 100644
--- a/src/objective-c/README.md
+++ b/src/objective-c/README.md
@@ -30,7 +30,7 @@ proceed.
## Write your API declaration in proto format
For this you can consult the [Protocol Buffers][]' official documentation, or learn from a quick
-example [here](https://github.com/grpc/grpc-common#defining-a-service).
+example [here](https://github.com/grpc/grpc/tree/master/examples#defining-a-service).
<a name="cocoapods"></a>
## Integrate a proto library in your project
diff --git a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
new file mode 100644
index 0000000000..d4f8084cb5
--- /dev/null
+++ b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
@@ -0,0 +1,28 @@
+Pod::Spec.new do |s|
+ s.name = "RemoteTest"
+ s.version = "0.0.1"
+ s.license = "New BSD"
+
+ s.ios.deployment_target = "6.0"
+ s.osx.deployment_target = "10.8"
+
+ # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
+ s.prepare_command = <<-CMD
+ protoc --objc_out=. --objcgrpc_out=. *.proto
+ CMD
+
+ s.subspec "Messages" do |ms|
+ ms.source_files = "*.pbobjc.{h,m}"
+ ms.header_mappings_dir = "."
+ ms.requires_arc = false
+ ms.dependency "Protobuf", "~> 3.0.0-alpha-4"
+ end
+
+ s.subspec "Services" do |ss|
+ ss.source_files = "*.pbrpc.{h,m}"
+ ss.header_mappings_dir = "."
+ ss.requires_arc = true
+ ss.dependency "gRPC", "~> 0.7"
+ ss.dependency "#{s.name}/Messages"
+ end
+end
diff --git a/src/objective-c/examples/RemoteTestClient/empty.proto b/src/objective-c/examples/RemoteTestClient/empty.proto
new file mode 100644
index 0000000000..a678048289
--- /dev/null
+++ b/src/objective-c/examples/RemoteTestClient/empty.proto
@@ -0,0 +1,44 @@
+// 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.testing;
+
+option objc_class_prefix = "RMT";
+
+// An empty message that you can re-use to avoid defining duplicated empty
+// messages in your project. A typical example is to use it as argument or the
+// return value of a service API. For instance:
+//
+// service Foo {
+// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
+// };
+//
+message Empty {}
diff --git a/src/objective-c/examples/RemoteTestClient/messages.proto b/src/objective-c/examples/RemoteTestClient/messages.proto
new file mode 100644
index 0000000000..85d93c2ff9
--- /dev/null
+++ b/src/objective-c/examples/RemoteTestClient/messages.proto
@@ -0,0 +1,133 @@
+// 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.
+
+// Message definitions to be used by integration test service definitions.
+
+syntax = "proto3";
+
+package grpc.testing;
+
+option objc_class_prefix = "RMT";
+
+// The type of payload that should be returned.
+enum PayloadType {
+ // Compressable text format.
+ COMPRESSABLE = 0;
+
+ // Uncompressable binary format.
+ UNCOMPRESSABLE = 1;
+
+ // Randomly chosen from all other formats defined in this enum.
+ RANDOM = 2;
+}
+
+// A block of data, to simply increase gRPC message size.
+message Payload {
+ // The type of data in body.
+ PayloadType type = 1;
+ // Primary contents of payload.
+ bytes body = 2;
+}
+
+// Unary request.
+message SimpleRequest {
+ // Desired payload type in the response from the server.
+ // If response_type is RANDOM, server randomly chooses one from other formats.
+ PayloadType response_type = 1;
+
+ // Desired payload size in the response from the server.
+ // If response_type is COMPRESSABLE, this denotes the size before compression.
+ int32 response_size = 2;
+
+ // Optional input payload sent along with the request.
+ Payload payload = 3;
+
+ // Whether SimpleResponse should include username.
+ bool fill_username = 4;
+
+ // Whether SimpleResponse should include OAuth scope.
+ bool fill_oauth_scope = 5;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+ // Payload to increase message size.
+ Payload payload = 1;
+ // The user the request came from, for verifying authentication was
+ // successful when the client expected it.
+ string username = 2;
+ // OAuth scope.
+ string oauth_scope = 3;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+ // Optional input payload sent along with the request.
+ Payload payload = 1;
+
+ // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+ // Aggregated size of payloads received from the client.
+ int32 aggregated_payload_size = 1;
+}
+
+// Configuration for a particular response.
+message ResponseParameters {
+ // Desired payload sizes in responses from the server.
+ // If response_type is COMPRESSABLE, this denotes the size before compression.
+ int32 size = 1;
+
+ // Desired interval between consecutive responses in the response stream in
+ // microseconds.
+ int32 interval_us = 2;
+}
+
+// Server-streaming request.
+message StreamingOutputCallRequest {
+ // Desired payload type in the response from the server.
+ // If response_type is RANDOM, the payload from each response in the stream
+ // might be of different types. This is to simulate a mixed type of payload
+ // stream.
+ PayloadType response_type = 1;
+
+ // Configuration for each expected response message.
+ repeated ResponseParameters response_parameters = 2;
+
+ // Optional input payload sent along with the request.
+ Payload payload = 3;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+ // Payload to increase response size.
+ Payload payload = 1;
+}
diff --git a/src/objective-c/examples/RemoteTestClient/test.proto b/src/objective-c/examples/RemoteTestClient/test.proto
new file mode 100644
index 0000000000..2f5a5489b3
--- /dev/null
+++ b/src/objective-c/examples/RemoteTestClient/test.proto
@@ -0,0 +1,73 @@
+// 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.
+
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+syntax = "proto3";
+
+import "empty.proto";
+import "messages.proto";
+
+package grpc.testing;
+
+option objc_class_prefix = "RMT";
+
+// A simple service to test the various types of RPCs and experiment with
+// performance with various types of payload.
+service TestService {
+ // One empty request followed by one empty response.
+ rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
+
+ // One request followed by one response.
+ // TODO(Issue 527): Describe required server behavior.
+ rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
+
+ // One request followed by a sequence of responses (streamed download).
+ // The server returns the payload with client desired type and sizes.
+ rpc StreamingOutputCall(StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+
+ // A sequence of requests followed by one response (streamed upload).
+ // The server returns the aggregated size of client payload as the result.
+ rpc StreamingInputCall(stream StreamingInputCallRequest)
+ returns (StreamingInputCallResponse);
+
+ // A sequence of requests with each request served by the server immediately.
+ // As one request could lead to multiple responses, this interface
+ // demonstrates the idea of full duplexing.
+ rpc FullDuplexCall(stream StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+
+ // A sequence of requests followed by a sequence of responses.
+ // The server buffers all the client requests and then serves them in order. A
+ // stream of responses are returned to the client when the server starts with
+ // first request.
+ rpc HalfDuplexCall(stream StreamingOutputCallRequest)
+ returns (stream StreamingOutputCallResponse);
+}
diff --git a/src/core/census/record_stat.c b/src/objective-c/examples/SwiftSample/AppDelegate.swift
index 3dd918618b..88027d997b 100644
--- a/src/core/census/record_stat.c
+++ b/src/objective-c/examples/SwiftSample/AppDelegate.swift
@@ -31,8 +31,9 @@
*
*/
-#include <grpc/census.h>
-#include "src/core/census/rpc_stat_id.h"
+import UIKit
-void census_record_stat(census_context *context, census_stat *stats,
- size_t nstats) {}
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+ var window: UIWindow?
+}
diff --git a/src/objective-c/examples/SwiftSample/Base.lproj/Main.storyboard b/src/objective-c/examples/SwiftSample/Base.lproj/Main.storyboard
new file mode 100644
index 0000000000..3a2a49bad8
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
+ </dependencies>
+ <scenes>
+ <!--View Controller-->
+ <scene sceneID="tne-QT-ifu">
+ <objects>
+ <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+ <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+ </objects>
+ </scene>
+ </scenes>
+</document>
diff --git a/src/objective-c/examples/SwiftSample/Bridging-Header.h b/src/objective-c/examples/SwiftSample/Bridging-Header.h
new file mode 100644
index 0000000000..65f768a760
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/Bridging-Header.h
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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 SwiftSample_Bridging_Header_h
+#define SwiftSample_Bridging_Header_h
+
+#import <RxLibrary/GRXWriteable.h>
+#import <RxLibrary/GRXWriter.h>
+#import <RxLibrary/GRXWriter+Immediate.h>
+#import <GRPCClient/GRPCCall.h>
+#import <ProtoRPC/ProtoMethod.h>
+#import <ProtoRPC/ProtoRPC.h>
+#import <RemoteTest/Test.pbrpc.h>
+
+#endif
diff --git a/src/objective-c/examples/SwiftSample/Images.xcassets/AppIcon.appiconset/Contents.json b/src/objective-c/examples/SwiftSample/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000000..36d2c80d88
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/src/objective-c/examples/SwiftSample/Info.plist b/src/objective-c/examples/SwiftSample/Info.plist
new file mode 100644
index 0000000000..10f0450b34
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/Info.plist
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>io.grpc.$(PRODUCT_NAME:rfc1034identifier)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UILaunchStoryboardName</key>
+ <string>Main</string>
+ <key>UIMainStoryboardFile</key>
+ <string>Main</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/src/objective-c/examples/SwiftSample/Podfile b/src/objective-c/examples/SwiftSample/Podfile
new file mode 100644
index 0000000000..3611b00863
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/Podfile
@@ -0,0 +1,9 @@
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '8.0'
+
+pod 'Protobuf', :path => "../../../../third_party/protobuf"
+pod 'gRPC', :path => "../../../.."
+pod 'RemoteTest', :path => "../RemoteTestClient"
+
+target 'SwiftSample' do
+end
diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..cfccdd453f
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.pbxproj
@@ -0,0 +1,354 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 253D3A297105CA46DA960A11 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC58ACA18DCCB1553531B885 /* libPods.a */; };
+ 633BFFC81B950B210007E424 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC71B950B210007E424 /* AppDelegate.swift */; };
+ 633BFFCA1B950B210007E424 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 633BFFC91B950B210007E424 /* ViewController.swift */; };
+ 633BFFCD1B950B210007E424 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCB1B950B210007E424 /* Main.storyboard */; };
+ 633BFFCF1B950B210007E424 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 633BFFCE1B950B210007E424 /* Images.xcassets */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
+ 633BFFC21B950B210007E424 /* SwiftSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 633BFFC61B950B210007E424 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 633BFFC71B950B210007E424 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+ 633BFFC91B950B210007E424 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
+ 633BFFCC1B950B210007E424 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 633BFFCE1B950B210007E424 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 6367AD231B951655007FD3A4 /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
+ C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+ DC58ACA18DCCB1553531B885 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 633BFFBF1B950B210007E424 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 253D3A297105CA46DA960A11 /* libPods.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 31F283C976AE97586C17CCD9 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */,
+ C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ 633BFFB91B950B210007E424 = {
+ isa = PBXGroup;
+ children = (
+ 633BFFC41B950B210007E424 /* SwiftSample */,
+ 633BFFC31B950B210007E424 /* Products */,
+ 31F283C976AE97586C17CCD9 /* Pods */,
+ 9D63A7F6423989BA306810CA /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 633BFFC31B950B210007E424 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 633BFFC21B950B210007E424 /* SwiftSample.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 633BFFC41B950B210007E424 /* SwiftSample */ = {
+ isa = PBXGroup;
+ children = (
+ 633BFFC71B950B210007E424 /* AppDelegate.swift */,
+ 633BFFC91B950B210007E424 /* ViewController.swift */,
+ 633BFFCB1B950B210007E424 /* Main.storyboard */,
+ 633BFFCE1B950B210007E424 /* Images.xcassets */,
+ 633BFFC51B950B210007E424 /* Supporting Files */,
+ 6367AD231B951655007FD3A4 /* Bridging-Header.h */,
+ );
+ name = SwiftSample;
+ sourceTree = SOURCE_ROOT;
+ };
+ 633BFFC51B950B210007E424 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 633BFFC61B950B210007E424 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 9D63A7F6423989BA306810CA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ DC58ACA18DCCB1553531B885 /* libPods.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 633BFFC11B950B210007E424 /* SwiftSample */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */;
+ buildPhases = (
+ 6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */,
+ 633BFFBE1B950B210007E424 /* Sources */,
+ 633BFFBF1B950B210007E424 /* Frameworks */,
+ 633BFFC01B950B210007E424 /* Resources */,
+ AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftSample;
+ productName = SwiftSample;
+ productReference = 633BFFC21B950B210007E424 /* SwiftSample.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 633BFFBA1B950B210007E424 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0640;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 633BFFC11B950B210007E424 = {
+ CreatedOnToolsVersion = 6.4;
+ };
+ };
+ };
+ buildConfigurationList = 633BFFBD1B950B210007E424 /* Build configuration list for PBXProject "SwiftSample" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 633BFFB91B950B210007E424;
+ productRefGroup = 633BFFC31B950B210007E424 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 633BFFC11B950B210007E424 /* SwiftSample */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 633BFFC01B950B210007E424 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 633BFFCD1B950B210007E424 /* Main.storyboard in Resources */,
+ 633BFFCF1B950B210007E424 /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 6BEEB33CA2705D7D2F2210E6 /* Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Check Pods Manifest.lock";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
+ showEnvVarsInLog = 0;
+ };
+ AC2F6F9AB1C090BB0BEE6E4D /* Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Pods Resources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 633BFFBE1B950B210007E424 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 633BFFCA1B950B210007E424 /* ViewController.swift in Sources */,
+ 633BFFC81B950B210007E424 /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 633BFFCB1B950B210007E424 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 633BFFCC1B950B210007E424 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 633BFFDF1B950B210007E424 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.4;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 633BFFE01B950B210007E424 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.4;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 633BFFE21B950B210007E424 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 12C7B447AA80E624D93B5C54 /* Pods.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h";
+ USER_HEADER_SEARCH_PATHS = "Pods/**";
+ };
+ name = Debug;
+ };
+ 633BFFE31B950B210007E424 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C335CBC4C160E0D9EDEE646B /* Pods.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Bridging-Header.h";
+ USER_HEADER_SEARCH_PATHS = "Pods/**";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 633BFFBD1B950B210007E424 /* Build configuration list for PBXProject "SwiftSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 633BFFDF1B950B210007E424 /* Debug */,
+ 633BFFE01B950B210007E424 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 633BFFE11B950B210007E424 /* Build configuration list for PBXNativeTarget "SwiftSample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 633BFFE21B950B210007E424 /* Debug */,
+ 633BFFE31B950B210007E424 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 633BFFBA1B950B210007E424 /* Project object */;
+}
diff --git a/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000000..3b0f1c15b2
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/SwiftSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:SwiftSample.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/src/objective-c/examples/SwiftSample/ViewController.swift b/src/objective-c/examples/SwiftSample/ViewController.swift
new file mode 100644
index 0000000000..76dad9e132
--- /dev/null
+++ b/src/objective-c/examples/SwiftSample/ViewController.swift
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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 UIKit
+
+class ViewController: UIViewController {
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ let RemoteHost = "grpc-test.sandbox.google.com"
+
+ let request = RMTSimpleRequest()
+ request.responseSize = 10
+ request.fillUsername = true
+ request.fillOauthScope = true
+
+
+ // Example gRPC call using a generated proto client library:
+
+ let service = RMTTestService(host: RemoteHost)
+ service.unaryCallWithRequest(request) { response, error in
+ if let response = response {
+ NSLog("1. Finished successfully with response:\n\(response)")
+ } else {
+ NSLog("1. Finished with error: \(error!)")
+ }
+ }
+
+
+ // Same but manipulating headers:
+
+ var RPC : ProtoRPC! // Needed to convince Swift to capture by reference (__block)
+ RPC = service.RPCToUnaryCallWithRequest(request) { response, error in
+ if let response = response {
+ NSLog("2. Finished successfully with response:\n\(response)")
+ } else {
+ NSLog("2. Finished with error: \(error!)")
+ }
+ NSLog("2. Response headers: \(RPC.responseHeaders)")
+ NSLog("2. Response trailers: \(RPC.responseTrailers)")
+ }
+
+ RPC.requestHeaders["My-Header"] = "My value"
+
+ RPC.start()
+
+
+ // Same example call using the generic gRPC client library:
+
+ let method = ProtoMethod(package: "grpc.testing", service: "TestService", method: "UnaryCall")
+
+ let requestsWriter = GRXWriter(value: request.data())
+
+ let call = GRPCCall(host: RemoteHost, path: method.HTTPPath, requestsWriter: requestsWriter)
+
+ call.requestHeaders["My-Header"] = "My value"
+
+ call.startWithWriteable(GRXWriteable { response, error in
+ if let response = response as? NSData {
+ NSLog("3. Received response:\n\(RMTSimpleResponse(data: response, error: nil))")
+ } else {
+ NSLog("3. Finished with error: \(error!)")
+ }
+ NSLog("3. Response headers: \(call.responseHeaders)")
+ NSLog("3. Response trailers: \(call.responseTrailers)")
+ })
+ }
+}
diff --git a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto b/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto
index dace1a5d26..19592e2ebd 100644
--- a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto
+++ b/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto
@@ -29,7 +29,7 @@
syntax = "proto3";
-package examples;
+package routeguide;
option objc_class_prefix = "RGD";
diff --git a/src/objective-c/tests/LocalClearTextTests.m b/src/objective-c/tests/LocalClearTextTests.m
index 4317614dd9..976fff55bc 100644
--- a/src/objective-c/tests/LocalClearTextTests.m
+++ b/src/objective-c/tests/LocalClearTextTests.m
@@ -42,12 +42,12 @@
#import <RxLibrary/GRXWriter+Immediate.h>
// These tests require a gRPC "RouteGuide" sample server to be running locally. You can compile and
-// run one by following the instructions here: https://github.com/grpc/grpc-common/blob/master/cpp/cpptutorial.md#try-it-out
+// run one by following the instructions here: https://github.com/grpc/grpc/blob/master/examples/cpp/cpptutorial.md#try-it-out
// Be sure to have the C gRPC library installed in your system (for example, by having followed the
// instructions at https://github.com/grpc/homebrew-grpc
static NSString * const kRouteGuideHost = @"http://localhost:50051";
-static NSString * const kPackage = @"examples";
+static NSString * const kPackage = @"routeguide";
static NSString * const kService = @"RouteGuide";
@interface LocalClearTextTests : XCTestCase
diff --git a/src/php/README.md b/src/php/README.md
index f432935fde..51322c7526 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -32,10 +32,10 @@ $ sudo php -d detect_unicode=0 go-pear.phar
**Linux (Debian):**
-Add [Debian unstable][] to your `sources.list` file. Example:
+Add [Debian jessie-backports][] to your `sources.list` file. Example:
```sh
-echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+echo "deb http://http.debian.net/debian jessie-backports main" | \
sudo tee -a /etc/apt/sources.list
```
@@ -73,29 +73,24 @@ This will download and run the [gRPC install script][] and compile the gRPC PHP
Clone this repository
-```
+```sh
$ git clone https://github.com/grpc/grpc.git
```
-Build and install the Protocol Buffers compiler (protoc)
+Build and install the gRPC C core libraries
-```
+```sh
$ cd grpc
$ git pull --recurse-submodules && git submodule update --init --recursive
-$ cd third_party/protobuf
-$ ./autogen.sh
-$ ./configure
$ make
-$ make check
$ sudo make install
```
-Build and install the gRPC C core libraries
+Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
```sh
-$ cd grpc
-$ make
-$ sudo make install
+$ cd grpc/third_party/protobuf
+$ sudo make install # 'make' should have been run by core grpc
```
Install the gRPC PHP extension
@@ -172,4 +167,4 @@ $ ./bin/run_gen_code_test.sh
[homebrew]:http://brew.sh
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/src/node/examples
-[Debian unstable]:https://www.debian.org/releases/sid/
+[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/php/composer.json b/src/php/composer.json
index 2d0fe0c87a..1d41f847ac 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -1,7 +1,7 @@
{
"name": "grpc/grpc",
"description": "gRPC library for PHP",
- "version": "0.5.1",
+ "version": "0.6.0",
"homepage": "http://grpc.io",
"license": "BSD-3-Clause",
"repositories": [
diff --git a/src/php/ext/grpc/README.md b/src/php/ext/grpc/README.md
index 88d2c481ec..6e1cb2002f 100644
--- a/src/php/ext/grpc/README.md
+++ b/src/php/ext/grpc/README.md
@@ -4,7 +4,7 @@ gRPC PHP Extension
# Requirements
* PHP 5.5+
- * [gRPC core library](https://github.com/grpc/grpc) 0.10.0
+ * [gRPC core library](https://github.com/grpc/grpc) 0.11.0
# Installation
@@ -22,26 +22,21 @@ Clone the gRPC source code repository
$ git clone https://github.com/grpc/grpc.git
```
-Build and install the Protocol Buffers compiler (protoc)
+Build and install the gRPC C core libraries
-```
-$ # from grpc
-$ git checkout --track origin/release-0_9
+```sh
+$ cd grpc
+$ git checkout --track origin/release-0_11
$ git pull --recurse-submodules && git submodule update --init --recursive
-$ cd third_party/protobuf
-$ ./autogen.sh
-$ ./configure
$ make
-$ make check
$ sudo make install
```
-Build and install the gRPC C core library
+Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
```sh
-$ # from grpc
-$ make
-$ sudo make install
+$ cd grpc/third_party/protobuf
+$ sudo make install # 'make' should have been run by core grpc
```
## Install the gRPC PHP extension
@@ -55,7 +50,7 @@ $ sudo pecl install grpc
Note: before a stable release, you may need to do
```sh
-$ sudo pecl install grpc-0.5.1
+$ sudo pecl install grpc-beta
```
OR
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 252623d0c3..3b99de7538 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -265,6 +265,9 @@ PHP_METHOD(Call, startBatch) {
HashTable *array_hash;
HashPosition array_pointer;
HashTable *status_hash;
+ HashTable *message_hash;
+ zval **message_value;
+ zval **message_flags;
char *key;
uint key_len;
ulong index;
@@ -319,13 +322,33 @@ PHP_METHOD(Call, startBatch) {
metadata.metadata;
break;
case GRPC_OP_SEND_MESSAGE:
- if (Z_TYPE_PP(value) != IS_STRING) {
+ if (Z_TYPE_PP(value) != IS_ARRAY) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Expected an array for send message",
+ 1 TSRMLS_CC);
+ goto cleanup;
+ }
+ message_hash = Z_ARRVAL_PP(value);
+ if (zend_hash_find(message_hash, "flags", sizeof("flags"),
+ (void **)&message_flags) == SUCCESS) {
+ if (Z_TYPE_PP(message_flags) != IS_LONG) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "Expected an int for message flags",
+ 1 TSRMLS_CC);
+ }
+ ops[op_num].flags = Z_LVAL_PP(message_flags) & GRPC_WRITE_USED_MASK;
+ }
+ if (zend_hash_find(message_hash, "message", sizeof("message"),
+ (void **)&message_value) != SUCCESS ||
+ Z_TYPE_PP(message_value) != IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Expected a string for send message",
1 TSRMLS_CC);
+ goto cleanup;
}
ops[op_num].data.send_message =
- string_to_byte_buffer(Z_STRVAL_PP(value), Z_STRLEN_PP(value));
+ string_to_byte_buffer(Z_STRVAL_PP(message_value),
+ Z_STRLEN_PP(message_value));
break;
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
break;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index 7a981675de..a4313b6bd4 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -169,7 +169,7 @@ PHP_METHOD(Channel, __construct) {
} else {
gpr_log(GPR_DEBUG, "Initialized secure channel");
channel->wrapped =
- grpc_secure_channel_create(creds->wrapped, target, &args);
+ grpc_secure_channel_create(creds->wrapped, target, &args, NULL);
}
efree(args.args);
}
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index 01cb94e3aa..8e3b7ff212 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -130,7 +130,7 @@ PHP_METHOD(Credentials, createSsl) {
}
grpc_credentials *creds = grpc_ssl_credentials_create(
pem_root_certs,
- pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair);
+ pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
@@ -160,7 +160,7 @@ PHP_METHOD(Credentials, createComposite) {
(wrapped_grpc_credentials *)zend_object_store_get_object(
cred2_obj TSRMLS_CC);
grpc_credentials *creds =
- grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped);
+ grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped, NULL);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
@@ -170,7 +170,7 @@ PHP_METHOD(Credentials, createComposite) {
* @return Credentials The new GCE credentials object
*/
PHP_METHOD(Credentials, createGce) {
- grpc_credentials *creds = grpc_compute_engine_credentials_create();
+ grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index bc2a05923b..381ae23b45 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,43 +10,48 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2015-07-09</date>
- <time>21:47:27</time>
+ <date>2015-09-01</date>
+ <time>13:37:33</time>
<version>
- <release>0.5.1</release>
- <api>0.5.1</api>
+ <release>0.6.0</release>
+ <api>0.6.0</api>
</version>
<stability>
- <release>alpha</release>
- <api>alpha</api>
+ <release>beta</release>
+ <api>beta</api>
</stability>
<license>BSD</license>
<notes>
-Update to wrap gRPC C Core version 0.10.0
+ - support per message compression disable
+ - expose per-call host override option
+ - expose connectivity API
+ - expose channel target and call peer
+ - add user-agent
+ - update to wrap gRPC C core library beta version 0.11.0
</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="cb45b62f767ae7b4377761df696649fc" name="call.c" role="src" />
+ <file baseinstalldir="/" md5sum="d64c9005993de02abac55664b0b9e0b2" name="call.c" role="src" />
<file baseinstalldir="/" md5sum="26acbf04c30162c2d2aca4688bb2aec8" name="call.h" role="src" />
- <file baseinstalldir="/" md5sum="50837fbdb2892795f1871b22e5979762" name="channel.c" role="src" />
- <file baseinstalldir="/" md5sum="f1b66029daeced20b47cf00cc6523fc8" name="channel.h" role="src" />
- <file baseinstalldir="/" md5sum="81a1193e93d8b6602add8ac360de565b" name="completion_queue.c" role="src" />
+ <file baseinstalldir="/" md5sum="15e56239b32c803f073e8a2b9f96e8c3" name="channel.c" role="src" />
+ <file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
+ <file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
<file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
<file baseinstalldir="/" md5sum="a22f8eac0164761058cc4d9eb2ceb069" name="config.m4" role="src" />
- <file baseinstalldir="/" md5sum="8c3f1e11dac623001378bfd53b554f08" name="credentials.c" role="src" />
+ <file baseinstalldir="/" md5sum="588752c908f7bc1663f7b8fc922ae661" name="credentials.c" role="src" />
<file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
<file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
<file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
- <file baseinstalldir="/" md5sum="6aaa7a290122d230f2d8c4e4e05da4a9" name="php_grpc.c" role="src" />
+ <file baseinstalldir="/" md5sum="6a550516a1423def0786851c76f87c85" name="php_grpc.c" role="src" />
<file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
<file baseinstalldir="/" md5sum="c1d0b42fd77b7d6740bf7744bee90af5" name="README.md" role="doc" />
- <file baseinstalldir="/" md5sum="30997dd423403e1f8ad09dcee598e5c4" name="server.c" role="src" />
+ <file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
<file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
- <file baseinstalldir="/" md5sum="f6930beafb6c0e061899262f2f077e98" name="server_credentials.c" role="src" />
+ <file baseinstalldir="/" md5sum="34ea881f1fe960d190d0713422cf8916" name="server_credentials.c" role="src" />
<file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
- <file baseinstalldir="/" md5sum="c89c623cd17177ebde18313fc5c17122" name="timeval.c" role="src" />
+ <file baseinstalldir="/" md5sum="7646ec78cb133f66ba59e03c6f451e39" name="timeval.c" role="src" />
<file baseinstalldir="/" md5sum="496e27a100b4d93ca3fb35c924c5e163" name="timeval.h" role="src" />
</dir>
</contents>
@@ -93,5 +98,25 @@ First alpha release
Update to wrap gRPC C Core version 0.10.0
</notes>
</release>
+ <release>
+ <version>
+ <release>0.6.0</release>
+ <api>0.6.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2015-09-01</date>
+ <license>BSD</license>
+ <notes>
+ - support per message compression disable
+ - expose per-call host override option
+ - expose connectivity API
+ - expose channel target and call peer
+ - add user-agent
+ - update to wrap gRPC C core library beta version 0.11.0
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index e9183c4598..79188246bc 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -118,7 +118,7 @@ PHP_METHOD(ServerCredentials, createSsl) {
/* TODO: add a force_client_auth field in ServerCredentials and pass it as
* the last parameter. */
grpc_server_credentials *creds = grpc_ssl_server_credentials_create(
- pem_root_certs, &pem_key_cert_pair, 1, 0);
+ pem_root_certs, &pem_key_cert_pair, 1, 0, NULL);
zval *creds_object = grpc_php_wrap_server_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index 35057224f8..a3c7a9e017 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -92,4 +92,4 @@ abstract class AbstractCall {
}
return call_user_func($this->deserialize, $value);
}
-} \ No newline at end of file
+}
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 2e980c5eed..381b114399 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -168,7 +168,8 @@ class BaseStub {
public function _simpleRequest($method,
$argument,
callable $deserialize,
- $metadata = array()) {
+ $metadata = array(),
+ $options = array()) {
list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata);
$call = new UnaryCall($this->channel, $method, $deserialize, $timeout);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
@@ -177,7 +178,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
- $call->start($argument, $actual_metadata);
+ $call->start($argument, $actual_metadata, $options);
return $call;
}
@@ -193,7 +194,6 @@ class BaseStub {
* @return ClientStreamingSurfaceActiveCall The active call object
*/
public function _clientStreamRequest($method,
- $arguments,
callable $deserialize,
$metadata = array()) {
list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata);
@@ -204,7 +204,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
- $call->start($arguments, $actual_metadata);
+ $call->start($actual_metadata);
return $call;
}
@@ -221,7 +221,8 @@ class BaseStub {
public function _serverStreamRequest($method,
$argument,
callable $deserialize,
- $metadata = array()) {
+ $metadata = array(),
+ $options = array()) {
list($actual_metadata, $timeout) = $this->_extract_timeout_from_metadata($metadata);
$call = new ServerStreamingCall($this->channel, $method, $deserialize, $timeout);
$jwt_aud_uri = $this->_get_jwt_aud_uri($method);
@@ -230,7 +231,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
- $call->start($argument, $actual_metadata);
+ $call->start($argument, $actual_metadata, $options);
return $call;
}
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index 76c642bef4..c432fd52d8 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -42,7 +42,7 @@ class BidiStreamingCall extends AbstractCall {
* Start the call
* @param array $metadata Metadata to send with the call, if applicable
*/
- public function start($metadata) {
+ public function start($metadata = array()) {
$this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
}
@@ -66,9 +66,15 @@ class BidiStreamingCall extends AbstractCall {
* Write a single message to the server. This cannot be called after
* writesDone is called.
* @param ByteBuffer $data The data to write
+ * @param array $options an array of options, possible keys:
+ * 'flags' => a number
*/
- public function write($data) {
- $this->call->startBatch([OP_SEND_MESSAGE => $data->serialize()]);
+ public function write($data, $options = array()) {
+ $message_array = ['message' => $data->serialize()];
+ if (isset($options['flags'])) {
+ $message_array['flags'] = $options['flags'];
+ }
+ $this->call->startBatch([OP_SEND_MESSAGE => $message_array]);
}
/**
@@ -86,7 +92,7 @@ class BidiStreamingCall extends AbstractCall {
public function getStatus() {
$status_event = $this->call->startBatch([
OP_RECV_STATUS_ON_CLIENT => true
- ]);
+ ]);
return $status_event->status;
}
} \ No newline at end of file
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 61439d3f47..b96c17e751 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -40,15 +40,25 @@ namespace Grpc;
class ClientStreamingCall extends AbstractCall {
/**
* Start the call.
- * @param Traversable $arg_iter The iterator of arguments to send
* @param array $metadata Metadata to send with the call, if applicable
*/
- public function start($arg_iter, $metadata = array()) {
- $event = $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
- foreach($arg_iter as $arg) {
- $this->call->startBatch([OP_SEND_MESSAGE => $arg->serialize()]);
+ public function start($metadata = array()) {
+ $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
+ }
+
+ /**
+ * Write a single message to the server. This cannot be called after
+ * wait is called.
+ * @param ByteBuffer $data The data to write
+ * @param array $options an array of options, possible keys:
+ * 'flags' => a number
+ */
+ public function write($data, $options = array()) {
+ $message_array = ['message' => $data->serialize()];
+ if (isset($options['flags'])) {
+ $message_array['flags'] = $options['flags'];
}
- $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]);
+ $this->call->startBatch([OP_SEND_MESSAGE => $message_array]);
}
/**
@@ -57,6 +67,7 @@ class ClientStreamingCall extends AbstractCall {
*/
public function wait() {
$event = $this->call->startBatch([
+ OP_SEND_CLOSE_FROM_CLIENT => true,
OP_RECV_INITIAL_METADATA => true,
OP_RECV_MESSAGE => true,
OP_RECV_STATUS_ON_CLIENT => true]);
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index 631c863345..a93c1a5d5e 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -40,14 +40,20 @@ namespace Grpc;
class ServerStreamingCall extends AbstractCall {
/**
* Start the call
- * @param $arg The argument to send
+ * @param $data The data to send
* @param array $metadata Metadata to send with the call, if applicable
+ * @param array $options an array of options, possible keys:
+ * 'flags' => a number
*/
- public function start($arg, $metadata = array()) {
+ public function start($data, $metadata = array(), $options = array()) {
+ $message_array = ['message' => $data->serialize()];
+ if (isset($options['flags'])) {
+ $message_array['flags'] = $options['flags'];
+ }
$event = $this->call->startBatch([
OP_SEND_INITIAL_METADATA => $metadata,
OP_RECV_INITIAL_METADATA => true,
- OP_SEND_MESSAGE => $arg->serialize(),
+ OP_SEND_MESSAGE => $message_array,
OP_SEND_CLOSE_FROM_CLIENT => true]);
$this->metadata = $event->metadata;
}
@@ -71,7 +77,7 @@ class ServerStreamingCall extends AbstractCall {
public function getStatus() {
$status_event = $this->call->startBatch([
OP_RECV_STATUS_ON_CLIENT => true
- ]);
+ ]);
return $status_event->status;
}
-} \ No newline at end of file
+}
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index 97a10a40f4..38af6b1d74 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -40,14 +40,20 @@ namespace Grpc;
class UnaryCall extends AbstractCall {
/**
* Start the call
- * @param $arg The argument to send
+ * @param $data The data to send
* @param array $metadata Metadata to send with the call, if applicable
+ * @param array $options an array of options, possible keys:
+ * 'flags' => a number
*/
- public function start($arg, $metadata = array()) {
+ public function start($data, $metadata = array(), $options = array()) {
+ $message_array = ['message' => $data->serialize()];
+ if (isset($options['flags'])) {
+ $message_array['flags'] = $options['flags'];
+ }
$event = $this->call->startBatch([
OP_SEND_INITIAL_METADATA => $metadata,
OP_RECV_INITIAL_METADATA => true,
- OP_SEND_MESSAGE => $arg->serialize(),
+ OP_SEND_MESSAGE => $message_array,
OP_SEND_CLOSE_FROM_CLIENT => true]);
$this->metadata = $event->metadata;
}
@@ -62,4 +68,4 @@ class UnaryCall extends AbstractCall {
OP_RECV_STATUS_ON_CLIENT => true]);
return array($this->deserializeResponse($event->message), $event->status);
}
-} \ No newline at end of file
+}
diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
index 287621d930..9cee188666 100644
--- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -47,6 +47,22 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
$this->assertTrue(self::$client->waitForReady(250000));
}
+ public function testGetTarget() {
+ $this->assertTrue(is_string(self::$client->getTarget()));
+ }
+
+ public function testWriteFlags() {
+ $div_arg = new math\DivArgs();
+ $div_arg->setDividend(7);
+ $div_arg->setDivisor(4);
+ $call = self::$client->Div($div_arg, array(), array('flags' => Grpc\WRITE_NO_COMPRESS));
+ $this->assertTrue(is_string($call->getPeer()));
+ list($response, $status) = $call->wait();
+ $this->assertSame(1, $response->getQuotient());
+ $this->assertSame(3, $response->getRemainder());
+ $this->assertSame(\Grpc\STATUS_OK, $status->code);
+ }
+
public function testSimpleRequest() {
$div_arg = new math\DivArgs();
$div_arg->setDividend(7);
@@ -75,15 +91,13 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
}
public function testClientStreaming() {
- $num_iter = function() {
- for ($i = 0; $i < 7; $i++) {
- $num = new math\Num();
- $num->setNum($i);
- yield $num;
- }
- };
- $call = self::$client->Sum($num_iter());
+ $call = self::$client->Sum();
$this->assertTrue(is_string($call->getPeer()));
+ for ($i = 0; $i < 7; $i++) {
+ $num = new math\Num();
+ $num->setNum($i);
+ $call->write($num);
+ }
list($response, $status) = $call->wait();
$this->assertSame(21, $response->getNum());
$this->assertSame(\Grpc\STATUS_OK, $status->code);
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 376d306da0..d55d5629b7 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -173,7 +173,11 @@ function clientStreaming($stub) {
return $request;
}, $request_lengths);
- list($result, $status) = $stub->StreamingInputCall($requests)->wait();
+ $call = $stub->StreamingInputCall();
+ foreach ($requests as $request) {
+ $call->write($request);
+ }
+ list($result, $status) = $call->wait();
hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
hardAssert($result->getAggregatedPayloadSize() === 74922,
'aggregated_payload_size was incorrect');
@@ -247,6 +251,19 @@ function pingPong($stub) {
}
/**
+ * Run the cancel_after_begin test.
+ * Passes when run against the Node server as of 2015-08-28
+ * @param $stub Stub object that has service methods.
+ */
+function cancelAfterBegin($stub) {
+ $call = $stub->StreamingInputCall();
+ $call->cancel();
+ list($result, $status) = $call->wait();
+ hardAssert($status->code === Grpc\STATUS_CANCELLED,
+ 'Call status was not CANCELLED');
+}
+
+/**
* Run the cancel_after_first_response test.
* Passes when run against the Node server as of 2015-04-30
* @param $stub Stub object that has service methods.
@@ -332,11 +349,7 @@ if (in_array($args['test_case'], array(
$opts['update_metadata'] = $auth->getUpdateMetadataFunc();
}
-$internal_stub = new Grpc\BaseStub($server_address, $opts);
-hardAssert(is_string($internal_stub->getTarget()),
- 'Unexpected target URI value');
-
-$stub = new grpc\testing\TestServiceClient($internal_stub);
+$stub = new grpc\testing\TestServiceClient($server_address, $opts);
echo "Connecting to $server_address\n";
echo "Running test case $args[test_case]\n";
@@ -357,6 +370,9 @@ switch ($args['test_case']) {
case 'ping_pong':
pingPong($stub);
break;
+ case 'cancel_after_begin':
+ cancelAfterBegin($stub);
+ break;
case 'cancel_after_first_response':
cancelAfterFirstResponse($stub);
break;
@@ -373,5 +389,6 @@ switch ($args['test_case']) {
jwtTokenCreds($stub, $args);
break;
default:
+ echo "Unsupported test case $args[test_case]\n";
exit(1);
}
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 4c0cf91d51..bd464f939f 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -91,6 +91,51 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
unset($server_call);
}
+ public function testMessageWriteFlags() {
+ $deadline = Grpc\Timeval::infFuture();
+ $req_text = 'message_write_flags_test';
+ $status_text = 'xyz';
+ $call = new Grpc\Call($this->channel,
+ 'dummy_method',
+ $deadline);
+
+ $event = $call->startBatch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_MESSAGE => ['message' => $req_text,
+ 'flags' => Grpc\WRITE_NO_COMPRESS],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+
+ $event = $this->server->requestCall();
+ $this->assertSame('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
+ ],
+ ]);
+
+ $event = $call->startBatch([
+ Grpc\OP_RECV_INITIAL_METADATA => true,
+ Grpc\OP_RECV_STATUS_ON_CLIENT => true
+ ]);
+
+ $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);
+ }
+
public function testClientServerFullRequestResponse() {
$deadline = Grpc\Timeval::infFuture();
$req_text = 'client_server_full_request_response';
@@ -104,7 +149,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
- Grpc\OP_SEND_MESSAGE => $req_text
+ Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
]);
$this->assertTrue($event->send_metadata);
@@ -117,7 +162,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
- Grpc\OP_SEND_MESSAGE => $reply_text,
+ Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
Grpc\OP_SEND_STATUS_FROM_SERVER => [
'metadata' => [],
'code' => Grpc\STATUS_OK,
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index 60341b983d..d7fca14a0d 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -107,6 +107,53 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
unset($server_call);
}
+ public function testMessageWriteFlags() {
+ $deadline = Grpc\Timeval::infFuture();
+ $req_text = 'message_write_flags_test';
+ $status_text = 'xyz';
+ $call = new Grpc\Call($this->channel,
+ 'dummy_method',
+ $deadline,
+ $this->host_override);
+
+ $event = $call->startBatch([
+ Grpc\OP_SEND_INITIAL_METADATA => [],
+ Grpc\OP_SEND_MESSAGE => ['message' => $req_text,
+ 'flags' => Grpc\WRITE_NO_COMPRESS],
+ Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
+ ]);
+
+ $this->assertTrue($event->send_metadata);
+ $this->assertTrue($event->send_close);
+
+ $event = $this->server->requestCall();
+ $this->assertSame('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
+ ],
+ ]);
+
+ $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);
+ }
+
public function testClientServerFullRequestResponse() {
$deadline = Grpc\Timeval::infFuture();
$req_text = 'client_server_full_request_response';
@@ -121,7 +168,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
- Grpc\OP_SEND_MESSAGE => $req_text
+ Grpc\OP_SEND_MESSAGE => ['message' => $req_text]
]);
$this->assertTrue($event->send_metadata);
@@ -134,7 +181,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
- Grpc\OP_SEND_MESSAGE => $reply_text,
+ Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
Grpc\OP_SEND_STATUS_FROM_SERVER => [
'metadata' => [],
'code' => Grpc\STATUS_OK,
diff --git a/src/python/README.md b/src/python/README.md
index affce64884..afe7c731f1 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -4,7 +4,7 @@ The Python facility of gRPC.
Status
-------
-Alpha : Ready for early adopters
+Beta : Core behavior well-used and proven; bugs lurk off the beaten path.
PREREQUISITES
-------------
@@ -16,10 +16,10 @@ INSTALLATION
**Linux (Debian):**
-Add [Debian unstable][] to your `sources.list` file. Example:
+Add [Debian jessie-backports][] to your `sources.list` file. Example:
```sh
-echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+echo "deb http://http.debian.net/debian jessie-backports main" | \
sudo tee -a /etc/apt/sources.list
```
@@ -92,4 +92,4 @@ $ ../../tools/distrib/python/submit.py
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html
[detailed example]:http://www.grpc.io/docs/installation/python.html
-[Debian unstable]:https://www.debian.org/releases/sid/
+[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h
index f6ff957baa..31fd470d36 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.h
+++ b/src/python/grpcio/grpc/_adapter/_c/types.h
@@ -57,8 +57,6 @@ ClientCredentials *pygrpc_ClientCredentials_composite(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored);
-ClientCredentials *pygrpc_ClientCredentials_service_account(
- PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs);
ClientCredentials *pygrpc_ClientCredentials_refresh_token(
@@ -114,6 +112,8 @@ 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;
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
index 42a50151f6..5604aba39d 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/call.c
@@ -43,6 +43,8 @@ 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.";
@@ -169,3 +171,16 @@ PyObject *pygrpc_Call_peer(Call *self) {
gpr_free(peer);
return py_peer;
}
+PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
+ PyObject *kwargs) {
+ ClientCredentials *creds;
+ grpc_call_error errcode;
+ static char *keywords[] = {"creds", NULL};
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O!:set_credentials", keywords,
+ &pygrpc_ClientCredentials_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/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
index c577ac05eb..79d39c4391 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
@@ -106,7 +106,8 @@ Channel *pygrpc_Channel_new(
}
self = (Channel *)type->tp_alloc(type, 0);
if (creds) {
- self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args);
+ 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);
}
@@ -164,7 +165,7 @@ PyObject *pygrpc_Channel_watch_connectivity_state(
int last_observed_state;
CompletionQueue *completion_queue;
char *keywords[] = {"last_observed_state", "deadline",
- "completion_queue", "tag"};
+ "completion_queue", "tag", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "idO!O:watch_connectivity_state", keywords,
&last_observed_state, &deadline, &pygrpc_CompletionQueue_type,
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c
index e314c15324..90652b7b47 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c
@@ -48,8 +48,6 @@ PyMethodDef pygrpc_ClientCredentials_methods[] = {
METH_CLASS|METH_KEYWORDS, ""},
{"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine,
METH_CLASS|METH_NOARGS, ""},
- {"service_account", (PyCFunction)pygrpc_ClientCredentials_service_account,
- METH_CLASS|METH_KEYWORDS, ""},
{"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt,
METH_CLASS|METH_KEYWORDS, ""},
{"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token,
@@ -135,9 +133,10 @@ ClientCredentials *pygrpc_ClientCredentials_ssl(
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);
+ self->c_creds =
+ grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL);
} else {
- self->c_creds = grpc_ssl_credentials_create(root_certs, NULL);
+ self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
}
if (!self->c_creds) {
Py_DECREF(self);
@@ -159,8 +158,8 @@ ClientCredentials *pygrpc_ClientCredentials_composite(
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_composite_credentials_create(
- creds1->c_creds, creds2->c_creds);
+ self->c_creds =
+ grpc_composite_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");
@@ -172,7 +171,7 @@ ClientCredentials *pygrpc_ClientCredentials_composite(
ClientCredentials *pygrpc_ClientCredentials_compute_engine(
PyTypeObject *type, PyObject *ignored) {
ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_compute_engine_credentials_create();
+ self->c_creds = grpc_google_compute_engine_credentials_create(NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
@@ -182,29 +181,6 @@ ClientCredentials *pygrpc_ClientCredentials_compute_engine(
return self;
}
-ClientCredentials *pygrpc_ClientCredentials_service_account(
- PyTypeObject *type, PyObject *args, PyObject *kwargs) {
- ClientCredentials *self;
- const char *json_key;
- const char *scope;
- double lifetime;
- static char *keywords[] = {"json_key", "scope", "token_lifetime", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssd:service_account", keywords,
- &json_key, &scope, &lifetime)) {
- return NULL;
- }
- self = (ClientCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_service_account_credentials_create(
- json_key, scope, pygrpc_cast_double_to_gpr_timespec(lifetime));
- if (!self->c_creds) {
- Py_DECREF(self);
- PyErr_SetString(PyExc_RuntimeError,
- "couldn't create service account credentials");
- return NULL;
- }
- return self;
-}
-
/* TODO: Rename this credentials to something like service_account_jwt_access */
ClientCredentials *pygrpc_ClientCredentials_jwt(
PyTypeObject *type, PyObject *args, PyObject *kwargs) {
@@ -218,7 +194,7 @@ ClientCredentials *pygrpc_ClientCredentials_jwt(
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
self->c_creds = grpc_service_account_jwt_access_credentials_create(
- json_key, pygrpc_cast_double_to_gpr_timespec(lifetime));
+ 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");
@@ -237,7 +213,8 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token(
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_refresh_token_credentials_create(json_refresh_token);
+ self->c_creds =
+ grpc_google_refresh_token_credentials_create(json_refresh_token, NULL);
if (!self->c_creds) {
Py_DECREF(self);
PyErr_SetString(PyExc_RuntimeError,
@@ -258,8 +235,8 @@ ClientCredentials *pygrpc_ClientCredentials_iam(
return NULL;
}
self = (ClientCredentials *)type->tp_alloc(type, 0);
- self->c_creds = grpc_iam_credentials_create(authorization_token,
- authority_selector);
+ 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");
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
index f6859b79d7..df51a99b6a 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c
@@ -99,11 +99,13 @@ ServerCredentials *pygrpc_ServerCredentials_ssl(
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", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zO:ssl", keywords,
- &root_certs, &py_key_cert_pairs)) {
+ 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)) {
@@ -128,11 +130,8 @@ ServerCredentials *pygrpc_ServerCredentials_ssl(
}
self = (ServerCredentials *)type->tp_alloc(type, 0);
- /* TODO: Add a force_client_auth parameter in the python object and pass it
- here as the last arg. */
self->c_creds = grpc_ssl_server_credentials_create(
- root_certs, key_cert_pairs, num_key_cert_pairs, 0);
+ 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/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
index e7bf9dc462..e2feec6ffb 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -59,6 +59,7 @@ from grpc._adapter import _types
_IGNORE_ME_TAG = object()
Code = _types.StatusCode
+WriteFlags = _types.OpWriteFlags
class Status(collections.namedtuple('Status', ['code', 'details'])):
@@ -125,9 +126,9 @@ class Call(object):
], _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
- def write(self, message, tag):
+ def write(self, message, tag, flags):
return self._internal.start_batch([
- _types.OpArgs.send_message(message, 0)
+ _types.OpArgs.send_message(message, flags)
], _TagAdapter(tag, Event.Kind.WRITE_ACCEPTED))
def complete(self, tag):
@@ -163,6 +164,12 @@ class Call(object):
def cancel(self):
return self._internal.cancel()
+ def peer(self):
+ return self._internal.peer()
+
+ def set_credentials(self, creds):
+ return self._internal.set_credentials(creds._internal)
+
class Channel(object):
"""Adapter from old _low.Channel interface to new _low.Channel."""
@@ -255,5 +262,6 @@ class ClientCredentials(object):
class ServerCredentials(object):
"""Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials."""
- def __init__(self, root_credentials, pair_sequence):
- self._internal = _low.ServerCredentials.ssl(root_credentials, list(pair_sequence))
+ 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 3859ebb0e2..70ceb2a911 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -78,6 +78,9 @@ class Call(_types.Call):
def peer(self):
return self.call.peer()
+ def set_credentials(self, creds):
+ return self.call.set_credentials(creds)
+
class Channel(_types.Channel):
diff --git a/src/python/grpcio/grpc/_adapter/fore.py b/src/python/grpcio/grpc/_adapter/fore.py
index 7d88bda263..acdd69c420 100644
--- a/src/python/grpcio/grpc/_adapter/fore.py
+++ b/src/python/grpcio/grpc/_adapter/fore.py
@@ -56,7 +56,7 @@ class _LowWrite(enum.Enum):
def _write(call, rpc_state, payload):
serialized_payload = rpc_state.serializer(payload)
if rpc_state.write.low is _LowWrite.OPEN:
- call.write(serialized_payload, call)
+ call.write(serialized_payload, call, 0)
rpc_state.write.low = _LowWrite.ACTIVE
else:
rpc_state.write.pending.append(serialized_payload)
@@ -164,7 +164,7 @@ class ForeLink(base_interfaces.ForeLink, activated.Activated):
if rpc_state.write.pending:
serialized_payload = rpc_state.write.pending.pop(0)
- call.write(serialized_payload, call)
+ call.write(serialized_payload, call, 0)
elif rpc_state.write.high is _common.HighWrite.CLOSED:
_status(call, rpc_state)
else:
@@ -288,7 +288,7 @@ class ForeLink(base_interfaces.ForeLink, activated.Activated):
self._port = self._server.add_http2_addr(address)
else:
server_credentials = _low.ServerCredentials(
- self._root_certificates, self._key_chain_pairs)
+ self._root_certificates, self._key_chain_pairs, False)
self._server = _low.Server(self._completion_queue)
self._port = self._server.add_secure_http2_addr(
address, server_credentials)
diff --git a/src/python/grpcio/grpc/_adapter/rear.py b/src/python/grpcio/grpc/_adapter/rear.py
index fd6f45f7a7..17fa47f746 100644
--- a/src/python/grpcio/grpc/_adapter/rear.py
+++ b/src/python/grpcio/grpc/_adapter/rear.py
@@ -78,7 +78,7 @@ class _RPCState(object):
def _write(operation_id, call, outstanding, write_state, serialized_payload):
if write_state.low is _LowWrite.OPEN:
- call.write(serialized_payload, operation_id)
+ call.write(serialized_payload, operation_id, 0)
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
write_state.low = _LowWrite.ACTIVE
elif write_state.low is _LowWrite.ACTIVE:
@@ -144,7 +144,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
if event.write_accepted:
if rpc_state.common.write.pending:
rpc_state.call.write(
- rpc_state.common.write.pending.pop(0), operation_id)
+ rpc_state.common.write.pending.pop(0), operation_id, 0)
rpc_state.outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
elif rpc_state.common.write.high is _common.HighWrite.CLOSED:
rpc_state.call.complete(operation_id)
@@ -263,7 +263,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
low_state = _LowWrite.OPEN
else:
serialized_payload = request_serializer(payload)
- call.write(serialized_payload, operation_id)
+ call.write(serialized_payload, operation_id, 0)
outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
low_state = _LowWrite.ACTIVE
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
index 2d74702fbd..dc40a7a611 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
@@ -106,26 +106,6 @@ def client_credentials_compute_engine():
credentials.c_credentials = grpc.grpc_compute_engine_credentials_create()
return credentials
-def client_credentials_service_account(
- json_key, scope, records.Timespec token_lifetime not None):
- if isinstance(json_key, bytes):
- pass
- elif isinstance(json_key, basestring):
- json_key = json_key.encode()
- else:
- raise TypeError("expected json_key to be str or bytes")
- if isinstance(scope, bytes):
- pass
- elif isinstance(scope, basestring):
- scope = scope.encode()
- else:
- raise TypeError("expected scope to be str or bytes")
- cdef ClientCredentials credentials = ClientCredentials()
- credentials.c_credentials = grpc.grpc_service_account_credentials_create(
- json_key, scope, token_lifetime.c_time)
- credentials.references.extend([json_key, scope])
- return credentials
-
#TODO rename to something like client_credentials_service_account_jwt_access.
def client_credentials_jwt(json_key, records.Timespec token_lifetime not None):
if isinstance(json_key, bytes):
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index d065383587..8b46972490 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -311,8 +311,6 @@ cdef extern from "grpc/grpc_security.h":
grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
grpc_credentials *creds2)
grpc_credentials *grpc_compute_engine_credentials_create()
- grpc_credentials *grpc_service_account_credentials_create(
- const char *json_key, const char *scope, gpr_timespec token_lifetime)
grpc_credentials *grpc_service_account_jwt_access_credentials_create(const char *json_key,
gpr_timespec token_lifetime)
grpc_credentials *grpc_refresh_token_credentials_create(
@@ -332,7 +330,7 @@ cdef extern from "grpc/grpc_security.h":
grpc_server_credentials *grpc_ssl_server_credentials_create(
const char *pem_root_certs,
grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
- size_t num_key_cert_pairs);
+ size_t num_key_cert_pairs)
void grpc_server_credentials_release(grpc_server_credentials *creds)
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
diff --git a/src/python/grpcio/grpc/_cython/adapter_low.py b/src/python/grpcio/grpc/_cython/adapter_low.py
index 2bb468eece..4f24da330f 100644
--- a/src/python/grpcio/grpc/_cython/adapter_low.py
+++ b/src/python/grpcio/grpc/_cython/adapter_low.py
@@ -60,10 +60,6 @@ class ClientCredentials(object):
raise NotImplementedError()
@staticmethod
- def service_account():
- raise NotImplementedError()
-
- @staticmethod
def jwt():
raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/_links/_constants.py b/src/python/grpcio/grpc/_links/_constants.py
new file mode 100644
index 0000000000..117fc5a639
--- /dev/null
+++ b/src/python/grpcio/grpc/_links/_constants.py
@@ -0,0 +1,42 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Constants for use within this package."""
+
+from grpc._adapter import _intermediary_low
+from grpc.beta import interfaces as beta_interfaces
+
+LOW_STATUS_CODE_TO_HIGH_STATUS_CODE = {
+ low: high for low, high in zip(
+ _intermediary_low.Code, beta_interfaces.StatusCode)
+}
+
+HIGH_STATUS_CODE_TO_LOW_STATUS_CODE = {
+ high: low for low, high in LOW_STATUS_CODE_TO_HIGH_STATUS_CODE.items()
+}
diff --git a/src/python/grpcio/grpc/_links/invocation.py b/src/python/grpcio/grpc/_links/invocation.py
index ee3d72fdbc..67ef86a176 100644
--- a/src/python/grpcio/grpc/_links/invocation.py
+++ b/src/python/grpcio/grpc/_links/invocation.py
@@ -36,11 +36,22 @@ import threading
import time
from grpc._adapter import _intermediary_low
+from grpc._links import _constants
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.foundation import activated
from grpc.framework.foundation import logging_pool
from grpc.framework.foundation import relay
from grpc.framework.interfaces.links import links
+_IDENTITY = lambda x: x
+
+_STOP = _intermediary_low.Event.Kind.STOP
+_WRITE = _intermediary_low.Event.Kind.WRITE_ACCEPTED
+_COMPLETE = _intermediary_low.Event.Kind.COMPLETE_ACCEPTED
+_READ = _intermediary_low.Event.Kind.READ_ACCEPTED
+_METADATA = _intermediary_low.Event.Kind.METADATA_ACCEPTED
+_FINISH = _intermediary_low.Event.Kind.FINISH
+
@enum.unique
class _Read(enum.Enum):
@@ -63,11 +74,28 @@ class _LowWrite(enum.Enum):
CLOSED = 'CLOSED'
+class _Context(beta_interfaces.GRPCInvocationContext):
+
+ def __init__(self):
+ self._lock = threading.Lock()
+ self._disable_next_compression = False
+
+ def disable_next_request_compression(self):
+ with self._lock:
+ self._disable_next_compression = True
+
+ def next_compression_disabled(self):
+ with self._lock:
+ disabled = self._disable_next_compression
+ self._disable_next_compression = False
+ return disabled
+
+
class _RPCState(object):
def __init__(
self, call, request_serializer, response_deserializer, sequence_number,
- read, allowance, high_write, low_write):
+ read, allowance, high_write, low_write, due, context):
self.call = call
self.request_serializer = request_serializer
self.response_deserializer = response_deserializer
@@ -76,27 +104,38 @@ class _RPCState(object):
self.allowance = allowance
self.high_write = high_write
self.low_write = low_write
+ self.due = due
+ self.context = context
+
+
+def _no_longer_due(kind, rpc_state, key, rpc_states):
+ rpc_state.due.remove(kind)
+ if not rpc_state.due:
+ del rpc_states[key]
class _Kernel(object):
def __init__(
- self, channel, host, request_serializers, response_deserializers,
- ticket_relay):
+ self, channel, host, metadata_transformer, request_serializers,
+ response_deserializers, ticket_relay):
self._lock = threading.Lock()
self._channel = channel
self._host = host
+ self._metadata_transformer = metadata_transformer
self._request_serializers = request_serializers
self._response_deserializers = response_deserializers
self._relay = ticket_relay
self._completion_queue = None
- self._rpc_states = None
+ self._rpc_states = {}
self._pool = None
def _on_write_event(self, operation_id, unused_event, rpc_state):
if rpc_state.high_write is _HighWrite.CLOSED:
rpc_state.call.complete(operation_id)
+ rpc_state.due.add(_COMPLETE)
+ rpc_state.due.remove(_WRITE)
rpc_state.low_write = _LowWrite.CLOSED
else:
ticket = links.Ticket(
@@ -105,16 +144,19 @@ class _Kernel(object):
rpc_state.sequence_number += 1
self._relay.add_value(ticket)
rpc_state.low_write = _LowWrite.OPEN
+ _no_longer_due(_WRITE, rpc_state, operation_id, self._rpc_states)
def _on_read_event(self, operation_id, event, rpc_state):
- if event.bytes is None:
+ if event.bytes is None or _FINISH not in rpc_state.due:
rpc_state.read = _Read.CLOSED
+ _no_longer_due(_READ, rpc_state, operation_id, self._rpc_states)
else:
if 0 < rpc_state.allowance:
rpc_state.allowance -= 1
rpc_state.call.read(operation_id)
else:
rpc_state.read = _Read.AWAITING_ALLOWANCE
+ _no_longer_due(_READ, rpc_state, operation_id, self._rpc_states)
ticket = links.Ticket(
operation_id, rpc_state.sequence_number, None, None, None, None, None,
None, rpc_state.response_deserializer(event.bytes), None, None, None,
@@ -123,62 +165,70 @@ class _Kernel(object):
self._relay.add_value(ticket)
def _on_metadata_event(self, operation_id, event, rpc_state):
- rpc_state.allowance -= 1
- rpc_state.call.read(operation_id)
- rpc_state.read = _Read.READING
- ticket = links.Ticket(
- operation_id, rpc_state.sequence_number, None, None,
- links.Ticket.Subscription.FULL, None, None, event.metadata, None, None,
- None, None, None, None)
- rpc_state.sequence_number += 1
- self._relay.add_value(ticket)
+ if _FINISH in rpc_state.due:
+ rpc_state.allowance -= 1
+ rpc_state.call.read(operation_id)
+ rpc_state.read = _Read.READING
+ rpc_state.due.add(_READ)
+ rpc_state.due.remove(_METADATA)
+ ticket = links.Ticket(
+ operation_id, rpc_state.sequence_number, None, None,
+ links.Ticket.Subscription.FULL, None, None, event.metadata, None,
+ None, None, None, None, None)
+ rpc_state.sequence_number += 1
+ self._relay.add_value(ticket)
+ else:
+ _no_longer_due(_METADATA, rpc_state, operation_id, self._rpc_states)
def _on_finish_event(self, operation_id, event, rpc_state):
- self._rpc_states.pop(operation_id, None)
+ _no_longer_due(_FINISH, rpc_state, operation_id, self._rpc_states)
if event.status.code is _intermediary_low.Code.OK:
termination = links.Ticket.Termination.COMPLETION
elif event.status.code is _intermediary_low.Code.CANCELLED:
termination = links.Ticket.Termination.CANCELLATION
elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED:
termination = links.Ticket.Termination.EXPIRATION
+ elif event.status.code is _intermediary_low.Code.UNIMPLEMENTED:
+ termination = links.Ticket.Termination.REMOTE_FAILURE
elif event.status.code is _intermediary_low.Code.UNKNOWN:
termination = links.Ticket.Termination.LOCAL_FAILURE
else:
termination = links.Ticket.Termination.TRANSMISSION_FAILURE
+ code = _constants.LOW_STATUS_CODE_TO_HIGH_STATUS_CODE[event.status.code]
ticket = links.Ticket(
operation_id, rpc_state.sequence_number, None, None, None, None, None,
- None, None, event.metadata, event.status.code, event.status.details,
- termination, None)
+ None, None, event.metadata, code, event.status.details, termination,
+ None)
rpc_state.sequence_number += 1
self._relay.add_value(ticket)
def _spin(self, completion_queue):
while True:
event = completion_queue.get(None)
- if event.kind is _intermediary_low.Event.Kind.STOP:
- return
- operation_id = event.tag
with self._lock:
- if self._completion_queue is None:
- continue
- rpc_state = self._rpc_states.get(operation_id)
- if rpc_state is not None:
- if event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
- self._on_write_event(operation_id, event, rpc_state)
- elif event.kind is _intermediary_low.Event.Kind.METADATA_ACCEPTED:
- self._on_metadata_event(operation_id, event, rpc_state)
- elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
- self._on_read_event(operation_id, event, rpc_state)
- elif event.kind is _intermediary_low.Event.Kind.FINISH:
- self._on_finish_event(operation_id, event, rpc_state)
- elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
- pass
- else:
- logging.error('Illegal RPC event! %s', (event,))
+ rpc_state = self._rpc_states.get(event.tag, None)
+ if event.kind is _STOP:
+ pass
+ elif event.kind is _WRITE:
+ self._on_write_event(event.tag, event, rpc_state)
+ elif event.kind is _METADATA:
+ self._on_metadata_event(event.tag, event, rpc_state)
+ elif event.kind is _READ:
+ self._on_read_event(event.tag, event, rpc_state)
+ elif event.kind is _FINISH:
+ self._on_finish_event(event.tag, event, rpc_state)
+ elif event.kind is _COMPLETE:
+ _no_longer_due(_COMPLETE, rpc_state, event.tag, self._rpc_states)
+ else:
+ logging.error('Illegal RPC event! %s', (event,))
+
+ if self._completion_queue is None and not self._rpc_states:
+ completion_queue.stop()
+ return
def _invoke(
self, operation_id, group, method, initial_metadata, payload, termination,
- timeout, allowance):
+ timeout, allowance, options):
"""Invoke an RPC.
Args:
@@ -193,6 +243,7 @@ class _Kernel(object):
timeout: A duration of time in seconds to allow for the RPC.
allowance: The number of payloads (beyond the free first one) that the
local ticket exchange mate has granted permission to be read.
+ options: A beta_interfaces.GRPCCallOptions value or None.
"""
if termination is links.Ticket.Termination.COMPLETION:
high_write = _HighWrite.CLOSED
@@ -201,46 +252,66 @@ class _Kernel(object):
else:
return
- request_serializer = self._request_serializers.get((group, method))
- response_deserializer = self._response_deserializers.get((group, method))
- if request_serializer is None or response_deserializer is None:
- cancellation_ticket = links.Ticket(
- operation_id, 0, None, None, None, None, None, None, None, None, None,
- None, links.Ticket.Termination.CANCELLATION)
- self._relay.add_value(cancellation_ticket)
- return
+ transformed_initial_metadata = self._metadata_transformer(initial_metadata)
+ request_serializer = self._request_serializers.get(
+ (group, method), _IDENTITY)
+ response_deserializer = self._response_deserializers.get(
+ (group, method), _IDENTITY)
call = _intermediary_low.Call(
self._channel, self._completion_queue, '/%s/%s' % (group, method),
self._host, time.time() + timeout)
- if initial_metadata is not None:
- for metadata_key, metadata_value in initial_metadata:
+ if options is not None and options.credentials is not None:
+ call.set_credentials(options.credentials._intermediary_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)
call.invoke(self._completion_queue, operation_id, operation_id)
if payload is None:
if high_write is _HighWrite.CLOSED:
call.complete(operation_id)
low_write = _LowWrite.CLOSED
+ due = set((_METADATA, _COMPLETE, _FINISH,))
else:
low_write = _LowWrite.OPEN
+ due = set((_METADATA, _FINISH,))
else:
- call.write(request_serializer(payload), operation_id)
+ if options is not None and options.disable_compression:
+ flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS
+ else:
+ flags = 0
+ call.write(request_serializer(payload), operation_id, flags)
low_write = _LowWrite.ACTIVE
+ due = set((_WRITE, _METADATA, _FINISH,))
+ context = _Context()
self._rpc_states[operation_id] = _RPCState(
- call, request_serializer, response_deserializer, 0,
+ call, request_serializer, response_deserializer, 1,
_Read.AWAITING_METADATA, 1 if allowance is None else (1 + allowance),
- high_write, low_write)
+ high_write, low_write, due, context)
+ protocol = links.Protocol(links.Protocol.Kind.INVOCATION_CONTEXT, context)
+ ticket = links.Ticket(
+ operation_id, 0, None, None, None, None, None, None, None, None, None,
+ None, None, protocol)
+ self._relay.add_value(ticket)
def _advance(self, operation_id, rpc_state, payload, termination, allowance):
if payload is not None:
- rpc_state.call.write(rpc_state.request_serializer(payload), operation_id)
+ disable_compression = rpc_state.context.next_compression_disabled()
+ if disable_compression:
+ flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS
+ else:
+ flags = 0
+ rpc_state.call.write(
+ rpc_state.request_serializer(payload), operation_id, flags)
rpc_state.low_write = _LowWrite.ACTIVE
+ rpc_state.due.add(_WRITE)
if allowance is not None:
if rpc_state.read is _Read.AWAITING_ALLOWANCE:
rpc_state.allowance += allowance - 1
rpc_state.call.read(operation_id)
rpc_state.read = _Read.READING
+ rpc_state.due.add(_READ)
else:
rpc_state.allowance += allowance
@@ -248,19 +319,26 @@ class _Kernel(object):
rpc_state.high_write = _HighWrite.CLOSED
if rpc_state.low_write is _LowWrite.OPEN:
rpc_state.call.complete(operation_id)
+ rpc_state.due.add(_COMPLETE)
rpc_state.low_write = _LowWrite.CLOSED
elif termination is not None:
rpc_state.call.cancel()
def add_ticket(self, ticket):
with self._lock:
- if self._completion_queue is None:
- return
if ticket.sequence_number == 0:
- self._invoke(
- ticket.operation_id, ticket.group, ticket.method,
- ticket.initial_metadata, ticket.payload, ticket.termination,
- ticket.timeout, ticket.allowance)
+ if self._completion_queue is None:
+ logging.error('Received invocation ticket %s after stop!', ticket)
+ else:
+ if (ticket.protocol is not None and
+ ticket.protocol.kind is links.Protocol.Kind.CALL_OPTION):
+ grpc_call_options = ticket.protocol.value
+ else:
+ grpc_call_options = None
+ self._invoke(
+ ticket.operation_id, ticket.group, ticket.method,
+ ticket.initial_metadata, ticket.payload, ticket.termination,
+ ticket.timeout, ticket.allowance, grpc_call_options)
else:
rpc_state = self._rpc_states.get(ticket.operation_id)
if rpc_state is not None:
@@ -276,7 +354,6 @@ class _Kernel(object):
"""
with self._lock:
self._completion_queue = _intermediary_low.CompletionQueue()
- self._rpc_states = {}
self._pool = logging_pool.pool(1)
self._pool.submit(self._spin, self._completion_queue)
@@ -288,11 +365,10 @@ class _Kernel(object):
has been called.
"""
with self._lock:
- self._completion_queue.stop()
+ if not self._rpc_states:
+ self._completion_queue.stop()
self._completion_queue = None
pool = self._pool
- self._pool = None
- self._rpc_states = None
pool.shutdown(wait=True)
@@ -307,10 +383,15 @@ class InvocationLink(links.Link, activated.Activated):
class _InvocationLink(InvocationLink):
def __init__(
- self, channel, host, request_serializers, response_deserializers):
+ self, channel, host, metadata_transformer, request_serializers,
+ response_deserializers):
self._relay = relay.relay(None)
self._kernel = _Kernel(
- channel, host, request_serializers, response_deserializers, self._relay)
+ channel, host,
+ _IDENTITY if metadata_transformer is None else metadata_transformer,
+ {} if request_serializers is None else request_serializers,
+ {} if response_deserializers is None else response_deserializers,
+ self._relay)
def _start(self):
self._relay.start()
@@ -347,12 +428,17 @@ class _InvocationLink(InvocationLink):
self._stop()
-def invocation_link(channel, host, request_serializers, response_deserializers):
+def invocation_link(
+ channel, host, metadata_transformer, request_serializers,
+ response_deserializers):
"""Creates an InvocationLink.
Args:
channel: An _intermediary_low.Channel for use by the link.
host: The host to specify when invoking RPCs.
+ metadata_transformer: A callable that takes an invocation-side initial
+ metadata value and returns another metadata value to send in its place.
+ May be None.
request_serializers: A dict from group-method pair to request object
serialization behavior.
response_deserializers: A dict from group-method pair to response object
@@ -362,4 +448,5 @@ def invocation_link(channel, host, request_serializers, response_deserializers):
An InvocationLink.
"""
return _InvocationLink(
- channel, host, request_serializers, response_deserializers)
+ channel, host, metadata_transformer, request_serializers,
+ response_deserializers)
diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py
index 43c4c0e80c..f56df84007 100644
--- a/src/python/grpcio/grpc/_links/service.py
+++ b/src/python/grpcio/grpc/_links/service.py
@@ -36,10 +36,14 @@ import threading
import time
from grpc._adapter import _intermediary_low
+from grpc._links import _constants
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.foundation import logging_pool
from grpc.framework.foundation import relay
from grpc.framework.interfaces.links import links
+_IDENTITY = lambda x: x
+
_TERMINATION_KIND_TO_CODE = {
links.Ticket.Termination.COMPLETION: _intermediary_low.Code.OK,
links.Ticket.Termination.CANCELLATION: _intermediary_low.Code.CANCELLED,
@@ -53,6 +57,13 @@ _TERMINATION_KIND_TO_CODE = {
links.Ticket.Termination.REMOTE_FAILURE: _intermediary_low.Code.UNKNOWN,
}
+_STOP = _intermediary_low.Event.Kind.STOP
+_WRITE = _intermediary_low.Event.Kind.WRITE_ACCEPTED
+_COMPLETE = _intermediary_low.Event.Kind.COMPLETE_ACCEPTED
+_SERVICE = _intermediary_low.Event.Kind.SERVICE_ACCEPTED
+_READ = _intermediary_low.Event.Kind.READ_ACCEPTED
+_FINISH = _intermediary_low.Event.Kind.FINISH
+
@enum.unique
class _Read(enum.Enum):
@@ -79,12 +90,34 @@ class _LowWrite(enum.Enum):
CLOSED = 'CLOSED'
+class _Context(beta_interfaces.GRPCServicerContext):
+
+ def __init__(self, call):
+ self._lock = threading.Lock()
+ self._call = call
+ self._disable_next_compression = False
+
+ def peer(self):
+ with self._lock:
+ return self._call.peer()
+
+ def disable_next_response_compression(self):
+ with self._lock:
+ self._disable_next_compression = True
+
+ def next_compression_disabled(self):
+ with self._lock:
+ disabled = self._disable_next_compression
+ self._disable_next_compression = False
+ return disabled
+
+
class _RPCState(object):
def __init__(
self, request_deserializer, response_serializer, sequence_number, read,
early_read, allowance, high_write, low_write, premetadataed,
- terminal_metadata, code, message):
+ terminal_metadata, code, message, due, context):
self.request_deserializer = request_deserializer
self.response_serializer = response_serializer
self.sequence_number = sequence_number
@@ -99,6 +132,14 @@ class _RPCState(object):
self.terminal_metadata = terminal_metadata
self.code = code
self.message = message
+ self.due = due
+ self.context = context
+
+
+def _no_longer_due(kind, rpc_state, key, rpc_states):
+ rpc_state.due.remove(kind)
+ if not rpc_state.due:
+ del rpc_states[key]
def _metadatafy(call, metadata):
@@ -106,13 +147,13 @@ def _metadatafy(call, metadata):
call.add_metadata(metadata_key, metadata_value)
-def _status(termination_kind, code, details):
- effective_details = b'' if details is None else details
- if code is None:
- effective_code = _TERMINATION_KIND_TO_CODE[termination_kind]
+def _status(termination_kind, high_code, details):
+ low_details = b'' if details is None else details
+ if high_code is None:
+ low_code = _TERMINATION_KIND_TO_CODE[termination_kind]
else:
- effective_code = code
- return _intermediary_low.Status(effective_code, effective_details)
+ low_code = _constants.HIGH_STATUS_CODE_TO_LOW_STATUS_CODE[high_code]
+ return _intermediary_low.Status(low_code, low_details)
class _Kernel(object):
@@ -124,6 +165,7 @@ class _Kernel(object):
self._relay = ticket_relay
self._completion_queue = None
+ self._due = set()
self._server = None
self._rpc_states = {}
self._pool = None
@@ -139,33 +181,33 @@ class _Kernel(object):
except ValueError:
logging.info('Illegal path "%s"!', service_acceptance.method)
return
- request_deserializer = self._request_deserializers.get((group, method))
- response_serializer = self._response_serializers.get((group, method))
- if request_deserializer is None or response_serializer is None:
- # TODO(nathaniel): Terminate the RPC with code NOT_FOUND.
- call.cancel()
- return
+ request_deserializer = self._request_deserializers.get(
+ (group, method), _IDENTITY)
+ response_serializer = self._response_serializers.get(
+ (group, method), _IDENTITY)
call.read(call)
+ context = _Context(call)
self._rpc_states[call] = _RPCState(
request_deserializer, response_serializer, 1, _Read.READING, None, 1,
- _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None)
+ _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None,
+ set((_READ, _FINISH,)), context)
+ protocol = links.Protocol(links.Protocol.Kind.SERVICER_CONTEXT, context)
ticket = links.Ticket(
call, 0, group, method, links.Ticket.Subscription.FULL,
service_acceptance.deadline - time.time(), None, event.metadata, None,
- None, None, None, None, 'TODO: Service Context Object!')
+ None, None, None, None, protocol)
self._relay.add_value(ticket)
def _on_read_event(self, event):
call = event.tag
- rpc_state = self._rpc_states.get(call, None)
- if rpc_state is None:
- return
+ rpc_state = self._rpc_states[call]
if event.bytes is None:
rpc_state.read = _Read.CLOSED
payload = None
termination = links.Ticket.Termination.COMPLETION
+ _no_longer_due(_READ, rpc_state, call, self._rpc_states)
else:
if 0 < rpc_state.allowance:
payload = rpc_state.request_deserializer(event.bytes)
@@ -174,6 +216,7 @@ class _Kernel(object):
call.read(call)
else:
rpc_state.early_read = event.bytes
+ _no_longer_due(_READ, rpc_state, call, self._rpc_states)
return
# TODO(issue 2916): Instead of returning:
# rpc_state.read = _Read.AWAITING_ALLOWANCE
@@ -185,9 +228,7 @@ class _Kernel(object):
def _on_write_event(self, event):
call = event.tag
- rpc_state = self._rpc_states.get(call, None)
- if rpc_state is None:
- return
+ rpc_state = self._rpc_states[call]
if rpc_state.high_write is _HighWrite.CLOSED:
if rpc_state.terminal_metadata is not None:
@@ -197,6 +238,8 @@ class _Kernel(object):
rpc_state.message)
call.status(status, call)
rpc_state.low_write = _LowWrite.CLOSED
+ rpc_state.due.add(_COMPLETE)
+ rpc_state.due.remove(_WRITE)
else:
ticket = links.Ticket(
call, rpc_state.sequence_number, None, None, None, None, 1, None,
@@ -204,12 +247,12 @@ class _Kernel(object):
rpc_state.sequence_number += 1
self._relay.add_value(ticket)
rpc_state.low_write = _LowWrite.OPEN
+ _no_longer_due(_WRITE, rpc_state, call, self._rpc_states)
def _on_finish_event(self, event):
call = event.tag
- rpc_state = self._rpc_states.pop(call, None)
- if rpc_state is None:
- return
+ 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:
return
@@ -229,28 +272,33 @@ class _Kernel(object):
def _spin(self, completion_queue, server):
while True:
event = completion_queue.get(None)
- if event.kind is _intermediary_low.Event.Kind.STOP:
- return
with self._lock:
- if self._server is None:
- continue
- elif event.kind is _intermediary_low.Event.Kind.SERVICE_ACCEPTED:
- self._on_service_acceptance_event(event, server)
- elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
+ if event.kind is _STOP:
+ self._due.remove(_STOP)
+ elif event.kind is _READ:
self._on_read_event(event)
- elif event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
+ elif event.kind is _WRITE:
self._on_write_event(event)
- elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
- pass
+ elif event.kind is _COMPLETE:
+ _no_longer_due(
+ _COMPLETE, self._rpc_states.get(event.tag), event.tag,
+ self._rpc_states)
elif event.kind is _intermediary_low.Event.Kind.FINISH:
self._on_finish_event(event)
+ elif event.kind is _SERVICE:
+ if self._server is None:
+ self._due.remove(_SERVICE)
+ else:
+ self._on_service_acceptance_event(event, server)
else:
logging.error('Illegal event! %s', (event,))
+ if not self._due and not self._rpc_states:
+ completion_queue.stop()
+ return
+
def add_ticket(self, ticket):
with self._lock:
- if self._server is None:
- return
call = ticket.operation_id
rpc_state = self._rpc_states.get(call)
if rpc_state is None:
@@ -278,6 +326,7 @@ class _Kernel(object):
rpc_state.early_read = None
if rpc_state.read is _Read.READING:
call.read(call)
+ rpc_state.due.add(_READ)
termination = None
else:
termination = links.Ticket.Termination.COMPLETION
@@ -288,7 +337,13 @@ class _Kernel(object):
self._relay.add_value(early_read_ticket)
if ticket.payload is not None:
- call.write(rpc_state.response_serializer(ticket.payload), call)
+ disable_compression = rpc_state.context.next_compression_disabled()
+ if disable_compression:
+ flags = _intermediary_low.WriteFlags.WRITE_NO_COMPRESS
+ else:
+ flags = 0
+ call.write(rpc_state.response_serializer(ticket.payload), call, flags)
+ rpc_state.due.add(_WRITE)
rpc_state.low_write = _LowWrite.ACTIVE
if ticket.terminal_metadata is not None:
@@ -307,6 +362,7 @@ class _Kernel(object):
links.Ticket.Termination.COMPLETION, rpc_state.code,
rpc_state.message)
call.status(status, call)
+ rpc_state.due.add(_COMPLETE)
rpc_state.low_write = _LowWrite.CLOSED
elif ticket.termination is not None:
if rpc_state.terminal_metadata is not None:
@@ -314,11 +370,10 @@ class _Kernel(object):
status = _status(
ticket.termination, rpc_state.code, rpc_state.message)
call.status(status, call)
- self._rpc_states.pop(call, None)
+ rpc_state.due.add(_COMPLETE)
- def add_port(self, port, server_credentials):
+ def add_port(self, address, server_credentials):
with self._lock:
- address = '[::]:%d' % port
if self._server is None:
self._completion_queue = _intermediary_low.CompletionQueue()
self._server = _intermediary_low.Server(self._completion_queue)
@@ -336,23 +391,19 @@ class _Kernel(object):
self._pool.submit(self._spin, self._completion_queue, self._server)
self._server.start()
self._server.service(None)
+ self._due.add(_SERVICE)
- def graceful_stop(self):
+ def begin_stop(self):
with self._lock:
self._server.stop()
+ self._due.add(_STOP)
self._server = None
- self._completion_queue.stop()
- self._completion_queue = None
+
+ def end_stop(self):
+ with self._lock:
pool = self._pool
- self._pool = None
- self._rpc_states = None
pool.shutdown(wait=True)
- def immediate_stop(self):
- # TODO(nathaniel): Implementation.
- raise NotImplementedError(
- 'TODO(nathaniel): after merge of rewritten lower layers')
-
class ServiceLink(links.Link):
"""A links.Link for use on the service-side of a gRPC connection.
@@ -362,17 +413,20 @@ class ServiceLink(links.Link):
"""
@abc.abstractmethod
- def add_port(self, port, server_credentials):
+ def add_port(self, address, server_credentials):
"""Adds a port on which to service RPCs after this link has been started.
Args:
- port: The port on which to service RPCs, or zero to request that a port be
- automatically selected and used.
- server_credentials: A ServerCredentials object, or None for insecure
- service.
+ address: The address on which to service RPCs with a port number of zero
+ requesting that a port number be automatically selected and used.
+ server_credentials: An _intermediary_low.ServerCredentials object, or
+ None for insecure service.
Returns:
- A port on which RPCs will be serviced after this link has been started.
+ An integer port on which RPCs will be serviced after this link has been
+ started. This is typically the same number as the port number contained
+ in the passed address, but will likely be different if the port number
+ contained in the passed address was zero.
"""
raise NotImplementedError()
@@ -386,18 +440,20 @@ class ServiceLink(links.Link):
raise NotImplementedError()
@abc.abstractmethod
- def stop_gracefully(self):
- """Stops this link.
+ def begin_stop(self):
+ """Indicate imminent link stop and immediate rejection of new RPCs.
New RPCs will be rejected as soon as this method is called, but ongoing RPCs
- will be allowed to continue until they terminate. This method blocks until
- all RPCs have terminated.
+ will be allowed to continue until they terminate. This method does not
+ block.
"""
raise NotImplementedError()
@abc.abstractmethod
- def stop_immediately(self):
- """Stops this link.
+ def end_stop(self):
+ """Finishes stopping this link.
+
+ begin_stop must have been called exactly once before calling this method.
All in-progress RPCs will be terminated immediately.
"""
@@ -409,7 +465,9 @@ class _ServiceLink(ServiceLink):
def __init__(self, request_deserializers, response_serializers):
self._relay = relay.relay(None)
self._kernel = _Kernel(
- request_deserializers, response_serializers, self._relay)
+ {} if request_deserializers is None else request_deserializers,
+ {} if response_serializers is None else response_serializers,
+ self._relay)
def accept_ticket(self, ticket):
self._kernel.add_ticket(ticket)
@@ -417,19 +475,18 @@ class _ServiceLink(ServiceLink):
def join_link(self, link):
self._relay.set_behavior(link.accept_ticket)
- def add_port(self, port, server_credentials):
- return self._kernel.add_port(port, server_credentials)
+ def add_port(self, address, server_credentials):
+ return self._kernel.add_port(address, server_credentials)
def start(self):
self._relay.start()
return self._kernel.start()
- def stop_gracefully(self):
- self._kernel.graceful_stop()
- self._relay.stop()
+ def begin_stop(self):
+ self._kernel.begin_stop()
- def stop_immediately(self):
- self._kernel.immediate_stop()
+ def end_stop(self):
+ self._kernel.end_stop()
self._relay.stop()
diff --git a/src/python/grpcio/grpc/beta/__init__.py b/src/python/grpcio/grpc/beta/__init__.py
new file mode 100644
index 0000000000..b89398809f
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/__init__.py
@@ -0,0 +1,28 @@
+# 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.
diff --git a/src/python/grpcio/grpc/beta/_connectivity_channel.py b/src/python/grpcio/grpc/beta/_connectivity_channel.py
new file mode 100644
index 0000000000..61674a70ad
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_connectivity_channel.py
@@ -0,0 +1,156 @@
+# 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.
+
+"""Affords a connectivity-state-listenable channel."""
+
+import threading
+import time
+
+from grpc._adapter import _low
+from grpc._adapter import _types
+from grpc.beta import interfaces
+from grpc.framework.foundation import callable_util
+
+_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
+ 'Exception calling channel subscription callback!')
+
+_LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = {
+ state: connectivity for state, connectivity in zip(
+ _types.ConnectivityState, interfaces.ChannelConnectivity)
+}
+
+
+class ConnectivityChannel(object):
+
+ def __init__(self, low_channel):
+ self._lock = threading.Lock()
+ self._low_channel = low_channel
+
+ self._polling = False
+ self._connectivity = None
+ self._try_to_connect = False
+ self._callbacks_and_connectivities = []
+ self._delivering = False
+
+ def _deliveries(self, connectivity):
+ callbacks_needing_update = []
+ for callback_and_connectivity in self._callbacks_and_connectivities:
+ callback, callback_connectivity = callback_and_connectivity
+ if callback_connectivity is not connectivity:
+ callbacks_needing_update.append(callback)
+ callback_and_connectivity[1] = connectivity
+ return callbacks_needing_update
+
+ def _deliver(self, initial_connectivity, initial_callbacks):
+ connectivity = initial_connectivity
+ callbacks = initial_callbacks
+ while True:
+ for callback in callbacks:
+ callable_util.call_logging_exceptions(
+ callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE,
+ connectivity)
+ with self._lock:
+ callbacks = self._deliveries(self._connectivity)
+ if callbacks:
+ connectivity = self._connectivity
+ else:
+ self._delivering = False
+ return
+
+ def _spawn_delivery(self, connectivity, callbacks):
+ delivering_thread = threading.Thread(
+ target=self._deliver, args=(connectivity, callbacks,))
+ delivering_thread.start()
+ self._delivering = True
+
+ # TODO(issue 3064): Don't poll.
+ def _poll_connectivity(self, low_channel, initial_try_to_connect):
+ try_to_connect = initial_try_to_connect
+ low_connectivity = low_channel.check_connectivity_state(try_to_connect)
+ with self._lock:
+ self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
+ low_connectivity]
+ callbacks = tuple(
+ callback for callback, unused_but_known_to_be_none_connectivity
+ in self._callbacks_and_connectivities)
+ for callback_and_connectivity in self._callbacks_and_connectivities:
+ callback_and_connectivity[1] = self._connectivity
+ if callbacks:
+ self._spawn_delivery(self._connectivity, callbacks)
+ completion_queue = _low.CompletionQueue()
+ while True:
+ low_channel.watch_connectivity_state(
+ low_connectivity, time.time() + 0.2, completion_queue, None)
+ event = completion_queue.next()
+ with self._lock:
+ if not self._callbacks_and_connectivities and not self._try_to_connect:
+ self._polling = False
+ self._connectivity = None
+ completion_queue.shutdown()
+ break
+ try_to_connect = self._try_to_connect
+ self._try_to_connect = False
+ if event.success or try_to_connect:
+ low_connectivity = low_channel.check_connectivity_state(try_to_connect)
+ with self._lock:
+ self._connectivity = _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY[
+ low_connectivity]
+ if not self._delivering:
+ callbacks = self._deliveries(self._connectivity)
+ if callbacks:
+ self._spawn_delivery(self._connectivity, callbacks)
+
+ def subscribe(self, callback, try_to_connect):
+ with self._lock:
+ if not self._callbacks_and_connectivities and not self._polling:
+ polling_thread = threading.Thread(
+ target=self._poll_connectivity,
+ args=(self._low_channel, bool(try_to_connect)))
+ polling_thread.start()
+ self._polling = True
+ self._callbacks_and_connectivities.append([callback, None])
+ elif not self._delivering and self._connectivity is not None:
+ self._spawn_delivery(self._connectivity, (callback,))
+ self._try_to_connect |= bool(try_to_connect)
+ self._callbacks_and_connectivities.append(
+ [callback, self._connectivity])
+ else:
+ self._try_to_connect |= bool(try_to_connect)
+ self._callbacks_and_connectivities.append([callback, None])
+
+ def unsubscribe(self, callback):
+ with self._lock:
+ for index, (subscribed_callback, unused_connectivity) in enumerate(
+ self._callbacks_and_connectivities):
+ if callback == subscribed_callback:
+ self._callbacks_and_connectivities.pop(index)
+ break
+
+ def low_channel(self):
+ return self._low_channel
diff --git a/src/python/grpcio/grpc/beta/_server.py b/src/python/grpcio/grpc/beta/_server.py
new file mode 100644
index 0000000000..daa42c475a
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_server.py
@@ -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.
+
+"""Beta API server implementation."""
+
+import threading
+
+from grpc._links import service
+from grpc.beta import interfaces
+from grpc.framework.core import implementations as _core_implementations
+from grpc.framework.crust import implementations as _crust_implementations
+from grpc.framework.foundation import logging_pool
+from grpc.framework.interfaces.base import base
+from grpc.framework.interfaces.links import utilities
+
+_DEFAULT_POOL_SIZE = 8
+_DEFAULT_TIMEOUT = 300
+_MAXIMUM_TIMEOUT = 24 * 60 * 60
+
+
+class _GRPCServicer(base.Servicer):
+
+ def __init__(self, delegate):
+ self._delegate = delegate
+
+ def service(self, group, method, context, output_operator):
+ try:
+ return self._delegate.service(group, method, context, output_operator)
+ except base.NoSuchMethodError as e:
+ if e.code is None and e.details is None:
+ raise base.NoSuchMethodError(
+ interfaces.StatusCode.UNIMPLEMENTED,
+ b'Method "%s" of service "%s" not implemented!' % (method, group))
+ else:
+ 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, grpc_link, end_link, pool):
+ self._grpc_link = grpc_link
+ self._end_link = end_link
+ self._pool = pool
+
+ def add_insecure_port(self, address):
+ return self._grpc_link.add_port(address, None)
+
+ 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
+
+
+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,
+ _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)
diff --git a/src/python/grpcio/grpc/beta/_stub.py b/src/python/grpcio/grpc/beta/_stub.py
new file mode 100644
index 0000000000..cfbecb852b
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/_stub.py
@@ -0,0 +1,111 @@
+# 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.
+
+"""Beta API stub implementation."""
+
+import threading
+
+from grpc._links import invocation
+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
+
+_DEFAULT_POOL_SIZE = 6
+
+
+class _AutoIntermediary(object):
+
+ def __init__(self, delegate, on_deletion):
+ self._delegate = delegate
+ self._on_deletion = on_deletion
+
+ def __getattr__(self, attr):
+ return getattr(self._delegate, attr)
+
+ def __del__(self):
+ self._on_deletion()
+
+
+def _assemble(
+ channel, host, metadata_transformer, request_serializers,
+ response_deserializers, thread_pool, thread_pool_size):
+ 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)
+
+
+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(
+ 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)
+
+
+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(
+ 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)
diff --git a/src/python/grpcio/grpc/beta/implementations.py b/src/python/grpcio/grpc/beta/implementations.py
new file mode 100644
index 0000000000..9b461fb3dd
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/implementations.py
@@ -0,0 +1,367 @@
+# 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.
+
+"""Entry points into the Beta API of gRPC Python."""
+
+# threading is referenced from specification in this module.
+import abc
+import enum
+import threading # pylint: disable=unused-import
+
+# cardinality and face are referenced from specification in this module.
+from grpc._adapter import _intermediary_low
+from grpc._adapter import _types
+from grpc.beta import _connectivity_channel
+from grpc.beta import _server
+from grpc.beta import _stub
+from grpc.beta import interfaces
+from grpc.framework.common import cardinality # pylint: disable=unused-import
+from grpc.framework.interfaces.face import face # pylint: disable=unused-import
+
+_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = (
+ 'Exception calling channel subscription callback!')
+
+
+class ClientCredentials(object):
+ """A value encapsulating the data required to create a secure Channel.
+
+ This class and its instances have no supported interface - it exists to define
+ the type of its instances and its instances exist to be passed to other
+ functions.
+ """
+
+ def __init__(self, low_credentials, intermediary_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.
+
+ Args:
+ root_certificates: The PEM-encoded root certificates or None to ask for
+ them to be retrieved from a default location.
+ private_key: The PEM-encoded private key to use or None if no private key
+ should be used.
+ certificate_chain: The PEM-encoded certificate chain to use or None if no
+ certificate chain should be used.
+
+ Returns:
+ A ClientCredentials 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
+
+
+class Channel(object):
+ """A channel to a remote host through which RPCs may be conducted.
+
+ Only the "subscribe" and "unsubscribe" methods are supported for application
+ use. This class' instance constructor and all other attributes are
+ unsupported.
+ """
+
+ def __init__(self, low_channel, intermediary_low_channel):
+ self._low_channel = low_channel
+ self._intermediary_low_channel = intermediary_low_channel
+ self._connectivity_channel = _connectivity_channel.ConnectivityChannel(
+ low_channel)
+
+ def subscribe(self, callback, try_to_connect=None):
+ """Subscribes to this Channel's connectivity.
+
+ Args:
+ callback: A callable to be invoked and passed an
+ interfaces.ChannelConnectivity identifying this Channel's connectivity.
+ The callable will be invoked immediately upon subscription and again for
+ every change to this Channel's connectivity thereafter until it is
+ unsubscribed.
+ try_to_connect: A boolean indicating whether or not this Channel should
+ attempt to connect if it is not already connected and ready to conduct
+ RPCs.
+ """
+ self._connectivity_channel.subscribe(callback, try_to_connect)
+
+ def unsubscribe(self, callback):
+ """Unsubscribes a callback from this Channel's connectivity.
+
+ Args:
+ callback: A callable previously registered with this Channel from having
+ been passed to its "subscribe" method.
+ """
+ self._connectivity_channel.unsubscribe(callback)
+
+
+def insecure_channel(host, port):
+ """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.
+
+ Returns:
+ A Channel to the remote host through which RPCs may be conducted.
+ """
+ intermediary_low_channel = _intermediary_low.Channel(
+ '%s:%d' % (host, port), None)
+ return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
+
+
+def secure_channel(host, port, client_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.
+
+ 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)
+ return Channel(intermediary_low_channel._internal, intermediary_low_channel) # pylint: disable=protected-access
+
+
+class StubOptions(object):
+ """A value encapsulating the various options for creation of a Stub.
+
+ 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, host, request_serializers, response_deserializers,
+ metadata_transformer, thread_pool, thread_pool_size):
+ self.host = host
+ self.request_serializers = request_serializers
+ self.response_deserializers = response_deserializers
+ self.metadata_transformer = metadata_transformer
+ self.thread_pool = thread_pool
+ self.thread_pool_size = thread_pool_size
+
+_EMPTY_STUB_OPTIONS = StubOptions(
+ None, None, None, None, None, None)
+
+
+def stub_options(
+ host=None, request_serializers=None, response_deserializers=None,
+ metadata_transformer=None, thread_pool=None, thread_pool_size=None):
+ """Creates a StubOptions value to be passed at stub creation.
+
+ All parameters are optional and should always be passed by keyword.
+
+ Args:
+ host: A host string to set on RPC calls.
+ request_serializers: A dictionary from service name-method name pair to
+ request serialization behavior.
+ response_deserializers: A dictionary from service name-method name pair to
+ response deserialization behavior.
+ metadata_transformer: A callable that given a metadata object produces
+ another metadata object to be used in the underlying communication on the
+ wire.
+ thread_pool: A thread pool to use in stubs.
+ thread_pool_size: The size of thread pool to create for use in stubs;
+ ignored if thread_pool has been passed.
+
+ Returns:
+ A StubOptions value created from the passed parameters.
+ """
+ return StubOptions(
+ host, request_serializers, response_deserializers,
+ metadata_transformer, thread_pool, thread_pool_size)
+
+
+def generic_stub(channel, options=None):
+ """Creates a face.GenericStub on which RPCs can be made.
+
+ Args:
+ channel: A Channel for use by the created stub.
+ options: A StubOptions customizing the created stub.
+
+ Returns:
+ A face.GenericStub on which RPCs can be made.
+ """
+ effective_options = _EMPTY_STUB_OPTIONS if options is None else options
+ return _stub.generic_stub(
+ channel._intermediary_low_channel, effective_options.host, # pylint: disable=protected-access
+ effective_options.metadata_transformer,
+ effective_options.request_serializers,
+ effective_options.response_deserializers, effective_options.thread_pool,
+ effective_options.thread_pool_size)
+
+
+def dynamic_stub(channel, service, cardinalities, options=None):
+ """Creates a face.DynamicStub with which RPCs can be invoked.
+
+ Args:
+ channel: A Channel for the returned face.DynamicStub to use.
+ service: The package-qualified full name of the service.
+ cardinalities: A dictionary from RPC method name to cardinality.Cardinality
+ value identifying the cardinality of the RPC method.
+ options: An optional StubOptions value further customizing the functionality
+ of the returned face.DynamicStub.
+
+ Returns:
+ A face.DynamicStub with which RPCs can be invoked.
+ """
+ effective_options = StubOptions() if options is None else options
+ return _stub.dynamic_stub(
+ channel._intermediary_low_channel, effective_options.host, service, # pylint: disable=protected-access
+ cardinalities, effective_options.metadata_transformer,
+ effective_options.request_serializers,
+ effective_options.response_deserializers, effective_options.thread_pool,
+ effective_options.thread_pool_size)
+
+
+class ServerCredentials(object):
+ """A value encapsulating the data required to open a secure port on a Server.
+
+ 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, intermediary_low_credentials):
+ self._low_credentials = low_credentials
+ self._intermediary_low_credentials = intermediary_low_credentials
+
+
+def ssl_server_credentials(
+ private_key_certificate_chain_pairs, root_certificates=None,
+ require_client_auth=False):
+ """Creates a ServerCredentials for use with an SSL-enabled Server.
+
+ Args:
+ private_key_certificate_chain_pairs: A nonempty sequence each element of
+ which is a pair the first element of which is a PEM-encoded private key
+ and the second element of which is the corresponding PEM-encoded
+ certificate chain.
+ root_certificates: PEM-encoded client root certificates to be used for
+ verifying authenticated clients. If omitted, require_client_auth must also
+ be omitted or be False.
+ require_client_auth: A boolean indicating whether or not to require clients
+ to be authenticated. May only be True if root_certificates is not None.
+
+ Returns:
+ A ServerCredentials for use with an SSL-enabled Server.
+ """
+ if len(private_key_certificate_chain_pairs) == 0:
+ raise ValueError(
+ 'At least one private key-certificate chain pairis required!')
+ elif require_client_auth and root_certificates is None:
+ raise ValueError(
+ 'Illegal to require client auth without providing root certificates!')
+ else:
+ intermediary_low_credentials = _intermediary_low.ServerCredentials(
+ root_certificates, private_key_certificate_chain_pairs,
+ require_client_auth)
+ return ServerCredentials(
+ intermediary_low_credentials._internal, intermediary_low_credentials) # pylint: disable=protected-access
+
+
+class ServerOptions(object):
+ """A value encapsulating the various options for creation of a Server.
+
+ 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, multi_method_implementation, request_deserializers,
+ response_serializers, thread_pool, thread_pool_size, default_timeout,
+ maximum_timeout):
+ self.multi_method_implementation = multi_method_implementation
+ self.request_deserializers = request_deserializers
+ self.response_serializers = response_serializers
+ self.thread_pool = thread_pool
+ self.thread_pool_size = thread_pool_size
+ self.default_timeout = default_timeout
+ self.maximum_timeout = maximum_timeout
+
+_EMPTY_SERVER_OPTIONS = ServerOptions(
+ None, None, None, None, None, None, None)
+
+
+def server_options(
+ multi_method_implementation=None, request_deserializers=None,
+ response_serializers=None, thread_pool=None, thread_pool_size=None,
+ default_timeout=None, maximum_timeout=None):
+ """Creates a ServerOptions value to be passed at server creation.
+
+ All parameters are optional and should always be passed by keyword.
+
+ Args:
+ multi_method_implementation: A face.MultiMethodImplementation to be called
+ to service an RPC if the server has no specific method implementation for
+ the name of the RPC for which service was requested.
+ request_deserializers: A dictionary from service name-method name pair to
+ request deserialization behavior.
+ response_serializers: A dictionary from service name-method name pair to
+ response serialization behavior.
+ thread_pool: A thread pool to use in stubs.
+ thread_pool_size: The size of thread pool to create for use in stubs;
+ ignored if thread_pool has been passed.
+ default_timeout: A duration in seconds to allow for RPC service when
+ servicing RPCs that did not include a timeout value when invoked.
+ maximum_timeout: A duration in seconds to allow for RPC service when
+ servicing RPCs no matter what timeout value was passed when the RPC was
+ invoked.
+
+ Returns:
+ A StubOptions value created from the passed parameters.
+ """
+ return ServerOptions(
+ multi_method_implementation, request_deserializers, response_serializers,
+ thread_pool, thread_pool_size, default_timeout, maximum_timeout)
+
+
+def server(service_implementations, options=None):
+ """Creates an interfaces.Server with which RPCs can be serviced.
+
+ Args:
+ service_implementations: A dictionary from service name-method name pair to
+ face.MethodImplementation.
+ options: An optional ServerOptions value further customizing the
+ functionality of the returned Server.
+
+ Returns:
+ An interfaces.Server with which RPCs can be serviced.
+ """
+ effective_options = _EMPTY_SERVER_OPTIONS if options is None else options
+ return _server.server(
+ service_implementations, effective_options.multi_method_implementation,
+ effective_options.request_deserializers,
+ effective_options.response_serializers, effective_options.thread_pool,
+ effective_options.thread_pool_size, effective_options.default_timeout,
+ effective_options.maximum_timeout)
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
new file mode 100644
index 0000000000..07c8618f70
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -0,0 +1,214 @@
+# 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.
+
+"""Constants and interfaces of the Beta API of gRPC Python."""
+
+import abc
+import enum
+
+from grpc._adapter import _types
+
+
+@enum.unique
+class ChannelConnectivity(enum.Enum):
+ """Mirrors grpc_connectivity_state in the gRPC Core.
+
+ Attributes:
+ IDLE: The channel is idle.
+ CONNECTING: The channel is connecting.
+ READY: The channel is ready to conduct RPCs.
+ TRANSIENT_FAILURE: The channel has seen a failure from which it expects to
+ recover.
+ FATAL_FAILURE: The channel has seen a failure from which it cannot recover.
+ """
+ IDLE = (_types.ConnectivityState.IDLE, 'idle',)
+ CONNECTING = (_types.ConnectivityState.CONNECTING, 'connecting',)
+ READY = (_types.ConnectivityState.READY, 'ready',)
+ TRANSIENT_FAILURE = (
+ _types.ConnectivityState.TRANSIENT_FAILURE, 'transient failure',)
+ FATAL_FAILURE = (_types.ConnectivityState.FATAL_FAILURE, 'fatal failure',)
+
+
+@enum.unique
+class StatusCode(enum.Enum):
+ """Mirrors grpc_status_code in the C core."""
+ OK = 0
+ CANCELLED = 1
+ UNKNOWN = 2
+ INVALID_ARGUMENT = 3
+ DEADLINE_EXCEEDED = 4
+ NOT_FOUND = 5
+ ALREADY_EXISTS = 6
+ PERMISSION_DENIED = 7
+ RESOURCE_EXHAUSTED = 8
+ FAILED_PRECONDITION = 9
+ ABORTED = 10
+ OUT_OF_RANGE = 11
+ UNIMPLEMENTED = 12
+ INTERNAL = 13
+ UNAVAILABLE = 14
+ DATA_LOSS = 15
+ UNAUTHENTICATED = 16
+
+
+class GRPCCallOptions(object):
+ """A value encapsulating gRPC-specific options passed on RPC invocation.
+
+ 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, disable_compression, subcall_of, credentials):
+ self.disable_compression = disable_compression
+ self.subcall_of = subcall_of
+ self.credentials = credentials
+
+
+def grpc_call_options(disable_compression=False, credentials=None):
+ """Creates a GRPCCallOptions value to be passed at RPC invocation.
+
+ All parameters are optional and should always be passed by keyword.
+
+ Args:
+ 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: A ClientCredentials object to use for the invoked RPC.
+ """
+ return GRPCCallOptions(disable_compression, None, credentials)
+
+
+class GRPCServicerContext(object):
+ """Exposes gRPC-specific options and behaviors to code servicing RPCs."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def peer(self):
+ """Identifies the peer that invoked the RPC being serviced.
+
+ Returns:
+ A string identifying the peer that invoked the RPC being serviced.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def disable_next_response_compression(self):
+ """Disables compression of the next response passed by the application."""
+ raise NotImplementedError()
+
+
+class GRPCInvocationContext(object):
+ """Exposes gRPC-specific options and behaviors to code invoking RPCs."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def disable_next_request_compression(self):
+ """Disables compression of the next request passed by the application."""
+ raise NotImplementedError()
+
+
+class Server(object):
+ """Services RPCs."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def add_insecure_port(self, address):
+ """Reserves a port for insecure RPC service once this Server becomes active.
+
+ This method may only be called before calling this Server's start method is
+ called.
+
+ Args:
+ address: The address for which to open a port.
+
+ Returns:
+ An integer port on which RPCs will be serviced after this link has been
+ started. This is typically the same number as the port number contained
+ in the passed address, but will likely be different if the port number
+ contained in the passed address was zero.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def add_secure_port(self, address, server_credentials):
+ """Reserves a port for secure RPC service after this Server becomes active.
+
+ This method may only be called before calling this Server's start method is
+ called.
+
+ Args:
+ address: The address for which to open a port.
+ server_credentials: A ServerCredentials.
+
+ Returns:
+ An integer port on which RPCs will be serviced after this link has been
+ started. This is typically the same number as the port number contained
+ in the passed address, but will likely be different if the port number
+ contained in the passed address was zero.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def start(self):
+ """Starts this Server's service of RPCs.
+
+ This method may only be called while the server is not serving RPCs (i.e. it
+ is not idempotent).
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def stop(self, grace):
+ """Stops this Server's service of RPCs.
+
+ All calls to this method immediately stop service of new RPCs. When existing
+ RPCs are aborted is controlled by the grace period parameter passed to this
+ method.
+
+ This method may be called at any time and is idempotent. Passing a smaller
+ grace value than has been passed in a previous call will have the effect of
+ stopping the Server sooner. Passing a larger grace value than has been
+ passed in a previous call will not have the effect of stopping the sooner
+ later.
+
+ Args:
+ grace: A duration of time in seconds to allow existing RPCs to complete
+ before being aborted by this Server's stopping. May be zero for
+ immediate abortion of all in-progress RPCs.
+
+ Returns:
+ A threading.Event that will be set when this Server has completely
+ stopped. The returned event may not be set until after the full grace
+ period (if some ongoing RPC continues for the full length of the period)
+ of it may be set much sooner (such as if this Server had no RPCs underway
+ at the time it was stopped or if all RPCs that it had underway completed
+ very early in the grace period).
+ """
+ raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/beta/utilities.py b/src/python/grpcio/grpc/beta/utilities.py
new file mode 100644
index 0000000000..fb07a76579
--- /dev/null
+++ b/src/python/grpcio/grpc/beta/utilities.py
@@ -0,0 +1,164 @@
+# 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.
+
+"""Utilities for the gRPC Python Beta API."""
+
+import threading
+import time
+
+# implementations is referenced from specification in this module.
+from grpc.beta import implementations # pylint: disable=unused-import
+from grpc.beta import interfaces
+from grpc.framework.foundation import callable_util
+from grpc.framework.foundation import future
+
+_DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = (
+ 'Exception calling connectivity future "done" callback!')
+
+
+class _ChannelReadyFuture(future.Future):
+
+ def __init__(self, channel):
+ self._condition = threading.Condition()
+ self._channel = channel
+
+ self._matured = False
+ self._cancelled = False
+ self._done_callbacks = []
+
+ def _block(self, timeout):
+ until = None if timeout is None else time.time() + timeout
+ with self._condition:
+ while True:
+ if self._cancelled:
+ raise future.CancelledError()
+ elif self._matured:
+ return
+ else:
+ if until is None:
+ self._condition.wait()
+ else:
+ remaining = until - time.time()
+ if remaining < 0:
+ raise future.TimeoutError()
+ else:
+ self._condition.wait(timeout=remaining)
+
+ def _update(self, connectivity):
+ with self._condition:
+ if (not self._cancelled and
+ connectivity is interfaces.ChannelConnectivity.READY):
+ self._matured = True
+ self._channel.unsubscribe(self._update)
+ self._condition.notify_all()
+ done_callbacks = tuple(self._done_callbacks)
+ self._done_callbacks = None
+ else:
+ return
+
+ for done_callback in done_callbacks:
+ callable_util.call_logging_exceptions(
+ done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
+
+ def cancel(self):
+ with self._condition:
+ if not self._matured:
+ self._cancelled = True
+ self._channel.unsubscribe(self._update)
+ self._condition.notify_all()
+ done_callbacks = tuple(self._done_callbacks)
+ self._done_callbacks = None
+ else:
+ return False
+
+ for done_callback in done_callbacks:
+ callable_util.call_logging_exceptions(
+ done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self)
+
+ def cancelled(self):
+ with self._condition:
+ return self._cancelled
+
+ def running(self):
+ with self._condition:
+ return not self._cancelled and not self._matured
+
+ def done(self):
+ with self._condition:
+ return self._cancelled or self._matured
+
+ def result(self, timeout=None):
+ self._block(timeout)
+ return None
+
+ def exception(self, timeout=None):
+ self._block(timeout)
+ return None
+
+ def traceback(self, timeout=None):
+ self._block(timeout)
+ return None
+
+ def add_done_callback(self, fn):
+ with self._condition:
+ if not self._cancelled and not self._matured:
+ self._done_callbacks.append(fn)
+ return
+
+ fn(self)
+
+ def start(self):
+ with self._condition:
+ self._channel.subscribe(self._update, try_to_connect=True)
+
+ def __del__(self):
+ with self._condition:
+ if not self._cancelled and not self._matured:
+ self._channel.unsubscribe(self._update)
+
+
+def channel_ready_future(channel):
+ """Creates a future.Future tracking when an implementations.Channel is ready.
+
+ Cancelling the returned future.Future does not tell the given
+ implementations.Channel to abandon attempts it may have been making to
+ connect; cancelling merely deactivates the return future.Future's
+ subscription to the given implementations.Channel's connectivity.
+
+ Args:
+ channel: An implementations.Channel.
+
+ Returns:
+ A future.Future that matures when the given Channel has connectivity
+ interfaces.ChannelConnectivity.READY.
+ """
+ ready_future = _ChannelReadyFuture(channel)
+ ready_future.start()
+ return ready_future
+
diff --git a/src/python/grpcio/grpc/framework/core/_constants.py b/src/python/grpcio/grpc/framework/core/_constants.py
index d3be3a4c4a..0f47cb48e0 100644
--- a/src/python/grpcio/grpc/framework/core/_constants.py
+++ b/src/python/grpcio/grpc/framework/core/_constants.py
@@ -44,14 +44,15 @@ TICKET_SUBSCRIPTION_FOR_BASE_SUBSCRIPTION_KIND = {
# ticket should be sent to the other side in the event of such an
# outcome.
ABORTION_OUTCOME_TO_TICKET_TERMINATION = {
- base.Outcome.CANCELLED: links.Ticket.Termination.CANCELLATION,
- base.Outcome.EXPIRED: links.Ticket.Termination.EXPIRATION,
- base.Outcome.LOCAL_SHUTDOWN: links.Ticket.Termination.SHUTDOWN,
- base.Outcome.REMOTE_SHUTDOWN: None,
- base.Outcome.RECEPTION_FAILURE: links.Ticket.Termination.RECEPTION_FAILURE,
- base.Outcome.TRANSMISSION_FAILURE: None,
- base.Outcome.LOCAL_FAILURE: links.Ticket.Termination.LOCAL_FAILURE,
- base.Outcome.REMOTE_FAILURE: links.Ticket.Termination.REMOTE_FAILURE,
+ base.Outcome.Kind.CANCELLED: links.Ticket.Termination.CANCELLATION,
+ base.Outcome.Kind.EXPIRED: links.Ticket.Termination.EXPIRATION,
+ base.Outcome.Kind.LOCAL_SHUTDOWN: links.Ticket.Termination.SHUTDOWN,
+ base.Outcome.Kind.REMOTE_SHUTDOWN: None,
+ base.Outcome.Kind.RECEPTION_FAILURE:
+ links.Ticket.Termination.RECEPTION_FAILURE,
+ base.Outcome.Kind.TRANSMISSION_FAILURE: None,
+ base.Outcome.Kind.LOCAL_FAILURE: links.Ticket.Termination.LOCAL_FAILURE,
+ base.Outcome.Kind.REMOTE_FAILURE: links.Ticket.Termination.REMOTE_FAILURE,
}
INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Core) internal error! )-:'
diff --git a/src/python/grpcio/grpc/framework/core/_context.py b/src/python/grpcio/grpc/framework/core/_context.py
index 76b3534530..a346e9d478 100644
--- a/src/python/grpcio/grpc/framework/core/_context.py
+++ b/src/python/grpcio/grpc/framework/core/_context.py
@@ -33,6 +33,7 @@ import time
# _interfaces is referenced from specification in this module.
from grpc.framework.core import _interfaces # pylint: disable=unused-import
+from grpc.framework.core import _utilities
from grpc.framework.interfaces.base import base
@@ -56,11 +57,12 @@ class OperationContext(base.OperationContext):
self._transmission_manager = transmission_manager
self._expiration_manager = expiration_manager
- def _abort(self, outcome):
+ def _abort(self, outcome_kind):
with self._lock:
if self._termination_manager.outcome is None:
+ outcome = _utilities.Outcome(outcome_kind, None, None)
self._termination_manager.abort(outcome)
- self._transmission_manager.abort(outcome, None, None)
+ self._transmission_manager.abort(outcome)
self._expiration_manager.terminate()
def outcome(self):
@@ -85,8 +87,8 @@ class OperationContext(base.OperationContext):
def cancel(self):
"""See base.OperationContext.cancel for specification."""
- self._abort(base.Outcome.CANCELLED)
+ self._abort(base.Outcome.Kind.CANCELLED)
def fail(self, exception):
"""See base.OperationContext.fail for specification."""
- self._abort(base.Outcome.LOCAL_FAILURE)
+ self._abort(base.Outcome.Kind.LOCAL_FAILURE)
diff --git a/src/python/grpcio/grpc/framework/core/_emission.py b/src/python/grpcio/grpc/framework/core/_emission.py
index 2d7b2e2f10..8ab59dc3e5 100644
--- a/src/python/grpcio/grpc/framework/core/_emission.py
+++ b/src/python/grpcio/grpc/framework/core/_emission.py
@@ -30,6 +30,7 @@
"""State and behavior for handling emitted values."""
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.interfaces.base import base
@@ -81,9 +82,10 @@ class EmissionManager(_interfaces.EmissionManager):
payload_present and self._completion_seen or
completion_present and self._completion_seen or
allowance_present and allowance <= 0):
- self._termination_manager.abort(base.Outcome.LOCAL_FAILURE)
- self._transmission_manager.abort(
- base.Outcome.LOCAL_FAILURE, None, None)
+ outcome = _utilities.Outcome(
+ base.Outcome.Kind.LOCAL_FAILURE, None, None)
+ self._termination_manager.abort(outcome)
+ self._transmission_manager.abort(outcome)
self._expiration_manager.terminate()
else:
self._initial_metadata_seen |= initial_metadata_present
diff --git a/src/python/grpcio/grpc/framework/core/_end.py b/src/python/grpcio/grpc/framework/core/_end.py
index fb2c532df6..8e07d9061e 100644
--- a/src/python/grpcio/grpc/framework/core/_end.py
+++ b/src/python/grpcio/grpc/framework/core/_end.py
@@ -30,7 +30,6 @@
"""Implementation of base.End."""
import abc
-import enum
import threading
import uuid
@@ -70,12 +69,12 @@ class _Cycle(object):
def _abort(operations):
for operation in operations:
- operation.abort(base.Outcome.LOCAL_SHUTDOWN)
+ operation.abort(base.Outcome.Kind.LOCAL_SHUTDOWN)
def _cancel_futures(futures):
for future in futures:
- futures.cancel()
+ future.cancel()
def _future_shutdown(lock, cycle, event):
@@ -83,8 +82,6 @@ def _future_shutdown(lock, cycle, event):
with lock:
_abort(cycle.operations.values())
_cancel_futures(cycle.futures)
- pool = cycle.pool
- cycle.pool.shutdown(wait=True)
return in_future
@@ -93,19 +90,19 @@ def _termination_action(lock, stats, operation_id, cycle):
Args:
lock: A lock to hold during the termination action.
- states: A mapping from base.Outcome values to integers to increment with
- the outcome given to 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 as its sole parameter and that
- should be used as the termination action for the operation associated
- with the given operation ID.
+ 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):
+ def termination_action(outcome_kind):
with lock:
- stats[outcome] += 1
+ stats[outcome_kind] += 1
cycle.operations.pop(operation_id, None)
if not cycle.operations:
for action in cycle.idle_actions:
@@ -113,6 +110,7 @@ def _termination_action(lock, stats, operation_id, cycle):
cycle.idle_actions = []
if cycle.grace:
_cancel_futures(cycle.futures)
+ cycle.pool.shutdown(wait=False)
return termination_action
@@ -129,7 +127,7 @@ class _End(End):
self._lock = threading.Condition()
self._servicer_package = servicer_package
- self._stats = {outcome: 0 for outcome in base.Outcome}
+ self._stats = {outcome_kind: 0 for outcome_kind in base.Outcome.Kind}
self._mate = None
@@ -170,7 +168,7 @@ class _End(End):
def operate(
self, group, method, subscription, timeout, initial_metadata=None,
- payload=None, completion=None):
+ payload=None, completion=None, protocol_options=None):
"""See base.End.operate for specification."""
operation_id = uuid.uuid4()
with self._lock:
@@ -179,9 +177,9 @@ class _End(End):
termination_action = _termination_action(
self._lock, self._stats, operation_id, self._cycle)
operation = _operation.invocation_operate(
- operation_id, group, method, subscription, timeout, initial_metadata,
- payload, completion, self._mate.accept_ticket, termination_action,
- self._cycle.pool)
+ operation_id, group, method, subscription, timeout, protocol_options,
+ initial_metadata, payload, completion, self._mate.accept_ticket,
+ termination_action, self._cycle.pool)
self._cycle.operations[operation_id] = operation
return operation.context, operation.operator
@@ -205,11 +203,11 @@ class _End(End):
def accept_ticket(self, ticket):
"""See links.Link.accept_ticket for specification."""
with self._lock:
- if self._cycle is not None and not self._cycle.grace:
+ if self._cycle is not None:
operation = self._cycle.operations.get(ticket.operation_id)
if operation is not None:
operation.handle_ticket(ticket)
- elif self._servicer_package is not None:
+ 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)
operation = _operation.service_operate(
diff --git a/src/python/grpcio/grpc/framework/core/_expiration.py b/src/python/grpcio/grpc/framework/core/_expiration.py
index d8690b3a02..ded0ab6bce 100644
--- a/src/python/grpcio/grpc/framework/core/_expiration.py
+++ b/src/python/grpcio/grpc/framework/core/_expiration.py
@@ -32,6 +32,7 @@
import time
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.foundation import later
from grpc.framework.interfaces.base import base
@@ -73,7 +74,8 @@ class _ExpirationManager(_interfaces.ExpirationManager):
if self._future is not None and index == self._index:
self._future = None
self._termination_manager.expire()
- self._transmission_manager.abort(base.Outcome.EXPIRED, None, None)
+ self._transmission_manager.abort(
+ _utilities.Outcome(base.Outcome.Kind.EXPIRED, None, None))
return expire
def start(self):
diff --git a/src/python/grpcio/grpc/framework/core/_ingestion.py b/src/python/grpcio/grpc/framework/core/_ingestion.py
index 7b8127f3fc..4129a8ce43 100644
--- a/src/python/grpcio/grpc/framework/core/_ingestion.py
+++ b/src/python/grpcio/grpc/framework/core/_ingestion.py
@@ -35,6 +35,7 @@ import enum
from grpc.framework.core import _constants
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.foundation import abandonment
from grpc.framework.foundation import callable_util
from grpc.framework.interfaces.base import base
@@ -46,7 +47,7 @@ _INGESTION_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!'
class _SubscriptionCreation(
collections.namedtuple(
'_SubscriptionCreation',
- ('kind', 'subscription', 'code', 'message',))):
+ ('kind', 'subscription', 'code', 'details',))):
"""A sum type for the outcome of ingestion initialization.
Attributes:
@@ -56,7 +57,7 @@ class _SubscriptionCreation(
code: A code value to be sent to the other side of the operation along with
an indication that the operation is being aborted due to an error on the
remote side of the operation. Only present if kind is Kind.REMOTE_ERROR.
- message: A message value to be sent to the other side of the operation
+ details: A details value to be sent to the other side of the operation
along with an indication that the operation is being aborted due to an
error on the remote side of the operation. Only present if kind is
Kind.REMOTE_ERROR.
@@ -114,7 +115,7 @@ class _ServiceSubscriptionCreator(_SubscriptionCreator):
group, method, self._operation_context, self._output_operator)
except base.NoSuchMethodError as e:
return _SubscriptionCreation(
- _SubscriptionCreation.Kind.REMOTE_ERROR, None, e.code, e.message)
+ _SubscriptionCreation.Kind.REMOTE_ERROR, None, e.code, e.details)
except abandonment.Abandoned:
return _SubscriptionCreation(
_SubscriptionCreation.Kind.ABANDONED, None, None, None)
@@ -139,7 +140,7 @@ class _IngestionManager(_interfaces.IngestionManager):
def __init__(
self, lock, pool, subscription, subscription_creator, termination_manager,
- transmission_manager, expiration_manager):
+ transmission_manager, expiration_manager, protocol_manager):
"""Constructor.
Args:
@@ -156,12 +157,14 @@ class _IngestionManager(_interfaces.IngestionManager):
transmission_manager: The _interfaces.TransmissionManager for the
operation.
expiration_manager: The _interfaces.ExpirationManager for the operation.
+ protocol_manager: The _interfaces.ProtocolManager for the operation.
"""
self._lock = lock
self._pool = pool
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._expiration_manager = expiration_manager
+ self._protocol_manager = protocol_manager
if subscription is None:
self._subscription_creator = subscription_creator
@@ -190,11 +193,13 @@ class _IngestionManager(_interfaces.IngestionManager):
self._pending_payloads = None
self._pending_completion = None
- def _abort_and_notify(self, outcome, code, message):
+ def _abort_and_notify(self, outcome_kind, code, details):
self._abort_internal_only()
- self._termination_manager.abort(outcome)
- self._transmission_manager.abort(outcome, code, message)
- self._expiration_manager.terminate()
+ if self._termination_manager.outcome is None:
+ outcome = _utilities.Outcome(outcome_kind, code, details)
+ self._termination_manager.abort(outcome)
+ self._transmission_manager.abort(outcome)
+ self._expiration_manager.terminate()
def _operator_next(self):
"""Computes the next step for full-subscription ingestion.
@@ -250,12 +255,13 @@ class _IngestionManager(_interfaces.IngestionManager):
else:
with self._lock:
if self._termination_manager.outcome is None:
- self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
+ self._abort_and_notify(
+ base.Outcome.Kind.LOCAL_FAILURE, None, None)
return
else:
with self._lock:
if self._termination_manager.outcome is None:
- self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
+ self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None)
return
def _operator_post_create(self, subscription):
@@ -279,18 +285,21 @@ class _IngestionManager(_interfaces.IngestionManager):
if outcome.return_value is None:
with self._lock:
if self._termination_manager.outcome is None:
- self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
+ self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None)
elif outcome.return_value.kind is _SubscriptionCreation.Kind.ABANDONED:
with self._lock:
if self._termination_manager.outcome is None:
- self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None)
+ self._abort_and_notify(base.Outcome.Kind.LOCAL_FAILURE, None, None)
elif outcome.return_value.kind is _SubscriptionCreation.Kind.REMOTE_ERROR:
code = outcome.return_value.code
- message = outcome.return_value.message
+ details = outcome.return_value.details
with self._lock:
if self._termination_manager.outcome is None:
- self._abort_and_notify(base.Outcome.REMOTE_FAILURE, code, message)
+ self._abort_and_notify(
+ base.Outcome.Kind.REMOTE_FAILURE, code, details)
elif outcome.return_value.subscription.kind is base.Subscription.Kind.FULL:
+ self._protocol_manager.set_protocol_receiver(
+ outcome.return_value.subscription.protocol_receiver)
self._operator_post_create(outcome.return_value.subscription)
else:
# TODO(nathaniel): Support other subscriptions.
@@ -373,7 +382,7 @@ class _IngestionManager(_interfaces.IngestionManager):
def invocation_ingestion_manager(
subscription, lock, pool, termination_manager, transmission_manager,
- expiration_manager):
+ expiration_manager, protocol_manager):
"""Creates an IngestionManager appropriate for invocation-side use.
Args:
@@ -385,18 +394,20 @@ def invocation_ingestion_manager(
transmission_manager: The _interfaces.TransmissionManager for the
operation.
expiration_manager: The _interfaces.ExpirationManager for the operation.
+ protocol_manager: The _interfaces.ProtocolManager for the operation.
Returns:
An IngestionManager appropriate for invocation-side use.
"""
return _IngestionManager(
lock, pool, subscription, None, termination_manager, transmission_manager,
- expiration_manager)
+ expiration_manager, protocol_manager)
def service_ingestion_manager(
servicer, operation_context, output_operator, lock, pool,
- termination_manager, transmission_manager, expiration_manager):
+ termination_manager, transmission_manager, expiration_manager,
+ protocol_manager):
"""Creates an IngestionManager appropriate for service-side use.
The returned IngestionManager will require its set_group_and_name method to be
@@ -415,6 +426,7 @@ def service_ingestion_manager(
transmission_manager: The _interfaces.TransmissionManager for the
operation.
expiration_manager: The _interfaces.ExpirationManager for the operation.
+ protocol_manager: The _interfaces.ProtocolManager for the operation.
Returns:
An IngestionManager appropriate for service-side use.
@@ -423,4 +435,4 @@ def service_ingestion_manager(
servicer, operation_context, output_operator)
return _IngestionManager(
lock, pool, None, subscription_creator, termination_manager,
- transmission_manager, expiration_manager)
+ transmission_manager, expiration_manager, protocol_manager)
diff --git a/src/python/grpcio/grpc/framework/core/_interfaces.py b/src/python/grpcio/grpc/framework/core/_interfaces.py
index deb5f34f9b..ffa686b2b7 100644
--- a/src/python/grpcio/grpc/framework/core/_interfaces.py
+++ b/src/python/grpcio/grpc/framework/core/_interfaces.py
@@ -50,13 +50,13 @@ class TerminationManager(object):
If the operation has already terminated the callback will not be called.
Args:
- callback: A callable that will be passed an interfaces.Outcome value.
+ callback: A callable that will be passed a base.Outcome value.
Returns:
None if the operation has not yet terminated and the passed callback will
- be called when it does, or a base.Outcome value describing the operation
- termination if the operation has terminated and the callback will not be
- called as a result of this method call.
+ be called when it does, or a base.Outcome value describing the
+ operation termination if the operation has terminated and the callback
+ will not be called as a result of this method call.
"""
raise NotImplementedError()
@@ -76,8 +76,13 @@ class TerminationManager(object):
raise NotImplementedError()
@abc.abstractmethod
- def reception_complete(self):
- """Indicates that reception from the other side is complete."""
+ def reception_complete(self, code, details):
+ """Indicates that reception from the other side is complete.
+
+ Args:
+ code: An application-specific code value.
+ details: An application-specific details value.
+ """
raise NotImplementedError()
@abc.abstractmethod
@@ -95,7 +100,7 @@ class TerminationManager(object):
"""Indicates that the operation must abort for the indicated reason.
Args:
- outcome: An interfaces.Outcome indicating operation abortion.
+ outcome: A base.Outcome indicating operation abortion.
"""
raise NotImplementedError()
@@ -106,8 +111,8 @@ class TransmissionManager(object):
@abc.abstractmethod
def kick_off(
- self, group, method, timeout, initial_metadata, payload, completion,
- allowance):
+ self, group, method, timeout, protocol_options, initial_metadata,
+ payload, completion, allowance):
"""Transmits the values associated with operation invocation."""
raise NotImplementedError()
@@ -155,19 +160,13 @@ class TransmissionManager(object):
raise NotImplementedError()
@abc.abstractmethod
- def abort(self, outcome, code, message):
+ def abort(self, outcome):
"""Indicates that the operation has aborted.
Args:
- outcome: An interfaces.Outcome for the operation. If None, indicates that
- the operation abortion should not be communicated to the other side of
- the operation.
- code: A code value to communicate to the other side of the operation
- along with indication of operation abortion. May be None, and has no
- effect if outcome is None.
- message: A message value to communicate to the other side of the
- operation along with indication of operation abortion. May be None, and
- has no effect if outcome is None.
+ outcome: A base.Outcome for the operation. If None, indicates that the
+ operation abortion should not be communicated to the other side of the
+ operation.
"""
raise NotImplementedError()
@@ -204,6 +203,31 @@ class ExpirationManager(object):
raise NotImplementedError()
+class ProtocolManager(object):
+ """A manager of protocol-specific values passing through an operation."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def set_protocol_receiver(self, protocol_receiver):
+ """Registers the customer object that will receive protocol objects.
+
+ Args:
+ protocol_receiver: A base.ProtocolReceiver to which protocol objects for
+ the operation should be passed.
+ """
+ raise NotImplementedError()
+
+ @abc.abstractmethod
+ def accept_protocol_context(self, protocol_context):
+ """Accepts the protocol context object for the operation.
+
+ Args:
+ protocol_context: An object designated for use as the protocol context
+ of the operation, with further semantics implementation-determined.
+ """
+ raise NotImplementedError()
+
+
class EmissionManager(base.Operator):
"""A manager of values emitted by customer code."""
__metaclass__ = abc.ABCMeta
@@ -279,8 +303,7 @@ class ReceptionManager(object):
"""Handle a ticket from the other side of the operation.
Args:
- ticket: An interfaces.BackToFrontTicket or interfaces.FrontToBackTicket
- appropriate to this end of the operation and this object.
+ ticket: A links.Ticket for the operation.
"""
raise NotImplementedError()
@@ -305,10 +328,10 @@ class Operation(object):
raise NotImplementedError()
@abc.abstractmethod
- def abort(self, outcome):
+ def abort(self, outcome_kind):
"""Aborts the operation.
Args:
- outcome: A base.Outcome value indicating operation abortion.
+ outcome_kind: A base.Outcome.Kind value indicating operation abortion.
"""
raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/core/_operation.py b/src/python/grpcio/grpc/framework/core/_operation.py
index cc873c03f9..020c0c9ed9 100644
--- a/src/python/grpcio/grpc/framework/core/_operation.py
+++ b/src/python/grpcio/grpc/framework/core/_operation.py
@@ -31,16 +31,16 @@
import threading
-# _utilities is referenced from specification in this module.
from grpc.framework.core import _context
from grpc.framework.core import _emission
from grpc.framework.core import _expiration
from grpc.framework.core import _ingestion
from grpc.framework.core import _interfaces
+from grpc.framework.core import _protocol
from grpc.framework.core import _reception
from grpc.framework.core import _termination
from grpc.framework.core import _transmission
-from grpc.framework.core import _utilities # pylint: disable=unused-import
+from grpc.framework.core import _utilities
class _EasyOperation(_interfaces.Operation):
@@ -75,17 +75,19 @@ class _EasyOperation(_interfaces.Operation):
with self._lock:
self._reception_manager.receive_ticket(ticket)
- def abort(self, outcome):
+ def abort(self, outcome_kind):
with self._lock:
if self._termination_manager.outcome is None:
+ outcome = _utilities.Outcome(outcome_kind, None, None)
self._termination_manager.abort(outcome)
- self._transmission_manager.abort(outcome, None, None)
+ self._transmission_manager.abort(outcome)
self._expiration_manager.terminate()
def invocation_operate(
- operation_id, group, method, subscription, timeout, initial_metadata,
- payload, completion, ticket_sink, termination_action, pool):
+ operation_id, group, method, subscription, timeout, protocol_options,
+ initial_metadata, payload, completion, ticket_sink, termination_action,
+ pool):
"""Constructs objects necessary for front-side operation management.
Args:
@@ -95,6 +97,8 @@ def invocation_operate(
subscription: A base.Subscription describing the customer's interest in the
results of the operation.
timeout: A length of time in seconds to allow for the operation.
+ protocol_options: A transport-specific, application-specific, and/or
+ protocol-specific value relating to the invocation. May be None.
initial_metadata: An initial metadata value to be sent to the other side of
the operation. May be None if the initial metadata will be passed later or
if there will be no initial metadata passed at all.
@@ -120,23 +124,27 @@ def invocation_operate(
operation_id, ticket_sink, lock, pool, termination_manager)
expiration_manager = _expiration.invocation_expiration_manager(
timeout, lock, termination_manager, transmission_manager)
+ protocol_manager = _protocol.invocation_protocol_manager(
+ subscription, lock, pool, termination_manager, transmission_manager,
+ expiration_manager)
operation_context = _context.OperationContext(
lock, termination_manager, transmission_manager, expiration_manager)
emission_manager = _emission.EmissionManager(
lock, termination_manager, transmission_manager, expiration_manager)
ingestion_manager = _ingestion.invocation_ingestion_manager(
subscription, lock, pool, termination_manager, transmission_manager,
- expiration_manager)
+ expiration_manager, protocol_manager)
reception_manager = _reception.ReceptionManager(
termination_manager, transmission_manager, expiration_manager,
- ingestion_manager)
+ protocol_manager, ingestion_manager)
termination_manager.set_expiration_manager(expiration_manager)
transmission_manager.set_expiration_manager(expiration_manager)
emission_manager.set_ingestion_manager(ingestion_manager)
transmission_manager.kick_off(
- group, method, timeout, initial_metadata, payload, completion, None)
+ group, method, timeout, protocol_options, initial_metadata, payload,
+ completion, None)
return _EasyOperation(
lock, termination_manager, transmission_manager, expiration_manager,
@@ -170,16 +178,20 @@ def service_operate(
ticket.timeout, servicer_package.default_timeout,
servicer_package.maximum_timeout, lock, termination_manager,
transmission_manager)
+ protocol_manager = _protocol.service_protocol_manager(
+ lock, pool, termination_manager, transmission_manager,
+ expiration_manager)
operation_context = _context.OperationContext(
lock, termination_manager, transmission_manager, expiration_manager)
emission_manager = _emission.EmissionManager(
lock, termination_manager, transmission_manager, expiration_manager)
ingestion_manager = _ingestion.service_ingestion_manager(
servicer_package.servicer, operation_context, emission_manager, lock,
- pool, termination_manager, transmission_manager, expiration_manager)
+ pool, termination_manager, transmission_manager, expiration_manager,
+ protocol_manager)
reception_manager = _reception.ReceptionManager(
termination_manager, transmission_manager, expiration_manager,
- ingestion_manager)
+ protocol_manager, ingestion_manager)
termination_manager.set_expiration_manager(expiration_manager)
transmission_manager.set_expiration_manager(expiration_manager)
diff --git a/src/python/grpcio/grpc/framework/core/_protocol.py b/src/python/grpcio/grpc/framework/core/_protocol.py
new file mode 100644
index 0000000000..3177b5e302
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/core/_protocol.py
@@ -0,0 +1,176 @@
+# 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.
+
+"""State and behavior for passing protocol objects in an operation."""
+
+import collections
+import enum
+
+from grpc.framework.core import _constants
+from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
+from grpc.framework.foundation import callable_util
+from grpc.framework.interfaces.base import base
+
+_EXCEPTION_LOG_MESSAGE = 'Exception delivering protocol object!'
+
+_LOCAL_FAILURE_OUTCOME = _utilities.Outcome(
+ base.Outcome.Kind.LOCAL_FAILURE, None, None)
+
+
+class _Awaited(
+ collections.namedtuple('_Awaited', ('kind', 'value',))):
+
+ @enum.unique
+ class Kind(enum.Enum):
+ NOT_YET_ARRIVED = 'not yet arrived'
+ ARRIVED = 'arrived'
+
+_NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None)
+_ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None)
+
+
+class _Transitory(
+ collections.namedtuple('_Transitory', ('kind', 'value',))):
+
+ @enum.unique
+ class Kind(enum.Enum):
+ NOT_YET_SEEN = 'not yet seen'
+ PRESENT = 'present'
+ GONE = 'gone'
+
+_NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None)
+_GONE = _Transitory(_Transitory.Kind.GONE, None)
+
+
+class _ProtocolManager(_interfaces.ProtocolManager):
+ """An implementation of _interfaces.ExpirationManager."""
+
+ def __init__(
+ self, protocol_receiver, lock, pool, termination_manager,
+ transmission_manager, expiration_manager):
+ """Constructor.
+
+ Args:
+ protocol_receiver: An _Awaited wrapping of the base.ProtocolReceiver to
+ which protocol objects should be passed during the operation. May be
+ of kind _Awaited.Kind.NOT_YET_ARRIVED if the customer's subscription is
+ not yet known and may be of kind _Awaited.Kind.ARRIVED but with a value
+ of None if the customer's subscription did not include a
+ ProtocolReceiver.
+ lock: The operation-wide lock.
+ pool: A thread pool.
+ termination_manager: The _interfaces.TerminationManager for the operation.
+ transmission_manager: The _interfaces.TransmissionManager for the
+ operation.
+ expiration_manager: The _interfaces.ExpirationManager for the operation.
+ """
+ self._lock = lock
+ self._pool = pool
+ self._termination_manager = termination_manager
+ self._transmission_manager = transmission_manager
+ self._expiration_manager = expiration_manager
+
+ self._protocol_receiver = protocol_receiver
+ self._context = _NOT_YET_SEEN
+
+ def _abort_and_notify(self, outcome):
+ if self._termination_manager.outcome is None:
+ self._termination_manager.abort(outcome)
+ self._transmission_manager.abort(outcome)
+ self._expiration_manager.terminate()
+
+ def _deliver(self, behavior, value):
+ def deliver():
+ delivery_outcome = callable_util.call_logging_exceptions(
+ behavior, _EXCEPTION_LOG_MESSAGE, value)
+ if delivery_outcome.kind is callable_util.Outcome.Kind.RAISED:
+ with self._lock:
+ self._abort_and_notify(_LOCAL_FAILURE_OUTCOME)
+ self._pool.submit(
+ callable_util.with_exceptions_logged(
+ deliver, _constants.INTERNAL_ERROR_LOG_MESSAGE))
+
+ def set_protocol_receiver(self, protocol_receiver):
+ """See _interfaces.ProtocolManager.set_protocol_receiver for spec."""
+ self._protocol_receiver = _Awaited(_Awaited.Kind.ARRIVED, protocol_receiver)
+ if (self._context.kind is _Transitory.Kind.PRESENT and
+ protocol_receiver is not None):
+ self._deliver(protocol_receiver.context, self._context.value)
+ self._context = _GONE
+
+ def accept_protocol_context(self, protocol_context):
+ """See _interfaces.ProtocolManager.accept_protocol_context for spec."""
+ if self._protocol_receiver.kind is _Awaited.Kind.ARRIVED:
+ if self._protocol_receiver.value is not None:
+ self._deliver(self._protocol_receiver.value.context, protocol_context)
+ self._context = _GONE
+ else:
+ self._context = _Transitory(_Transitory.Kind.PRESENT, protocol_context)
+
+
+def invocation_protocol_manager(
+ subscription, lock, pool, termination_manager, transmission_manager,
+ expiration_manager):
+ """Creates an _interfaces.ProtocolManager for invocation-side use.
+
+ Args:
+ subscription: The local customer's subscription to the operation.
+ lock: The operation-wide lock.
+ pool: A thread pool.
+ termination_manager: The _interfaces.TerminationManager for the operation.
+ transmission_manager: The _interfaces.TransmissionManager for the
+ operation.
+ expiration_manager: The _interfaces.ExpirationManager for the operation.
+ """
+ if subscription.kind is base.Subscription.Kind.FULL:
+ awaited_protocol_receiver = _Awaited(
+ _Awaited.Kind.ARRIVED, subscription.protocol_receiver)
+ else:
+ awaited_protocol_receiver = _ARRIVED_AND_NONE
+ return _ProtocolManager(
+ awaited_protocol_receiver, lock, pool, termination_manager,
+ transmission_manager, expiration_manager)
+
+
+def service_protocol_manager(
+ lock, pool, termination_manager, transmission_manager, expiration_manager):
+ """Creates an _interfaces.ProtocolManager for service-side use.
+
+ Args:
+ lock: The operation-wide lock.
+ pool: A thread pool.
+ termination_manager: The _interfaces.TerminationManager for the operation.
+ transmission_manager: The _interfaces.TransmissionManager for the
+ operation.
+ expiration_manager: The _interfaces.ExpirationManager for the operation.
+ """
+ return _ProtocolManager(
+ _NOT_YET_ARRIVED, lock, pool, termination_manager, transmission_manager,
+ expiration_manager)
diff --git a/src/python/grpcio/grpc/framework/core/_reception.py b/src/python/grpcio/grpc/framework/core/_reception.py
index 1cebe3874b..ff81450dee 100644
--- a/src/python/grpcio/grpc/framework/core/_reception.py
+++ b/src/python/grpcio/grpc/framework/core/_reception.py
@@ -30,39 +30,52 @@
"""State and behavior for ticket reception."""
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.interfaces.base import base
from grpc.framework.interfaces.base import utilities
from grpc.framework.interfaces.links import links
-_REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME = {
- links.Ticket.Termination.CANCELLATION: base.Outcome.CANCELLED,
- links.Ticket.Termination.EXPIRATION: base.Outcome.EXPIRED,
- links.Ticket.Termination.SHUTDOWN: base.Outcome.REMOTE_SHUTDOWN,
- links.Ticket.Termination.RECEPTION_FAILURE: base.Outcome.RECEPTION_FAILURE,
+_REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME_KIND = {
+ links.Ticket.Termination.CANCELLATION: base.Outcome.Kind.CANCELLED,
+ links.Ticket.Termination.EXPIRATION: base.Outcome.Kind.EXPIRED,
+ links.Ticket.Termination.SHUTDOWN: base.Outcome.Kind.REMOTE_SHUTDOWN,
+ links.Ticket.Termination.RECEPTION_FAILURE:
+ base.Outcome.Kind.RECEPTION_FAILURE,
links.Ticket.Termination.TRANSMISSION_FAILURE:
- base.Outcome.TRANSMISSION_FAILURE,
- links.Ticket.Termination.LOCAL_FAILURE: base.Outcome.REMOTE_FAILURE,
- links.Ticket.Termination.REMOTE_FAILURE: base.Outcome.LOCAL_FAILURE,
+ base.Outcome.Kind.TRANSMISSION_FAILURE,
+ links.Ticket.Termination.LOCAL_FAILURE: base.Outcome.Kind.REMOTE_FAILURE,
+ links.Ticket.Termination.REMOTE_FAILURE: base.Outcome.Kind.LOCAL_FAILURE,
}
+_RECEPTION_FAILURE_OUTCOME = _utilities.Outcome(
+ base.Outcome.Kind.RECEPTION_FAILURE, None, None)
+
+
+def _carrying_protocol_context(ticket):
+ return ticket.protocol is not None and ticket.protocol.kind in (
+ links.Protocol.Kind.INVOCATION_CONTEXT,
+ links.Protocol.Kind.SERVICER_CONTEXT,)
+
class ReceptionManager(_interfaces.ReceptionManager):
"""A ReceptionManager based around a _Receiver passed to it."""
def __init__(
self, termination_manager, transmission_manager, expiration_manager,
- ingestion_manager):
+ protocol_manager, ingestion_manager):
"""Constructor.
Args:
termination_manager: The operation's _interfaces.TerminationManager.
transmission_manager: The operation's _interfaces.TransmissionManager.
expiration_manager: The operation's _interfaces.ExpirationManager.
+ protocol_manager: The operation's _interfaces.ProtocolManager.
ingestion_manager: The operation's _interfaces.IngestionManager.
"""
self._termination_manager = termination_manager
self._transmission_manager = transmission_manager
self._expiration_manager = expiration_manager
+ self._protocol_manager = protocol_manager
self._ingestion_manager = ingestion_manager
self._lowest_unseen_sequence_number = 0
@@ -73,7 +86,7 @@ class ReceptionManager(_interfaces.ReceptionManager):
self._aborted = True
if self._termination_manager.outcome is None:
self._termination_manager.abort(outcome)
- self._transmission_manager.abort(None, None, None)
+ self._transmission_manager.abort(None)
self._expiration_manager.terminate()
def _sequence_failure(self, ticket):
@@ -95,6 +108,10 @@ class ReceptionManager(_interfaces.ReceptionManager):
def _process_one(self, ticket):
if ticket.sequence_number == 0:
self._ingestion_manager.set_group_and_method(ticket.group, ticket.method)
+ if _carrying_protocol_context(ticket):
+ self._protocol_manager.accept_protocol_context(ticket.protocol.value)
+ else:
+ self._protocol_manager.accept_protocol_context(None)
if ticket.timeout is not None:
self._expiration_manager.change_timeout(ticket.timeout)
if ticket.termination is None:
@@ -102,6 +119,7 @@ class ReceptionManager(_interfaces.ReceptionManager):
else:
completion = utilities.completion(
ticket.terminal_metadata, ticket.code, ticket.message)
+ self._termination_manager.reception_complete(ticket.code, ticket.message)
self._ingestion_manager.advance(
ticket.initial_metadata, ticket.payload, completion, ticket.allowance)
if ticket.allowance is not None:
@@ -129,10 +147,12 @@ class ReceptionManager(_interfaces.ReceptionManager):
if self._aborted:
return
elif self._sequence_failure(ticket):
- self._abort(base.Outcome.RECEPTION_FAILURE)
+ self._abort(_RECEPTION_FAILURE_OUTCOME)
elif ticket.termination not in (None, links.Ticket.Termination.COMPLETION):
- outcome = _REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME[ticket.termination]
- self._abort(outcome)
+ outcome_kind = _REMOTE_TICKET_TERMINATION_TO_LOCAL_OUTCOME_KIND[
+ ticket.termination]
+ self._abort(
+ _utilities.Outcome(outcome_kind, ticket.code, ticket.message))
elif ticket.sequence_number == self._lowest_unseen_sequence_number:
self._process(ticket)
else:
diff --git a/src/python/grpcio/grpc/framework/core/_termination.py b/src/python/grpcio/grpc/framework/core/_termination.py
index ad9f6123d8..bdb9147e5b 100644
--- a/src/python/grpcio/grpc/framework/core/_termination.py
+++ b/src/python/grpcio/grpc/framework/core/_termination.py
@@ -33,6 +33,7 @@ import abc
from grpc.framework.core import _constants
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.foundation import callable_util
from grpc.framework.interfaces.base import base
@@ -74,7 +75,8 @@ class _TerminationManager(TerminationManager):
predicate: One of _invocation_completion_predicate or
_service_completion_predicate to be used to determine when the operation
has completed.
- action: A behavior to pass the operation outcome on operation termination.
+ action: A behavior to pass the operation outcome's kind on operation
+ termination.
pool: A thread pool.
"""
self._predicate = predicate
@@ -82,14 +84,19 @@ class _TerminationManager(TerminationManager):
self._pool = pool
self._expiration_manager = None
- self.outcome = None
self._callbacks = []
+ self._code = None
+ self._details = None
self._emission_complete = False
self._transmission_complete = False
self._reception_complete = False
self._ingestion_complete = False
+ # The None-ness of outcome is the operation-wide record of whether and how
+ # the operation has terminated.
+ self.outcome = None
+
def set_expiration_manager(self, expiration_manager):
self._expiration_manager = expiration_manager
@@ -106,8 +113,10 @@ class _TerminationManager(TerminationManager):
act = callable_util.with_exceptions_logged(
self._action, _constants.INTERNAL_ERROR_LOG_MESSAGE)
- if outcome is base.Outcome.LOCAL_FAILURE:
- self._pool.submit(act, outcome)
+ # TODO(issue 3202): Don't call the local application's callbacks if it has
+ # previously shown a programming defect.
+ if False and outcome.kind is base.Outcome.Kind.LOCAL_FAILURE:
+ self._pool.submit(act, base.Outcome.Kind.LOCAL_FAILURE)
else:
def call_callbacks_and_act(callbacks, outcome):
for callback in callbacks:
@@ -115,9 +124,11 @@ class _TerminationManager(TerminationManager):
callback, _constants.TERMINATION_CALLBACK_EXCEPTION_LOG_MESSAGE,
outcome)
if callback_outcome.exception is not None:
- outcome = base.Outcome.LOCAL_FAILURE
+ act_outcome_kind = base.Outcome.Kind.LOCAL_FAILURE
break
- act(outcome)
+ else:
+ act_outcome_kind = outcome.kind
+ act(act_outcome_kind)
self._pool.submit(
callable_util.with_exceptions_logged(
@@ -132,7 +143,9 @@ class _TerminationManager(TerminationManager):
if self._predicate(
self._emission_complete, self._transmission_complete,
self._reception_complete, self._ingestion_complete):
- self._terminate_and_notify(base.Outcome.COMPLETED)
+ self._terminate_and_notify(
+ _utilities.Outcome(
+ base.Outcome.Kind.COMPLETED, self._code, self._details))
return True
else:
return False
@@ -163,10 +176,12 @@ class _TerminationManager(TerminationManager):
else:
return False
- def reception_complete(self):
+ def reception_complete(self, code, details):
"""See superclass method for specification."""
if self.outcome is None:
self._reception_complete = True
+ self._code = code
+ self._details = details
self._perhaps_complete()
def ingestion_complete(self):
@@ -177,7 +192,8 @@ class _TerminationManager(TerminationManager):
def expire(self):
"""See _interfaces.TerminationManager.expire for specification."""
- self._terminate_internal_only(base.Outcome.EXPIRED)
+ self._terminate_internal_only(
+ _utilities.Outcome(base.Outcome.Kind.EXPIRED, None, None))
def abort(self, outcome):
"""See _interfaces.TerminationManager.abort for specification."""
diff --git a/src/python/grpcio/grpc/framework/core/_transmission.py b/src/python/grpcio/grpc/framework/core/_transmission.py
index efef87dd4c..65b12c4160 100644
--- a/src/python/grpcio/grpc/framework/core/_transmission.py
+++ b/src/python/grpcio/grpc/framework/core/_transmission.py
@@ -29,14 +29,21 @@
"""State and behavior for ticket transmission during an operation."""
+import collections
+import enum
+
from grpc.framework.core import _constants
from grpc.framework.core import _interfaces
+from grpc.framework.core import _utilities
from grpc.framework.foundation import callable_util
from grpc.framework.interfaces.base import base
from grpc.framework.interfaces.links import links
_TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!'
+_TRANSMISSION_FAILURE_OUTCOME = _utilities.Outcome(
+ base.Outcome.Kind.TRANSMISSION_FAILURE, None, None)
+
def _explode_completion(completion):
if completion is None:
@@ -47,6 +54,31 @@ def _explode_completion(completion):
links.Ticket.Termination.COMPLETION)
+class _Abort(
+ collections.namedtuple(
+ '_Abort', ('kind', 'termination', 'code', 'details',))):
+ """Tracks whether the operation aborted and what is to be done about it.
+
+ Attributes:
+ kind: A Kind value describing the overall kind of the _Abort.
+ termination: A links.Ticket.Termination value to be sent to the other side
+ of the operation. Only valid if kind is Kind.ABORTED_NOTIFY_NEEDED.
+ code: A code value to be sent to the other side of the operation. Only
+ valid if kind is Kind.ABORTED_NOTIFY_NEEDED.
+ details: A details value to be sent to the other side of the operation.
+ Only valid if kind is Kind.ABORTED_NOTIFY_NEEDED.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ NOT_ABORTED = 'not aborted'
+ ABORTED_NOTIFY_NEEDED = 'aborted notify needed'
+ ABORTED_NO_NOTIFY = 'aborted no notify'
+
+_NOT_ABORTED = _Abort(_Abort.Kind.NOT_ABORTED, None, None, None)
+_ABORTED_NO_NOTIFY = _Abort(_Abort.Kind.ABORTED_NO_NOTIFY, None, None, None)
+
+
class TransmissionManager(_interfaces.TransmissionManager):
"""An _interfaces.TransmissionManager that sends links.Tickets."""
@@ -79,8 +111,7 @@ class TransmissionManager(_interfaces.TransmissionManager):
self._initial_metadata = None
self._payloads = []
self._completion = None
- self._aborted = False
- self._abortion_outcome = None
+ self._abort = _NOT_ABORTED
self._transmitting = False
def set_expiration_manager(self, expiration_manager):
@@ -94,24 +125,15 @@ class TransmissionManager(_interfaces.TransmissionManager):
A links.Ticket to be sent to the other side of the operation or None if
there is nothing to be sent at this time.
"""
- if self._aborted:
- if self._abortion_outcome is None:
- return None
- else:
- termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION[
- self._abortion_outcome]
- if termination is None:
- return None
- else:
- self._abortion_outcome = None
- if self._completion is None:
- code, message = None, None
- else:
- code, message = self._completion.code, self._completion.message
- return links.Ticket(
- self._operation_id, self._lowest_unused_sequence_number, None,
- None, None, None, None, None, None, None, code, message,
- termination, None)
+ if self._abort.kind is _Abort.Kind.ABORTED_NO_NOTIFY:
+ return None
+ elif self._abort.kind is _Abort.Kind.ABORTED_NOTIFY_NEEDED:
+ termination = self._abort.termination
+ code, details = self._abort.code, self._abort.details
+ self._abort = _ABORTED_NO_NOTIFY
+ return links.Ticket(
+ self._operation_id, self._lowest_unused_sequence_number, None, None,
+ None, None, None, None, None, None, code, details, termination, None)
action = False
# TODO(nathaniel): Support other subscriptions.
@@ -174,8 +196,9 @@ class TransmissionManager(_interfaces.TransmissionManager):
return
else:
with self._lock:
+ self._abort = _ABORTED_NO_NOTIFY
if self._termination_manager.outcome is None:
- self._termination_manager.abort(base.Outcome.TRANSMISSION_FAILURE)
+ self._termination_manager.abort(_TRANSMISSION_FAILURE_OUTCOME)
self._expiration_manager.terminate()
return
@@ -184,23 +207,27 @@ class TransmissionManager(_interfaces.TransmissionManager):
self._transmitting = True
def kick_off(
- self, group, method, timeout, initial_metadata, payload, completion,
- allowance):
+ self, group, method, timeout, protocol_options, initial_metadata,
+ payload, completion, allowance):
"""See _interfaces.TransmissionManager.kickoff for specification."""
# TODO(nathaniel): Support other subscriptions.
subscription = links.Ticket.Subscription.FULL
terminal_metadata, code, message, termination = _explode_completion(
completion)
self._remote_allowance = 1 if payload is None else 0
+ protocol = links.Protocol(links.Protocol.Kind.CALL_OPTION, protocol_options)
ticket = links.Ticket(
self._operation_id, 0, group, method, subscription, timeout, allowance,
initial_metadata, payload, terminal_metadata, code, message,
- termination, None)
+ termination, protocol)
self._lowest_unused_sequence_number = 1
self._transmit(ticket)
def advance(self, initial_metadata, payload, completion, allowance):
"""See _interfaces.TransmissionManager.advance for specification."""
+ if self._abort.kind is not _Abort.Kind.NOT_ABORTED:
+ return
+
effective_initial_metadata = initial_metadata
effective_payload = payload
effective_completion = completion
@@ -246,7 +273,9 @@ class TransmissionManager(_interfaces.TransmissionManager):
def timeout(self, timeout):
"""See _interfaces.TransmissionManager.timeout for specification."""
- if self._transmitting:
+ if self._abort.kind is not _Abort.Kind.NOT_ABORTED:
+ return
+ elif self._transmitting:
self._timeout = timeout
else:
ticket = links.Ticket(
@@ -257,7 +286,9 @@ class TransmissionManager(_interfaces.TransmissionManager):
def allowance(self, allowance):
"""See _interfaces.TransmissionManager.allowance for specification."""
- if self._transmitting or not self._payloads:
+ if self._abort.kind is not _Abort.Kind.NOT_ABORTED:
+ return
+ elif self._transmitting or not self._payloads:
self._remote_allowance += allowance
else:
self._remote_allowance += allowance - 1
@@ -281,22 +312,24 @@ class TransmissionManager(_interfaces.TransmissionManager):
self._remote_complete = True
self._local_allowance = 0
- def abort(self, outcome, code, message):
+ def abort(self, outcome):
"""See _interfaces.TransmissionManager.abort for specification."""
- if self._transmitting:
- self._aborted, self._abortion_outcome = True, outcome
- else:
- self._aborted = True
- if outcome is not None:
- termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION[
- outcome]
- if termination is not None:
- if self._completion is None:
- code, message = None, None
- else:
- code, message = self._completion.code, self._completion.message
+ if self._abort.kind is _Abort.Kind.NOT_ABORTED:
+ if outcome is None:
+ self._abort = _ABORTED_NO_NOTIFY
+ else:
+ termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION.get(
+ outcome.kind)
+ if termination is None:
+ self._abort = _ABORTED_NO_NOTIFY
+ elif self._transmitting:
+ self._abort = _Abort(
+ _Abort.Kind.ABORTED_NOTIFY_NEEDED, termination, outcome.code,
+ outcome.details)
+ else:
ticket = links.Ticket(
self._operation_id, self._lowest_unused_sequence_number, None,
- None, None, None, None, None, None, None, code, message,
- termination, None)
+ None, None, None, None, None, None, None, outcome.code,
+ outcome.details, termination, None)
self._transmit(ticket)
+ self._abort = _ABORTED_NO_NOTIFY
diff --git a/src/python/grpcio/grpc/framework/core/_utilities.py b/src/python/grpcio/grpc/framework/core/_utilities.py
index 5b0d798751..abedc727e4 100644
--- a/src/python/grpcio/grpc/framework/core/_utilities.py
+++ b/src/python/grpcio/grpc/framework/core/_utilities.py
@@ -31,6 +31,8 @@
import collections
+from grpc.framework.interfaces.base import base
+
class ServicerPackage(
collections.namedtuple(
@@ -44,3 +46,9 @@ class ServicerPackage(
maximum_timeout: A float indicating the maximum length of time in seconds to
allow for an operation.
"""
+
+
+class Outcome(
+ base.Outcome,
+ collections.namedtuple('Outcome', ('kind', 'code', 'details',))):
+ """A trivial implementation of base.Outcome."""
diff --git a/src/python/grpcio/grpc/framework/crust/__init__.py b/src/python/grpcio/grpc/framework/crust/__init__.py
new file mode 100644
index 0000000000..7086519106
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/crust/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/grpcio/grpc/framework/crust/_calls.py b/src/python/grpcio/grpc/framework/crust/_calls.py
new file mode 100644
index 0000000000..bff940d747
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/crust/_calls.py
@@ -0,0 +1,223 @@
+# 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.
+
+"""Utility functions for invoking RPCs."""
+
+from grpc.framework.crust import _control
+from grpc.framework.interfaces.base import utilities
+from grpc.framework.interfaces.face import face
+
+_ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!'
+
+_EMPTY_COMPLETION = utilities.completion(None, None, None)
+
+
+def _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ complete):
+ rendezvous = _control.Rendezvous(None, None)
+ subscription = utilities.full_subscription(
+ rendezvous, _control.protocol_receiver(rendezvous))
+ operation_context, operator = end.operate(
+ group, method, subscription, timeout, protocol_options=protocol_options,
+ initial_metadata=initial_metadata, payload=payload,
+ completion=_EMPTY_COMPLETION if complete else None)
+ rendezvous.set_operator_and_context(operator, operation_context)
+ outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
+ if outcome is not None:
+ rendezvous.set_outcome(outcome)
+ return rendezvous, operation_context, outcome
+
+
+def _event_return_unary(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool):
+ if outcome is None:
+ def in_pool():
+ abortion = rendezvous.add_abortion_callback(abortion_callback)
+ if abortion is None:
+ try:
+ receiver.initial_metadata(rendezvous.initial_metadata())
+ receiver.response(next(rendezvous))
+ receiver.complete(
+ rendezvous.terminal_metadata(), rendezvous.code(),
+ rendezvous.details())
+ except face.AbortionError:
+ pass
+ else:
+ abortion_callback(abortion)
+ pool.submit(_control.pool_wrap(in_pool, operation_context))
+ return rendezvous
+
+
+def _event_return_stream(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool):
+ if outcome is None:
+ def in_pool():
+ abortion = rendezvous.add_abortion_callback(abortion_callback)
+ if abortion is None:
+ try:
+ receiver.initial_metadata(rendezvous.initial_metadata())
+ for response in rendezvous:
+ receiver.response(response)
+ receiver.complete(
+ rendezvous.terminal_metadata(), rendezvous.code(),
+ rendezvous.details())
+ except face.AbortionError:
+ pass
+ else:
+ abortion_callback(abortion)
+ pool.submit(_control.pool_wrap(in_pool, operation_context))
+ return rendezvous
+
+
+def blocking_unary_unary(
+ end, group, method, timeout, with_call, protocol_options, initial_metadata,
+ payload):
+ """Services in a blocking fashion a unary-unary servicer method."""
+ rendezvous, unused_operation_context, unused_outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ True)
+ if with_call:
+ return next(rendezvous), rendezvous
+ else:
+ return next(rendezvous)
+
+
+def future_unary_unary(
+ end, group, method, timeout, protocol_options, initial_metadata, payload):
+ """Services a value-in value-out servicer method by returning a Future."""
+ rendezvous, unused_operation_context, unused_outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ True)
+ return rendezvous
+
+
+def inline_unary_stream(
+ end, group, method, timeout, protocol_options, initial_metadata, payload):
+ """Services a value-in stream-out servicer method."""
+ rendezvous, unused_operation_context, unused_outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ True)
+ return rendezvous
+
+
+def blocking_stream_unary(
+ end, group, method, timeout, with_call, protocol_options, initial_metadata,
+ payload_iterator, pool):
+ """Services in a blocking fashion a stream-in value-out servicer method."""
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, None,
+ False)
+ if outcome is None:
+ def in_pool():
+ for payload in payload_iterator:
+ rendezvous.consume(payload)
+ rendezvous.terminate()
+ pool.submit(_control.pool_wrap(in_pool, operation_context))
+ if with_call:
+ return next(rendezvous), rendezvous
+ else:
+ return next(rendezvous)
+ else:
+ if with_call:
+ return next(rendezvous), rendezvous
+ else:
+ return next(rendezvous)
+
+
+def future_stream_unary(
+ end, group, method, timeout, protocol_options, initial_metadata,
+ payload_iterator, pool):
+ """Services a stream-in value-out servicer method by returning a Future."""
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, None,
+ False)
+ if outcome is None:
+ def in_pool():
+ for payload in payload_iterator:
+ rendezvous.consume(payload)
+ rendezvous.terminate()
+ pool.submit(_control.pool_wrap(in_pool, operation_context))
+ return rendezvous
+
+
+def inline_stream_stream(
+ end, group, method, timeout, protocol_options, initial_metadata,
+ payload_iterator, pool):
+ """Services a stream-in stream-out servicer method."""
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, None,
+ False)
+ if outcome is None:
+ def in_pool():
+ for payload in payload_iterator:
+ rendezvous.consume(payload)
+ rendezvous.terminate()
+ pool.submit(_control.pool_wrap(in_pool, operation_context))
+ return rendezvous
+
+
+def event_unary_unary(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ receiver, abortion_callback, pool):
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ True)
+ return _event_return_unary(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
+
+
+def event_unary_stream(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ receiver, abortion_callback, pool):
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, payload,
+ True)
+ return _event_return_stream(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
+
+
+def event_stream_unary(
+ end, group, method, timeout, protocol_options, initial_metadata, receiver,
+ abortion_callback, pool):
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, None,
+ False)
+ return _event_return_unary(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
+
+
+def event_stream_stream(
+ end, group, method, timeout, protocol_options, initial_metadata, receiver,
+ abortion_callback, pool):
+ rendezvous, operation_context, outcome = _invoke(
+ end, group, method, timeout, protocol_options, initial_metadata, None,
+ False)
+ return _event_return_stream(
+ receiver, abortion_callback, rendezvous, operation_context, outcome, pool)
diff --git a/src/python/grpcio/grpc/framework/crust/_control.py b/src/python/grpcio/grpc/framework/crust/_control.py
new file mode 100644
index 0000000000..5e9efdf732
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/crust/_control.py
@@ -0,0 +1,581 @@
+# 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.
+
+"""State and behavior for translating between sync and async control flow."""
+
+import collections
+import enum
+import sys
+import threading
+import time
+
+from grpc.framework.foundation import abandonment
+from grpc.framework.foundation import callable_util
+from grpc.framework.foundation import future
+from grpc.framework.foundation import stream
+from grpc.framework.interfaces.base import base
+from grpc.framework.interfaces.base import utilities
+from grpc.framework.interfaces.face import face
+
+_DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!'
+_INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Crust) Internal Error! )-:'
+
+_CANNOT_SET_INITIAL_METADATA = (
+ 'Could not set initial metadata - has it already been set, or has a ' +
+ 'payload already been sent?')
+_CANNOT_SET_TERMINAL_METADATA = (
+ 'Could not set terminal metadata - has it already been set, or has RPC ' +
+ 'completion already been indicated?')
+_CANNOT_SET_CODE = (
+ 'Could not set code - has it already been set, or has RPC completion ' +
+ 'already been indicated?')
+_CANNOT_SET_DETAILS = (
+ 'Could not set details - has it already been set, or has RPC completion ' +
+ 'already been indicated?')
+
+
+class _DummyOperator(base.Operator):
+
+ def advance(
+ self, initial_metadata=None, payload=None, completion=None,
+ allowance=None):
+ pass
+
+_DUMMY_OPERATOR = _DummyOperator()
+
+
+class _Awaited(
+ collections.namedtuple('_Awaited', ('kind', 'value',))):
+
+ @enum.unique
+ class Kind(enum.Enum):
+ NOT_YET_ARRIVED = 'not yet arrived'
+ ARRIVED = 'arrived'
+
+_NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None)
+_ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None)
+
+
+class _Transitory(
+ collections.namedtuple('_Transitory', ('kind', 'value',))):
+
+ @enum.unique
+ class Kind(enum.Enum):
+ NOT_YET_SEEN = 'not yet seen'
+ PRESENT = 'present'
+ GONE = 'gone'
+
+_NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None)
+_GONE = _Transitory(_Transitory.Kind.GONE, None)
+
+
+class _Termination(
+ collections.namedtuple(
+ '_Termination', ('terminated', 'abortion', 'abortion_error',))):
+ """Values indicating whether and how an RPC has terminated.
+
+ Attributes:
+ terminated: A boolean indicating whether or not the RPC has terminated.
+ abortion: A face.Abortion value describing the RPC's abortion or None if the
+ RPC did not abort.
+ abortion_error: A face.AbortionError describing the RPC's abortion or None
+ if the RPC did not abort.
+ """
+
+_NOT_TERMINATED = _Termination(False, None, None)
+
+_OPERATION_OUTCOME_KIND_TO_TERMINATION_CONSTRUCTOR = {
+ base.Outcome.Kind.COMPLETED: lambda *unused_args: _Termination(
+ True, None, None),
+ base.Outcome.Kind.CANCELLED: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.CANCELLED, *args),
+ face.CancellationError(*args)),
+ base.Outcome.Kind.EXPIRED: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.EXPIRED, *args),
+ face.ExpirationError(*args)),
+ base.Outcome.Kind.LOCAL_SHUTDOWN: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.LOCAL_SHUTDOWN, *args),
+ face.LocalShutdownError(*args)),
+ base.Outcome.Kind.REMOTE_SHUTDOWN: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.REMOTE_SHUTDOWN, *args),
+ face.RemoteShutdownError(*args)),
+ base.Outcome.Kind.RECEPTION_FAILURE: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args),
+ face.NetworkError(*args)),
+ base.Outcome.Kind.TRANSMISSION_FAILURE: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args),
+ face.NetworkError(*args)),
+ base.Outcome.Kind.LOCAL_FAILURE: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.LOCAL_FAILURE, *args),
+ face.LocalError(*args)),
+ base.Outcome.Kind.REMOTE_FAILURE: lambda *args: _Termination(
+ True, face.Abortion(face.Abortion.Kind.REMOTE_FAILURE, *args),
+ face.RemoteError(*args)),
+}
+
+
+def _wait_once_until(condition, until):
+ if until is None:
+ condition.wait()
+ else:
+ remaining = until - time.time()
+ if remaining < 0:
+ raise future.TimeoutError()
+ else:
+ condition.wait(timeout=remaining)
+
+
+def _done_callback_as_operation_termination_callback(
+ done_callback, rendezvous):
+ def operation_termination_callback(operation_outcome):
+ rendezvous.set_outcome(operation_outcome)
+ done_callback(rendezvous)
+ return operation_termination_callback
+
+
+def _abortion_callback_as_operation_termination_callback(
+ rpc_abortion_callback, rendezvous_set_outcome):
+ def operation_termination_callback(operation_outcome):
+ termination = rendezvous_set_outcome(operation_outcome)
+ if termination.abortion is not None:
+ rpc_abortion_callback(termination.abortion)
+ return operation_termination_callback
+
+
+class Rendezvous(base.Operator, future.Future, stream.Consumer, face.Call):
+ """A rendez-vous for the threads of an operation.
+
+ Instances of this object present iterator and stream.Consumer interfaces for
+ interacting with application code and present a base.Operator interface and
+ maintain a base.Operator internally for interacting with base interface code.
+ """
+
+ def __init__(self, operator, operation_context):
+ self._condition = threading.Condition()
+
+ self._operator = operator
+ self._operation_context = operation_context
+
+ self._protocol_context = _NOT_YET_ARRIVED
+
+ self._up_initial_metadata = _NOT_YET_ARRIVED
+ self._up_payload = None
+ self._up_allowance = 1
+ self._up_completion = _NOT_YET_ARRIVED
+ self._down_initial_metadata = _NOT_YET_SEEN
+ self._down_payload = None
+ self._down_allowance = 1
+ self._down_terminal_metadata = _NOT_YET_SEEN
+ self._down_code = _NOT_YET_SEEN
+ self._down_details = _NOT_YET_SEEN
+
+ self._termination = _NOT_TERMINATED
+
+ # The semantics of future.Future.cancel and future.Future.cancelled are
+ # slightly wonky, so they have to be tracked separately from the rest of the
+ # result of the RPC. This field tracks whether cancellation was requested
+ # prior to termination of the RPC
+ self._cancelled = False
+
+ def set_operator_and_context(self, operator, operation_context):
+ with self._condition:
+ self._operator = operator
+ self._operation_context = operation_context
+
+ def _down_completion(self):
+ if self._down_terminal_metadata.kind is _Transitory.Kind.NOT_YET_SEEN:
+ terminal_metadata = None
+ self._down_terminal_metadata = _GONE
+ elif self._down_terminal_metadata.kind is _Transitory.Kind.PRESENT:
+ terminal_metadata = self._down_terminal_metadata.value
+ self._down_terminal_metadata = _GONE
+ else:
+ terminal_metadata = None
+ if self._down_code.kind is _Transitory.Kind.NOT_YET_SEEN:
+ code = None
+ self._down_code = _GONE
+ elif self._down_code.kind is _Transitory.Kind.PRESENT:
+ code = self._down_code.value
+ self._down_code = _GONE
+ else:
+ code = None
+ if self._down_details.kind is _Transitory.Kind.NOT_YET_SEEN:
+ details = None
+ self._down_details = _GONE
+ elif self._down_details.kind is _Transitory.Kind.PRESENT:
+ details = self._down_details.value
+ self._down_details = _GONE
+ else:
+ details = None
+ return utilities.completion(terminal_metadata, code, details)
+
+ def _set_outcome(self, outcome):
+ if not self._termination.terminated:
+ self._operator = _DUMMY_OPERATOR
+ self._operation_context = None
+ self._down_initial_metadata = _GONE
+ self._down_payload = None
+ self._down_terminal_metadata = _GONE
+ self._down_code = _GONE
+ self._down_details = _GONE
+
+ if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
+ initial_metadata = None
+ else:
+ initial_metadata = self._up_initial_metadata.value
+ if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED:
+ terminal_metadata = None
+ else:
+ terminal_metadata = self._up_completion.value.terminal_metadata
+ if outcome.kind is base.Outcome.Kind.COMPLETED:
+ code = self._up_completion.value.code
+ details = self._up_completion.value.message
+ else:
+ code = outcome.code
+ details = outcome.details
+ self._termination = _OPERATION_OUTCOME_KIND_TO_TERMINATION_CONSTRUCTOR[
+ outcome.kind](initial_metadata, terminal_metadata, code, details)
+
+ self._condition.notify_all()
+
+ return self._termination
+
+ def advance(
+ self, initial_metadata=None, payload=None, completion=None,
+ allowance=None):
+ with self._condition:
+ if initial_metadata is not None:
+ self._up_initial_metadata = _Awaited(
+ _Awaited.Kind.ARRIVED, initial_metadata)
+ if payload is not None:
+ if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
+ self._up_initial_metadata = _ARRIVED_AND_NONE
+ self._up_payload = payload
+ self._up_allowance -= 1
+ if completion is not None:
+ if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED:
+ self._up_initial_metadata = _ARRIVED_AND_NONE
+ self._up_completion = _Awaited(
+ _Awaited.Kind.ARRIVED, completion)
+ if allowance is not None:
+ if self._down_payload is not None:
+ self._operator.advance(payload=self._down_payload)
+ self._down_payload = None
+ self._down_allowance += allowance - 1
+ else:
+ self._down_allowance += allowance
+ self._condition.notify_all()
+
+ def cancel(self):
+ with self._condition:
+ if self._operation_context is not None:
+ self._operation_context.cancel()
+ self._cancelled = True
+ return False
+
+ def cancelled(self):
+ with self._condition:
+ return self._cancelled
+
+ def running(self):
+ with self._condition:
+ return not self._termination.terminated
+
+ def done(self):
+ with self._condition:
+ return self._termination.terminated
+
+ def result(self, timeout=None):
+ until = None if timeout is None else time.time() + timeout
+ with self._condition:
+ while True:
+ if self._termination.terminated:
+ if self._termination.abortion is None:
+ return self._up_payload
+ elif self._termination.abortion.kind is face.Abortion.Kind.CANCELLED:
+ raise future.CancelledError()
+ else:
+ raise self._termination.abortion_error # pylint: disable=raising-bad-type
+ else:
+ _wait_once_until(self._condition, until)
+
+ def exception(self, timeout=None):
+ until = None if timeout is None else time.time() + timeout
+ with self._condition:
+ while True:
+ if self._termination.terminated:
+ if self._termination.abortion is None:
+ return None
+ else:
+ return self._termination.abortion_error
+ else:
+ _wait_once_until(self._condition, until)
+
+ def traceback(self, timeout=None):
+ until = None if timeout is None else time.time() + timeout
+ with self._condition:
+ while True:
+ if self._termination.terminated:
+ if self._termination.abortion_error is None:
+ return None
+ else:
+ abortion_error = self._termination.abortion_error
+ break
+ else:
+ _wait_once_until(self._condition, until)
+
+ try:
+ raise abortion_error
+ except face.AbortionError:
+ return sys.exc_info()[2]
+
+ def add_done_callback(self, fn):
+ with self._condition:
+ if self._operation_context is not None:
+ outcome = self._operation_context.add_termination_callback(
+ _done_callback_as_operation_termination_callback(fn, self))
+ if outcome is None:
+ return
+ else:
+ self._set_outcome(outcome)
+
+ fn(self)
+
+ def consume(self, value):
+ with self._condition:
+ while True:
+ if self._termination.terminated:
+ return
+ elif 0 < self._down_allowance:
+ self._operator.advance(payload=value)
+ self._down_allowance -= 1
+ return
+ else:
+ self._condition.wait()
+
+ def terminate(self):
+ with self._condition:
+ if self._termination.terminated:
+ return
+ elif self._down_code.kind is _Transitory.Kind.GONE:
+ # Conform to specified idempotence of terminate by ignoring extra calls.
+ return
+ else:
+ completion = self._down_completion()
+ self._operator.advance(completion=completion)
+
+ def consume_and_terminate(self, value):
+ with self._condition:
+ while True:
+ if self._termination.terminated:
+ return
+ elif 0 < self._down_allowance:
+ completion = self._down_completion()
+ self._operator.advance(payload=value, completion=completion)
+ return
+ else:
+ self._condition.wait()
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ with self._condition:
+ while True:
+ if self._termination.abortion_error is not None:
+ raise self._termination.abortion_error
+ elif self._up_payload is not None:
+ payload = self._up_payload
+ self._up_payload = None
+ if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED:
+ self._operator.advance(allowance=1)
+ return payload
+ elif self._up_completion.kind is _Awaited.Kind.ARRIVED:
+ raise StopIteration()
+ else:
+ self._condition.wait()
+
+ def is_active(self):
+ with self._condition:
+ return not self._termination.terminated
+
+ def time_remaining(self):
+ if self._operation_context is None:
+ return 0
+ else:
+ return self._operation_context.time_remaining()
+
+ def add_abortion_callback(self, abortion_callback):
+ with self._condition:
+ if self._operation_context is None:
+ return self._termination.abortion
+ else:
+ outcome = self._operation_context.add_termination_callback(
+ _abortion_callback_as_operation_termination_callback(
+ abortion_callback, self.set_outcome))
+ if outcome is not None:
+ return self._set_outcome(outcome).abortion
+ else:
+ return self._termination.abortion
+
+ def protocol_context(self):
+ with self._condition:
+ while True:
+ if self._protocol_context.kind is _Awaited.Kind.ARRIVED:
+ return self._protocol_context.value
+ elif self._termination.abortion_error is not None:
+ raise self._termination.abortion_error
+ else:
+ self._condition.wait()
+
+ def initial_metadata(self):
+ with self._condition:
+ while True:
+ if self._up_initial_metadata.kind is _Awaited.Kind.ARRIVED:
+ return self._up_initial_metadata.value
+ elif self._termination.terminated:
+ return None
+ else:
+ self._condition.wait()
+
+ def terminal_metadata(self):
+ with self._condition:
+ while True:
+ if self._up_completion.kind is _Awaited.Kind.ARRIVED:
+ return self._up_completion.value.terminal_metadata
+ elif self._termination.terminated:
+ return None
+ else:
+ self._condition.wait()
+
+ def code(self):
+ with self._condition:
+ while True:
+ if self._up_completion.kind is _Awaited.Kind.ARRIVED:
+ return self._up_completion.value.code
+ elif self._termination.terminated:
+ return None
+ else:
+ self._condition.wait()
+
+ def details(self):
+ with self._condition:
+ while True:
+ if self._up_completion.kind is _Awaited.Kind.ARRIVED:
+ return self._up_completion.value.message
+ elif self._termination.terminated:
+ return None
+ else:
+ self._condition.wait()
+
+ def set_initial_metadata(self, initial_metadata):
+ with self._condition:
+ if (self._down_initial_metadata.kind is not
+ _Transitory.Kind.NOT_YET_SEEN):
+ raise ValueError(_CANNOT_SET_INITIAL_METADATA)
+ else:
+ self._down_initial_metadata = _GONE
+ self._operator.advance(initial_metadata=initial_metadata)
+
+ def set_terminal_metadata(self, terminal_metadata):
+ with self._condition:
+ if (self._down_terminal_metadata.kind is not
+ _Transitory.Kind.NOT_YET_SEEN):
+ raise ValueError(_CANNOT_SET_TERMINAL_METADATA)
+ else:
+ self._down_terminal_metadata = _Transitory(
+ _Transitory.Kind.PRESENT, terminal_metadata)
+
+ def set_code(self, code):
+ with self._condition:
+ if self._down_code.kind is not _Transitory.Kind.NOT_YET_SEEN:
+ raise ValueError(_CANNOT_SET_CODE)
+ else:
+ self._down_code = _Transitory(_Transitory.Kind.PRESENT, code)
+
+ def set_details(self, details):
+ with self._condition:
+ if self._down_details.kind is not _Transitory.Kind.NOT_YET_SEEN:
+ raise ValueError(_CANNOT_SET_DETAILS)
+ else:
+ self._down_details = _Transitory(_Transitory.Kind.PRESENT, details)
+
+ def set_protocol_context(self, protocol_context):
+ with self._condition:
+ self._protocol_context = _Awaited(
+ _Awaited.Kind.ARRIVED, protocol_context)
+ self._condition.notify_all()
+
+ def set_outcome(self, outcome):
+ with self._condition:
+ return self._set_outcome(outcome)
+
+
+class _ProtocolReceiver(base.ProtocolReceiver):
+
+ def __init__(self, rendezvous):
+ self._rendezvous = rendezvous
+
+ def context(self, protocol_context):
+ self._rendezvous.set_protocol_context(protocol_context)
+
+
+def protocol_receiver(rendezvous):
+ return _ProtocolReceiver(rendezvous)
+
+
+def pool_wrap(behavior, operation_context):
+ """Wraps an operation-related behavior so that it may be called in a pool.
+
+ Args:
+ behavior: A callable related to carrying out an operation.
+ operation_context: A base_interfaces.OperationContext for the operation.
+
+ Returns:
+ A callable that when called carries out the behavior of the given callable
+ and handles whatever exceptions it raises appropriately.
+ """
+ def translation(*args):
+ try:
+ behavior(*args)
+ except (
+ abandonment.Abandoned,
+ face.CancellationError,
+ face.ExpirationError,
+ face.LocalShutdownError,
+ face.RemoteShutdownError,
+ face.NetworkError,
+ face.RemoteError,
+ ) as e:
+ if operation_context.outcome() is None:
+ operation_context.fail(e)
+ except Exception as e:
+ operation_context.fail(e)
+ return callable_util.with_exceptions_logged(
+ translation, _INTERNAL_ERROR_LOG_MESSAGE)
diff --git a/src/python/grpcio/grpc/framework/crust/_service.py b/src/python/grpcio/grpc/framework/crust/_service.py
new file mode 100644
index 0000000000..9903415c09
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/crust/_service.py
@@ -0,0 +1,173 @@
+# 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.
+
+"""Behaviors for servicing RPCs."""
+
+from grpc.framework.crust import _control
+from grpc.framework.foundation import abandonment
+from grpc.framework.interfaces.base import utilities
+from grpc.framework.interfaces.face import face
+
+
+class _ServicerContext(face.ServicerContext):
+
+ def __init__(self, rendezvous):
+ self._rendezvous = rendezvous
+
+ def is_active(self):
+ return self._rendezvous.is_active()
+
+ def time_remaining(self):
+ return self._rendezvous.time_remaining()
+
+ def add_abortion_callback(self, abortion_callback):
+ return self._rendezvous.add_abortion_callback(abortion_callback)
+
+ def cancel(self):
+ self._rendezvous.cancel()
+
+ def protocol_context(self):
+ return self._rendezvous.protocol_context()
+
+ def invocation_metadata(self):
+ return self._rendezvous.initial_metadata()
+
+ def initial_metadata(self, initial_metadata):
+ self._rendezvous.set_initial_metadata(initial_metadata)
+
+ def terminal_metadata(self, terminal_metadata):
+ self._rendezvous.set_terminal_metadata(terminal_metadata)
+
+ def code(self, code):
+ self._rendezvous.set_code(code)
+
+ def details(self, details):
+ self._rendezvous.set_details(details)
+
+
+def _adaptation(pool, in_pool):
+ def adaptation(operator, operation_context):
+ rendezvous = _control.Rendezvous(operator, operation_context)
+ subscription = utilities.full_subscription(
+ rendezvous, _control.protocol_receiver(rendezvous))
+ outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
+ if outcome is None:
+ pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous)
+ return subscription
+ else:
+ raise abandonment.Abandoned()
+ return adaptation
+
+
+def adapt_inline_unary_unary(method, pool):
+ def in_pool(rendezvous):
+ request = next(rendezvous)
+ response = method(request, _ServicerContext(rendezvous))
+ rendezvous.consume_and_terminate(response)
+ return _adaptation(pool, in_pool)
+
+
+def adapt_inline_unary_stream(method, pool):
+ def in_pool(rendezvous):
+ request = next(rendezvous)
+ response_iterator = method(request, _ServicerContext(rendezvous))
+ for response in response_iterator:
+ rendezvous.consume(response)
+ rendezvous.terminate()
+ return _adaptation(pool, in_pool)
+
+
+def adapt_inline_stream_unary(method, pool):
+ def in_pool(rendezvous):
+ response = method(rendezvous, _ServicerContext(rendezvous))
+ rendezvous.consume_and_terminate(response)
+ return _adaptation(pool, in_pool)
+
+
+def adapt_inline_stream_stream(method, pool):
+ def in_pool(rendezvous):
+ response_iterator = method(rendezvous, _ServicerContext(rendezvous))
+ for response in response_iterator:
+ rendezvous.consume(response)
+ rendezvous.terminate()
+ return _adaptation(pool, in_pool)
+
+
+def adapt_event_unary_unary(method, pool):
+ def in_pool(rendezvous):
+ request = next(rendezvous)
+ method(
+ request, rendezvous.consume_and_terminate, _ServicerContext(rendezvous))
+ return _adaptation(pool, in_pool)
+
+
+def adapt_event_unary_stream(method, pool):
+ def in_pool(rendezvous):
+ request = next(rendezvous)
+ method(request, rendezvous, _ServicerContext(rendezvous))
+ return _adaptation(pool, in_pool)
+
+
+def adapt_event_stream_unary(method, pool):
+ def in_pool(rendezvous):
+ request_consumer = method(
+ rendezvous.consume_and_terminate, _ServicerContext(rendezvous))
+ for request in rendezvous:
+ request_consumer.consume(request)
+ request_consumer.terminate()
+ return _adaptation(pool, in_pool)
+
+
+def adapt_event_stream_stream(method, pool):
+ def in_pool(rendezvous):
+ request_consumer = method(rendezvous, _ServicerContext(rendezvous))
+ for request in rendezvous:
+ request_consumer.consume(request)
+ request_consumer.terminate()
+ return _adaptation(pool, in_pool)
+
+
+def adapt_multi_method(multi_method, pool):
+ def adaptation(group, method, operator, operation_context):
+ rendezvous = _control.Rendezvous(operator, operation_context)
+ subscription = utilities.full_subscription(
+ rendezvous, _control.protocol_receiver(rendezvous))
+ outcome = operation_context.add_termination_callback(rendezvous.set_outcome)
+ if outcome is None:
+ def in_pool():
+ request_consumer = multi_method.service(
+ group, method, rendezvous, _ServicerContext(rendezvous))
+ for request in rendezvous:
+ request_consumer.consume(request)
+ request_consumer.terminate()
+ pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous)
+ return subscription
+ else:
+ raise abandonment.Abandoned()
+ return adaptation
diff --git a/src/python/grpcio/grpc/framework/crust/implementations.py b/src/python/grpcio/grpc/framework/crust/implementations.py
new file mode 100644
index 0000000000..4ebc4e9ae8
--- /dev/null
+++ b/src/python/grpcio/grpc/framework/crust/implementations.py
@@ -0,0 +1,364 @@
+# 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.
+
+"""Entry points into the Crust layer of RPC Framework."""
+
+from grpc.framework.common import cardinality
+from grpc.framework.common import style
+from grpc.framework.crust import _calls
+from grpc.framework.crust import _service
+from grpc.framework.interfaces.base import base
+from grpc.framework.interfaces.face import face
+
+
+class _BaseServicer(base.Servicer):
+
+ def __init__(self, adapted_methods, adapted_multi_method):
+ self._adapted_methods = adapted_methods
+ self._adapted_multi_method = adapted_multi_method
+
+ def service(self, group, method, context, output_operator):
+ adapted_method = self._adapted_methods.get((group, method), None)
+ if adapted_method is not None:
+ return adapted_method(output_operator, context)
+ elif self._adapted_multi_method is not None:
+ try:
+ return self._adapted_multi_method(
+ group, method, output_operator, context)
+ except face.NoSuchMethodError:
+ raise base.NoSuchMethodError(None, None)
+ else:
+ raise base.NoSuchMethodError(None, None)
+
+
+class _UnaryUnaryMultiCallable(face.UnaryUnaryMultiCallable):
+
+ def __init__(self, end, group, method, pool):
+ self._end = end
+ self._group = group
+ self._method = method
+ self._pool = pool
+
+ def __call__(
+ self, request, timeout, metadata=None, with_call=False,
+ protocol_options=None):
+ return _calls.blocking_unary_unary(
+ self._end, self._group, self._method, timeout, with_call,
+ protocol_options, metadata, request)
+
+ def future(self, request, timeout, metadata=None, protocol_options=None):
+ return _calls.future_unary_unary(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request)
+
+ def event(
+ self, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_unary_unary(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request, receiver, abortion_callback, self._pool)
+
+
+class _UnaryStreamMultiCallable(face.UnaryStreamMultiCallable):
+
+ def __init__(self, end, group, method, pool):
+ self._end = end
+ self._group = group
+ self._method = method
+ self._pool = pool
+
+ def __call__(self, request, timeout, metadata=None, protocol_options=None):
+ return _calls.inline_unary_stream(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request)
+
+ def event(
+ self, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_unary_stream(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request, receiver, abortion_callback, self._pool)
+
+
+class _StreamUnaryMultiCallable(face.StreamUnaryMultiCallable):
+
+ def __init__(self, end, group, method, pool):
+ self._end = end
+ self._group = group
+ self._method = method
+ self._pool = pool
+
+ def __call__(
+ self, request_iterator, timeout, metadata=None,
+ with_call=False, protocol_options=None):
+ return _calls.blocking_stream_unary(
+ self._end, self._group, self._method, timeout, with_call,
+ protocol_options, metadata, request_iterator, self._pool)
+
+ def future(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
+ return _calls.future_stream_unary(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request_iterator, self._pool)
+
+ def event(
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.event_stream_unary(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, receiver, abortion_callback, self._pool)
+
+
+class _StreamStreamMultiCallable(face.StreamStreamMultiCallable):
+
+ def __init__(self, end, group, method, pool):
+ self._end = end
+ self._group = group
+ self._method = method
+ self._pool = pool
+
+ def __call__(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
+ return _calls.inline_stream_stream(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, request_iterator, self._pool)
+
+ def event(
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.event_stream_stream(
+ self._end, self._group, self._method, timeout, protocol_options,
+ metadata, receiver, abortion_callback, self._pool)
+
+
+class _GenericStub(face.GenericStub):
+ """An face.GenericStub implementation."""
+
+ def __init__(self, end, pool):
+ self._end = end
+ self._pool = pool
+
+ def blocking_unary_unary(
+ self, group, method, request, timeout, metadata=None,
+ with_call=None, protocol_options=None):
+ return _calls.blocking_unary_unary(
+ self._end, group, method, timeout, with_call, protocol_options,
+ metadata, request)
+
+ def future_unary_unary(
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.future_unary_unary(
+ self._end, group, method, timeout, protocol_options, metadata, request)
+
+ def inline_unary_stream(
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.inline_unary_stream(
+ self._end, group, method, timeout, protocol_options, metadata, request)
+
+ def blocking_stream_unary(
+ self, group, method, request_iterator, timeout, metadata=None,
+ with_call=None, protocol_options=None):
+ return _calls.blocking_stream_unary(
+ self._end, group, method, timeout, with_call, protocol_options,
+ metadata, request_iterator, self._pool)
+
+ def future_stream_unary(
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.future_stream_unary(
+ self._end, group, method, timeout, protocol_options, metadata,
+ request_iterator, self._pool)
+
+ def inline_stream_stream(
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
+ return _calls.inline_stream_stream(
+ self._end, group, method, timeout, protocol_options, metadata,
+ request_iterator, self._pool)
+
+ def event_unary_unary(
+ self, group, method, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_unary_unary(
+ self._end, group, method, timeout, protocol_options, metadata, request,
+ receiver, abortion_callback, self._pool)
+
+ def event_unary_stream(
+ self, group, method, request, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_unary_stream(
+ self._end, group, method, timeout, protocol_options, metadata, request,
+ receiver, abortion_callback, self._pool)
+
+ def event_stream_unary(
+ self, group, method, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_stream_unary(
+ self._end, group, method, timeout, protocol_options, metadata, receiver,
+ abortion_callback, self._pool)
+
+ def event_stream_stream(
+ self, group, method, receiver, abortion_callback, timeout,
+ metadata=None, protocol_options=None):
+ return _calls.event_stream_stream(
+ self._end, group, method, timeout, protocol_options, metadata, receiver,
+ abortion_callback, self._pool)
+
+ def unary_unary(self, group, method):
+ return _UnaryUnaryMultiCallable(self._end, group, method, self._pool)
+
+ def unary_stream(self, group, method):
+ return _UnaryStreamMultiCallable(self._end, group, method, self._pool)
+
+ def stream_unary(self, group, method):
+ return _StreamUnaryMultiCallable(self._end, group, method, self._pool)
+
+ def stream_stream(self, group, method):
+ return _StreamStreamMultiCallable(self._end, group, method, self._pool)
+
+
+class _DynamicStub(face.DynamicStub):
+ """An face.DynamicStub implementation."""
+
+ def __init__(self, end, group, cardinalities, pool):
+ self._end = end
+ self._group = group
+ self._cardinalities = cardinalities
+ self._pool = pool
+
+ def __getattr__(self, attr):
+ method_cardinality = self._cardinalities.get(attr)
+ if method_cardinality is cardinality.Cardinality.UNARY_UNARY:
+ return _UnaryUnaryMultiCallable(self._end, self._group, attr, self._pool)
+ elif method_cardinality is cardinality.Cardinality.UNARY_STREAM:
+ return _UnaryStreamMultiCallable(self._end, self._group, attr, self._pool)
+ elif method_cardinality is cardinality.Cardinality.STREAM_UNARY:
+ return _StreamUnaryMultiCallable(self._end, self._group, attr, self._pool)
+ elif method_cardinality is cardinality.Cardinality.STREAM_STREAM:
+ return _StreamStreamMultiCallable(
+ self._end, self._group, attr, self._pool)
+ else:
+ raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr)
+
+
+def _adapt_method_implementations(method_implementations, pool):
+ adapted_implementations = {}
+ for name, method_implementation in method_implementations.iteritems():
+ if method_implementation.style is style.Service.INLINE:
+ if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ adapted_implementations[name] = _service.adapt_inline_unary_unary(
+ method_implementation.unary_unary_inline, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ adapted_implementations[name] = _service.adapt_inline_unary_stream(
+ method_implementation.unary_stream_inline, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ adapted_implementations[name] = _service.adapt_inline_stream_unary(
+ method_implementation.stream_unary_inline, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ adapted_implementations[name] = _service.adapt_inline_stream_stream(
+ method_implementation.stream_stream_inline, pool)
+ elif method_implementation.style is style.Service.EVENT:
+ if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
+ adapted_implementations[name] = _service.adapt_event_unary_unary(
+ method_implementation.unary_unary_event, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
+ adapted_implementations[name] = _service.adapt_event_unary_stream(
+ method_implementation.unary_stream_event, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
+ adapted_implementations[name] = _service.adapt_event_stream_unary(
+ method_implementation.stream_unary_event, pool)
+ elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
+ adapted_implementations[name] = _service.adapt_event_stream_stream(
+ method_implementation.stream_stream_event, pool)
+ return adapted_implementations
+
+
+def servicer(method_implementations, multi_method_implementation, pool):
+ """Creates a base.Servicer.
+
+ It is guaranteed that any passed face.MultiMethodImplementation will
+ only be called to service an RPC if there is no
+ face.MethodImplementation for the RPC method in the passed
+ method_implementations dictionary.
+
+ Args:
+ method_implementations: A dictionary from RPC method name to
+ face.MethodImplementation object to be used to service the named
+ RPC method.
+ multi_method_implementation: An face.MultiMethodImplementation to be
+ used to service any RPCs not serviced by the
+ face.MethodImplementations given in the method_implementations
+ dictionary, or None.
+ pool: A thread pool.
+
+ Returns:
+ A base.Servicer that services RPCs via the given implementations.
+ """
+ adapted_implementations = _adapt_method_implementations(
+ method_implementations, pool)
+ if multi_method_implementation is None:
+ adapted_multi_method_implementation = None
+ else:
+ adapted_multi_method_implementation = _service.adapt_multi_method(
+ multi_method_implementation, pool)
+ return _BaseServicer(
+ adapted_implementations, adapted_multi_method_implementation)
+
+
+def generic_stub(end, pool):
+ """Creates an face.GenericStub.
+
+ Args:
+ end: A base.End.
+ pool: A futures.ThreadPoolExecutor.
+
+ Returns:
+ A face.GenericStub that performs RPCs via the given base.End.
+ """
+ return _GenericStub(end, pool)
+
+
+def dynamic_stub(end, group, cardinalities, pool):
+ """Creates an face.DynamicStub.
+
+ Args:
+ end: A base.End.
+ group: The group identifier for all RPCs to be made with the created
+ face.DynamicStub.
+ cardinalities: A dict from method identifier to cardinality.Cardinality
+ value identifying the cardinality of every RPC method to be supported by
+ the created face.DynamicStub.
+ pool: A futures.ThreadPoolExecutor.
+
+ Returns:
+ A face.DynamicStub that performs RPCs via the given base.End.
+ """
+ return _DynamicStub(end, group, cardinalities, pool)
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py
index bc52efb4c5..a1e70be5e8 100644
--- a/src/python/grpcio/grpc/framework/interfaces/base/base.py
+++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py
@@ -40,7 +40,7 @@ applications choose.
# threading is referenced from specification in this module.
import abc
import enum
-import threading
+import threading # pylint: disable=unused-import
# abandonment is referenced from specification in this module.
from grpc.framework.foundation import abandonment # pylint: disable=unused-import
@@ -69,19 +69,30 @@ class NoSuchMethodError(Exception):
self.details = details
-@enum.unique
-class Outcome(enum.Enum):
- """Operation outcomes."""
+class Outcome(object):
+ """The outcome of an operation.
- COMPLETED = 'completed'
- CANCELLED = 'cancelled'
- EXPIRED = 'expired'
- LOCAL_SHUTDOWN = 'local shutdown'
- REMOTE_SHUTDOWN = 'remote shutdown'
- RECEPTION_FAILURE = 'reception failure'
- TRANSMISSION_FAILURE = 'transmission failure'
- LOCAL_FAILURE = 'local failure'
- REMOTE_FAILURE = 'remote failure'
+ Attributes:
+ kind: A Kind value coarsely identifying how the operation terminated.
+ code: An application-specific code value or None if no such value was
+ provided.
+ details: An application-specific details value or None if no such value was
+ provided.
+ """
+
+ @enum.unique
+ class Kind(enum.Enum):
+ """Ways in which an operation can terminate."""
+
+ COMPLETED = 'completed'
+ CANCELLED = 'cancelled'
+ EXPIRED = 'expired'
+ LOCAL_SHUTDOWN = 'local shutdown'
+ REMOTE_SHUTDOWN = 'remote shutdown'
+ RECEPTION_FAILURE = 'reception failure'
+ TRANSMISSION_FAILURE = 'transmission failure'
+ LOCAL_FAILURE = 'local failure'
+ REMOTE_FAILURE = 'remote failure'
class Completion(object):
@@ -173,6 +184,19 @@ class Operator(object):
"""
raise NotImplementedError()
+class ProtocolReceiver(object):
+ """A means of receiving protocol values during an operation."""
+ __metaclass__ = abc.ABCMeta
+
+ @abc.abstractmethod
+ def context(self, protocol_context):
+ """Accepts the protocol context object for the operation.
+
+ Args:
+ protocol_context: The protocol context object for the operation.
+ """
+ raise NotImplementedError()
+
class Subscription(object):
"""Describes customer code's interest in values from the other side.
@@ -188,7 +212,11 @@ class Subscription(object):
otherwise.
operator: An Operator to be passed values from the other side of the
operation. Must be non-None if kind is Kind.FULL. Must be None otherwise.
+ protocol_receiver: A ProtocolReceiver to be passed protocol objects as they
+ become available during the operation. Must be non-None if kind is
+ Kind.FULL.
"""
+ __metaclass__ = abc.ABCMeta
@enum.unique
class Kind(enum.Enum):
@@ -263,7 +291,7 @@ class End(object):
@abc.abstractmethod
def operate(
self, group, method, subscription, timeout, initial_metadata=None,
- payload=None, completion=None):
+ payload=None, completion=None, protocol_options=None):
"""Commences an operation.
Args:
@@ -279,6 +307,8 @@ class End(object):
payload: An initial payload for the operation.
completion: A Completion value indicating the end of transmission to the
other side of the operation.
+ protocol_options: A value specified by the provider of a Base interface
+ implementation affording custom state and behavior.
Returns:
A pair of objects affording information about the operation and action
@@ -294,8 +324,8 @@ class End(object):
"""Reports the number of terminated operations broken down by outcome.
Returns:
- A dictionary from Outcome value to an integer identifying the number
- of operations that terminated with that outcome.
+ A dictionary from Outcome.Kind value to an integer identifying the number
+ of operations that terminated with that outcome kind.
"""
raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/interfaces/base/utilities.py b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
index a9ee1a0981..87a85018f5 100644
--- a/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
+++ b/src/python/grpcio/grpc/framework/interfaces/base/utilities.py
@@ -45,11 +45,12 @@ class _Subscription(
base.Subscription,
collections.namedtuple(
'_Subscription',
- ('kind', 'termination_callback', 'allowance', 'operator',))):
+ ('kind', 'termination_callback', 'allowance', 'operator',
+ 'protocol_receiver',))):
"""A trivial implementation of base.Subscription."""
_NONE_SUBSCRIPTION = _Subscription(
- base.Subscription.Kind.NONE, None, None, None)
+ base.Subscription.Kind.NONE, None, None, None, None)
def completion(terminal_metadata, code, message):
@@ -66,14 +67,16 @@ def completion(terminal_metadata, code, message):
return _Completion(terminal_metadata, code, message)
-def full_subscription(operator):
+def full_subscription(operator, protocol_receiver):
"""Creates a "full" base.Subscription for the given base.Operator.
Args:
operator: A base.Operator to be used in an operation.
+ protocol_receiver: A base.ProtocolReceiver to be used in an operation.
Returns:
A base.Subscription of kind base.Subscription.Kind.FULL wrapping the given
- base.Operator.
+ base.Operator and base.ProtocolReceiver.
"""
- return _Subscription(base.Subscription.Kind.FULL, None, None, operator)
+ return _Subscription(
+ base.Subscription.Kind.FULL, None, None, operator, protocol_receiver)
diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py
index 948e7505b6..bc9a434a76 100644
--- a/src/python/grpcio/grpc/framework/interfaces/face/face.py
+++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py
@@ -184,6 +184,16 @@ class RpcContext(object):
"""
raise NotImplementedError()
+ @abc.abstractmethod
+ def protocol_context(self):
+ """Accesses a custom object specified by an implementation provider.
+
+ Returns:
+ A value specified by the provider of a Face interface implementation
+ affording custom state and behavior.
+ """
+ raise NotImplementedError()
+
class Call(RpcContext):
"""Invocation-side utility object for an RPC."""
@@ -354,7 +364,8 @@ class UnaryUnaryMultiCallable(object):
@abc.abstractmethod
def __call__(
- self, request, timeout, metadata=None, with_call=False):
+ self, request, timeout, metadata=None, with_call=False,
+ protocol_options=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -364,6 +375,8 @@ class UnaryUnaryMultiCallable(object):
the RPC.
with_call: Whether or not to include return a Call for the RPC in addition
to the reponse.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
The response value for the RPC, and a Call for the RPC if with_call was
@@ -375,7 +388,7 @@ class UnaryUnaryMultiCallable(object):
raise NotImplementedError()
@abc.abstractmethod
- def future(self, request, timeout, metadata=None):
+ def future(self, request, timeout, metadata=None, protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -383,6 +396,8 @@ class UnaryUnaryMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and a future.Future. In the
@@ -395,7 +410,7 @@ class UnaryUnaryMultiCallable(object):
@abc.abstractmethod
def event(
self, request, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -406,6 +421,8 @@ class UnaryUnaryMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A Call for the RPC.
@@ -418,7 +435,7 @@ class UnaryStreamMultiCallable(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def __call__(self, request, timeout, metadata=None):
+ def __call__(self, request, timeout, metadata=None, protocol_options=None):
"""Invokes the underlying RPC.
Args:
@@ -426,6 +443,8 @@ class UnaryStreamMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and an iterator of response
@@ -437,7 +456,7 @@ class UnaryStreamMultiCallable(object):
@abc.abstractmethod
def event(
self, request, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -448,6 +467,8 @@ class UnaryStreamMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A Call object for the RPC.
@@ -462,7 +483,7 @@ class StreamUnaryMultiCallable(object):
@abc.abstractmethod
def __call__(
self, request_iterator, timeout, metadata=None,
- with_call=False):
+ with_call=False, protocol_options=None):
"""Synchronously invokes the underlying RPC.
Args:
@@ -472,6 +493,8 @@ class StreamUnaryMultiCallable(object):
the RPC.
with_call: Whether or not to include return a Call for the RPC in addition
to the reponse.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
The response value for the RPC, and a Call for the RPC if with_call was
@@ -483,7 +506,8 @@ class StreamUnaryMultiCallable(object):
raise NotImplementedError()
@abc.abstractmethod
- def future(self, request_iterator, timeout, metadata=None):
+ def future(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -491,6 +515,8 @@ class StreamUnaryMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and a future.Future. In the
@@ -502,7 +528,8 @@ class StreamUnaryMultiCallable(object):
@abc.abstractmethod
def event(
- self, receiver, abortion_callback, timeout, metadata=None):
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -512,6 +539,8 @@ class StreamUnaryMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A single object that is both a Call object for the RPC and a
@@ -525,7 +554,8 @@ class StreamStreamMultiCallable(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
- def __call__(self, request_iterator, timeout, metadata=None):
+ def __call__(
+ self, request_iterator, timeout, metadata=None, protocol_options=None):
"""Invokes the underlying RPC.
Args:
@@ -533,6 +563,8 @@ class StreamStreamMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and an iterator of response
@@ -543,7 +575,8 @@ class StreamStreamMultiCallable(object):
@abc.abstractmethod
def event(
- self, receiver, abortion_callback, timeout, metadata=None):
+ self, receiver, abortion_callback, timeout, metadata=None,
+ protocol_options=None):
"""Asynchronously invokes the underlying RPC.
Args:
@@ -553,6 +586,8 @@ class StreamStreamMultiCallable(object):
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of
the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A single object that is both a Call object for the RPC and a
@@ -646,7 +681,7 @@ class GenericStub(object):
@abc.abstractmethod
def blocking_unary_unary(
self, group, method, request, timeout, metadata=None,
- with_call=False):
+ with_call=False, protocol_options=None):
"""Invokes a unary-request-unary-response method.
This method blocks until either returning the response value of the RPC
@@ -661,6 +696,8 @@ class GenericStub(object):
metadata: A metadata value to be passed to the service-side of the RPC.
with_call: Whether or not to include return a Call for the RPC in addition
to the reponse.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
The response value for the RPC, and a Call for the RPC if with_call was
@@ -673,7 +710,8 @@ class GenericStub(object):
@abc.abstractmethod
def future_unary_unary(
- self, group, method, request, timeout, metadata=None):
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
"""Invokes a unary-request-unary-response method.
Args:
@@ -682,6 +720,8 @@ class GenericStub(object):
request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and a future.Future. In the
@@ -693,7 +733,8 @@ class GenericStub(object):
@abc.abstractmethod
def inline_unary_stream(
- self, group, method, request, timeout, metadata=None):
+ self, group, method, request, timeout, metadata=None,
+ protocol_options=None):
"""Invokes a unary-request-stream-response method.
Args:
@@ -702,6 +743,8 @@ class GenericStub(object):
request: The request value for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and an iterator of response
@@ -713,7 +756,7 @@ class GenericStub(object):
@abc.abstractmethod
def blocking_stream_unary(
self, group, method, request_iterator, timeout, metadata=None,
- with_call=False):
+ with_call=False, protocol_options=None):
"""Invokes a stream-request-unary-response method.
This method blocks until either returning the response value of the RPC
@@ -728,6 +771,8 @@ class GenericStub(object):
metadata: A metadata value to be passed to the service-side of the RPC.
with_call: Whether or not to include return a Call for the RPC in addition
to the reponse.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
The response value for the RPC, and a Call for the RPC if with_call was
@@ -740,7 +785,8 @@ class GenericStub(object):
@abc.abstractmethod
def future_stream_unary(
- self, group, method, request_iterator, timeout, metadata=None):
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
"""Invokes a stream-request-unary-response method.
Args:
@@ -749,6 +795,8 @@ class GenericStub(object):
request_iterator: An iterator that yields request values for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and a future.Future. In the
@@ -760,7 +808,8 @@ class GenericStub(object):
@abc.abstractmethod
def inline_stream_stream(
- self, group, method, request_iterator, timeout, metadata=None):
+ self, group, method, request_iterator, timeout, metadata=None,
+ protocol_options=None):
"""Invokes a stream-request-stream-response method.
Args:
@@ -769,6 +818,8 @@ class GenericStub(object):
request_iterator: An iterator that yields request values for the RPC.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
An object that is both a Call for the RPC and an iterator of response
@@ -780,7 +831,7 @@ class GenericStub(object):
@abc.abstractmethod
def event_unary_unary(
self, group, method, request, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Event-driven invocation of a unary-request-unary-response method.
Args:
@@ -792,6 +843,8 @@ class GenericStub(object):
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A Call for the RPC.
@@ -801,7 +854,7 @@ class GenericStub(object):
@abc.abstractmethod
def event_unary_stream(
self, group, method, request, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Event-driven invocation of a unary-request-stream-response method.
Args:
@@ -813,6 +866,8 @@ class GenericStub(object):
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A Call for the RPC.
@@ -822,7 +877,7 @@ class GenericStub(object):
@abc.abstractmethod
def event_stream_unary(
self, group, method, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Event-driven invocation of a unary-request-unary-response method.
Args:
@@ -833,6 +888,8 @@ class GenericStub(object):
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A pair of a Call object for the RPC and a stream.Consumer to which the
@@ -843,7 +900,7 @@ class GenericStub(object):
@abc.abstractmethod
def event_stream_stream(
self, group, method, receiver, abortion_callback, timeout,
- metadata=None):
+ metadata=None, protocol_options=None):
"""Event-driven invocation of a unary-request-stream-response method.
Args:
@@ -854,6 +911,8 @@ class GenericStub(object):
in the event of RPC abortion.
timeout: A duration of time in seconds to allow for the RPC.
metadata: A metadata value to be passed to the service-side of the RPC.
+ protocol_options: A value specified by the provider of a Face interface
+ implementation affording custom state and behavior.
Returns:
A pair of a Call object for the RPC and a stream.Consumer to which the
diff --git a/src/python/grpcio/grpc/framework/interfaces/links/links.py b/src/python/grpcio/grpc/framework/interfaces/links/links.py
index b98a30a399..24f0e3b354 100644
--- a/src/python/grpcio/grpc/framework/interfaces/links/links.py
+++ b/src/python/grpcio/grpc/framework/interfaces/links/links.py
@@ -34,14 +34,13 @@ import collections
import enum
-class Transport(collections.namedtuple('Transport', ('kind', 'value',))):
- """A sum type for handles to an underlying transport system.
+class Protocol(collections.namedtuple('Protocol', ('kind', 'value',))):
+ """A sum type for handles to a system that transmits tickets.
Attributes:
- kind: A Kind value identifying the kind of value being passed to or from
- the underlying transport.
- value: The value being passed through RPC Framework between the high-level
- application and the underlying transport.
+ kind: A Kind value identifying the kind of value being passed.
+ value: The value being passed between the high-level application and the
+ system affording ticket transport.
"""
@enum.unique
@@ -56,8 +55,7 @@ class Ticket(
'Ticket',
('operation_id', 'sequence_number', 'group', 'method', 'subscription',
'timeout', 'allowance', 'initial_metadata', 'payload',
- 'terminal_metadata', 'code', 'message', 'termination',
- 'transport',))):
+ 'terminal_metadata', 'code', 'message', 'termination', 'protocol',))):
"""A sum type for all values sent from a front to a back.
Attributes:
@@ -99,8 +97,8 @@ class Ticket(
termination: A Termination value describing the end of the operation, or
None if the operation has not yet terminated. If set, no further tickets
may be sent in the same direction.
- transport: A Transport value or None, with further semantics being a matter
- between high-level application and underlying transport.
+ protocol: A Protocol value or None, with further semantics being a matter
+ between high-level application and underlying ticket transport.
"""
@enum.unique
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index caa71a4f7c..4735ce080b 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -104,7 +104,7 @@ _COMMAND_CLASS = {
setuptools.setup(
name='grpcio',
- version='0.10.0a0',
+ version='0.11.0',
ext_modules=_EXTENSION_MODULES,
packages=list(_PACKAGES),
package_dir=_PACKAGE_DIRECTORIES,
diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio_test/grpc_interop/client.py
index 2dd2103cbe..36afe6c096 100644
--- a/src/python/grpcio_test/grpc_interop/client.py
+++ b/src/python/grpcio_test/grpc_interop/client.py
@@ -70,7 +70,13 @@ def _oauth_access_token(args):
def _stub(args):
if args.oauth_scope:
- metadata_transformer = lambda x: [('Authorization', 'Bearer %s' % _oauth_access_token(args))]
+ if args.test_case == 'oauth2_auth_token':
+ access_token = _oauth_access_token(args)
+ metadata_transformer = lambda x: [
+ ('Authorization', 'Bearer %s' % access_token)]
+ else:
+ metadata_transformer = lambda x: [
+ ('Authorization', 'Bearer %s' % _oauth_access_token(args))]
else:
metadata_transformer = lambda x: []
if args.use_tls:
diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio_test/grpc_interop/methods.py
index 7a831f3cbd..52b800af7a 100644
--- a/src/python/grpcio_test/grpc_interop/methods.py
+++ b/src/python/grpcio_test/grpc_interop/methods.py
@@ -346,7 +346,7 @@ def _compute_engine_creds(stub, args):
response.username))
-def _service_account_creds(stub, args):
+def _oauth2_auth_token(stub, args):
json_key_filename = os.environ[
oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
@@ -359,7 +359,6 @@ def _service_account_creds(stub, args):
'expected to find oauth scope "%s" in received "%s"' %
(response.oauth_scope, args.oauth_scope))
-
@enum.unique
class TestCase(enum.Enum):
EMPTY_UNARY = 'empty_unary'
@@ -370,7 +369,7 @@ class TestCase(enum.Enum):
CANCEL_AFTER_BEGIN = 'cancel_after_begin'
CANCEL_AFTER_FIRST_RESPONSE = 'cancel_after_first_response'
COMPUTE_ENGINE_CREDS = 'compute_engine_creds'
- SERVICE_ACCOUNT_CREDS = 'service_account_creds'
+ OAUTH2_AUTH_TOKEN = 'oauth2_auth_token'
TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server'
def test_interoperability(self, stub, args):
@@ -392,7 +391,7 @@ class TestCase(enum.Enum):
_timeout_on_sleeping_server(stub)
elif self is TestCase.COMPUTE_ENGINE_CREDS:
_compute_engine_creds(stub, args)
- elif self is TestCase.SERVICE_ACCOUNT_CREDS:
- _service_account_creds(stub, args)
+ elif self is TestCase.OAUTH2_AUTH_TOKEN:
+ _oauth2_auth_token(stub, args)
else:
raise NotImplementedError('Test case "%s" not implemented!' % self.name)
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/alpha_python_plugin_test.py b/src/python/grpcio_test/grpc_protoc_plugin/alpha_python_plugin_test.py
new file mode 100644
index 0000000000..b200d129a9
--- /dev/null
+++ b/src/python/grpcio_test/grpc_protoc_plugin/alpha_python_plugin_test.py
@@ -0,0 +1,541 @@
+# 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 argparse
+import contextlib
+import distutils.spawn
+import errno
+import itertools
+import os
+import pkg_resources
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+import unittest
+
+from grpc.framework.alpha import exceptions
+from grpc.framework.foundation import future
+
+# Identifiers of entities we expect to find in the generated module.
+SERVICER_IDENTIFIER = 'EarlyAdopterTestServiceServicer'
+SERVER_IDENTIFIER = 'EarlyAdopterTestServiceServer'
+STUB_IDENTIFIER = 'EarlyAdopterTestServiceStub'
+SERVER_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_server'
+STUB_FACTORY_IDENTIFIER = 'early_adopter_create_TestService_stub'
+
+# The timeout used in tests of RPCs that are supposed to expire.
+SHORT_TIMEOUT = 2
+# The timeout used in tests of RPCs that are not supposed to expire. The
+# absurdly large value doesn't matter since no passing execution of this test
+# module will ever wait the duration.
+LONG_TIMEOUT = 600
+NO_DELAY = 0
+
+
+class _ServicerMethods(object):
+
+ def __init__(self, test_pb2, delay):
+ self._condition = threading.Condition()
+ self._delay = delay
+ self._paused = False
+ self._fail = False
+ self._test_pb2 = test_pb2
+
+ @contextlib.contextmanager
+ def pause(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._paused = True
+ yield
+ with self._condition:
+ self._paused = False
+ self._condition.notify_all()
+
+ @contextlib.contextmanager
+ def fail(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._fail = True
+ yield
+ with self._condition:
+ self._fail = False
+
+ def _control(self): # pylint: disable=invalid-name
+ with self._condition:
+ if self._fail:
+ raise ValueError()
+ while self._paused:
+ self._condition.wait()
+ time.sleep(self._delay)
+
+ def UnaryCall(self, request, unused_rpc_context):
+ response = self._test_pb2.SimpleResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * request.response_size
+ self._control()
+ return response
+
+ def StreamingOutputCall(self, request, unused_rpc_context):
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def StreamingInputCall(self, request_iter, unused_rpc_context):
+ response = self._test_pb2.StreamingInputCallResponse()
+ aggregated_payload_size = 0
+ for request in request_iter:
+ aggregated_payload_size += len(request.payload.payload_compressable)
+ response.aggregated_payload_size = aggregated_payload_size
+ self._control()
+ return response
+
+ def FullDuplexCall(self, request_iter, unused_rpc_context):
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def HalfDuplexCall(self, request_iter, unused_rpc_context):
+ responses = []
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ responses.append(response)
+ for response in responses:
+ yield response
+
+
+@contextlib.contextmanager
+def _CreateService(test_pb2, delay):
+ """Provides a servicer backend and a stub.
+
+ The servicer is just the implementation
+ of the actual servicer passed to the face player of the python RPC
+ implementation; the two are detached.
+
+ Non-zero delay puts a delay on each call to the servicer, representative of
+ communication latency. Timeout is the default timeout for the stub while
+ waiting for the service.
+
+ Args:
+ test_pb2: The test_pb2 module generated by this test.
+ delay: Delay in seconds per response from the servicer.
+
+ Yields:
+ A (servicer_methods, servicer, stub) three-tuple where servicer_methods is
+ the back-end of the service bound to the stub and the server and stub
+ are both activated and ready for use.
+ """
+ servicer_methods = _ServicerMethods(test_pb2, delay)
+
+ class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)):
+
+ def UnaryCall(self, request, context):
+ return servicer_methods.UnaryCall(request, context)
+
+ def StreamingOutputCall(self, request, context):
+ return servicer_methods.StreamingOutputCall(request, context)
+
+ def StreamingInputCall(self, request_iter, context):
+ return servicer_methods.StreamingInputCall(request_iter, context)
+
+ def FullDuplexCall(self, request_iter, context):
+ return servicer_methods.FullDuplexCall(request_iter, context)
+
+ def HalfDuplexCall(self, request_iter, context):
+ return servicer_methods.HalfDuplexCall(request_iter, context)
+
+ servicer = Servicer()
+ server = getattr(
+ test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer, 0)
+ with server:
+ port = server.port()
+ stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)('localhost', port)
+ with stub:
+ yield servicer_methods, stub, server
+
+
+def _streaming_input_request_iterator(test_pb2):
+ for _ in range(3):
+ request = test_pb2.StreamingInputCallRequest()
+ request.payload.payload_type = test_pb2.COMPRESSABLE
+ request.payload.payload_compressable = 'a'
+ yield request
+
+
+def _streaming_output_request(test_pb2):
+ request = test_pb2.StreamingOutputCallRequest()
+ sizes = [1, 2, 3]
+ request.response_parameters.add(size=sizes[0], interval_us=0)
+ request.response_parameters.add(size=sizes[1], interval_us=0)
+ request.response_parameters.add(size=sizes[2], interval_us=0)
+ return request
+
+
+def _full_duplex_request_iterator(test_pb2):
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+
+
+class PythonPluginTest(unittest.TestCase):
+ """Test case for the gRPC Python protoc-plugin.
+
+ While reading these tests, remember that the futures API
+ (`stub.method.async()`) only gives futures for the *non-streaming* responses,
+ else it behaves like its blocking cousin.
+ """
+
+ def setUp(self):
+ # Assume that the appropriate protoc and grpc_python_plugins are on the
+ # path.
+ protoc_command = 'protoc'
+ protoc_plugin_filename = distutils.spawn.find_executable(
+ 'grpc_python_plugin')
+ test_proto_filename = pkg_resources.resource_filename(
+ 'grpc_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'
+
+ # Ensure that the output directory exists.
+ self.outdir = tempfile.mkdtemp()
+
+ # Invoke protoc with the plugin.
+ cmd = [
+ protoc_command,
+ '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename,
+ '-I .',
+ '--python_out=%s' % self.outdir,
+ '--python-grpc_out=%s' % self.outdir,
+ os.path.basename(test_proto_filename),
+ ]
+ subprocess.check_call(' '.join(cmd), shell=True, env=os.environ,
+ cwd=os.path.dirname(test_proto_filename))
+ sys.path.append(self.outdir)
+
+ def tearDown(self):
+ try:
+ shutil.rmtree(self.outdir)
+ except OSError as exc:
+ if exc.errno != errno.ENOENT:
+ raise
+
+ # TODO(atash): Figure out which of these tests is hanging flakily with small
+ # probability.
+
+ def testImportAttributes(self):
+ # check that we can access the generated module and its members.
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ self.assertIsNotNone(getattr(test_pb2, SERVICER_IDENTIFIER, None))
+ self.assertIsNotNone(getattr(test_pb2, SERVER_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
+ with _CreateService(
+ test_pb2, NO_DELAY) as (servicer, stub, unused_server):
+ request = test_pb2.SimpleRequest(response_size=13)
+
+ def testUnaryCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods.
+ request = test_pb2.SimpleRequest(response_size=13)
+ response = stub.UnaryCall(request, timeout)
+ expected_response = methods.UnaryCall(request, 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallAsync(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = test_pb2.SimpleRequest(response_size=13)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ # Check that the call does not block waiting for the server to respond.
+ with methods.pause():
+ response_future = stub.UnaryCall.async(request, LONG_TIMEOUT)
+ response = response_future.result()
+ expected_response = methods.UnaryCall(request, 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallAsyncExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ request = test_pb2.SimpleRequest(response_size=13)
+ with methods.pause():
+ response_future = stub.UnaryCall.async(request, SHORT_TIMEOUT)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testUnaryCallAsyncCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = test_pb2.SimpleRequest(response_size=13)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ response_future = stub.UnaryCall.async(request, 1)
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+
+ def testUnaryCallAsyncFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = test_pb2.SimpleRequest(response_size=13)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.fail():
+ response_future = stub.UnaryCall.async(request, LONG_TIMEOUT)
+ self.assertIsNotNone(response_future.exception())
+
+ def testStreamingOutputCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ responses = stub.StreamingOutputCall(request, LONG_TIMEOUT)
+ expected_responses = methods.StreamingOutputCall(
+ request, 'not a real RpcContext!')
+ for expected_response, response in itertools.izip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testStreamingOutputCallExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT)
+ with self.assertRaises(exceptions.ExpirationError):
+ list(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testStreamingOutputCallCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ unused_methods, stub, unused_server):
+ responses = stub.StreamingOutputCall(request, SHORT_TIMEOUT)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(future.CancelledError):
+ next(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this times out '
+ 'instead of raising the proper error.')
+ def testStreamingOutputCallFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.fail():
+ responses = stub.StreamingOutputCall(request, 1)
+ self.assertIsNotNone(responses)
+ with self.assertRaises(exceptions.ServicerError):
+ next(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testStreamingInputCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ response = stub.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT)
+ expected_response = methods.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallAsync(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ response_future = stub.StreamingInputCall.async(
+ _streaming_input_request_iterator(test_pb2), LONG_TIMEOUT)
+ response = response_future.result()
+ expected_response = methods.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallAsyncExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ response_future = stub.StreamingInputCall.async(
+ _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT)
+ with self.assertRaises(exceptions.ExpirationError):
+ response_future.result()
+ self.assertIsInstance(
+ response_future.exception(), exceptions.ExpirationError)
+
+ def testStreamingInputCallAsyncCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ timeout = 6 # TODO(issue 2039): LONG_TIMEOUT like the other methods.
+ response_future = stub.StreamingInputCall.async(
+ _streaming_input_request_iterator(test_pb2), timeout)
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+ with self.assertRaises(future.CancelledError):
+ response_future.result()
+
+ def testStreamingInputCallAsyncFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.fail():
+ response_future = stub.StreamingInputCall.async(
+ _streaming_input_request_iterator(test_pb2), SHORT_TIMEOUT)
+ self.assertIsNotNone(response_future.exception())
+
+ def testFullDuplexCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ responses = stub.FullDuplexCall(
+ _full_duplex_request_iterator(test_pb2), LONG_TIMEOUT)
+ expected_responses = methods.FullDuplexCall(
+ _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!')
+ for expected_response, response in itertools.izip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testFullDuplexCallExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.pause():
+ responses = stub.FullDuplexCall(request_iterator, SHORT_TIMEOUT)
+ with self.assertRaises(exceptions.ExpirationError):
+ list(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testFullDuplexCallCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(future.CancelledError):
+ next(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this hangs forever '
+ 'and fix.')
+ def testFullDuplexCallFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ with methods.fail():
+ responses = stub.FullDuplexCall(request_iterator, LONG_TIMEOUT)
+ self.assertIsNotNone(responses)
+ with self.assertRaises(exceptions.ServicerError):
+ next(responses)
+
+ @unittest.skip('TODO(atash,nathaniel): figure out why this flakily hangs '
+ 'forever and fix.')
+ def testHalfDuplexCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2, NO_DELAY) as (
+ methods, stub, unused_server):
+ def half_duplex_request_iterator():
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+ responses = stub.HalfDuplexCall(
+ half_duplex_request_iterator(), LONG_TIMEOUT)
+ expected_responses = methods.HalfDuplexCall(
+ half_duplex_request_iterator(), 'not a real RpcContext!')
+ for check in itertools.izip_longest(expected_responses, responses):
+ expected_response, response = check
+ self.assertEqual(expected_response, response)
+
+ def testHalfDuplexCallWedged(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ condition = threading.Condition()
+ wait_cell = [False]
+ @contextlib.contextmanager
+ def wait(): # pylint: disable=invalid-name
+ # Where's Python 3's 'nonlocal' statement when you need it?
+ with condition:
+ wait_cell[0] = True
+ yield
+ with condition:
+ wait_cell[0] = False
+ condition.notify_all()
+ def half_duplex_request_iterator():
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ with condition:
+ while wait_cell[0]:
+ condition.wait()
+ with _CreateService(test_pb2, NO_DELAY) as (methods, stub, unused_server):
+ with wait():
+ responses = stub.HalfDuplexCall(
+ half_duplex_request_iterator(), SHORT_TIMEOUT)
+ # half-duplex waits for the client to send all info
+ with self.assertRaises(exceptions.ExpirationError):
+ next(responses)
+
+
+if __name__ == '__main__':
+ os.chdir(os.path.dirname(sys.argv[0]))
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py
new file mode 100644
index 0000000000..259b978de2
--- /dev/null
+++ b/src/python/grpcio_test/grpc_protoc_plugin/beta_python_plugin_test.py
@@ -0,0 +1,501 @@
+# 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 argparse
+import contextlib
+import distutils.spawn
+import errno
+import itertools
+import os
+import pkg_resources
+import shutil
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+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
+
+# Identifiers of entities we expect to find in the generated module.
+SERVICER_IDENTIFIER = 'BetaTestServiceServicer'
+STUB_IDENTIFIER = 'BetaTestServiceStub'
+SERVER_FACTORY_IDENTIFIER = 'beta_create_TestService_server'
+STUB_FACTORY_IDENTIFIER = 'beta_create_TestService_stub'
+
+
+class _ServicerMethods(object):
+
+ def __init__(self, test_pb2):
+ self._condition = threading.Condition()
+ self._paused = False
+ self._fail = False
+ self._test_pb2 = test_pb2
+
+ @contextlib.contextmanager
+ def pause(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._paused = True
+ yield
+ with self._condition:
+ self._paused = False
+ self._condition.notify_all()
+
+ @contextlib.contextmanager
+ def fail(self): # pylint: disable=invalid-name
+ with self._condition:
+ self._fail = True
+ yield
+ with self._condition:
+ self._fail = False
+
+ def _control(self): # pylint: disable=invalid-name
+ with self._condition:
+ if self._fail:
+ raise ValueError()
+ while self._paused:
+ self._condition.wait()
+
+ def UnaryCall(self, request, unused_rpc_context):
+ response = self._test_pb2.SimpleResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * request.response_size
+ self._control()
+ return response
+
+ def StreamingOutputCall(self, request, unused_rpc_context):
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def StreamingInputCall(self, request_iter, unused_rpc_context):
+ response = self._test_pb2.StreamingInputCallResponse()
+ aggregated_payload_size = 0
+ for request in request_iter:
+ aggregated_payload_size += len(request.payload.payload_compressable)
+ response.aggregated_payload_size = aggregated_payload_size
+ self._control()
+ return response
+
+ def FullDuplexCall(self, request_iter, unused_rpc_context):
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ yield response
+
+ def HalfDuplexCall(self, request_iter, unused_rpc_context):
+ responses = []
+ for request in request_iter:
+ for parameter in request.response_parameters:
+ response = self._test_pb2.StreamingOutputCallResponse()
+ response.payload.payload_type = self._test_pb2.COMPRESSABLE
+ response.payload.payload_compressable = 'a' * parameter.size
+ self._control()
+ responses.append(response)
+ for response in responses:
+ yield response
+
+
+@contextlib.contextmanager
+def _CreateService(test_pb2):
+ """Provides a servicer backend and a stub.
+
+ The servicer is just the implementation of the actual servicer passed to the
+ face player of the python RPC implementation; the two are detached.
+
+ Args:
+ test_pb2: The test_pb2 module generated by this test.
+
+ Yields:
+ A (servicer_methods, stub) pair where servicer_methods is the back-end of
+ the service bound to the stub and and stub is the stub on which to invoke
+ RPCs.
+ """
+ servicer_methods = _ServicerMethods(test_pb2)
+
+ class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)):
+
+ def UnaryCall(self, request, context):
+ return servicer_methods.UnaryCall(request, context)
+
+ def StreamingOutputCall(self, request, context):
+ return servicer_methods.StreamingOutputCall(request, context)
+
+ def StreamingInputCall(self, request_iter, context):
+ return servicer_methods.StreamingInputCall(request_iter, context)
+
+ def FullDuplexCall(self, request_iter, context):
+ return servicer_methods.FullDuplexCall(request_iter, context)
+
+ def HalfDuplexCall(self, request_iter, context):
+ return servicer_methods.HalfDuplexCall(request_iter, context)
+
+ servicer = Servicer()
+ server = getattr(test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer)
+ port = server.add_insecure_port('[::]:0')
+ server.start()
+ channel = implementations.insecure_channel('localhost', port)
+ stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)(channel)
+ yield servicer_methods, stub
+ server.stop(0)
+
+
+def _streaming_input_request_iterator(test_pb2):
+ for _ in range(3):
+ request = test_pb2.StreamingInputCallRequest()
+ request.payload.payload_type = test_pb2.COMPRESSABLE
+ request.payload.payload_compressable = 'a'
+ yield request
+
+
+def _streaming_output_request(test_pb2):
+ request = test_pb2.StreamingOutputCallRequest()
+ sizes = [1, 2, 3]
+ request.response_parameters.add(size=sizes[0], interval_us=0)
+ request.response_parameters.add(size=sizes[1], interval_us=0)
+ request.response_parameters.add(size=sizes[2], interval_us=0)
+ return request
+
+
+def _full_duplex_request_iterator(test_pb2):
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+
+
+class PythonPluginTest(unittest.TestCase):
+ """Test case for the gRPC Python protoc-plugin.
+
+ While reading these tests, remember that the futures API
+ (`stub.method.future()`) only gives futures for the *response-unary*
+ methods and does not exist for response-streaming methods.
+ """
+
+ def setUp(self):
+ # Assume that the appropriate protoc and grpc_python_plugins are on the
+ # path.
+ protoc_command = 'protoc'
+ protoc_plugin_filename = distutils.spawn.find_executable(
+ 'grpc_python_plugin')
+ test_proto_filename = pkg_resources.resource_filename(
+ 'grpc_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'
+
+ # Ensure that the output directory exists.
+ self.outdir = tempfile.mkdtemp()
+
+ # Invoke protoc with the plugin.
+ cmd = [
+ protoc_command,
+ '--plugin=protoc-gen-python-grpc=%s' % protoc_plugin_filename,
+ '-I .',
+ '--python_out=%s' % self.outdir,
+ '--python-grpc_out=%s' % self.outdir,
+ os.path.basename(test_proto_filename),
+ ]
+ subprocess.check_call(' '.join(cmd), shell=True, env=os.environ,
+ cwd=os.path.dirname(test_proto_filename))
+ sys.path.append(self.outdir)
+
+ def tearDown(self):
+ try:
+ shutil.rmtree(self.outdir)
+ except OSError as exc:
+ if exc.errno != errno.ENOENT:
+ raise
+
+ def testImportAttributes(self):
+ # check that we can access the generated module and its members.
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ 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
+ 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
+ with _CreateService(test_pb2) as (methods, stub):
+ request = test_pb2.SimpleRequest(response_size=13)
+ response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
+ expected_response = methods.UnaryCall(request, 'not a real context!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallFuture(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ 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.
+ with methods.pause():
+ response_future = stub.UnaryCall.future(
+ request, test_constants.LONG_TIMEOUT)
+ response = response_future.result()
+ expected_response = methods.UnaryCall(request, 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testUnaryCallFutureExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ request = test_pb2.SimpleRequest(response_size=13)
+ with methods.pause():
+ response_future = stub.UnaryCall.future(
+ request, test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(face.ExpirationError):
+ response_future.result()
+
+ def testUnaryCallFutureCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = test_pb2.SimpleRequest(response_size=13)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ response_future = stub.UnaryCall.future(request, 1)
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+
+ def testUnaryCallFutureFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = test_pb2.SimpleRequest(response_size=13)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.fail():
+ response_future = stub.UnaryCall.future(
+ request, test_constants.LONG_TIMEOUT)
+ self.assertIsNotNone(response_future.exception())
+
+ def testStreamingOutputCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2) as (methods, stub):
+ responses = stub.StreamingOutputCall(
+ request, test_constants.LONG_TIMEOUT)
+ expected_responses = methods.StreamingOutputCall(
+ request, 'not a real RpcContext!')
+ for expected_response, response in itertools.izip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ def testStreamingOutputCallExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ responses = stub.StreamingOutputCall(
+ request, test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(face.ExpirationError):
+ list(responses)
+
+ def testStreamingOutputCallCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2) as (unused_methods, stub):
+ responses = stub.StreamingOutputCall(
+ request, test_constants.LONG_TIMEOUT)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(face.CancellationError):
+ next(responses)
+
+ def testStreamingOutputCallFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request = _streaming_output_request(test_pb2)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.fail():
+ responses = stub.StreamingOutputCall(request, 1)
+ self.assertIsNotNone(responses)
+ with self.assertRaises(face.RemoteError):
+ next(responses)
+
+ def testStreamingInputCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ response = stub.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2),
+ test_constants.LONG_TIMEOUT)
+ expected_response = methods.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallFuture(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ response_future = stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(test_pb2),
+ test_constants.LONG_TIMEOUT)
+ response = response_future.result()
+ expected_response = methods.StreamingInputCall(
+ _streaming_input_request_iterator(test_pb2), 'not a real RpcContext!')
+ self.assertEqual(expected_response, response)
+
+ def testStreamingInputCallFutureExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ response_future = stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(test_pb2),
+ test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(face.ExpirationError):
+ response_future.result()
+ self.assertIsInstance(
+ response_future.exception(), face.ExpirationError)
+
+ def testStreamingInputCallFutureCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ response_future = stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(test_pb2),
+ test_constants.LONG_TIMEOUT)
+ response_future.cancel()
+ self.assertTrue(response_future.cancelled())
+ with self.assertRaises(future.CancelledError):
+ response_future.result()
+
+ def testStreamingInputCallFutureFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.fail():
+ response_future = stub.StreamingInputCall.future(
+ _streaming_input_request_iterator(test_pb2),
+ test_constants.LONG_TIMEOUT)
+ self.assertIsNotNone(response_future.exception())
+
+ def testFullDuplexCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ responses = stub.FullDuplexCall(
+ _full_duplex_request_iterator(test_pb2), test_constants.LONG_TIMEOUT)
+ expected_responses = methods.FullDuplexCall(
+ _full_duplex_request_iterator(test_pb2), 'not a real RpcContext!')
+ for expected_response, response in itertools.izip_longest(
+ expected_responses, responses):
+ self.assertEqual(expected_response, response)
+
+ def testFullDuplexCallExpired(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.pause():
+ responses = stub.FullDuplexCall(
+ request_iterator, test_constants.SHORT_TIMEOUT)
+ with self.assertRaises(face.ExpirationError):
+ list(responses)
+
+ def testFullDuplexCallCancelled(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ responses = stub.FullDuplexCall(
+ request_iterator, test_constants.LONG_TIMEOUT)
+ next(responses)
+ responses.cancel()
+ with self.assertRaises(face.CancellationError):
+ next(responses)
+
+ def testFullDuplexCallFailed(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ request_iterator = _full_duplex_request_iterator(test_pb2)
+ with _CreateService(test_pb2) as (methods, stub):
+ with methods.fail():
+ responses = stub.FullDuplexCall(
+ request_iterator, test_constants.LONG_TIMEOUT)
+ self.assertIsNotNone(responses)
+ with self.assertRaises(face.RemoteError):
+ next(responses)
+
+ def testHalfDuplexCall(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ with _CreateService(test_pb2) as (methods, stub):
+ def half_duplex_request_iterator():
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=2, interval_us=0)
+ request.response_parameters.add(size=3, interval_us=0)
+ yield request
+ responses = stub.HalfDuplexCall(
+ half_duplex_request_iterator(), test_constants.LONG_TIMEOUT)
+ expected_responses = methods.HalfDuplexCall(
+ half_duplex_request_iterator(), 'not a real RpcContext!')
+ for check in itertools.izip_longest(expected_responses, responses):
+ expected_response, response = check
+ self.assertEqual(expected_response, response)
+
+ def testHalfDuplexCallWedged(self):
+ import test_pb2 # pylint: disable=g-import-not-at-top
+ condition = threading.Condition()
+ wait_cell = [False]
+ @contextlib.contextmanager
+ def wait(): # pylint: disable=invalid-name
+ # Where's Python 3's 'nonlocal' statement when you need it?
+ with condition:
+ wait_cell[0] = True
+ yield
+ with condition:
+ wait_cell[0] = False
+ condition.notify_all()
+ def half_duplex_request_iterator():
+ request = test_pb2.StreamingOutputCallRequest()
+ request.response_parameters.add(size=1, interval_us=0)
+ yield request
+ with condition:
+ while wait_cell[0]:
+ condition.wait()
+ with _CreateService(test_pb2) as (methods, stub):
+ with wait():
+ responses = stub.HalfDuplexCall(
+ half_duplex_request_iterator(), test_constants.SHORT_TIMEOUT)
+ # half-duplex waits for the client to send all info
+ with self.assertRaises(face.ExpirationError):
+ next(responses)
+
+
+if __name__ == '__main__':
+ os.chdir(os.path.dirname(sys.argv[0]))
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py b/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
index 27a5b82e9c..90ad0b9bcb 100644
--- a/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
+++ b/src/python/grpcio_test/grpc_test/_adapter/_intermediary_low_test.py
@@ -191,7 +191,7 @@ class EchoTest(unittest.TestCase):
metadata[server_leading_binary_metadata_key])
for datum in test_data:
- client_call.write(datum, write_tag)
+ client_call.write(datum, write_tag, _low.WriteFlags.WRITE_NO_COMPRESS)
write_accepted = self.client_events.get()
self.assertIsNotNone(write_accepted)
self.assertIs(write_accepted.kind, _low.Event.Kind.WRITE_ACCEPTED)
@@ -206,7 +206,7 @@ class EchoTest(unittest.TestCase):
self.assertIsNotNone(read_accepted.bytes)
server_data.append(read_accepted.bytes)
- server_call.write(read_accepted.bytes, write_tag)
+ server_call.write(read_accepted.bytes, write_tag, 0)
write_accepted = self.server_events.get()
self.assertIsNotNone(write_accepted)
self.assertEqual(_low.Event.Kind.WRITE_ACCEPTED, write_accepted.kind)
@@ -370,14 +370,14 @@ class CancellationTest(unittest.TestCase):
self.assertIsNotNone(metadata_accepted)
for datum in test_data:
- client_call.write(datum, write_tag)
+ client_call.write(datum, write_tag, 0)
write_accepted = self.client_events.get()
server_call.read(read_tag)
read_accepted = self.server_events.get()
server_data.append(read_accepted.bytes)
- server_call.write(read_accepted.bytes, write_tag)
+ server_call.write(read_accepted.bytes, write_tag, 0)
write_accepted = self.server_events.get()
self.assertIsNotNone(write_accepted)
diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
index 72b1ae5642..cafb6b6eae 100644
--- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
+++ b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py
@@ -27,7 +27,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""Tests the RPC Framework Core's implementation of the Base interface."""
+"""Tests Base interface compliance of the core-over-gRPC-links stack."""
import collections
import logging
@@ -38,6 +38,7 @@ import unittest
from grpc._adapter import _intermediary_low
from grpc._links import invocation
from grpc._links import service
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.core import implementations
from grpc.framework.interfaces.base import utilities
from grpc_test import test_common as grpc_test_common
@@ -45,12 +46,6 @@ 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
-_INVOCATION_INITIAL_METADATA = ((b'0', b'abc'), (b'1', b'def'), (b'2', b'ghi'),)
-_SERVICE_INITIAL_METADATA = ((b'3', b'jkl'), (b'4', b'mno'), (b'5', b'pqr'),)
-_SERVICE_TERMINAL_METADATA = ((b'6', b'stu'), (b'7', b'vwx'), (b'8', b'yza'),)
-_CODE = _intermediary_low.Code.OK
-_MESSAGE = b'test message'
-
class _SerializationBehaviors(
collections.namedtuple(
@@ -95,10 +90,10 @@ class _Implementation(test_interfaces.Implementation):
service_grpc_link = service.service_link(
serialization_behaviors.request_deserializers,
serialization_behaviors.response_serializers)
- port = service_grpc_link.add_port(0, None)
+ port = service_grpc_link.add_port('[::]:0', None)
channel = _intermediary_low.Channel('localhost:%d' % port, None)
invocation_grpc_link = invocation.invocation_link(
- channel, b'localhost',
+ channel, b'localhost', None,
serialization_behaviors.request_serializers,
serialization_behaviors.response_deserializers)
@@ -114,19 +109,22 @@ class _Implementation(test_interfaces.Implementation):
def destantiate(self, memo):
invocation_grpc_link, service_grpc_link = memo
invocation_grpc_link.stop()
- service_grpc_link.stop_gracefully()
+ service_grpc_link.begin_stop()
+ service_grpc_link.end_stop()
def invocation_initial_metadata(self):
- return _INVOCATION_INITIAL_METADATA
+ return grpc_test_common.INVOCATION_INITIAL_METADATA
def service_initial_metadata(self):
- return _SERVICE_INITIAL_METADATA
+ return grpc_test_common.SERVICE_INITIAL_METADATA
def invocation_completion(self):
return utilities.completion(None, None, None)
def service_completion(self):
- return utilities.completion(_SERVICE_TERMINAL_METADATA, _CODE, _MESSAGE)
+ return utilities.completion(
+ grpc_test_common.SERVICE_TERMINAL_METADATA,
+ beta_interfaces.StatusCode.OK, grpc_test_common.DETAILS)
def metadata_transmitted(self, original_metadata, transmitted_metadata):
return original_metadata is None or grpc_test_common.metadata_transmitted(
@@ -146,14 +144,6 @@ class _Implementation(test_interfaces.Implementation):
return True
-def setUpModule():
- logging.warn('setUpModule!')
-
-
-def tearDownModule():
- logging.warn('tearDownModule!')
-
-
def load_tests(loader, tests, pattern):
return unittest.TestSuite(
tests=tuple(
diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
new file mode 100644
index 0000000000..a4d4dee38c
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py
@@ -0,0 +1,161 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Face compliance of the crust-over-core-over-gRPC-links stack."""
+
+import collections
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc._links import invocation
+from grpc._links import service
+from grpc.beta import interfaces as beta_interfaces
+from grpc.framework.core import implementations as core_implementations
+from grpc.framework.crust import implementations as crust_implementations
+from grpc.framework.foundation import logging_pool
+from grpc.framework.interfaces.links import utilities
+from 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
+
+
+class _SerializationBehaviors(
+ collections.namedtuple(
+ '_SerializationBehaviors',
+ ('request_serializers', 'request_deserializers', 'response_serializers',
+ 'response_deserializers',))):
+ pass
+
+
+def _serialization_behaviors_from_test_methods(test_methods):
+ request_serializers = {}
+ request_deserializers = {}
+ response_serializers = {}
+ response_deserializers = {}
+ for (group, method), test_method in test_methods.iteritems():
+ request_serializers[group, method] = test_method.serialize_request
+ request_deserializers[group, method] = test_method.deserialize_request
+ response_serializers[group, method] = test_method.serialize_response
+ response_deserializers[group, method] = test_method.deserialize_response
+ return _SerializationBehaviors(
+ request_serializers, request_deserializers, response_serializers,
+ response_deserializers)
+
+
+class _Implementation(test_interfaces.Implementation):
+
+ def instantiate(
+ self, methods, method_implementations, multi_method_implementation):
+ pool = logging_pool.pool(test_constants.POOL_SIZE)
+ servicer = crust_implementations.servicer(
+ method_implementations, multi_method_implementation, pool)
+ serialization_behaviors = _serialization_behaviors_from_test_methods(
+ methods)
+ invocation_end_link = core_implementations.invocation_end_link()
+ service_end_link = core_implementations.service_end_link(
+ servicer, test_constants.DEFAULT_TIMEOUT,
+ test_constants.MAXIMUM_TIMEOUT)
+ service_grpc_link = service.service_link(
+ serialization_behaviors.request_deserializers,
+ serialization_behaviors.response_serializers)
+ port = service_grpc_link.add_port('[::]:0', None)
+ channel = _intermediary_low.Channel('localhost:%d' % port, None)
+ invocation_grpc_link = invocation.invocation_link(
+ channel, b'localhost', None,
+ serialization_behaviors.request_serializers,
+ serialization_behaviors.response_deserializers)
+
+ invocation_end_link.join_link(invocation_grpc_link)
+ invocation_grpc_link.join_link(invocation_end_link)
+ service_grpc_link.join_link(service_end_link)
+ service_end_link.join_link(service_grpc_link)
+ service_end_link.start()
+ invocation_end_link.start()
+ invocation_grpc_link.start()
+ service_grpc_link.start()
+
+ generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
+ # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
+ group = next(iter(methods))[0]
+ # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
+ # _digest.TestServiceDigest.
+ cardinalities = {
+ method: method_object.cardinality()
+ for (group, method), method_object in methods.iteritems()}
+ dynamic_stub = crust_implementations.dynamic_stub(
+ invocation_end_link, group, cardinalities, pool)
+
+ return generic_stub, {group: dynamic_stub}, (
+ invocation_end_link, invocation_grpc_link, service_grpc_link,
+ service_end_link, pool)
+
+ def destantiate(self, memo):
+ (invocation_end_link, invocation_grpc_link, service_grpc_link,
+ service_end_link, pool) = memo
+ invocation_end_link.stop(0).wait()
+ invocation_grpc_link.stop()
+ service_grpc_link.begin_stop()
+ service_end_link.stop(0).wait()
+ service_grpc_link.end_stop()
+ invocation_end_link.join_link(utilities.NULL_LINK)
+ invocation_grpc_link.join_link(utilities.NULL_LINK)
+ service_grpc_link.join_link(utilities.NULL_LINK)
+ service_end_link.join_link(utilities.NULL_LINK)
+ pool.shutdown(wait=True)
+
+ def invocation_metadata(self):
+ return grpc_test_common.INVOCATION_INITIAL_METADATA
+
+ def initial_metadata(self):
+ return grpc_test_common.SERVICE_INITIAL_METADATA
+
+ def terminal_metadata(self):
+ return grpc_test_common.SERVICE_TERMINAL_METADATA
+
+ def code(self):
+ return beta_interfaces.StatusCode.OK
+
+ def details(self):
+ return grpc_test_common.DETAILS
+
+ def metadata_transmitted(self, original_metadata, transmitted_metadata):
+ return original_metadata is None or grpc_test_common.metadata_transmitted(
+ original_metadata, transmitted_metadata)
+
+
+def load_tests(loader, tests, pattern):
+ return unittest.TestSuite(
+ tests=tuple(
+ loader.loadTestsFromTestCase(test_case_class)
+ for test_case_class in test_cases.test_cases(_Implementation())))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py b/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
index 373a2b2a1f..8e12e8cc22 100644
--- a/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
+++ b/src/python/grpcio_test/grpc_test/_links/_lonely_invocation_link_test.py
@@ -45,7 +45,8 @@ class LonelyInvocationLinkTest(unittest.TestCase):
def testUpAndDown(self):
channel = _intermediary_low.Channel('nonexistent:54321', None)
- invocation_link = invocation.invocation_link(channel, 'nonexistent', {}, {})
+ invocation_link = invocation.invocation_link(
+ channel, 'nonexistent', None, {}, {})
invocation_link.start()
invocation_link.stop()
@@ -58,8 +59,7 @@ class LonelyInvocationLinkTest(unittest.TestCase):
channel = _intermediary_low.Channel('nonexistent:54321', None)
invocation_link = invocation.invocation_link(
- channel, 'nonexistent', {(test_group, test_method): _NULL_BEHAVIOR},
- {(test_group, test_method): _NULL_BEHAVIOR})
+ channel, 'nonexistent', None, {}, {})
invocation_link.join_link(invocation_link_mate)
invocation_link.start()
diff --git a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py b/src/python/grpcio_test/grpc_test/_links/_transmission_test.py
index db011bca66..77e83d5561 100644
--- a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py
+++ b/src/python/grpcio_test/grpc_test/_links/_transmission_test.py
@@ -34,6 +34,7 @@ import unittest
from grpc._adapter import _intermediary_low
from grpc._links import invocation
from grpc._links import service
+from grpc.beta import interfaces as beta_interfaces
from grpc.framework.interfaces.links import links
from grpc_test import test_common
from grpc_test._links import _proto_scenarios
@@ -50,11 +51,11 @@ class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
service_link = service.service_link(
{self.group_and_method(): self.deserialize_request},
{self.group_and_method(): self.serialize_response})
- port = service_link.add_port(0, None)
+ port = service_link.add_port('[::]:0', None)
service_link.start()
channel = _intermediary_low.Channel('localhost:%d' % port, None)
invocation_link = invocation.invocation_link(
- channel, 'localhost',
+ channel, 'localhost', None,
{self.group_and_method(): self.serialize_request},
{self.group_and_method(): self.deserialize_response})
invocation_link.start()
@@ -62,7 +63,8 @@ class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
def destroy_transmitting_links(self, invocation_side_link, service_side_link):
invocation_side_link.stop()
- service_side_link.stop_gracefully()
+ service_side_link.begin_stop()
+ service_side_link.end_stop()
def create_invocation_initial_metadata(self):
return (
@@ -92,7 +94,8 @@ class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
return None, None
def create_service_completion(self):
- return _intermediary_low.Code.OK, 'An exuberant test "details" message!'
+ return (
+ beta_interfaces.StatusCode.OK, b'An exuberant test "details" message!')
def assertMetadataTransmitted(self, original_metadata, transmitted_metadata):
self.assertTrue(
@@ -109,18 +112,18 @@ class RoundTripTest(unittest.TestCase):
test_group = 'test package.Test Group'
test_method = 'test method'
identity_transformation = {(test_group, test_method): _IDENTITY}
- test_code = _intermediary_low.Code.OK
+ test_code = beta_interfaces.StatusCode.OK
test_message = 'a test message'
service_link = service.service_link(
identity_transformation, identity_transformation)
service_mate = test_utilities.RecordingLink()
service_link.join_link(service_mate)
- port = service_link.add_port(0, None)
+ port = service_link.add_port('[::]:0', None)
service_link.start()
channel = _intermediary_low.Channel('localhost:%d' % port, None)
invocation_link = invocation.invocation_link(
- channel, 'localhost', identity_transformation, identity_transformation)
+ channel, None, None, identity_transformation, identity_transformation)
invocation_mate = test_utilities.RecordingLink()
invocation_link.join_link(invocation_mate)
invocation_link.start()
@@ -140,7 +143,8 @@ class RoundTripTest(unittest.TestCase):
invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
invocation_link.stop()
- service_link.stop_gracefully()
+ service_link.begin_stop()
+ service_link.end_stop()
self.assertIs(
service_mate.tickets()[-1].termination,
@@ -148,11 +152,13 @@ class RoundTripTest(unittest.TestCase):
self.assertIs(
invocation_mate.tickets()[-1].termination,
links.Ticket.Termination.COMPLETION)
+ self.assertIs(invocation_mate.tickets()[-1].code, test_code)
+ self.assertEqual(invocation_mate.tickets()[-1].message, test_message)
def _perform_scenario_test(self, scenario):
test_operation_id = object()
test_group, test_method = scenario.group_and_method()
- test_code = _intermediary_low.Code.OK
+ test_code = beta_interfaces.StatusCode.OK
test_message = 'a scenario test message'
service_link = service.service_link(
@@ -160,11 +166,11 @@ class RoundTripTest(unittest.TestCase):
{(test_group, test_method): scenario.serialize_response})
service_mate = test_utilities.RecordingLink()
service_link.join_link(service_mate)
- port = service_link.add_port(0, None)
+ port = service_link.add_port('[::]:0', None)
service_link.start()
channel = _intermediary_low.Channel('localhost:%d' % port, None)
invocation_link = invocation.invocation_link(
- channel, 'localhost',
+ channel, 'localhost', None,
{(test_group, test_method): scenario.serialize_request},
{(test_group, test_method): scenario.deserialize_response})
invocation_mate = test_utilities.RecordingLink()
@@ -206,7 +212,8 @@ class RoundTripTest(unittest.TestCase):
invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
invocation_link.stop()
- service_link.stop_gracefully()
+ service_link.begin_stop()
+ service_link.end_stop()
observed_requests = tuple(
ticket.payload for ticket in service_mate.tickets()
diff --git a/src/python/grpcio_test/grpc_test/beta/__init__.py b/src/python/grpcio_test/grpc_test/beta/__init__.py
new file mode 100644
index 0000000000..7086519106
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
new file mode 100644
index 0000000000..fad57da9d0
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
@@ -0,0 +1,232 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Face interface compliance of the gRPC Python Beta API."""
+
+import threading
+import unittest
+
+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
+
+_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
+
+_GROUP = 'group'
+_UNARY_UNARY = 'unary-unary'
+_UNARY_STREAM = 'unary-stream'
+_STREAM_UNARY = 'stream-unary'
+_STREAM_STREAM = 'stream-stream'
+
+_REQUEST = b'abc'
+_RESPONSE = b'123'
+
+
+class _Servicer(object):
+
+ def __init__(self):
+ self._condition = threading.Condition()
+ self._peer = None
+ self._serviced = False
+
+ def unary_unary(self, request, context):
+ with self._condition:
+ self._request = request
+ self._peer = context.protocol_context().peer()
+ context.protocol_context().disable_next_response_compression()
+ self._serviced = True
+ self._condition.notify_all()
+ return _RESPONSE
+
+ def unary_stream(self, request, context):
+ with self._condition:
+ self._request = request
+ self._peer = context.protocol_context().peer()
+ context.protocol_context().disable_next_response_compression()
+ self._serviced = True
+ self._condition.notify_all()
+ return
+ yield
+
+ def stream_unary(self, request_iterator, context):
+ for request in request_iterator:
+ self._request = request
+ with self._condition:
+ self._peer = context.protocol_context().peer()
+ context.protocol_context().disable_next_response_compression()
+ self._serviced = True
+ self._condition.notify_all()
+ return _RESPONSE
+
+ def stream_stream(self, request_iterator, context):
+ for request in request_iterator:
+ with self._condition:
+ self._peer = context.protocol_context().peer()
+ context.protocol_context().disable_next_response_compression()
+ yield _RESPONSE
+ with self._condition:
+ self._serviced = True
+ self._condition.notify_all()
+
+ def peer(self):
+ with self._condition:
+ return self._peer
+
+ def block_until_serviced(self):
+ with self._condition:
+ while not self._serviced:
+ self._condition.wait()
+
+
+class _BlockingIterator(object):
+
+ def __init__(self, upstream):
+ self._condition = threading.Condition()
+ self._upstream = upstream
+ self._allowed = []
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ with self._condition:
+ while True:
+ if self._allowed is None:
+ raise StopIteration()
+ elif self._allowed:
+ return self._allowed.pop(0)
+ else:
+ self._condition.wait()
+
+ def allow(self):
+ with self._condition:
+ try:
+ self._allowed.append(next(self._upstream))
+ except StopIteration:
+ self._allowed = None
+ self._condition.notify_all()
+
+
+class BetaFeaturesTest(unittest.TestCase):
+
+ def setUp(self):
+ self._servicer = _Servicer()
+ 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),
+ }
+
+ 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,
+ }
+
+ server_options = implementations.server_options(
+ thread_pool_size=test_constants.POOL_SIZE)
+ self._server = implementations.server(
+ method_implementations, options=server_options)
+ server_credentials = implementations.ssl_server_credentials(
+ [(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(
+ resources.test_root_certificates(), None, None)
+ channel = test_utilities.not_really_secure_channel(
+ 'localhost', port, self._client_credentials, _SERVER_HOST_OVERRIDE)
+ stub_options = implementations.stub_options(
+ thread_pool_size=test_constants.POOL_SIZE)
+ self._dynamic_stub = implementations.dynamic_stub(
+ channel, _GROUP, cardinalities, options=stub_options)
+
+ def tearDown(self):
+ self._dynamic_stub = None
+ self._server.stop(test_constants.SHORT_TIMEOUT).wait()
+
+ def test_unary_unary(self):
+ call_options = interfaces.grpc_call_options(
+ disable_compression=True, credentials=self._client_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())
+
+ def test_unary_stream(self):
+ call_options = interfaces.grpc_call_options(
+ disable_compression=True, credentials=self._client_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())
+
+ def test_stream_unary(self):
+ call_options = interfaces.grpc_call_options(
+ credentials=self._client_credentials)
+ request_iterator = _BlockingIterator(iter((_REQUEST,)))
+ response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future(
+ request_iterator, test_constants.LONG_TIMEOUT,
+ protocol_options=call_options)
+ response_future.protocol_context().disable_next_request_compression()
+ request_iterator.allow()
+ response_future.protocol_context().disable_next_request_compression()
+ request_iterator.allow()
+ self._servicer.block_until_serviced()
+ self.assertIsNotNone(self._servicer.peer())
+ self.assertEqual(_RESPONSE, response_future.result())
+
+ def test_stream_stream(self):
+ call_options = interfaces.grpc_call_options(
+ credentials=self._client_credentials)
+ request_iterator = _BlockingIterator(iter((_REQUEST,)))
+ response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)(
+ request_iterator, test_constants.SHORT_TIMEOUT,
+ protocol_options=call_options)
+ response_iterator.protocol_context().disable_next_request_compression()
+ request_iterator.allow()
+ response = next(response_iterator)
+ response_iterator.protocol_context().disable_next_request_compression()
+ request_iterator.allow()
+ self._servicer.block_until_serviced()
+ self.assertIsNotNone(self._servicer.peer())
+ self.assertEqual(_RESPONSE, response)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py b/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
new file mode 100644
index 0000000000..b3c05bdb0c
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py
@@ -0,0 +1,191 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests of grpc.beta._connectivity_channel."""
+
+import threading
+import time
+import unittest
+
+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
+
+
+def _drive_completion_queue(completion_queue):
+ while True:
+ event = completion_queue.next(time.time() + 24 * 60 * 60)
+ if event.type == _types.EventType.QUEUE_SHUTDOWN:
+ break
+
+
+class _Callback(object):
+
+ def __init__(self):
+ self._condition = threading.Condition()
+ self._connectivities = []
+
+ def update(self, connectivity):
+ with self._condition:
+ self._connectivities.append(connectivity)
+ self._condition.notify()
+
+ def connectivities(self):
+ with self._condition:
+ return tuple(self._connectivities)
+
+ def block_until_connectivities_satisfy(self, predicate):
+ with self._condition:
+ while True:
+ connectivities = tuple(self._connectivities)
+ if predicate(connectivities):
+ return connectivities
+ else:
+ self._condition.wait()
+
+
+class ChannelConnectivityTest(unittest.TestCase):
+
+ def test_lonely_channel_connectivity(self):
+ low_channel = _low.Channel('localhost:12345', ())
+ callback = _Callback()
+
+ connectivity_channel = _connectivity_channel.ConnectivityChannel(
+ low_channel)
+ connectivity_channel.subscribe(callback.update, try_to_connect=False)
+ first_connectivities = callback.block_until_connectivities_satisfy(bool)
+ connectivity_channel.subscribe(callback.update, try_to_connect=True)
+ second_connectivities = callback.block_until_connectivities_satisfy(
+ lambda connectivities: 2 <= len(connectivities))
+ # Wait for a connection that will never happen.
+ time.sleep(test_constants.SHORT_TIMEOUT)
+ third_connectivities = callback.connectivities()
+ connectivity_channel.unsubscribe(callback.update)
+ fourth_connectivities = callback.connectivities()
+ connectivity_channel.unsubscribe(callback.update)
+ fifth_connectivities = callback.connectivities()
+
+ self.assertSequenceEqual(
+ (interfaces.ChannelConnectivity.IDLE,), first_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.READY, second_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.READY, third_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.READY, fourth_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.READY, fifth_connectivities)
+
+ def test_immediately_connectable_channel_connectivity(self):
+ server_completion_queue = _low.CompletionQueue()
+ server = _low.Server(server_completion_queue, [])
+ port = server.add_http2_port('[::]:0')
+ server.start()
+ server_completion_queue_thread = threading.Thread(
+ target=_drive_completion_queue, args=(server_completion_queue,))
+ server_completion_queue_thread.start()
+ low_channel = _low.Channel('localhost:%d' % port, ())
+ first_callback = _Callback()
+ second_callback = _Callback()
+
+ connectivity_channel = _connectivity_channel.ConnectivityChannel(
+ low_channel)
+ connectivity_channel.subscribe(first_callback.update, try_to_connect=False)
+ first_connectivities = first_callback.block_until_connectivities_satisfy(
+ bool)
+ # Wait for a connection that will never happen because try_to_connect=True
+ # has not yet been passed.
+ time.sleep(test_constants.SHORT_TIMEOUT)
+ second_connectivities = first_callback.connectivities()
+ connectivity_channel.subscribe(second_callback.update, try_to_connect=True)
+ third_connectivities = first_callback.block_until_connectivities_satisfy(
+ lambda connectivities: 2 <= len(connectivities))
+ fourth_connectivities = second_callback.block_until_connectivities_satisfy(
+ bool)
+ # Wait for a connection that will happen (or may already have happened).
+ first_callback.block_until_connectivities_satisfy(
+ lambda connectivities:
+ interfaces.ChannelConnectivity.READY in connectivities)
+ second_callback.block_until_connectivities_satisfy(
+ lambda connectivities:
+ interfaces.ChannelConnectivity.READY in connectivities)
+ connectivity_channel.unsubscribe(first_callback.update)
+ connectivity_channel.unsubscribe(second_callback.update)
+
+ server.shutdown()
+ server_completion_queue.shutdown()
+ server_completion_queue_thread.join()
+
+ self.assertSequenceEqual(
+ (interfaces.ChannelConnectivity.IDLE,), first_connectivities)
+ self.assertSequenceEqual(
+ (interfaces.ChannelConnectivity.IDLE,), second_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.TRANSIENT_FAILURE, third_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.FATAL_FAILURE, third_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.TRANSIENT_FAILURE,
+ fourth_connectivities)
+ self.assertNotIn(
+ interfaces.ChannelConnectivity.FATAL_FAILURE, fourth_connectivities)
+
+ def test_reachable_then_unreachable_channel_connectivity(self):
+ server_completion_queue = _low.CompletionQueue()
+ server = _low.Server(server_completion_queue, [])
+ port = server.add_http2_port('[::]:0')
+ server.start()
+ server_completion_queue_thread = threading.Thread(
+ target=_drive_completion_queue, args=(server_completion_queue,))
+ server_completion_queue_thread.start()
+ low_channel = _low.Channel('localhost:%d' % port, ())
+ callback = _Callback()
+
+ connectivity_channel = _connectivity_channel.ConnectivityChannel(
+ low_channel)
+ connectivity_channel.subscribe(callback.update, try_to_connect=True)
+ callback.block_until_connectivities_satisfy(
+ lambda connectivities:
+ interfaces.ChannelConnectivity.READY in connectivities)
+ # Now take down the server and confirm that channel readiness is repudiated.
+ server.shutdown()
+ callback.block_until_connectivities_satisfy(
+ lambda connectivities:
+ connectivities[-1] is not interfaces.ChannelConnectivity.READY)
+ connectivity_channel.unsubscribe(callback.update)
+
+ server.shutdown()
+ server_completion_queue.shutdown()
+ server_completion_queue_thread.join()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py b/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
new file mode 100644
index 0000000000..aa33e1e6f8
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_face_interface_test.py
@@ -0,0 +1,138 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Face interface compliance of the gRPC Python Beta API."""
+
+import collections
+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
+
+_SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
+
+
+class _SerializationBehaviors(
+ collections.namedtuple(
+ '_SerializationBehaviors',
+ ('request_serializers', 'request_deserializers', 'response_serializers',
+ 'response_deserializers',))):
+ pass
+
+
+def _serialization_behaviors_from_test_methods(test_methods):
+ request_serializers = {}
+ request_deserializers = {}
+ response_serializers = {}
+ response_deserializers = {}
+ for (group, method), test_method in test_methods.iteritems():
+ request_serializers[group, method] = test_method.serialize_request
+ request_deserializers[group, method] = test_method.deserialize_request
+ response_serializers[group, method] = test_method.serialize_response
+ response_deserializers[group, method] = test_method.deserialize_response
+ return _SerializationBehaviors(
+ request_serializers, request_deserializers, response_serializers,
+ response_deserializers)
+
+
+class _Implementation(test_interfaces.Implementation):
+
+ def instantiate(
+ self, methods, method_implementations, multi_method_implementation):
+ serialization_behaviors = _serialization_behaviors_from_test_methods(
+ methods)
+ # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
+ service = next(iter(methods))[0]
+ # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
+ # _digest.TestServiceDigest.
+ cardinalities = {
+ method: method_object.cardinality()
+ for (group, method), method_object in methods.iteritems()}
+
+ server_options = implementations.server_options(
+ request_deserializers=serialization_behaviors.request_deserializers,
+ response_serializers=serialization_behaviors.response_serializers,
+ thread_pool_size=test_constants.POOL_SIZE)
+ server = implementations.server(
+ method_implementations, options=server_options)
+ server_credentials = implementations.ssl_server_credentials(
+ [(resources.private_key(), resources.certificate_chain(),),])
+ port = server.add_secure_port('[::]:0', server_credentials)
+ server.start()
+ client_credentials = implementations.ssl_client_credentials(
+ resources.test_root_certificates(), None, None)
+ channel = test_utilities.not_really_secure_channel(
+ 'localhost', port, client_credentials, _SERVER_HOST_OVERRIDE)
+ stub_options = implementations.stub_options(
+ request_serializers=serialization_behaviors.request_serializers,
+ response_deserializers=serialization_behaviors.response_deserializers,
+ thread_pool_size=test_constants.POOL_SIZE)
+ generic_stub = implementations.generic_stub(channel, options=stub_options)
+ dynamic_stub = implementations.dynamic_stub(
+ channel, service, cardinalities, options=stub_options)
+ return generic_stub, {service: dynamic_stub}, server
+
+ def destantiate(self, memo):
+ memo.stop(test_constants.SHORT_TIMEOUT).wait()
+
+ def invocation_metadata(self):
+ return grpc_test_common.INVOCATION_INITIAL_METADATA
+
+ def initial_metadata(self):
+ return grpc_test_common.SERVICE_INITIAL_METADATA
+
+ def terminal_metadata(self):
+ return grpc_test_common.SERVICE_TERMINAL_METADATA
+
+ def code(self):
+ return interfaces.StatusCode.OK
+
+ def details(self):
+ return grpc_test_common.DETAILS
+
+ def metadata_transmitted(self, original_metadata, transmitted_metadata):
+ return original_metadata is None or grpc_test_common.metadata_transmitted(
+ original_metadata, transmitted_metadata)
+
+
+def load_tests(loader, tests, pattern):
+ return unittest.TestSuite(
+ tests=tuple(
+ loader.loadTestsFromTestCase(test_case_class)
+ for test_case_class in test_cases.test_cases(_Implementation())))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/_not_found_test.py b/src/python/grpcio_test/grpc_test/beta/_not_found_test.py
new file mode 100644
index 0000000000..5feb997fef
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_not_found_test.py
@@ -0,0 +1,75 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests of RPC-method-not-found behavior."""
+
+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
+
+
+class NotFoundTest(unittest.TestCase):
+
+ def setUp(self):
+ self._server = implementations.server({})
+ port = self._server.add_insecure_port('[::]:0')
+ channel = implementations.insecure_channel('localhost', port)
+ self._generic_stub = implementations.generic_stub(channel)
+ self._server.start()
+
+ def tearDown(self):
+ self._server.stop(0).wait()
+ self._generic_stub = None
+
+ def test_blocking_unary_unary_not_found(self):
+ with self.assertRaises(face.LocalError) as exception_assertion_context:
+ self._generic_stub.blocking_unary_unary(
+ 'groop', 'meffod', b'abc', test_constants.LONG_TIMEOUT,
+ with_call=True)
+ self.assertIs(
+ exception_assertion_context.exception.code,
+ interfaces.StatusCode.UNIMPLEMENTED)
+
+ def test_future_stream_unary_not_found(self):
+ rpc_future = self._generic_stub.future_stream_unary(
+ 'grupe', 'mevvod', b'def', test_constants.LONG_TIMEOUT)
+ with self.assertRaises(face.LocalError) as exception_assertion_context:
+ rpc_future.result()
+ self.assertIs(
+ exception_assertion_context.exception.code,
+ interfaces.StatusCode.UNIMPLEMENTED)
+ self.assertIs(
+ rpc_future.exception().code, interfaces.StatusCode.UNIMPLEMENTED)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py b/src/python/grpcio_test/grpc_test/beta/_utilities_test.py
new file mode 100644
index 0000000000..996cea9118
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/_utilities_test.py
@@ -0,0 +1,123 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests of grpc.beta.utilities."""
+
+import threading
+import time
+import unittest
+
+from grpc._adapter import _low
+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
+
+
+def _drive_completion_queue(completion_queue):
+ while True:
+ event = completion_queue.next(time.time() + 24 * 60 * 60)
+ if event.type == _types.EventType.QUEUE_SHUTDOWN:
+ break
+
+
+class _Callback(object):
+
+ def __init__(self):
+ self._condition = threading.Condition()
+ self._value = None
+
+ def accept_value(self, value):
+ with self._condition:
+ self._value = value
+ self._condition.notify_all()
+
+ def block_until_called(self):
+ with self._condition:
+ while self._value is None:
+ self._condition.wait()
+ return self._value
+
+
+class ChannelConnectivityTest(unittest.TestCase):
+
+ def test_lonely_channel_connectivity(self):
+ channel = implementations.insecure_channel('localhost', 12345)
+ callback = _Callback()
+
+ ready_future = utilities.channel_ready_future(channel)
+ ready_future.add_done_callback(callback.accept_value)
+ with self.assertRaises(future.TimeoutError):
+ ready_future.result(test_constants.SHORT_TIMEOUT)
+ self.assertFalse(ready_future.cancelled())
+ self.assertFalse(ready_future.done())
+ self.assertTrue(ready_future.running())
+ ready_future.cancel()
+ value_passed_to_callback = callback.block_until_called()
+ self.assertIs(ready_future, value_passed_to_callback)
+ self.assertTrue(ready_future.cancelled())
+ self.assertTrue(ready_future.done())
+ self.assertFalse(ready_future.running())
+
+ def test_immediately_connectable_channel_connectivity(self):
+ server_completion_queue = _low.CompletionQueue()
+ server = _low.Server(server_completion_queue, [])
+ port = server.add_http2_port('[::]:0')
+ server.start()
+ server_completion_queue_thread = threading.Thread(
+ target=_drive_completion_queue, args=(server_completion_queue,))
+ server_completion_queue_thread.start()
+ channel = implementations.insecure_channel('localhost', port)
+ callback = _Callback()
+
+ try:
+ ready_future = utilities.channel_ready_future(channel)
+ ready_future.add_done_callback(callback.accept_value)
+ self.assertIsNone(
+ ready_future.result(test_constants.SHORT_TIMEOUT))
+ value_passed_to_callback = callback.block_until_called()
+ self.assertIs(ready_future, value_passed_to_callback)
+ self.assertFalse(ready_future.cancelled())
+ self.assertTrue(ready_future.done())
+ self.assertFalse(ready_future.running())
+ # Cancellation after maturity has no effect.
+ ready_future.cancel()
+ self.assertFalse(ready_future.cancelled())
+ self.assertTrue(ready_future.done())
+ self.assertFalse(ready_future.running())
+ finally:
+ ready_future.cancel()
+ server.shutdown()
+ server_completion_queue.shutdown()
+ server_completion_queue_thread.join()
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/beta/test_utilities.py b/src/python/grpcio_test/grpc_test/beta/test_utilities.py
new file mode 100644
index 0000000000..24a8600e12
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/beta/test_utilities.py
@@ -0,0 +1,56 @@
+# 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.
+
+"""Test-appropriate entry points into the gRPC Python Beta API."""
+
+from grpc._adapter import _intermediary_low
+from grpc.beta import implementations
+
+
+def not_really_secure_channel(
+ host, port, client_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
+ connect.
+ server_host_override: The target name used for SSL host name checking.
+
+ Returns:
+ An implementations.Channel to the remote host through which RPCs may be
+ conducted.
+ """
+ hostport = '%s:%d' % (host, port)
+ intermediary_low_channel = _intermediary_low.Channel(
+ hostport, client_credentials._intermediary_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_test/grpc_test/credentials/README
new file mode 100644
index 0000000000..cb20dcb49f
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/README
@@ -0,0 +1 @@
+These are test keys *NOT* to be used in production.
diff --git a/src/python/grpcio_test/grpc_test/credentials/ca.pem b/src/python/grpcio_test/grpc_test/credentials/ca.pem
new file mode 100755
index 0000000000..6c8511a73c
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.key b/src/python/grpcio_test/grpc_test/credentials/server1.key
new file mode 100755
index 0000000000..143a5b8765
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio_test/grpc_test/credentials/server1.pem
new file mode 100755
index 0000000000..8e582e571f
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/credentials/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
new file mode 100644
index 0000000000..30bb85f6c3
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py
@@ -0,0 +1,111 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Face interface compliance of the crust-over-core stack."""
+
+import collections
+import unittest
+
+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
+
+
+class _Implementation(test_interfaces.Implementation):
+
+ def instantiate(
+ self, methods, method_implementations, multi_method_implementation):
+ pool = logging_pool.pool(test_constants.POOL_SIZE)
+ servicer = crust_implementations.servicer(
+ method_implementations, multi_method_implementation, pool)
+
+ service_end_link = core_implementations.service_end_link(
+ servicer, test_constants.DEFAULT_TIMEOUT,
+ test_constants.MAXIMUM_TIMEOUT)
+ invocation_end_link = core_implementations.invocation_end_link()
+ invocation_end_link.join_link(service_end_link)
+ service_end_link.join_link(invocation_end_link)
+ service_end_link.start()
+ invocation_end_link.start()
+
+ generic_stub = crust_implementations.generic_stub(invocation_end_link, pool)
+ # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest.
+ group = next(iter(methods))[0]
+ # TODO(nathaniel): Add a "cardinalities_by_group" attribute to
+ # _digest.TestServiceDigest.
+ cardinalities = {
+ method: method_object.cardinality()
+ for (group, method), method_object in methods.iteritems()}
+ dynamic_stub = crust_implementations.dynamic_stub(
+ invocation_end_link, group, cardinalities, pool)
+
+ return generic_stub, {group: dynamic_stub}, (
+ invocation_end_link, service_end_link, pool)
+
+ def destantiate(self, memo):
+ invocation_end_link, service_end_link, pool = memo
+ invocation_end_link.stop(0).wait()
+ service_end_link.stop(0).wait()
+ invocation_end_link.join_link(utilities.NULL_LINK)
+ service_end_link.join_link(utilities.NULL_LINK)
+ pool.shutdown(wait=True)
+
+ def invocation_metadata(self):
+ return object()
+
+ def initial_metadata(self):
+ return object()
+
+ def terminal_metadata(self):
+ return object()
+
+ def code(self):
+ return object()
+
+ def details(self):
+ return object()
+
+ def metadata_transmitted(self, original_metadata, transmitted_metadata):
+ return original_metadata is transmitted_metadata
+
+
+def load_tests(loader, tests, pattern):
+ return unittest.TestSuite(
+ tests=tuple(
+ loader.loadTestsFromTestCase(test_case_class)
+ for test_case_class in test_cases.test_cases(_Implementation())))
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
index e4d2a7a0d7..46a01876d8 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_control.py
@@ -236,8 +236,8 @@ class Instruction(
collections.namedtuple(
'Instruction',
('kind', 'advance_args', 'advance_kwargs', 'conclude_success',
- 'conclude_message', 'conclude_invocation_outcome',
- 'conclude_service_outcome',))):
+ 'conclude_message', 'conclude_invocation_outcome_kind',
+ 'conclude_service_outcome_kind',))):
""""""
@enum.unique
@@ -532,24 +532,24 @@ class _SequenceController(Controller):
self._state.service_side_outcome = outcome
if self._todo is not None or self._remaining_elements:
self._failed('Premature service-side outcome %s!' % (outcome,))
- elif outcome is not self._sequence.outcome.service:
+ elif outcome.kind is not self._sequence.outcome_kinds.service:
self._failed(
- 'Incorrect service-side outcome: %s should have been %s' % (
- outcome, self._sequence.outcome.service))
+ 'Incorrect service-side outcome kind: %s should have been %s' % (
+ outcome.kind, self._sequence.outcome_kinds.service))
elif self._state.invocation_side_outcome is not None:
- self._passed(self._state.invocation_side_outcome, outcome)
+ self._passed(self._state.invocation_side_outcome.kind, outcome.kind)
def invocation_on_termination(self, outcome):
with self._condition:
self._state.invocation_side_outcome = outcome
if self._todo is not None or self._remaining_elements:
self._failed('Premature invocation-side outcome %s!' % (outcome,))
- elif outcome is not self._sequence.outcome.invocation:
+ elif outcome.kind is not self._sequence.outcome_kinds.invocation:
self._failed(
- 'Incorrect invocation-side outcome: %s should have been %s' % (
- outcome, self._sequence.outcome.invocation))
+ 'Incorrect invocation-side outcome kind: %s should have been %s' % (
+ outcome.kind, self._sequence.outcome_kinds.invocation))
elif self._state.service_side_outcome is not None:
- self._passed(outcome, self._state.service_side_outcome)
+ self._passed(outcome.kind, self._state.service_side_outcome.kind)
class _SequenceControllerCreator(ControllerCreator):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
index 1d77aaebe6..f547d91681 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/_sequence.py
@@ -103,13 +103,14 @@ class Element(collections.namedtuple('Element', ('kind', 'transmission',))):
SERVICE_FAILURE = 'service failure'
-class Outcome(collections.namedtuple('Outcome', ('invocation', 'service',))):
+class OutcomeKinds(
+ collections.namedtuple('Outcome', ('invocation', 'service',))):
"""A description of the expected outcome of an operation test.
Attributes:
- invocation: The base.Outcome value expected on the invocation side of the
- operation.
- service: The base.Outcome value expected on the service side of the
+ invocation: The base.Outcome.Kind value expected on the invocation side of
+ the operation.
+ service: The base.Outcome.Kind value expected on the service side of the
operation.
"""
@@ -117,7 +118,8 @@ class Outcome(collections.namedtuple('Outcome', ('invocation', 'service',))):
class Sequence(
collections.namedtuple(
'Sequence',
- ('name', 'maximum_duration', 'invocation', 'elements', 'outcome',))):
+ ('name', 'maximum_duration', 'invocation', 'elements',
+ 'outcome_kinds',))):
"""Describes at a high level steps to perform in a test.
Attributes:
@@ -128,7 +130,8 @@ class Sequence(
under test.
elements: A sequence of Element values describing at coarse granularity
actions to take during the operation under test.
- outcome: An Outcome value describing the expected outcome of the test.
+ outcome_kinds: An OutcomeKinds value describing the expected outcome kinds
+ of the test.
"""
_EASY = Sequence(
@@ -139,7 +142,7 @@ _EASY = Sequence(
Element(
Element.Kind.SERVICE_TRANSMISSION, Transmission(True, True, True)),
),
- Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED))
+ OutcomeKinds(base.Outcome.Kind.COMPLETED, base.Outcome.Kind.COMPLETED))
_PEASY = Sequence(
'Peasy',
@@ -154,7 +157,7 @@ _PEASY = Sequence(
Element(
Element.Kind.SERVICE_TRANSMISSION, Transmission(False, True, True)),
),
- Outcome(base.Outcome.COMPLETED, base.Outcome.COMPLETED))
+ OutcomeKinds(base.Outcome.Kind.COMPLETED, base.Outcome.Kind.COMPLETED))
# TODO(issue 2959): Finish this test suite. This tuple of sequences should
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
index 87332cf612..ddda1018c3 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py
@@ -44,7 +44,8 @@ from grpc_test.framework.interfaces.base import test_interfaces
_SYNCHRONICITY_VARIATION = (('Sync', False), ('Async', True))
-_EMPTY_OUTCOME_DICT = {outcome: 0 for outcome in base.Outcome}
+_EMPTY_OUTCOME_KIND_DICT = {
+ outcome_kind: 0 for outcome_kind in base.Outcome.Kind}
class _Serialization(test_interfaces.Serialization):
@@ -118,8 +119,19 @@ class _Operator(base.Operator):
'Deliberately raised exception from Operator.advance (in a test)!')
+class _ProtocolReceiver(base.ProtocolReceiver):
+
+ def __init__(self):
+ self._condition = threading.Condition()
+ self._contexts = []
+
+ def context(self, protocol_context):
+ with self._condition:
+ self._contexts.append(protocol_context)
+
+
class _Servicer(base.Servicer):
- """An base.Servicer with instrumented for testing."""
+ """A base.Servicer with instrumented for testing."""
def __init__(self, group, method, controllers, pool):
self._condition = threading.Condition()
@@ -143,7 +155,7 @@ class _Servicer(base.Servicer):
controller.service_on_termination)
if outcome is not None:
controller.service_on_termination(outcome)
- return utilities.full_subscription(operator)
+ return utilities.full_subscription(operator, _ProtocolReceiver())
class _OperationTest(unittest.TestCase):
@@ -168,7 +180,8 @@ class _OperationTest(unittest.TestCase):
test_operator = _Operator(
self._controller, self._controller.on_invocation_advance,
self._pool, None)
- subscription = utilities.full_subscription(test_operator)
+ subscription = utilities.full_subscription(
+ test_operator, _ProtocolReceiver())
else:
# TODO(nathaniel): support and test other subscription kinds.
self.fail('Non-full subscriptions not yet supported!')
@@ -223,11 +236,12 @@ class _OperationTest(unittest.TestCase):
self.assertTrue(
instruction.conclude_success, msg=instruction.conclude_message)
- expected_invocation_stats = dict(_EMPTY_OUTCOME_DICT)
- expected_invocation_stats[instruction.conclude_invocation_outcome] += 1
+ expected_invocation_stats = dict(_EMPTY_OUTCOME_KIND_DICT)
+ expected_invocation_stats[
+ instruction.conclude_invocation_outcome_kind] += 1
self.assertDictEqual(expected_invocation_stats, invocation_stats)
- expected_service_stats = dict(_EMPTY_OUTCOME_DICT)
- expected_service_stats[instruction.conclude_service_outcome] += 1
+ expected_service_stats = dict(_EMPTY_OUTCOME_KIND_DICT)
+ expected_service_stats[instruction.conclude_service_outcome_kind] += 1
self.assertDictEqual(expected_service_stats, service_stats)
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
new file mode 100644
index 0000000000..363d9ce8f1
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py
@@ -0,0 +1,37 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A test 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
+
+# TODO(issue 3069): Replace uses of this constant with
+# test_constants.SHORT_TIMEOUT.
+REALLY_SHORT_TIMEOUT = 0.1
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
index 857ad5cf3e..2d2a081955 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py
@@ -37,6 +37,7 @@ 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
@@ -72,6 +73,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
Overriding implementations must call this implementation.
"""
+ self._invoker = None
self.implementation.destantiate(self._memo)
def testSuccessfulUnaryRequestUnaryResponse(self):
@@ -80,8 +82,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
for test_messages in test_messages_sequence:
request = test_messages.request()
- response = self._invoker.blocking(group, method)(
- request, test_constants.LONG_TIMEOUT)
+ response, call = self._invoker.blocking(group, method)(
+ request, test_constants.LONG_TIMEOUT, with_call=True)
test_messages.verify(request, response, self)
@@ -103,8 +105,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
for test_messages in test_messages_sequence:
requests = test_messages.requests()
- response = self._invoker.blocking(group, method)(
- iter(requests), test_constants.LONG_TIMEOUT)
+ response, call = self._invoker.blocking(group, method)(
+ iter(requests), test_constants.LONG_TIMEOUT, with_call=True)
test_messages.verify(requests, response, self)
@@ -170,7 +172,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
self._invoker.blocking(group, method)(
- request, test_constants.SHORT_TIMEOUT)
+ request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
def testExpiredUnaryRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
@@ -181,7 +183,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
response_iterator = self._invoker.blocking(group, method)(
- request, test_constants.SHORT_TIMEOUT)
+ request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testExpiredStreamRequestUnaryResponse(self):
@@ -193,7 +195,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
self._invoker.blocking(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
def testExpiredStreamRequestStreamResponse(self):
for (group, method), test_messages_sequence in (
@@ -204,7 +206,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause(), self.assertRaises(
face.ExpirationError):
response_iterator = self._invoker.blocking(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testFailedUnaryRequestUnaryResponse(self):
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
index ea5cdeaea3..7cb273bf78 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py
@@ -37,6 +37,7 @@ 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
@@ -73,6 +74,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
Overriding implementations must call this implementation.
"""
+ self._invoker = None
self.implementation.destantiate(self._memo)
def testSuccessfulUnaryRequestUnaryResponse(self):
@@ -264,7 +266,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
self._invoker.event(group, method)(
- request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
+ request, receiver, receiver.abort,
+ _3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@@ -278,7 +281,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
self._invoker.event(group, method)(
- request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
+ request, receiver, receiver.abort,
+ _3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@@ -290,7 +294,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
receiver = _receiver.Receiver()
self._invoker.event(group, method)(
- receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
+ receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
receiver.block_until_terminated()
self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
@@ -303,7 +307,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
receiver = _receiver.Receiver()
call_consumer = self._invoker.event(group, method)(
- receiver, receiver.abort, test_constants.SHORT_TIMEOUT)
+ receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
for request in requests:
call_consumer.consume(request)
receiver.block_until_terminated()
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
index a649362cef..272a37f15f 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py
@@ -40,6 +40,7 @@ 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
@@ -102,6 +103,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
Overriding implementations must call this implementation.
"""
+ self._invoker = None
self.implementation.destantiate(self._memo)
self._digest_pool.shutdown(wait=True)
@@ -265,7 +267,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_future = self._invoker.future(
- group, method)(request, test_constants.SHORT_TIMEOUT)
+ group, method)(request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
self.assertIsInstance(
response_future.exception(), face.ExpirationError)
with self.assertRaises(face.ExpirationError):
@@ -279,7 +281,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_iterator = self._invoker.future(group, method)(
- request, test_constants.SHORT_TIMEOUT)
+ request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
with self.assertRaises(face.ExpirationError):
list(response_iterator)
@@ -291,7 +293,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_future = self._invoker.future(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
self.assertIsInstance(
response_future.exception(), face.ExpirationError)
with self.assertRaises(face.ExpirationError):
@@ -305,7 +307,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.pause():
response_iterator = self._invoker.future(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
with self.assertRaises(face.ExpirationError):
list(response_iterator)
@@ -317,7 +319,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.fail():
response_future = self._invoker.future(group, method)(
- request, test_constants.SHORT_TIMEOUT)
+ request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
# Because the servicer fails outside of the thread from which the
# servicer-side runtime called into it its failure is
@@ -340,7 +342,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
# expiration of the RPC.
with self._control.fail(), self.assertRaises(face.ExpirationError):
response_iterator = self._invoker.future(group, method)(
- request, test_constants.SHORT_TIMEOUT)
+ request, _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
def testFailedStreamRequestUnaryResponse(self):
@@ -351,7 +353,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
with self._control.fail():
response_future = self._invoker.future(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
# Because the servicer fails outside of the thread from which the
# servicer-side runtime called into it its failure is
@@ -374,5 +376,5 @@ class TestCase(test_coverage.Coverage, unittest.TestCase):
# expiration of the RPC.
with self._control.fail(), self.assertRaises(face.ExpirationError):
response_iterator = self._invoker.future(group, method)(
- iter(requests), test_constants.SHORT_TIMEOUT)
+ iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT)
list(response_iterator)
diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
index 1dd2ec3633..808e2c4e36 100644
--- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
+++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py
@@ -1,4 +1,4 @@
-B# Copyright 2015, Google Inc.
+# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio_test/grpc_test/resources.py b/src/python/grpcio_test/grpc_test/resources.py
new file mode 100644
index 0000000000..2c3045313d
--- /dev/null
+++ b/src/python/grpcio_test/grpc_test/resources.py
@@ -0,0 +1,56 @@
+# 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.
+
+"""Constants and functions for data used in interoperability testing."""
+
+import os
+
+import pkg_resources
+
+_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/ca.pem'
+_PRIVATE_KEY_RESOURCE_PATH = 'credentials/server1.key'
+_CERTIFICATE_CHAIN_RESOURCE_PATH = 'credentials/server1.pem'
+
+
+def test_root_certificates():
+ return pkg_resources.resource_string(
+ __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)
+
+
+def certificate_chain():
+ return pkg_resources.resource_string(
+ __name__, _CERTIFICATE_CHAIN_RESOURCE_PATH)
diff --git a/src/python/grpcio_test/grpc_test/test_common.py b/src/python/grpcio_test/grpc_test/test_common.py
index f8e1f1e43f..44284be88b 100644
--- a/src/python/grpcio_test/grpc_test/test_common.py
+++ b/src/python/grpcio_test/grpc_test/test_common.py
@@ -31,6 +31,11 @@
import collections
+INVOCATION_INITIAL_METADATA = ((b'0', b'abc'), (b'1', b'def'), (b'2', b'ghi'),)
+SERVICE_INITIAL_METADATA = ((b'3', b'jkl'), (b'4', b'mno'), (b'5', b'pqr'),)
+SERVICE_TERMINAL_METADATA = ((b'6', b'stu'), (b'7', b'vwx'), (b'8', b'yza'),)
+DETAILS = b'test details'
+
def metadata_transmitted(original_metadata, transmitted_metadata):
"""Judges whether or not metadata was acceptably transmitted.
diff --git a/src/python/grpcio_test/setup.py b/src/python/grpcio_test/setup.py
index 898ea204ac..802dd1e53a 100644
--- a/src/python/grpcio_test/setup.py
+++ b/src/python/grpcio_test/setup.py
@@ -55,6 +55,11 @@ _PACKAGE_DATA = {
'grpc_protoc_plugin': [
'test.proto',
],
+ 'grpc_test': [
+ 'credentials/ca.pem',
+ 'credentials/server1.key',
+ 'credentials/server1.pem',
+ ],
}
_SETUP_REQUIRES = (
diff --git a/src/ruby/.rspec b/src/ruby/.rspec
index 2320752db4..efeee2c1d2 100755
--- a/src/ruby/.rspec
+++ b/src/ruby/.rspec
@@ -1,5 +1,6 @@
-I.
-Ipb
+--backtrace
--require spec_helper
--format documentation
--color
diff --git a/src/ruby/README.md b/src/ruby/README.md
index f8902e34c5..8c56ceb135 100644
--- a/src/ruby/README.md
+++ b/src/ruby/README.md
@@ -19,10 +19,10 @@ INSTALLATION
**Linux (Debian):**
-Add [Debian unstable][] to your `sources.list` file. Example:
+Add [Debian jessie-backports][] to your `sources.list` file. Example:
```sh
-echo "deb http://ftp.us.debian.org/debian unstable main contrib non-free" | \
+echo "deb http://http.debian.net/debian jessie-backports main" | \
sudo tee -a /etc/apt/sources.list
```
@@ -99,4 +99,4 @@ Directory structure is the layout for [ruby extensions][]
[ruby extensions]:http://guides.rubygems.org/gems-with-extensions/
[rubydoc]: http://www.rubydoc.info/gems/grpc
[grpc.io]: http://www.grpc.io/docs/installation/ruby.html
-[Debian unstable]:https://www.debian.org/releases/sid/
+[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb
index 6319cda309..0ebd26f780 100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -50,7 +50,7 @@ def do_div(stub)
GRPC.logger.info('----------------')
req = Math::DivArgs.new(dividend: 7, divisor: 3)
GRPC.logger.info("div(7/3): req=#{req.inspect}")
- resp = stub.div(req, INFINITE_FUTURE)
+ resp = stub.div(req, timeout: INFINITE_FUTURE)
GRPC.logger.info("Answer: #{resp.inspect}")
GRPC.logger.info('----------------')
end
@@ -71,7 +71,7 @@ def do_fib(stub)
GRPC.logger.info('----------------')
req = Math::FibArgs.new(limit: 11)
GRPC.logger.info("fib(11): req=#{req.inspect}")
- resp = stub.fib(req, INFINITE_FUTURE)
+ resp = stub.fib(req, timeout: INFINITE_FUTURE)
resp.each do |r|
GRPC.logger.info("Answer: #{r.inspect}")
end
@@ -86,7 +86,7 @@ def do_div_many(stub)
reqs << Math::DivArgs.new(dividend: 5, divisor: 2)
reqs << Math::DivArgs.new(dividend: 7, divisor: 2)
GRPC.logger.info("div(7/3), div(5/2), div(7/2): reqs=#{reqs.inspect}")
- resp = stub.div_many(reqs, 10)
+ resp = stub.div_many(reqs, timeout: INFINITE_FUTURE)
resp.each do |r|
GRPC.logger.info("Answer: #{r.inspect}")
end
diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb
index b41ccf6ce1..562f197317 100755
--- a/src/ruby/bin/math_server.rb
+++ b/src/ruby/bin/math_server.rb
@@ -41,9 +41,25 @@ $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
require 'forwardable'
require 'grpc'
+require 'logger'
require 'math_services'
require 'optparse'
+# RubyLogger defines a logger for gRPC based on the standard ruby logger.
+module RubyLogger
+ def logger
+ LOGGER
+ end
+
+ LOGGER = Logger.new(STDOUT)
+end
+
+# GRPC is the general RPC module
+module GRPC
+ # Inject the noop #logger if no module-level logger method has been injected.
+ extend RubyLogger
+end
+
# Holds state for a fibonacci series
class Fibber
def initialize(limit)
@@ -155,7 +171,8 @@ end
def test_server_creds
certs = load_test_certs
- GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+ GRPC::Core::ServerCredentials.new(
+ nil, [{ private_key: certs[1], cert_chain: certs[2] }], false)
end
def main
diff --git a/src/ruby/bin/noproto_server.rb b/src/ruby/bin/noproto_server.rb
index 90baaf9a2e..72a5762040 100755
--- a/src/ruby/bin/noproto_server.rb
+++ b/src/ruby/bin/noproto_server.rb
@@ -77,7 +77,8 @@ end
def test_server_creds
certs = load_test_certs
- GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+ GRPC::Core::ServerCredentials.new(
+ nil, [{ private_key: certs[1], cert_chain: certs[2] }], false)
end
def main
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 6491aa4fb4..90afdc3fe1 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -150,7 +150,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
ch = grpc_insecure_channel_create(target_chars, &args, NULL);
} else {
creds = grpc_rb_get_wrapped_credentials(credentials);
- ch = grpc_secure_channel_create(creds, target_chars, &args);
+ ch = grpc_secure_channel_create(creds, target_chars, &args, NULL);
}
if (args.args != NULL) {
xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
index a9dcdbce9f..ae757f6986 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_credentials.c
@@ -154,7 +154,7 @@ static VALUE grpc_rb_default_credentials_create(VALUE cls) {
Creates the default credential instances. */
static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) {
grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials);
- wrapper->wrapped = grpc_compute_engine_credentials_create();
+ wrapper->wrapped = grpc_google_compute_engine_credentials_create(NULL);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError,
"could not create composite engine credentials, not sure why");
@@ -181,8 +181,8 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) {
TypedData_Get_Struct(other, grpc_rb_credentials,
&grpc_rb_credentials_data_type, other_wrapper);
wrapper = ALLOC(grpc_rb_credentials);
- wrapper->wrapped = grpc_composite_credentials_create(self_wrapper->wrapped,
- other_wrapper->wrapped);
+ wrapper->wrapped = grpc_composite_credentials_create(
+ self_wrapper->wrapped, other_wrapper->wrapped, NULL);
if (wrapper->wrapped == NULL) {
rb_raise(rb_eRuntimeError,
"could not create composite credentials, not sure why");
@@ -234,12 +234,13 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
return Qnil;
}
if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
- creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL);
+ creds =
+ grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), 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),
- &key_cert_pair);
+ &key_cert_pair, NULL);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 7e76349d2e..4469658869 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -49,6 +49,9 @@ static VALUE grpc_rb_cServer = Qnil;
/* id_at is the constructor method of the ruby standard Time class. */
static ID id_at;
+/* id_insecure_server is used to indicate that a server is insecure */
+static VALUE id_insecure_server;
+
/* grpc_rb_server wraps a grpc_server. It provides a peer ruby object,
'mark' to minimize copying when a server is created from ruby. */
typedef struct grpc_rb_server {
@@ -234,6 +237,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue,
grpc_call_error_detail_of(err), err);
return Qnil;
}
+
ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout);
if (ev.type == GRPC_QUEUE_TIMEOUT) {
grpc_request_call_stack_cleanup(&st);
@@ -298,43 +302,22 @@ static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) {
if (s->wrapped != NULL) {
grpc_server_shutdown_and_notify(s->wrapped, cq, NULL);
ev = grpc_rb_completion_queue_pluck_event(cqueue, Qnil, timeout);
-
if (!ev.success) {
- rb_warn("server shutdown failed, there will be a LEAKED object warning");
- return Qnil;
- /*
- TODO: renable the rb_raise below.
-
- At the moment if the timeout is INFINITE_FUTURE as recommended, the
- pluck blocks forever, even though
-
- the outstanding server_request_calls correctly fail on the other
- thread that they are running on.
-
- it's almost as if calls that fail on the other thread do not get
- cleaned up by shutdown request, even though it caused htem to
- terminate.
-
- rb_raise(rb_eRuntimeError, "grpc server shutdown did not succeed");
- return Qnil;
-
- The workaround is just to use a timeout and return without really
- shutting down the server, and rely on the grpc core garbage collection
- it down as a 'LEAKED OBJECT'.
-
- */
+ rb_warn("server shutdown failed, cancelling the calls, objects may leak");
+ grpc_server_cancel_all_calls(s->wrapped);
+ return Qfalse;
}
grpc_server_destroy(s->wrapped);
s->wrapped = NULL;
}
- return Qnil;
+ return Qtrue;
}
/*
call-seq:
// insecure port
insecure_server = Server.new(cq, {'arg1': 'value1'})
- insecure_server.add_http2_port('mydomain:50051')
+ insecure_server.add_http2_port('mydomain:50051', :this_port_is_insecure)
// secure port
server_creds = ...
@@ -342,21 +325,22 @@ static VALUE grpc_rb_server_destroy(int argc, VALUE *argv, VALUE self) {
secure_server.add_http_port('mydomain:50051', server_creds)
Adds a http2 port to server */
-static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
- VALUE port = Qnil;
- VALUE rb_creds = Qnil;
+static VALUE grpc_rb_server_add_http2_port(VALUE self, VALUE port,
+ VALUE rb_creds) {
grpc_rb_server *s = NULL;
grpc_server_credentials *creds = NULL;
int recvd_port = 0;
- /* "11" == 1 mandatory args, 1 (rb_creds) is optional */
- rb_scan_args(argc, argv, "11", &port, &rb_creds);
-
TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "destroyed!");
return Qnil;
- } else if (rb_creds == Qnil) {
+ } else if (TYPE(rb_creds) == T_SYMBOL) {
+ if (id_insecure_server != SYM2ID(rb_creds)) {
+ rb_raise(rb_eTypeError,
+ "bad creds symbol, want :this_port_is_insecure");
+ return Qnil;
+ }
recvd_port =
grpc_server_add_insecure_http2_port(s->wrapped, StringValueCStr(port));
if (recvd_port == 0) {
@@ -398,8 +382,9 @@ void Init_grpc_server() {
rb_define_alias(grpc_rb_cServer, "close", "destroy");
rb_define_method(grpc_rb_cServer, "add_http2_port",
grpc_rb_server_add_http2_port,
- -1);
+ 2);
id_at = rb_intern("at");
+ id_insecure_server = rb_intern("this_port_is_insecure");
}
/* Gets the wrapped server from the ruby wrapper */
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index 62c211d769..ea4d0d864e 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -135,62 +135,117 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) {
return copy;
}
-/* The attribute used on the mark object to hold the pem_root_certs. */
+/* The attribute used on the mark object to preserve the pem_root_certs. */
static ID id_pem_root_certs;
-/* The attribute used on the mark object to hold the pem_private_key. */
-static ID id_pem_private_key;
+/* The attribute used on the mark object to preserve the pem_key_certs */
+static ID id_pem_key_certs;
-/* The attribute used on the mark object to hold the pem_private_key. */
-static ID id_pem_cert_chain;
+/* The key used to access the pem cert in a key_cert pair hash */
+static VALUE sym_cert_chain;
+
+/* The key used to access the pem private key in a key_cert pair hash */
+static VALUE sym_private_key;
/*
call-seq:
- creds = ServerCredentials.new(pem_root_certs, pem_private_key,
- pem_cert_chain)
- creds = ServerCredentials.new(nil, pem_private_key,
- pem_cert_chain)
-
- pem_root_certs: (required) PEM encoding of the server root certificate
- pem_private_key: (optional) PEM encoding of the server's private key
- pem_cert_chain: (optional) PEM encoding of the server's cert chain
+ creds = ServerCredentials.new(nil,
+ [{private_key: <pem_private_key1>,
+ {cert_chain: <pem_cert_chain1>}],
+ force_client_auth)
+ creds = ServerCredentials.new(pem_root_certs,
+ [{private_key: <pem_private_key1>,
+ {cert_chain: <pem_cert_chain1>}],
+ force_client_auth)
+
+ pem_root_certs: (optional) PEM encoding of the server root certificate
+ pem_private_key: (required) PEM encoding of the server's private keys
+ force_client_auth: indicatees
Initializes ServerCredential instances. */
static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
- VALUE pem_private_key,
- VALUE pem_cert_chain) {
- /* TODO support multiple key cert pairs in the ruby API. */
+ VALUE pem_key_certs,
+ VALUE force_client_auth) {
grpc_rb_server_credentials *wrapper = NULL;
grpc_server_credentials *creds = NULL;
- grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
- TypedData_Get_Struct(self, grpc_rb_server_credentials,
- &grpc_rb_server_credentials_data_type, wrapper);
- if (pem_cert_chain == Qnil) {
- rb_raise(rb_eRuntimeError,
- "could not create a server credential: nil pem_cert_chain");
+ grpc_ssl_pem_key_cert_pair *key_cert_pairs = NULL;
+ VALUE cert = Qnil;
+ VALUE key = Qnil;
+ VALUE key_cert = Qnil;
+ int auth_client = 0;
+ int num_key_certs = 0;
+ int i;
+
+ if (NIL_P(force_client_auth) ||
+ !(force_client_auth == Qfalse || force_client_auth == Qtrue)) {
+ rb_raise(rb_eTypeError,
+ "bad force_client_auth: got:<%s> want: <True|False|nil>",
+ rb_obj_classname(force_client_auth));
return Qnil;
- } else if (pem_private_key == Qnil) {
- rb_raise(rb_eRuntimeError,
- "could not create a server credential: nil pem_private_key");
+ }
+ if (NIL_P(pem_key_certs) || TYPE(pem_key_certs) != T_ARRAY) {
+ rb_raise(rb_eTypeError, "bad pem_key_certs: got:<%s> want: <Array>",
+ rb_obj_classname(pem_key_certs));
+ return Qnil;
+ }
+ num_key_certs = RARRAY_LEN(pem_key_certs);
+ if (num_key_certs == 0) {
+ rb_raise(rb_eTypeError, "bad pem_key_certs: it had no elements");
return Qnil;
}
- key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
- key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
- /* TODO Add a force_client_auth parameter and pass it here. */
+ for (i = 0; i < num_key_certs; i++) {
+ key_cert = rb_ary_entry(pem_key_certs, i);
+ if (key_cert == Qnil) {
+ rb_raise(rb_eTypeError,
+ "could not create a server credential: nil key_cert");
+ return Qnil;
+ } else if (TYPE(key_cert) != T_HASH) {
+ rb_raise(rb_eTypeError,
+ "could not create a server credential: want <Hash>, got <%s>",
+ rb_obj_classname(key_cert));
+ return Qnil;
+ } else if (rb_hash_aref(key_cert, sym_private_key) == Qnil) {
+ rb_raise(rb_eTypeError,
+ "could not create a server credential: want nil private key");
+ return Qnil;
+ } else if (rb_hash_aref(key_cert, sym_cert_chain) == Qnil) {
+ rb_raise(rb_eTypeError,
+ "could not create a server credential: want nil cert chain");
+ return Qnil;
+ }
+ }
+
+ auth_client = TYPE(force_client_auth) == T_TRUE;
+ key_cert_pairs = ALLOC_N(grpc_ssl_pem_key_cert_pair, num_key_certs);
+ for (i = 0; i < num_key_certs; i++) {
+ key_cert = rb_ary_entry(pem_key_certs, i);
+ key = rb_hash_aref(key_cert, sym_private_key);
+ cert = rb_hash_aref(key_cert, sym_cert_chain);
+ key_cert_pairs[i].private_key = RSTRING_PTR(key);
+ key_cert_pairs[i].cert_chain = RSTRING_PTR(cert);
+ }
+
+ TypedData_Get_Struct(self, grpc_rb_server_credentials,
+ &grpc_rb_server_credentials_data_type, wrapper);
+
if (pem_root_certs == Qnil) {
- creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1, 0);
+ creds = grpc_ssl_server_credentials_create(NULL, key_cert_pairs,
+ num_key_certs,
+ auth_client, NULL);
} else {
creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs),
- &key_cert_pair, 1, 0);
+ key_cert_pairs, num_key_certs,
+ auth_client, NULL);
}
+ xfree(key_cert_pairs);
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
+ return Qnil;
}
wrapper->wrapped = creds;
/* Add the input objects as hidden fields to preserve them. */
- rb_ivar_set(self, id_pem_cert_chain, pem_cert_chain);
- rb_ivar_set(self, id_pem_private_key, pem_private_key);
+ rb_ivar_set(self, id_pem_key_certs, pem_key_certs);
rb_ivar_set(self, id_pem_root_certs, pem_root_certs);
return self;
@@ -210,9 +265,10 @@ void Init_grpc_server_credentials() {
rb_define_method(grpc_rb_cServerCredentials, "initialize_copy",
grpc_rb_server_credentials_init_copy, 1);
- id_pem_cert_chain = rb_intern("__pem_cert_chain");
- id_pem_private_key = rb_intern("__pem_private_key");
+ id_pem_key_certs = rb_intern("__pem_key_certs");
id_pem_root_certs = rb_intern("__pem_root_certs");
+ sym_private_key = ID2SYM(rb_intern("private_key"));
+ sym_cert_chain = ID2SYM(rb_intern("cert_chain"));
}
/* Gets the wrapped grpc_server_credentials from the ruby wrapper */
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 20a6206e7e..093606bb8b 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.license = 'BSD-3-Clause'
s.required_ruby_version = '>= 2.0.0'
- s.requirements << 'libgrpc ~> 0.10.0 needs to be installed'
+ s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
s.files = %w( Rakefile )
s.files += Dir.glob('lib/**/*')
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 67bf35ce02..3740ac52da 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -277,10 +277,11 @@ module GRPC
@stop_mutex.synchronize do
@stopped = true
end
- @pool.stop
deadline = from_relative_time(@poll_period)
-
+ return if @server.close(@cq, deadline)
+ deadline = from_relative_time(@poll_period)
@server.close(@cq, deadline)
+ @pool.stop
end
# determines if the server has been stopped
@@ -383,7 +384,6 @@ module GRPC
@pool.start
@server.start
loop_handle_server_calls
- @running = false
end
# Sends UNAVAILABLE if there are too many unprocessed jobs
@@ -414,23 +414,24 @@ module GRPC
fail 'not running' unless @running
loop_tag = Object.new
until stopped?
- deadline = from_relative_time(@poll_period)
begin
- an_rpc = @server.request_call(@cq, loop_tag, deadline)
+ an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE)
c = new_active_server_call(an_rpc)
+ unless c.nil?
+ mth = an_rpc.method.to_sym
+ @pool.schedule(c) do |call|
+ rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
+ end
+ end
rescue Core::CallError, RuntimeError => e
# these might happen for various reasonse. The correct behaviour of
- # the server is to log them and continue.
- GRPC.logger.warn("server call failed: #{e}")
+ # the server is to log them and continue, if it's not shutting down.
+ GRPC.logger.warn("server call failed: #{e}") unless stopped?
next
end
- unless c.nil?
- mth = an_rpc.method.to_sym
- @pool.schedule(c) do |call|
- rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
- end
- end
end
+ @running = false
+ GRPC.logger.info("stopped: #{self}")
end
def new_active_server_call(an_rpc)
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 431e8774b5..108c22b25e 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
# GRPC contains the General RPC module.
module GRPC
- VERSION = '0.10.0'
+ VERSION = '0.11.0'
end
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index e2e1ecbd62..a311bb76e6 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -64,7 +64,8 @@ end
# creates a ServerCredentials from the test certificates.
def test_server_creds
certs = load_test_certs
- GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+ GRPC::Core::ServerCredentials.new(
+ nil, [{private_key: certs[1], cert_chain: certs[2]}], false)
end
# produces a string of null chars (\0) of length l.
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 2e673ff413..ad0fb26896 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -28,16 +28,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
-require 'spec_helper'
include GRPC::Core
-def load_test_certs
- test_root = File.join(File.dirname(__FILE__), 'testdata')
- files = ['ca.pem', 'server1.key', 'server1.pem']
- files.map { |f| File.open(File.join(test_root, f)).read }
-end
-
shared_context 'setup: tags' do
let(:sent_message) { 'sent message' }
let(:reply_text) { 'the reply' }
@@ -47,7 +40,7 @@ shared_context 'setup: tags' do
end
def deadline
- Time.now + 2
+ Time.now + 5
end
def server_allows_client_to_proceed
@@ -402,7 +395,7 @@ describe 'the http client/server' do
@client_queue = GRPC::Core::CompletionQueue.new
@server_queue = GRPC::Core::CompletionQueue.new
@server = GRPC::Core::Server.new(@server_queue, nil)
- server_port = @server.add_http2_port(server_host)
+ server_port = @server.add_http2_port(server_host, :this_port_is_insecure)
@server.start
@ch = Channel.new("0.0.0.0:#{server_port}", nil)
end
@@ -420,12 +413,19 @@ describe 'the http client/server' do
end
describe 'the secure http client/server' do
+ def load_test_certs
+ test_root = File.join(File.dirname(__FILE__), 'testdata')
+ files = ['ca.pem', 'server1.key', 'server1.pem']
+ files.map { |f| File.open(File.join(test_root, f)).read }
+ end
+
before(:example) do
certs = load_test_certs
server_host = '0.0.0.0:0'
@client_queue = GRPC::Core::CompletionQueue.new
@server_queue = GRPC::Core::CompletionQueue.new
- server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
+ server_creds = GRPC::Core::ServerCredentials.new(
+ nil, [{ private_key: certs[1], cert_chain: certs[2] }], false)
@server = GRPC::Core::Server.new(@server_queue, nil)
server_port = @server.add_http2_port(server_host, server_creds)
@server.start
diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/credentials_spec.rb
index 8e72e85d54..b02219dfdb 100644
--- a/src/ruby/spec/credentials_spec.rb
+++ b/src/ruby/spec/credentials_spec.rb
@@ -29,15 +29,15 @@
require 'grpc'
-def load_test_certs
- test_root = File.join(File.dirname(__FILE__), 'testdata')
- files = ['ca.pem', 'server1.pem', 'server1.key']
- files.map { |f| File.open(File.join(test_root, f)).read }
-end
+describe GRPC::Core::Credentials do
+ Credentials = GRPC::Core::Credentials
-Credentials = GRPC::Core::Credentials
+ def load_test_certs
+ test_root = File.join(File.dirname(__FILE__), 'testdata')
+ files = ['ca.pem', 'server1.pem', 'server1.key']
+ files.map { |f| File.open(File.join(test_root, f)).read }
+ end
-describe Credentials do
describe '#new' do
it 'can be constructed with fake inputs' do
expect { Credentials.new('root_certs', 'key', 'cert') }.not_to raise_error
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index fcd7bd082f..b05e3284fe 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -46,7 +46,7 @@ describe GRPC::ActiveCall do
@server_queue = GRPC::Core::CompletionQueue.new
host = '0.0.0.0:0'
@server = GRPC::Core::Server.new(@server_queue, nil)
- server_port = @server.add_http2_port(host)
+ server_port = @server.add_http2_port(host, :this_port_is_insecure)
@server.start
@ch = GRPC::Core::Channel.new("0.0.0.0:#{server_port}", nil)
end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index edcc962a7d..a05433df75 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -498,7 +498,7 @@ describe 'ClientStub' do
def create_test_server
@server_queue = GRPC::Core::CompletionQueue.new
@server = GRPC::Core::Server.new(@server_queue, nil)
- @server.add_http2_port('0.0.0.0:0')
+ @server.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
end
def expect_server_to_be_invoked(notifier)
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 1295fd7fdd..e484a9ea50 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -139,7 +139,7 @@ describe GRPC::RpcServer do
@server_queue = GRPC::Core::CompletionQueue.new
server_host = '0.0.0.0:0'
@server = GRPC::Core::Server.new(@server_queue, nil)
- server_port = @server.add_http2_port(server_host)
+ server_port = @server.add_http2_port(server_host, :this_port_is_insecure)
@host = "localhost:#{server_port}"
@ch = GRPC::Core::Channel.new(@host, nil)
end
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index 6999a69105..9bc82638c7 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -179,14 +179,13 @@ describe Grpc::Health::Checker do
describe 'running on RpcServer' do
RpcServer = GRPC::RpcServer
- StatusCodes = GRPC::Core::StatusCodes
CheckerStub = Grpc::Health::Checker.rpc_stub_class
before(:each) do
@server_queue = GRPC::Core::CompletionQueue.new
server_host = '0.0.0.0:0'
@server = GRPC::Core::Server.new(@server_queue, nil)
- server_port = @server.add_http2_port(server_host)
+ server_port = @server.add_http2_port(server_host, :this_port_is_insecure)
@host = "localhost:#{server_port}"
@ch = GRPC::Core::Channel.new(@host, nil)
@client_opts = { channel_override: @ch }
diff --git a/src/ruby/spec/server_credentials_spec.rb b/src/ruby/spec/server_credentials_spec.rb
index 55598bc8df..8ae577009d 100644
--- a/src/ruby/spec/server_credentials_spec.rb
+++ b/src/ruby/spec/server_credentials_spec.rb
@@ -31,8 +31,9 @@ require 'grpc'
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
- files = ['ca.pem', 'server1.pem', 'server1.key']
- files.map { |f| File.open(File.join(test_root, f)).read }
+ files = ['ca.pem', 'server1.key', 'server1.pem']
+ contents = files.map { |f| File.open(File.join(test_root, f)).read }
+ [contents[0], [{ private_key: contents[1], cert_chain: contents[2] }], false]
end
describe GRPC::Core::ServerCredentials do
@@ -40,7 +41,8 @@ describe GRPC::Core::ServerCredentials do
describe '#new' do
it 'can be constructed from a fake CA PEM, server PEM and a server key' do
- expect { Creds.new('a', 'b', 'c') }.not_to raise_error
+ creds = Creds.new('a', [{ private_key: 'a', cert_chain: 'b' }], false)
+ expect(creds).to_not be_nil
end
it 'can be constructed using the test certificates' do
@@ -48,21 +50,44 @@ describe GRPC::Core::ServerCredentials do
expect { Creds.new(*certs) }.not_to raise_error
end
+ it 'cannot be constructed without a nil key_cert pair array' do
+ root_cert, _, _ = load_test_certs
+ blk = proc do
+ Creds.new(root_cert, nil, false)
+ end
+ expect(&blk).to raise_error
+ end
+
+ it 'cannot be constructed without any key_cert pairs' do
+ root_cert, _, _ = load_test_certs
+ blk = proc do
+ Creds.new(root_cert, [], false)
+ end
+ expect(&blk).to raise_error
+ end
+
it 'cannot be constructed without a server cert chain' do
root_cert, server_key, _ = load_test_certs
- blk = proc { Creds.new(root_cert, server_key, nil) }
+ blk = proc do
+ Creds.new(root_cert,
+ [{ server_key: server_key, cert_chain: nil }],
+ false)
+ end
expect(&blk).to raise_error
end
it 'cannot be constructed without a server key' do
root_cert, _, _ = load_test_certs
- blk = proc { Creds.new(root_cert, nil, cert_chain) }
+ blk = proc do
+ Creds.new(root_cert,
+ [{ server_key: nil, cert_chain: cert_chain }])
+ end
expect(&blk).to raise_error
end
it 'can be constructed without a root_cret' do
- _, server_key, cert_chain = load_test_certs
- blk = proc { Creds.new(nil, server_key, cert_chain) }
+ _, cert_pairs, _ = load_test_certs
+ blk = proc { Creds.new(nil, cert_pairs, false) }
expect(&blk).to_not raise_error
end
end
diff --git a/src/ruby/spec/server_spec.rb b/src/ruby/spec/server_spec.rb
index 47fe575343..439b19fb8d 100644
--- a/src/ruby/spec/server_spec.rb
+++ b/src/ruby/spec/server_spec.rb
@@ -32,7 +32,8 @@ require 'grpc'
def load_test_certs
test_root = File.join(File.dirname(__FILE__), 'testdata')
files = ['ca.pem', 'server1.key', 'server1.pem']
- files.map { |f| File.open(File.join(test_root, f)).read }
+ contents = files.map { |f| File.open(File.join(test_root, f)).read }
+ [contents[0], [{ private_key: contents[1], cert_chain: contents[2] }], false]
end
Server = GRPC::Core::Server
@@ -104,7 +105,7 @@ describe Server do
it 'runs without failing' do
blk = proc do
s = Server.new(@cq, nil)
- s.add_http2_port('localhost:0')
+ s.add_http2_port('localhost:0', :this_port_is_insecure)
s.close(@cq)
end
expect(&blk).to_not raise_error
@@ -113,7 +114,10 @@ describe Server do
it 'fails if the server is closed' do
s = Server.new(@cq, nil)
s.close(@cq)
- expect { s.add_http2_port('localhost:0') }.to raise_error(RuntimeError)
+ blk = proc do
+ s.add_http2_port('localhost:0', :this_port_is_insecure)
+ end
+ expect(&blk).to raise_error(RuntimeError)
end
end
@@ -198,7 +202,7 @@ describe Server do
def start_a_server
s = Server.new(@cq, nil)
- s.add_http2_port('0.0.0.0:0')
+ s.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
s.start
s
end