aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/cpp_generator.cc397
-rw-r--r--src/compiler/cpp_generator.h34
-rw-r--r--src/compiler/cpp_plugin.cc50
-rw-r--r--src/compiler/generator_helpers.h41
-rw-r--r--src/compiler/objective_c_generator.cc236
-rw-r--r--src/compiler/objective_c_generator.h48
-rw-r--r--src/compiler/objective_c_generator_helpers.h58
-rw-r--r--src/compiler/objective_c_plugin.cc98
-rw-r--r--src/compiler/python_generator.cc43
-rw-r--r--src/core/channel/call_op_string.c51
-rw-r--r--src/core/channel/census_filter.c106
-rw-r--r--src/core/channel/channel_stack.c75
-rw-r--r--src/core/channel/channel_stack.h91
-rw-r--r--src/core/channel/child_channel.c36
-rw-r--r--src/core/channel/child_channel.h5
-rw-r--r--src/core/channel/client_channel.c313
-rw-r--r--src/core/channel/connected_channel.c332
-rw-r--r--src/core/channel/http_client_filter.c144
-rw-r--r--src/core/channel/http_filter.c137
-rw-r--r--src/core/channel/http_server_filter.c346
-rw-r--r--src/core/channel/metadata_buffer.c149
-rw-r--r--src/core/channel/metadata_buffer.h70
-rw-r--r--src/core/channel/noop_filter.c39
-rw-r--r--src/core/httpcli/httpcli.c13
-rw-r--r--src/core/httpcli/httpcli_security_connector.c (renamed from src/core/httpcli/httpcli_security_context.c)42
-rw-r--r--src/core/httpcli/httpcli_security_connector.h (renamed from src/core/httpcli/httpcli_security_context.h)12
-rw-r--r--src/core/httpcli/parser.c2
-rw-r--r--src/core/iomgr/endpoint_pair_windows.c85
-rw-r--r--src/core/iomgr/iocp_windows.c39
-rw-r--r--src/core/iomgr/iocp_windows.h1
-rw-r--r--src/core/iomgr/iomgr.c11
-rw-r--r--src/core/iomgr/pollset_multipoller_with_poll_posix.c6
-rw-r--r--src/core/iomgr/pollset_posix.c32
-rw-r--r--src/core/iomgr/resolve_address_windows.c8
-rw-r--r--src/core/iomgr/socket_windows.c10
-rw-r--r--src/core/iomgr/socket_windows.h6
-rw-r--r--src/core/iomgr/tcp_client_windows.c6
-rw-r--r--src/core/iomgr/tcp_posix.c11
-rw-r--r--src/core/iomgr/tcp_server.h6
-rw-r--r--src/core/iomgr/tcp_server_posix.c63
-rw-r--r--src/core/iomgr/tcp_server_windows.c48
-rw-r--r--src/core/iomgr/tcp_windows.c29
-rw-r--r--src/core/profiling/timers.c141
-rw-r--r--src/core/profiling/timers.h71
-rw-r--r--src/core/profiling/timers_preciseclock.h (renamed from src/ruby/ext/grpc/rb_metadata.h)35
-rw-r--r--src/core/security/auth.c150
-rw-r--r--src/core/security/credentials.c236
-rw-r--r--src/core/security/credentials.h47
-rw-r--r--src/core/security/google_default_credentials.c6
-rw-r--r--src/core/security/secure_transport_setup.c14
-rw-r--r--src/core/security/secure_transport_setup.h4
-rw-r--r--src/core/security/security_connector.c (renamed from src/core/security/security_context.c)294
-rw-r--r--src/core/security/security_connector.h201
-rw-r--r--src/core/security/security_context.h215
-rw-r--r--src/core/security/server_secure_chttp2.c50
-rw-r--r--src/core/support/alloc.c2
-rw-r--r--src/core/support/file.c38
-rw-r--r--src/core/support/file.h6
-rw-r--r--src/core/support/histogram.c2
-rw-r--r--src/core/support/slice_buffer.c57
-rw-r--r--src/core/support/thd.c (renamed from src/core/security/factories.c)50
-rw-r--r--src/core/support/thd_posix.c16
-rw-r--r--src/core/support/thd_win32.c72
-rw-r--r--src/core/support/time_win32.c20
-rw-r--r--src/core/surface/call.c703
-rw-r--r--src/core/surface/call.h44
-rw-r--r--src/core/surface/call_log_batch.c121
-rw-r--r--src/core/surface/channel.c150
-rw-r--r--src/core/surface/channel.h3
-rw-r--r--src/core/surface/channel_create.c5
-rw-r--r--src/core/surface/client.c52
-rw-r--r--src/core/surface/completion_queue.c41
-rw-r--r--src/core/surface/completion_queue.h7
-rw-r--r--src/core/surface/init.c12
-rw-r--r--src/core/surface/lame_client.c81
-rw-r--r--src/core/surface/secure_channel_create.c47
-rw-r--r--src/core/surface/server.c226
-rw-r--r--src/core/surface/server.h7
-rw-r--r--src/core/surface/server_chttp2.c12
-rw-r--r--src/core/transport/chttp2/frame.h1
-rw-r--r--src/core/transport/chttp2/frame_settings.c8
-rw-r--r--src/core/transport/chttp2/stream_encoder.c119
-rw-r--r--src/core/transport/chttp2_transport.c551
-rw-r--r--src/core/transport/metadata.c55
-rw-r--r--src/core/transport/metadata.h12
-rw-r--r--src/core/transport/stream_op.c186
-rw-r--r--src/core/transport/stream_op.h74
-rw-r--r--src/core/transport/transport.c42
-rw-r--r--src/core/transport/transport.h107
-rw-r--r--src/core/transport/transport_impl.h16
-rw-r--r--src/core/transport/transport_op_string.c164
-rw-r--r--src/core/tsi/ssl_transport_security.c5
-rw-r--r--src/cpp/client/channel.cc26
-rw-r--r--src/cpp/client/channel.h5
-rw-r--r--src/cpp/client/client_context.cc15
-rw-r--r--src/cpp/client/generic_stub.cc (renamed from src/ruby/ext/grpc/rb_event.h)30
-rw-r--r--src/cpp/client/insecure_credentials.cc2
-rw-r--r--src/cpp/client/secure_credentials.cc49
-rw-r--r--src/cpp/client/secure_credentials.h61
-rw-r--r--src/cpp/common/call.cc26
-rw-r--r--src/cpp/common/completion_queue.cc12
-rw-r--r--src/cpp/server/async_server_context.cc4
-rw-r--r--src/cpp/server/secure_server_credentials.cc34
-rw-r--r--src/cpp/server/secure_server_credentials.h60
-rw-r--r--src/cpp/server/server.cc32
-rw-r--r--src/cpp/server/server_builder.cc21
-rw-r--r--src/cpp/server/server_context.cc17
-rw-r--r--src/cpp/server/thread_pool.cc52
-rw-r--r--src/cpp/server/thread_pool.h14
-rw-r--r--src/cpp/util/byte_buffer.cc1
-rw-r--r--src/cpp/util/time.cc7
-rw-r--r--src/csharp/Grpc.Auth/.gitignore3
-rw-r--r--src/csharp/Grpc.Auth/GoogleCredential.cs124
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj93
-rw-r--r--src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs104
-rw-r--r--src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs14
-rw-r--r--src/csharp/Grpc.Auth/app.config15
-rw-r--r--src/csharp/Grpc.Auth/packages.config12
-rw-r--r--src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.Core/.gitignore3
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj22
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec8
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs3
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs10
-rw-r--r--src/csharp/Grpc.Core/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.Core/RpcException.cs2
-rw-r--r--src/csharp/Grpc.Core/Server.cs176
-rw-r--r--src/csharp/Grpc.Core/Status.cs5
-rw-r--r--src/csharp/Grpc.Core/packages.config4
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs10
-rw-r--r--src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.Examples.MathServer/.gitignore2
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj52
-rw-r--r--src/csharp/Grpc.Examples.MathServer/MathServer.cs61
-rw-r--r--src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs12
-rw-r--r--src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj12
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs21
-rw-r--r--src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.Examples.Tests/packages.config13
-rw-r--r--src/csharp/Grpc.Examples/MathExamples.cs67
-rw-r--r--src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj5
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/app.config15
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj5
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/app.config15
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj43
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs69
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting/app.config15
-rw-r--r--src/csharp/Grpc.IntegrationTesting/packages.config9
-rw-r--r--src/csharp/Grpc.nuspec4
-rw-r--r--src/csharp/Grpc.sln12
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c4
-rw-r--r--src/node/README.md6
-rw-r--r--src/node/binding.gyp21
-rw-r--r--src/node/examples/math_server.js40
-rw-r--r--src/node/examples/pubsub/label.proto79
-rw-r--r--src/node/examples/pubsub/pubsub.proto734
-rw-r--r--src/node/examples/pubsub/pubsub_demo.js285
-rw-r--r--src/node/ext/byte_buffer.cc1
-rw-r--r--src/node/ext/channel.cc2
-rw-r--r--src/node/ext/completion_queue_async_worker.cc22
-rw-r--r--src/node/ext/completion_queue_async_worker.h5
-rw-r--r--src/node/ext/server.cc2
-rw-r--r--src/node/index.js19
-rw-r--r--src/node/interop/interop_client.js4
-rw-r--r--src/node/package.json2
-rw-r--r--src/node/src/client.js4
-rw-r--r--src/node/src/server.js47
-rw-r--r--src/node/test/math_client_test.js20
-rw-r--r--src/node/test/surface_test.js183
-rw-r--r--src/node/test/test_service.json55
-rw-r--r--src/node/test/test_service.proto52
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.h2
-rw-r--r--src/objective-c/GRPCClient/GRPCCall.m4
-rw-r--r--src/objective-c/GRPCClient/GRPCClient.podspec14
-rw-r--r--src/objective-c/GRPCClient/GRPCMethodName.h3
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.h5
-rw-r--r--src/objective-c/GRPCClient/private/GRPCChannel.m41
-rw-r--r--src/objective-c/GRPCClient/private/GRPCCompletionQueue.m2
-rw-r--r--src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m2
-rw-r--r--[-rwxr-xr-x]src/objective-c/GRPCClient/private/GRPCSecureChannel.h (renamed from src/php/lib/autoload.php)21
-rw-r--r--src/objective-c/GRPCClient/private/GRPCSecureChannel.m52
-rw-r--r--src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h38
-rw-r--r--src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m (renamed from src/core/channel/http_filter.h)15
-rw-r--r--src/objective-c/GRPCClient/private/NSData+GRPC.m2
-rw-r--r--src/objective-c/ProtoRPC/ProtoRPC.h (renamed from src/cpp/util/time.h)25
-rw-r--r--src/objective-c/ProtoRPC/ProtoRPC.m91
-rw-r--r--src/objective-c/ProtoRPC/ProtoService.h49
-rw-r--r--src/objective-c/ProtoRPC/ProtoService.m81
-rw-r--r--src/objective-c/RxLibrary/GRXWriteable.h6
-rw-r--r--src/objective-c/RxLibrary/GRXWriteable.m24
-rw-r--r--src/objective-c/RxLibrary/RxLibrary.podspec13
-rw-r--r--src/objective-c/examples/Sample/Podfile9
-rw-r--r--src/objective-c/examples/Sample/Podfile.lock20
l---------src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCCall.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCMethodName.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXImmediateWriter.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXMappingWriter.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriteable.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Immediate.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Transformations.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter.h1
l---------src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/NSEnumerator+GRXUtil.h1
-rw-r--r--src/objective-c/examples/Sample/Pods/Local Podspecs/GRPCClient.podspec14
-rw-r--r--src/objective-c/examples/Sample/Pods/Local Podspecs/RxLibrary.podspec13
-rw-r--r--src/objective-c/examples/Sample/Pods/Manifest.lock20
-rw-r--r--src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj4582
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.markdown3
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.plist29
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-environment.h20
-rwxr-xr-xsrc/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh74
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig0
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.markdown3
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.plist29
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-environment.h20
-rwxr-xr-xsrc/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh74
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown3
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.plist29
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-dummy.m5
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-environment.h20
-rwxr-xr-xsrc/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-resources.sh74
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.debug.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.release.xcconfig6
-rw-r--r--src/objective-c/examples/Sample/README.md3
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.h103
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.m179
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.h578
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.m2256
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec18
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h167
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m163
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/empty.proto46
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/messages.proto135
-rw-r--r--src/objective-c/examples/Sample/RemoteTestClient/test.proto74
-rw-r--r--src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.h387
-rw-r--r--src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.m1435
-rw-r--r--src/objective-c/examples/Sample/RouteGuideClient/Route_guide.podspec17
-rw-r--r--src/objective-c/examples/Sample/RouteGuideClient/route_guide.proto121
-rw-r--r--src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj1491
-rw-r--r--src/objective-c/examples/Sample/Sample.xcworkspace/contents.xcworkspacedata10
-rw-r--r--src/objective-c/examples/Sample/Sample/AppDelegate.h1
-rw-r--r--src/objective-c/examples/Sample/Sample/AppDelegate.m25
-rw-r--r--src/objective-c/examples/Sample/Sample/ViewController.h3
-rw-r--r--src/objective-c/examples/Sample/Sample/ViewController.m37
-rw-r--r--src/objective-c/examples/Sample/SampleTests/RemoteProtoTests.m133
-rw-r--r--src/objective-c/examples/Sample/SampleTests/RemoteTests.m144
-rw-r--r--src/objective-c/examples/Sample/SampleTests/SampleTests.m108
-rwxr-xr-x[-rw-r--r--]src/php/bin/generate_proto_php.sh (renamed from src/ruby/lib/grpc/core/event.rb)24
-rwxr-xr-xsrc/php/bin/interop_client.sh5
-rwxr-xr-xsrc/php/bin/run_gen_code_test.sh3
-rwxr-xr-xsrc/php/bin/run_tests.sh6
-rw-r--r--src/php/composer.json15
-rw-r--r--src/php/composer.lock19
-rw-r--r--src/php/ext/grpc/byte_buffer.c17
-rw-r--r--src/php/ext/grpc/byte_buffer.h2
-rw-r--r--src/php/ext/grpc/call.c52
-rw-r--r--src/php/ext/grpc/call.h8
-rw-r--r--src/php/ext/grpc/channel.c17
-rwxr-xr-xsrc/php/ext/grpc/channel.h8
-rwxr-xr-xsrc/php/ext/grpc/config.m42
-rw-r--r--src/php/ext/grpc/credentials.c16
-rw-r--r--src/php/ext/grpc/php_grpc.c6
-rw-r--r--src/php/ext/grpc/server.c28
-rwxr-xr-xsrc/php/ext/grpc/server.h8
-rw-r--r--src/php/ext/grpc/server_credentials.c16
-rwxr-xr-xsrc/php/ext/grpc/server_credentials.h10
-rw-r--r--src/php/ext/grpc/timeval.c26
-rwxr-xr-xsrc/php/ext/grpc/timeval.h10
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/AbstractCall.php (renamed from src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php)51
-rwxr-xr-xsrc/php/lib/Grpc/AbstractSurfaceActiveCall.php98
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php69
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/BidiStreamingCall.php (renamed from src/php/lib/Grpc/ActiveCall.php)64
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/ClientStreamingCall.php (renamed from src/php/lib/Grpc/ClientStreamingSurfaceActiveCall.php)31
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/ServerStreamingCall.php (renamed from src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php)43
-rw-r--r--[-rwxr-xr-x]src/php/lib/Grpc/UnaryCall.php (renamed from src/php/lib/Grpc/SimpleSurfaceActiveCall.php)34
-rw-r--r--src/php/tests/generated_code/AbstractGeneratedCodeTest.php97
-rwxr-xr-xsrc/php/tests/generated_code/GeneratedCodeTest.php69
-rw-r--r--src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php47
-rwxr-xr-xsrc/php/tests/generated_code/math.php479
-rw-r--r--src/php/tests/generated_code/math.proto80
-rwxr-xr-xsrc/php/tests/interop/empty.php25
-rw-r--r--src/php/tests/interop/empty.proto (renamed from src/node/examples/pubsub/empty.proto)7
-rwxr-xr-xsrc/php/tests/interop/interop_client.php10
-rwxr-xr-xsrc/php/tests/interop/messages.php1074
-rw-r--r--src/php/tests/interop/messages.proto132
-rwxr-xr-xsrc/php/tests/interop/test.php52
-rw-r--r--src/php/tests/interop/test.proto72
-rwxr-xr-xsrc/php/tests/unit_tests/CallTest.php12
-rwxr-xr-xsrc/php/tests/unit_tests/EndToEndTest.php22
-rwxr-xr-xsrc/php/tests/unit_tests/SecureEndToEndTest.php24
-rwxr-xr-xsrc/php/tests/unit_tests/TimevalTest.php6
-rw-r--r--src/python/README.md22
-rw-r--r--src/python/interop/interop/_insecure_interop_test.py4
-rw-r--r--src/python/interop/interop/_interop_test_case.py10
-rw-r--r--src/python/interop/interop/_secure_interop_test.py9
-rw-r--r--src/python/interop/interop/client.py30
-rw-r--r--src/python/interop/interop/empty_pb2.py5
-rw-r--r--src/python/interop/interop/messages_pb2.py5
-rw-r--r--src/python/interop/interop/methods.py60
-rw-r--r--src/python/interop/interop/server.py8
-rw-r--r--src/python/interop/interop/test_pb2.py223
-rw-r--r--src/python/interop/setup.py16
-rw-r--r--src/python/src/.gitignore3
-rw-r--r--src/python/src/MANIFEST.in1
-rw-r--r--src/python/src/README.rst27
-rw-r--r--src/python/src/grpc/_adapter/_c_test.py5
-rw-r--r--src/python/src/grpc/_adapter/_call.c254
-rw-r--r--src/python/src/grpc/_adapter/_call.h33
-rw-r--r--src/python/src/grpc/_adapter/_channel.h5
-rw-r--r--src/python/src/grpc/_adapter/_client_credentials.h3
-rw-r--r--src/python/src/grpc/_adapter/_completion_queue.c221
-rw-r--r--src/python/src/grpc/_adapter/_completion_queue.h3
-rw-r--r--src/python/src/grpc/_adapter/_datatypes.py2
-rw-r--r--src/python/src/grpc/_adapter/_links_test.py11
-rw-r--r--src/python/src/grpc/_adapter/_low_test.py58
-rw-r--r--src/python/src/grpc/_adapter/_server.c20
-rw-r--r--src/python/src/grpc/_adapter/_server.h9
-rw-r--r--src/python/src/grpc/_adapter/_server_credentials.h3
-rw-r--r--src/python/src/grpc/_adapter/_tag.c65
-rw-r--r--src/python/src/grpc/_adapter/_tag.h70
-rw-r--r--src/python/src/grpc/_adapter/rear.py12
-rw-r--r--src/python/src/grpc/early_adopter/implementations.py91
-rw-r--r--src/python/src/grpc/early_adopter/implementations_test.py4
-rw-r--r--src/python/src/setup.py22
-rwxr-xr-xsrc/ruby/.rspec1
-rw-r--r--src/ruby/.rubocop_todo.yml32
-rw-r--r--src/ruby/CHANGELOG.md11
-rwxr-xr-xsrc/ruby/Rakefile1
-rwxr-xr-xsrc/ruby/bin/apis/pubsub_demo.rb9
-rwxr-xr-xsrc/ruby/bin/interop/interop_client.rb46
-rwxr-xr-xsrc/ruby/bin/interop/interop_server.rb2
-rwxr-xr-xsrc/ruby/bin/math_server.rb2
-rwxr-xr-xsrc/ruby/bin/noproto_server.rb2
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.c204
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.h16
-rw-r--r--src/ruby/ext/grpc/rb_call.c821
-rw-r--r--src/ruby/ext/grpc/rb_call.h8
-rw-r--r--src/ruby/ext/grpc/rb_channel.c92
-rw-r--r--src/ruby/ext/grpc/rb_channel.h3
-rw-r--r--src/ruby/ext/grpc/rb_channel_args.c17
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.c73
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.h10
-rw-r--r--src/ruby/ext/grpc/rb_credentials.c68
-rw-r--r--src/ruby/ext/grpc/rb_credentials.h4
-rw-r--r--src/ruby/ext/grpc/rb_event.c361
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c153
-rw-r--r--src/ruby/ext/grpc/rb_grpc.h30
-rw-r--r--src/ruby/ext/grpc/rb_metadata.c215
-rw-r--r--src/ruby/ext/grpc/rb_server.c145
-rw-r--r--src/ruby/ext/grpc/rb_server.h4
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.c45
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.h4
-rwxr-xr-xsrc/ruby/grpc.gemspec19
-rw-r--r--src/ruby/lib/grpc.rb2
-rw-r--r--src/ruby/lib/grpc/errors.rb15
-rw-r--r--src/ruby/lib/grpc/generic/active_call.rb275
-rw-r--r--src/ruby/lib/grpc/generic/bidi_call.rb92
-rw-r--r--src/ruby/lib/grpc/generic/client_stub.rb73
-rw-r--r--src/ruby/lib/grpc/generic/rpc_desc.rb19
-rw-r--r--src/ruby/lib/grpc/generic/rpc_server.rb423
-rw-r--r--src/ruby/lib/grpc/notifier.rb (renamed from src/ruby/spec/alloc_spec.rb)34
-rw-r--r--src/ruby/lib/grpc/version.rb2
-rw-r--r--src/ruby/spec/byte_buffer_spec.rb67
-rw-r--r--src/ruby/spec/call_spec.rb63
-rw-r--r--src/ruby/spec/channel_spec.rb31
-rw-r--r--src/ruby/spec/client_server_spec.rb368
-rw-r--r--src/ruby/spec/credentials_spec.rb4
-rw-r--r--src/ruby/spec/event_spec.rb53
-rw-r--r--src/ruby/spec/generic/active_call_spec.rb144
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb110
-rw-r--r--src/ruby/spec/generic/rpc_desc_spec.rb130
-rw-r--r--src/ruby/spec/generic/rpc_server_pool_spec.rb5
-rw-r--r--src/ruby/spec/generic/rpc_server_spec.rb187
-rw-r--r--src/ruby/spec/metadata_spec.rb64
-rw-r--r--src/ruby/spec/server_spec.rb2
-rw-r--r--src/ruby/spec/spec_helper.rb12
408 files changed, 17113 insertions, 15998 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index d5004624d4..1324198847 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -109,11 +109,52 @@ bool HasBidiStreaming(const grpc::protobuf::FileDescriptor *file) {
}
return false;
}
+
+grpc::string FilenameIdentifier(const grpc::string &filename) {
+ grpc::string result;
+ for (unsigned i = 0; i < filename.size(); i++) {
+ char c = filename[i];
+ if (isalnum(c)) {
+ result.push_back(c);
+ } else {
+ static char hex[] = "0123456789abcdef";
+ result.push_back('_');
+ result.push_back(hex[(c >> 4) & 0xf]);
+ result.push_back(hex[c & 0xf]);
+ }
+ }
+ return result;
+}
} // namespace
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->name();
+ vars["filename_identifier"] = FilenameIdentifier(file->name());
+ vars["filename_base"] = grpc_generator::StripProto(file->name());
+
+ printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+ printer.Print(vars, "// If you make any local change, they will be lost.\n");
+ printer.Print(vars, "// source: $filename$\n");
+ printer.Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
+ printer.Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
+ printer.Print(vars, "\n");
+ printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
+ printer.Print(vars, "\n");
+
+ return output;
+}
+
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
grpc::string temp =
"#include <grpc++/impl/internal_stub.h>\n"
+ "#include <grpc++/impl/rpc_method.h>\n"
"#include <grpc++/impl/service_type.h>\n"
"#include <grpc++/status.h>\n"
"\n"
@@ -132,7 +173,9 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file) {
temp.append("template <class OutMessage> class ClientWriter;\n");
temp.append("template <class InMessage> class ServerReader;\n");
temp.append("template <class OutMessage> class ClientAsyncWriter;\n");
- temp.append("template <class OutMessage, class InMessage> class ServerAsyncReader;\n");
+ temp.append(
+ "template <class OutMessage, class InMessage> class "
+ "ServerAsyncReader;\n");
}
if (HasServerOnlyStreaming(file)) {
temp.append("template <class InMessage> class ClientReader;\n");
@@ -155,17 +198,22 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file) {
"class ServerAsyncReaderWriter;\n");
}
temp.append("} // namespace grpc\n");
- return temp;
-}
-grpc::string GetSourceIncludes() {
- return "#include <grpc++/async_unary_call.h>\n"
- "#include <grpc++/channel_interface.h>\n"
- "#include <grpc++/impl/client_unary_call.h>\n"
- "#include <grpc++/impl/rpc_method.h>\n"
- "#include <grpc++/impl/rpc_service_method.h>\n"
- "#include <grpc++/impl/service_type.h>\n"
- "#include <grpc++/stream.h>\n";
+ temp.append("\n");
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts =
+ grpc_generator::tokenize(file->package(), ".");
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ temp.append("namespace ");
+ temp.append(*part);
+ temp.append(" {\n");
+ }
+ temp.append("\n");
+ }
+
+ return temp;
}
void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
@@ -201,11 +249,11 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
*vars,
"std::unique_ptr< ::grpc::ClientReader< $Response$>> $Method$("
"::grpc::ClientContext* context, const $Request$& request);\n");
- printer->Print(
- *vars,
- "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> Async$Method$("
- "::grpc::ClientContext* context, const $Request$& request, "
- "::grpc::CompletionQueue* cq, void* tag);\n");
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
+ "Async$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq, void* tag);\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
@@ -219,10 +267,16 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
}
}
-void PrintHeaderServerMethodSync(
- grpc::protobuf::io::Printer *printer,
- const grpc::protobuf::MethodDescriptor *method,
- std::map<grpc::string, grpc::string> *vars) {
+void PrintHeaderClientMethodData(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
+}
+
+void PrintHeaderServerMethodSync(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -306,10 +360,18 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
"class Stub GRPC_FINAL : public ::grpc::InternalStub {\n"
" public:\n");
printer->Indent();
+ printer->Print(
+ "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i), vars);
}
printer->Outdent();
+ printer->Print(" private:\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodData(printer, service->method(i), vars);
+ }
+ printer->Outdent();
printer->Print("};\n");
printer->Print(
"static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
@@ -353,16 +415,103 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
printer->Print("};\n");
}
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
std::map<grpc::string, grpc::string> vars;
+ if (!params.services_namespace.empty()) {
+ vars["services_namespace"] = params.services_namespace;
+ printer.Print(vars, "\nnamespace $services_namespace$ {\n\n");
+ }
+
for (int i = 0; i < file->service_count(); ++i) {
PrintHeaderService(&printer, file->service(i), &vars);
printer.Print("\n");
}
+
+ if (!params.services_namespace.empty()) {
+ printer.Print(vars, "} // namespace $services_namespace$\n\n");
+ }
+
+ return output;
+}
+
+grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->name();
+ vars["filename_identifier"] = FilenameIdentifier(file->name());
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts =
+ grpc_generator::tokenize(file->package(), ".");
+
+ for (auto part = parts.rbegin(); part != parts.rend(); part++) {
+ vars["part"] = *part;
+ printer.Print(vars, "} // namespace $part$\n");
+ }
+ printer.Print(vars, "\n");
+ }
+
+ printer.Print(vars, "\n");
+ printer.Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
+
+ return output;
+}
+
+grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->name();
+ vars["filename_base"] = grpc_generator::StripProto(file->name());
+
+ printer.Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+ printer.Print(vars, "// If you make any local change, they will be lost.\n");
+ printer.Print(vars, "// source: $filename$\n\n");
+ printer.Print(vars, "#include \"$filename_base$.pb.h\"\n");
+ printer.Print(vars, "#include \"$filename_base$.grpc.pb.h\"\n");
+ printer.Print(vars, "\n");
+
+ return output;
+}
+
+grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &param) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+
+ printer.Print(vars, "#include <grpc++/async_unary_call.h>\n");
+ printer.Print(vars, "#include <grpc++/channel_interface.h>\n");
+ printer.Print(vars, "#include <grpc++/impl/client_unary_call.h>\n");
+ printer.Print(vars, "#include <grpc++/impl/rpc_service_method.h>\n");
+ printer.Print(vars, "#include <grpc++/impl/service_type.h>\n");
+ printer.Print(vars, "#include <grpc++/stream.h>\n");
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts =
+ grpc_generator::tokenize(file->package(), ".");
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer.Print(vars, "namespace $part$ {\n");
+ }
+ }
+
+ printer.Print(vars, "\n");
+
return output;
}
@@ -376,18 +525,18 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Stub::$Method$("
+ "::grpc::Status $ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response) {\n");
printer->Print(*vars,
- " return ::grpc::BlockingUnaryCall(channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+ " return ::grpc::BlockingUnaryCall(channel(), "
+ "rpcmethod_$Method$_, "
"context, request, response);\n"
"}\n\n");
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
- "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+ "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
"const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
@@ -395,88 +544,83 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ClientAsyncResponseReader< $Response$>>(new "
"::grpc::ClientAsyncResponseReader< $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$]), "
+ "rpcmethod_$Method$_, "
"context, request, tag));\n"
"}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientWriter< $Request$>> "
- "$Service$::Stub::$Method$("
+ "$ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, $Response$* response) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientWriter< "
"$Request$>>(new ::grpc::ClientWriter< $Request$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
+ "rpcmethod_$Method$_, "
"context, response));\n"
"}\n\n");
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> "
- "$Service$::Stub::Async$Method$("
+ "$ns$$Service$::Stub::Async$Method$("
"::grpc::ClientContext* context, $Response$* response, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncWriter< "
"$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
+ "rpcmethod_$Method$_, "
"context, response, tag));\n"
"}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientReader< $Response$>> "
- "$Service$::Stub::$Method$("
+ "$ns$$Service$::Stub::$Method$("
"::grpc::ClientContext* context, const $Request$& request) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientReader< "
"$Response$>>(new ::grpc::ClientReader< $Response$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
+ "rpcmethod_$Method$_, "
"context, request));\n"
"}\n\n");
printer->Print(*vars,
"std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
- "$Service$::Stub::Async$Method$("
+ "$ns$$Service$::Stub::Async$Method$("
"::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncReader< "
"$Response$>>(new ::grpc::ClientAsyncReader< $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
+ "rpcmethod_$Method$_, "
"context, request, tag));\n"
"}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
"std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> "
- "$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
+ "$ns$$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientReaderWriter< "
"$Request$, $Response$>>(new ::grpc::ClientReaderWriter< "
"$Request$, $Response$>("
"channel(),"
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
+ "rpcmethod_$Method$_, "
"context));\n"
"}\n\n");
- printer->Print(*vars,
- "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
- "$Request$, $Response$>> "
- "$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
- "::grpc::CompletionQueue* cq, void* tag) {\n");
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
+ "$Request$, $Response$>> "
+ "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
"$Request$, $Response$>>(new "
"::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
"channel(), cq, "
- "::grpc::RpcMethod($Service$_method_names[$Idx$], "
- "::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
+ "rpcmethod_$Method$_, "
"context, tag));\n"
"}\n\n");
}
@@ -492,7 +636,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"const $Request$* request, $Response$* response) {\n");
printer->Print(
@@ -501,7 +645,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerReader< $Request$>* reader, "
"$Response$* response) {\n");
@@ -511,7 +655,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"const $Request$* request, "
"::grpc::ServerWriter< $Response$>* writer) {\n");
@@ -521,7 +665,7 @@ void PrintSourceServerMethod(grpc::protobuf::io::Printer *printer,
printer->Print("}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(*vars,
- "::grpc::Status $Service$::Service::$Method$("
+ "::grpc::Status $ns$$Service$::Service::$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerReaderWriter< $Response$, $Request$>* "
"stream) {\n");
@@ -543,46 +687,46 @@ void PrintSourceServerAsyncMethod(
grpc_cpp_generator::ClassName(method->output_type(), true);
if (NoStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"$Request$* request, "
"::grpc::ServerAsyncResponseWriter< $Response$>* response, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
- printer->Print(
- *vars,
- " AsynchronousService::RequestAsyncUnary($Idx$, context, request, response, cq, tag);\n");
+ printer->Print(*vars,
+ " AsynchronousService::RequestAsyncUnary($Idx$, context, "
+ "request, response, cq, tag);\n");
printer->Print("}\n\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
- printer->Print(
- *vars,
- " AsynchronousService::RequestClientStreaming($Idx$, context, reader, cq, tag);\n");
+ printer->Print(*vars,
+ " AsynchronousService::RequestClientStreaming($Idx$, "
+ "context, reader, cq, tag);\n");
printer->Print("}\n\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"$Request$* request, "
"::grpc::ServerAsyncWriter< $Response$>* writer, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
- printer->Print(
- *vars,
- " AsynchronousService::RequestServerStreaming($Idx$, context, request, writer, cq, tag);\n");
+ printer->Print(*vars,
+ " AsynchronousService::RequestServerStreaming($Idx$, "
+ "context, request, writer, cq, tag);\n");
printer->Print("}\n\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
- "void $Service$::AsyncService::Request$Method$("
+ "void $ns$$Service$::AsyncService::Request$Method$("
"::grpc::ServerContext* context, "
"::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
"::grpc::CompletionQueue* cq, void *tag) {\n");
- printer->Print(
- *vars,
- " AsynchronousService::RequestBidiStreaming($Idx$, context, stream, cq, tag);\n");
+ printer->Print(*vars,
+ " AsynchronousService::RequestBidiStreaming($Idx$, "
+ "context, stream, cq, tag);\n");
printer->Print("}\n\n");
}
}
@@ -592,7 +736,8 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name();
- printer->Print(*vars, "static const char* $Service$_method_names[] = {\n");
+ printer->Print(*vars,
+ "static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Method"] = service->method(i)->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
@@ -601,26 +746,56 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
printer->Print(
*vars,
- "std::unique_ptr< $Service$::Stub> $Service$::NewStub("
+ "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
"const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
- " std::unique_ptr< $Service$::Stub> stub(new $Service$::Stub());\n"
- " stub->set_channel(channel);\n"
+ " std::unique_ptr< $ns$$Service$::Stub> stub(new "
+ "$ns$$Service$::Stub(channel));\n"
" return stub;\n"
"}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
+ "::grpc::ChannelInterface>& channel)\n");
+ printer->Indent();
+ printer->Print(": ::grpc::InternalStub(channel)");
+ for (int i = 0; i < service->method_count(); ++i) {
+ const grpc::protobuf::MethodDescriptor *method = service->method(i);
+ (*vars)["Method"] = method->name();
+ (*vars)["Idx"] = as_string(i);
+ if (NoStreaming(method)) {
+ (*vars)["StreamingType"] = "NORMAL_RPC";
+ } else if (ClientOnlyStreaming(method)) {
+ (*vars)["StreamingType"] = "CLIENT_STREAMING";
+ } else if (ServerOnlyStreaming(method)) {
+ (*vars)["StreamingType"] = "SERVER_STREAMING";
+ } else {
+ (*vars)["StreamingType"] = "BIDI_STREAMING";
+ }
+ printer->Print(
+ *vars,
+ ", rpcmethod_$Method$_("
+ "$prefix$$Service$_method_names[$Idx$], "
+ "::grpc::RpcMethod::$StreamingType$, "
+ "channel->RegisterMethod($prefix$$Service$_method_names[$Idx$])"
+ ")\n");
+ }
+ printer->Print("{}\n\n");
+ printer->Outdent();
+
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Idx"] = as_string(i);
PrintSourceClientMethod(printer, service->method(i), vars);
}
(*vars)["MethodCount"] = as_string(service->method_count());
- printer->Print(
- *vars,
- "$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : "
- "::grpc::AsynchronousService(cq, $Service$_method_names, $MethodCount$) "
- "{}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::AsyncService::AsyncService(::grpc::"
+ "CompletionQueue* cq) : "
+ "::grpc::AsynchronousService(cq, "
+ "$prefix$$Service$_method_names, $MethodCount$) "
+ "{}\n\n");
printer->Print(*vars,
- "$Service$::Service::~Service() {\n"
+ "$ns$$Service$::Service::~Service() {\n"
" delete service_;\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
@@ -629,7 +804,7 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
PrintSourceServerAsyncMethod(printer, service->method(i), vars);
}
printer->Print(*vars,
- "::grpc::RpcService* $Service$::Service::service() {\n");
+ "::grpc::RpcService* $ns$$Service$::Service::service() {\n");
printer->Indent();
printer->Print(
"if (service_ != nullptr) {\n"
@@ -648,52 +823,53 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::NORMAL_RPC,\n"
- " new ::grpc::RpcMethodHandler< $Service$::Service, $Request$, "
+ " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, "
+ "$Request$, "
"$Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, const $Request$*, $Response$*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::CLIENT_STREAMING,\n"
" new ::grpc::ClientStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"::grpc::ServerReader< $Request$>*, $Response$*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (ServerOnlyStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::SERVER_STREAMING,\n"
" new ::grpc::ServerStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"const $Request$*, ::grpc::ServerWriter< $Response$>*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
} else if (BidiStreaming(method)) {
printer->Print(
*vars,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
- " $Service$_method_names[$Idx$],\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::BIDI_STREAMING,\n"
" new ::grpc::BidiStreamingHandler< "
- "$Service$::Service, $Request$, $Response$>(\n"
- " std::function< ::grpc::Status($Service$::Service*, "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, "
"::grpc::ServerReaderWriter< $Response$, $Request$>*)>("
- "&$Service$::Service::$Method$), this),\n"
+ "&$ns$$Service$::Service::$Method$), this),\n"
" new $Request$, new $Response$));\n");
}
}
@@ -702,7 +878,8 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
printer->Print("}\n\n");
}
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file) {
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
grpc::string output;
grpc::protobuf::io::StringOutputStream output_stream(&output);
grpc::protobuf::io::Printer printer(&output_stream, '$');
@@ -713,6 +890,13 @@ grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file) {
if (!file->package().empty()) {
vars["Package"].append(".");
}
+ if (!params.services_namespace.empty()) {
+ vars["ns"] = params.services_namespace + "::";
+ vars["prefix"] = params.services_namespace;
+ } else {
+ vars["ns"] = "";
+ vars["prefix"] = "";
+ }
for (int i = 0; i < file->service_count(); ++i) {
PrintSourceService(&printer, file->service(i), &vars);
@@ -721,4 +905,23 @@ grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file) {
return output;
}
+grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params) {
+ grpc::string temp;
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts =
+ grpc_generator::tokenize(file->package(), ".");
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ temp.append("} // namespace ");
+ temp.append(*part);
+ temp.append("\n");
+ }
+ temp.append("\n");
+ }
+
+ return temp;
+}
+
} // namespace grpc_cpp_generator
diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h
index 2ecdb5c47e..70c2e985f6 100644
--- a/src/compiler/cpp_generator.h
+++ b/src/compiler/cpp_generator.h
@@ -38,17 +38,43 @@
namespace grpc_cpp_generator {
+// Contains all the parameters that are parsed from the command line.
+struct Parameters {
+ // Puts the service into a namespace
+ grpc::string services_namespace;
+};
+
+// Return the prologue of the generated header file.
+grpc::string GetHeaderPrologue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
+
// Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
// Return the includes needed for generated source file.
-grpc::string GetSourceIncludes();
+grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
+
+// Return the epilogue of the generated header file.
+grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
+
+// Return the prologue of the generated source file.
+grpc::string GetSourcePrologue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
// Return the services for generated header file.
-grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetHeaderServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
// Return the services for generated source file.
-grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
+
+// Return the epilogue of the generated source file.
+grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
+ const Parameters &params);
} // namespace grpc_cpp_generator
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 5b83aa85cf..88c704948e 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -58,18 +58,48 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
return false;
}
+ grpc_cpp_generator::Parameters generator_parameters;
+
+ if (!parameter.empty()) {
+ std::vector<grpc::string> parameters_list =
+ grpc_generator::tokenize(parameter, ",");
+ for (auto parameter_string = parameters_list.begin();
+ parameter_string != parameters_list.end();
+ parameter_string++) {
+ std::vector<grpc::string> param =
+ grpc_generator::tokenize(*parameter_string, "=");
+ if (param[0] == "services_namespace") {
+ generator_parameters.services_namespace = param[1];
+ } else {
+ *error = grpc::string("Unknown parameter: ") + *parameter_string;
+ return false;
+ }
+ }
+ }
+
grpc::string file_name = grpc_generator::StripProto(file->name());
- // Generate .pb.h
- Insert(context, file_name + ".pb.h", "includes",
- grpc_cpp_generator::GetHeaderIncludes(file));
- Insert(context, file_name + ".pb.h", "namespace_scope",
- grpc_cpp_generator::GetHeaderServices(file));
- // Generate .pb.cc
- Insert(context, file_name + ".pb.cc", "includes",
- grpc_cpp_generator::GetSourceIncludes());
- Insert(context, file_name + ".pb.cc", "namespace_scope",
- grpc_cpp_generator::GetSourceServices(file));
+ grpc::string header_code =
+ grpc_cpp_generator::GetHeaderPrologue(file, generator_parameters) +
+ grpc_cpp_generator::GetHeaderIncludes(file, generator_parameters) +
+ grpc_cpp_generator::GetHeaderServices(file, generator_parameters) +
+ grpc_cpp_generator::GetHeaderEpilogue(file, generator_parameters);
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
+ context->Open(file_name + ".grpc.pb.h"));
+ grpc::protobuf::io::CodedOutputStream header_coded_out(
+ header_output.get());
+ header_coded_out.WriteRaw(header_code.data(), header_code.size());
+
+ grpc::string source_code =
+ grpc_cpp_generator::GetSourcePrologue(file, generator_parameters) +
+ grpc_cpp_generator::GetSourceIncludes(file, generator_parameters) +
+ grpc_cpp_generator::GetSourceServices(file, generator_parameters) +
+ grpc_cpp_generator::GetSourceEpilogue(file, generator_parameters);
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
+ context->Open(file_name + ".grpc.pb.cc"));
+ grpc::protobuf::io::CodedOutputStream source_coded_out(
+ source_output.get());
+ source_coded_out.WriteRaw(source_code.data(), source_code.size());
return true;
}
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 1e6727dd4c..374e1374cf 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -75,6 +75,47 @@ inline grpc::string StringReplace(grpc::string str, const grpc::string &from,
return str;
}
+inline std::vector<grpc::string> tokenize(const grpc::string &input,
+ const grpc::string &delimiters) {
+ std::vector<grpc::string> tokens;
+ size_t pos, last_pos = 0;
+
+ for (;;) {
+ bool done = false;
+ pos = input.find_first_of(delimiters, last_pos);
+ if (pos == grpc::string::npos) {
+ done = true;
+ pos = input.length();
+ }
+
+ tokens.push_back(input.substr(last_pos, pos - last_pos));
+ if (done) return tokens;
+
+ last_pos = pos + 1;
+ }
+}
+
+inline grpc::string CapitalizeFirstLetter(grpc::string s) {
+ if (s.empty()) {
+ return s;
+ }
+ s[0] = ::toupper(s[0]);
+ return s;
+}
+
+inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) {
+ std::vector<grpc::string> tokens = tokenize(str, "_");
+ grpc::string result = "";
+ for (unsigned int i = 0; i < tokens.size(); i++) {
+ result += CapitalizeFirstLetter(tokens[i]);
+ }
+ return result;
+}
+
+inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+ return LowerUnderscoreToUpperCamel(StripProto(file->name()));
+}
+
} // namespace grpc_generator
#endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
new file mode 100644
index 0000000000..c68c9c37c2
--- /dev/null
+++ b/src/compiler/objective_c_generator.cc
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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 <map>
+
+#include "src/compiler/objective_c_generator.h"
+#include "src/compiler/objective_c_generator_helpers.h"
+
+#include "src/compiler/config.h"
+
+#include <sstream>
+
+namespace grpc_objective_c_generator {
+namespace {
+
+void PrintSimpleBlockSignature(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["method_name"] = method->name();
+ (*vars)["request_type"] = PrefixedName(method->input_type()->name());
+ (*vars)["response_type"] = PrefixedName(method->output_type()->name());
+
+ if (method->server_streaming()) {
+ printer->Print("// When the response stream finishes, the handler is "
+ "called with nil for both arguments.\n\n");
+ } else {
+ printer->Print("// The handler is only called once.\n\n");
+ }
+ printer->Print(*vars, "- (id<GRXLiveSource>)$method_name$WithRequest:"
+ "($request_type$)request completionHandler:(void(^)"
+ "($response_type$ *, NSError *))handler");
+}
+
+void PrintSimpleDelegateSignature(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["method_name"] = method->name();
+ (*vars)["request_type"] = PrefixedName(method->input_type()->name());
+
+ printer->Print(*vars, "- (id<GRXLiveSource>)$method_name$WithRequest:"
+ "($request_type$)request delegate:(id<GRXSink>)delegate");
+}
+
+void PrintAdvancedSignature(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["method_name"] = method->name();
+ printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:"
+ "(id<GRXSource>)request");
+}
+
+void PrintSourceMethodSimpleBlock(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ PrintSimpleBlockSignature(printer, method, vars);
+
+ (*vars)["method_name"] = method->name();
+ printer->Print(" {\n");
+ printer->Indent();
+ printer->Print(*vars, "return [[self $method_name$WithRequest:request] "
+ "connectHandler:^(id value, NSError *error) {\n");
+ printer->Indent();
+ printer->Print("handler(value, error);\n");
+ printer->Outdent();
+ printer->Print("}];\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void PrintSourceMethodSimpleDelegate(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ PrintSimpleDelegateSignature(printer, method, vars);
+
+ (*vars)["method_name"] = method->name();
+ printer->Print(" {\n");
+ printer->Indent();
+ printer->Print(*vars, "return [[self $method_name$WithRequest:request]"
+ "connectToSink:delegate];\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void PrintSourceMethodAdvanced(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ PrintAdvancedSignature(printer, method, vars);
+
+ (*vars)["method_name"] = method->name();
+ printer->Print(" {\n");
+ printer->Indent();
+ printer->Print(*vars, "return [self $method_name$WithRequest:request "
+ "client:[self newClient]];\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void PrintSourceMethodHandler(grpc::protobuf::io::Printer *printer,
+ const grpc::protobuf::MethodDescriptor *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["method_name"] = method->name();
+ (*vars)["response_type"] = PrefixedName(method->output_type()->name());
+ (*vars)["caps_name"] = grpc_generator::CapitalizeFirstLetter(method->name());
+
+ printer->Print(*vars, "- (GRXSource *)$method_name$WithRequest:"
+ "(id<GRXSource>)request client:(PBgRPCClient *)client {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return [self responseWithMethod:$@\"$caps_name\"\n");
+ printer->Print(*vars,
+ " class:[$response_type$ class]\n");
+ printer->Print(" request:request\n");
+ printer->Print(" client:client];\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+}
+
+grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service,
+ const grpc::string message_header) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+ printer.Print("#import \"PBgRPCClient.h\"\n");
+ printer.Print("#import \"PBStub.h\"\n");
+ vars["message_header"] = message_header;
+ printer.Print(vars, "#import \"$message_header$\"\n\n");
+ printer.Print("@protocol GRXSource\n");
+ printer.Print("@class GRXSource\n\n");
+ vars["service_name"] = service->name();
+ printer.Print("@protocol $service_name$Stub <NSObject>\n\n");
+ printer.Print("#pragma mark Simple block handlers\n\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSimpleBlockSignature(&printer, service->method(i), &vars);
+ printer.Print(";\n");
+ }
+ printer.Print("\n");
+ printer.Print("#pragma mark Simple delegate handlers.\n\n");
+ printer.Print("# TODO(jcanizales): Use high-level snippets to remove this duplication.");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSimpleDelegateSignature(&printer, service->method(i), &vars);
+ printer.Print(";\n");
+ }
+ printer.Print("\n");
+ printer.Print("#pragma mark Advanced handlers.\n\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintAdvancedSignature(&printer, service->method(i), &vars);
+ printer.Print(";\n");
+ }
+ printer.Print("\n");
+ printer.Print("@end\n\n");
+ printer.Print("// Basic stub that only does marshalling and parsing\n");
+ printer.Print(vars, "@interface $service_name$Stub :"
+ " PBStub<$service_name$Stub>\n");
+ printer.Print("- (instancetype)initWithHost:(NSString *)host;\n");
+ printer.Print("@end\n");
+ return output;
+}
+
+grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service) {
+ grpc::string output;
+ grpc::protobuf::io::StringOutputStream output_stream(&output);
+ grpc::protobuf::io::Printer printer(&output_stream, '$');
+ std::map<grpc::string, grpc::string> vars;
+ vars["service_name"] = service->name();
+ printer.Print(vars, "#import \"$service_name$Stub.pb.h\"\n");
+ printer.Print("#import \"PBGeneratedMessage+GRXSource.h\"\n\n");
+ vars["full_name"] = service->full_name();
+ printer.Print(vars,
+ "static NSString *const kInterface = @\"$full_name$\";\n");
+ printer.Print("@implementation $service_name$Stub\n\n");
+ printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
+ printer.Indent();
+ printer.Print("if ((self = [super initWithHost:host "
+ "interface:kInterface])) {\n");
+ printer.Print("}\n");
+ printer.Print("return self;\n");
+ printer.Outdent();
+ printer.Print("}\n\n");
+ printer.Print("#pragma mark Simple block handlers.\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSourceMethodSimpleBlock(&printer, service->method(i), &vars);
+ }
+ printer.Print("\n");
+ printer.Print("#pragma mark Simple delegate handlers.\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSourceMethodSimpleDelegate(&printer, service->method(i), &vars);
+ }
+ printer.Print("\n");
+ printer.Print("#pragma mark Advanced handlers.\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSourceMethodAdvanced(&printer, service->method(i), &vars);
+ }
+ printer.Print("\n");
+ printer.Print("#pragma mark Handlers for subclasses "
+ "(stub wrappers) to override.\n");
+ for (int i = 0; i < service->method_count(); i++) {
+ PrintSourceMethodHandler(&printer, service->method(i), &vars);
+ }
+ printer.Print("@end\n");
+ return output;
+}
+
+} // namespace grpc_objective_c_generator
diff --git a/src/compiler/objective_c_generator.h b/src/compiler/objective_c_generator.h
new file mode 100644
index 0000000000..93c730b34e
--- /dev/null
+++ b/src/compiler/objective_c_generator.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
+
+#include "src/compiler/config.h"
+
+namespace grpc_objective_c_generator {
+
+grpc::string GetHeader(const grpc::protobuf::ServiceDescriptor *service,
+ const grpc::string message_header);
+
+grpc::string GetSource(const grpc::protobuf::ServiceDescriptor *service);
+
+} // namespace grpc_objective_c_generator
+
+#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_H
diff --git a/src/compiler/objective_c_generator_helpers.h b/src/compiler/objective_c_generator_helpers.h
new file mode 100644
index 0000000000..6a7c13991f
--- /dev/null
+++ b/src/compiler/objective_c_generator_helpers.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
+#define GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
+
+#include <map>
+#include "src/compiler/config.h"
+#include "src/compiler/generator_helpers.h"
+
+namespace grpc_objective_c_generator {
+
+const grpc::string prefix = "PBG";
+
+inline grpc::string MessageHeaderName(const grpc::protobuf::FileDescriptor *file) {
+ return grpc_generator::FileNameInUpperCamel(file) + ".pb.h";
+}
+
+inline grpc::string StubFileName(grpc::string service_name) {
+ return prefix + service_name + "Stub";
+}
+
+inline grpc::string PrefixedName(grpc::string name) {
+ return prefix + name;
+}
+
+}
+#endif // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
new file mode 100644
index 0000000000..eebce0cd20
--- /dev/null
+++ b/src/compiler/objective_c_plugin.cc
@@ -0,0 +1,98 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+// Generates Objective C gRPC service interface out of Protobuf IDL.
+
+#include <memory>
+
+#include "src/compiler/config.h"
+#include "src/compiler/objective_c_generator.h"
+#include "src/compiler/objective_c_generator_helpers.h"
+
+class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
+ public:
+ ObjectiveCGrpcGenerator() {}
+ virtual ~ObjectiveCGrpcGenerator() {}
+
+ virtual bool Generate(const grpc::protobuf::FileDescriptor *file,
+ const grpc::string &parameter,
+ grpc::protobuf::compiler::GeneratorContext *context,
+ grpc::string *error) const {
+
+ if (file->service_count() == 0) {
+ // No services. Do nothing.
+ return true;
+ }
+
+ for (int i = 0; i < file->service_count(); i++) {
+ const grpc::protobuf::ServiceDescriptor *service = file->service(i);
+ grpc::string file_name = grpc_objective_c_generator::StubFileName(
+ service->name());
+
+ // Generate .pb.h
+ grpc::string header_code = grpc_objective_c_generator::GetHeader(
+ service, grpc_objective_c_generator::MessageHeaderName(file));
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
+ context->Open(file_name + ".pb.h"));
+ grpc::protobuf::io::CodedOutputStream header_coded_out(
+ header_output.get());
+ header_coded_out.WriteRaw(header_code.data(), header_code.size());
+
+ // Generate .pb.m
+ grpc::string source_code = grpc_objective_c_generator::GetSource(service);
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
+ context->Open(file_name + ".pb.m"));
+ grpc::protobuf::io::CodedOutputStream source_coded_out(
+ source_output.get());
+ source_coded_out.WriteRaw(source_code.data(), source_code.size());
+ }
+
+ return true;
+ }
+
+ private:
+ // Insert the given code into the given file at the given insertion point.
+ void Insert(grpc::protobuf::compiler::GeneratorContext *context,
+ const grpc::string &filename, const grpc::string &insertion_point,
+ const grpc::string &code) const {
+ std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
+ context->OpenForInsert(filename, insertion_point));
+ grpc::protobuf::io::CodedOutputStream coded_out(output.get());
+ coded_out.WriteRaw(code.data(), code.size());
+ }
+};
+
+int main(int argc, char *argv[]) {
+ ObjectiveCGrpcGenerator generator;
+ return grpc::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index c2d4cda31a..72149bc4e3 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -271,7 +271,7 @@ bool GetModuleAndMessagePath(const Descriptor* type,
bool PrintServerFactory(const grpc::string& package_qualified_service_name,
const ServiceDescriptor* service, Printer* out) {
out->Print("def early_adopter_create_$Service$_server(servicer, port, "
- "root_certificates, key_chain_pairs):\n",
+ "private_key=None, certificate_chain=None):\n",
"Service", service->name());
{
IndentScope raii_create_server_indent(out);
@@ -309,17 +309,20 @@ bool PrintServerFactory(const grpc::string& package_qualified_service_name,
make_pair(method->name(), output_message_module_and_class));
}
out->Print("method_service_descriptions = {\n");
- for (auto& name_and_description_constructor :
- method_description_constructors) {
+ for (auto name_and_description_constructor =
+ method_description_constructors.begin();
+ name_and_description_constructor !=
+ method_description_constructors.end();
+ name_and_description_constructor++) {
IndentScope raii_descriptions_indent(out);
- const grpc::string method_name = name_and_description_constructor.first;
+ const grpc::string method_name = name_and_description_constructor->first;
auto input_message_module_and_class =
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",
method_name, "Constructor",
- name_and_description_constructor.second);
+ name_and_description_constructor->second);
{
IndentScope raii_description_arguments_indent(out);
out->Print("servicer.$Method$,\n", "Method", method_name);
@@ -336,10 +339,10 @@ bool PrintServerFactory(const grpc::string& package_qualified_service_name,
}
out->Print("}\n");
out->Print(
- "return implementations.secure_server("
+ "return implementations.server("
"\"$PackageQualifiedServiceName$\","
- " method_service_descriptions, port, root_certificates,"
- " key_chain_pairs)\n",
+ " method_service_descriptions, port, private_key=private_key,"
+ " certificate_chain=certificate_chain)\n",
"PackageQualifiedServiceName", package_qualified_service_name);
}
return true;
@@ -350,7 +353,10 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
map<grpc::string, grpc::string> dict = ListToDict({
"Service", service->name(),
});
- out->Print(dict, "def early_adopter_create_$Service$_stub(host, port):\n");
+ out->Print(dict, "def early_adopter_create_$Service$_stub(host, port,"
+ " metadata_transformer=None,"
+ " secure=False, root_certificates=None, private_key=None,"
+ " certificate_chain=None, server_host_override=None):\n");
{
IndentScope raii_create_server_indent(out);
map<grpc::string, grpc::string> method_description_constructors;
@@ -387,17 +393,20 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
make_pair(method->name(), output_message_module_and_class));
}
out->Print("method_invocation_descriptions = {\n");
- for (auto& name_and_description_constructor :
- method_description_constructors) {
+ for (auto name_and_description_constructor =
+ method_description_constructors.begin();
+ name_and_description_constructor !=
+ method_description_constructors.end();
+ name_and_description_constructor++) {
IndentScope raii_descriptions_indent(out);
- const grpc::string method_name = name_and_description_constructor.first;
+ const grpc::string method_name = name_and_description_constructor->first;
auto input_message_module_and_class =
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",
method_name, "Constructor",
- name_and_description_constructor.second);
+ name_and_description_constructor->second);
{
IndentScope raii_description_arguments_indent(out);
out->Print(
@@ -413,9 +422,13 @@ bool PrintStubFactory(const grpc::string& package_qualified_service_name,
}
out->Print("}\n");
out->Print(
- "return implementations.insecure_stub("
+ "return implementations.stub("
"\"$PackageQualifiedServiceName$\","
- " method_invocation_descriptions, host, port)\n",
+ " method_invocation_descriptions, host, port,"
+ " metadata_transformer=metadata_transformer, secure=secure,"
+ " root_certificates=root_certificates, private_key=private_key,"
+ " certificate_chain=certificate_chain,"
+ " server_host_override=server_host_override)\n",
"PackageQualifiedServiceName", package_qualified_service_name);
}
return true;
diff --git a/src/core/channel/call_op_string.c b/src/core/channel/call_op_string.c
index 08f2e95deb..5f7e1be268 100644
--- a/src/core/channel/call_op_string.c
+++ b/src/core/channel/call_op_string.c
@@ -43,12 +43,27 @@
static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
gpr_strvec_add(b, gpr_strdup(" key="));
- gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
- GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT));
+ gpr_strvec_add(
+ b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
+ GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT));
gpr_strvec_add(b, gpr_strdup(" value="));
gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice),
- GPR_SLICE_LENGTH(md->value->slice), GPR_HEXDUMP_PLAINTEXT));
+ GPR_SLICE_LENGTH(md->value->slice),
+ GPR_HEXDUMP_PLAINTEXT));
+}
+
+static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
+ grpc_linked_mdelem *m;
+ for (m = md.list.head; m != NULL; m = m->next) {
+ put_metadata(b, m->md);
+ }
+ if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) {
+ char *tmp;
+ gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec,
+ md.deadline.tv_nsec);
+ gpr_strvec_add(b, tmp);
+ }
}
char *grpc_call_op_string(grpc_call_op *op) {
@@ -69,16 +84,7 @@ char *grpc_call_op_string(grpc_call_op *op) {
switch (op->type) {
case GRPC_SEND_METADATA:
gpr_strvec_add(&b, gpr_strdup("SEND_METADATA"));
- put_metadata(&b, op->data.metadata);
- break;
- case GRPC_SEND_DEADLINE:
- gpr_asprintf(&tmp, "SEND_DEADLINE %d.%09d", op->data.deadline.tv_sec,
- op->data.deadline.tv_nsec);
- gpr_strvec_add(&b, tmp);
- break;
- case GRPC_SEND_START:
- gpr_asprintf(&tmp, "SEND_START pollset=%p", op->data.start.pollset);
- gpr_strvec_add(&b, tmp);
+ put_metadata_list(&b, op->data.metadata);
break;
case GRPC_SEND_MESSAGE:
gpr_strvec_add(&b, gpr_strdup("SEND_MESSAGE"));
@@ -94,15 +100,7 @@ char *grpc_call_op_string(grpc_call_op *op) {
break;
case GRPC_RECV_METADATA:
gpr_strvec_add(&b, gpr_strdup("RECV_METADATA"));
- put_metadata(&b, op->data.metadata);
- break;
- case GRPC_RECV_DEADLINE:
- gpr_asprintf(&tmp, "RECV_DEADLINE %d.%09d", op->data.deadline.tv_sec,
- op->data.deadline.tv_nsec);
- gpr_strvec_add(&b, tmp);
- break;
- case GRPC_RECV_END_OF_INITIAL_METADATA:
- gpr_strvec_add(&b, gpr_strdup("RECV_END_OF_INITIAL_METADATA"));
+ put_metadata_list(&b, op->data.metadata);
break;
case GRPC_RECV_MESSAGE:
gpr_strvec_add(&b, gpr_strdup("RECV_MESSAGE"));
@@ -113,12 +111,21 @@ char *grpc_call_op_string(grpc_call_op *op) {
case GRPC_RECV_FINISH:
gpr_strvec_add(&b, gpr_strdup("RECV_FINISH"));
break;
+ case GRPC_RECV_SYNTHETIC_STATUS:
+ gpr_asprintf(&tmp, "RECV_SYNTHETIC_STATUS status=%d message='%s'",
+ op->data.synthetic_status.status,
+ op->data.synthetic_status.message);
+ gpr_strvec_add(&b, tmp);
+ break;
case GRPC_CANCEL_OP:
gpr_strvec_add(&b, gpr_strdup("CANCEL_OP"));
break;
}
gpr_asprintf(&tmp, " flags=0x%08x", op->flags);
gpr_strvec_add(&b, tmp);
+ if (op->bind_pollset) {
+ gpr_strvec_add(&b, gpr_strdup("bind_pollset"));
+ }
out = gpr_strvec_flatten(&b, NULL);
gpr_strvec_destroy(&b);
diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c
index ba7b7ba59c..7e393a01a6 100644
--- a/src/core/channel/census_filter.c
+++ b/src/core/channel/census_filter.c
@@ -49,6 +49,11 @@ typedef struct call_data {
census_op_id op_id;
census_rpc_stats stats;
gpr_timespec start_ts;
+
+ /* recv callback */
+ grpc_stream_op_buffer* recv_ops;
+ void (*on_done_recv)(void* user_data, int success);
+ void* recv_user_data;
} call_data;
typedef struct channel_data {
@@ -60,55 +65,68 @@ static void init_rpc_stats(census_rpc_stats* stats) {
stats->cnt = 1;
}
-static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
+static void extract_and_annotate_method_tag(grpc_stream_op_buffer* sopb,
+ call_data* calld,
channel_data* chand) {
- if (op->data.metadata->key == chand->path_str) {
- gpr_log(GPR_DEBUG,
- (const char*)GPR_SLICE_START_PTR(op->data.metadata->value->slice));
- census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
- op->data.metadata->value->slice));
+ grpc_linked_mdelem* m;
+ size_t i;
+ for (i = 0; i < sopb->nops; i++) {
+ grpc_stream_op* op = &sopb->ops[i];
+ if (op->type != GRPC_OP_METADATA) continue;
+ for (m = op->data.metadata.list.head; m != NULL; m = m->next) {
+ if (m->md->key == chand->path_str) {
+ gpr_log(GPR_DEBUG, "%s",
+ (const char*)GPR_SLICE_START_PTR(m->md->value->slice));
+ census_add_method_tag(calld->op_id, (const char*)GPR_SLICE_START_PTR(
+ m->md->value->slice));
+ }
+ }
}
}
-static void client_call_op(grpc_call_element* elem,
- grpc_call_element* from_elem, grpc_call_op* op) {
+static void client_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
- GPR_ASSERT(calld != NULL);
- GPR_ASSERT(chand != NULL);
- GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
- switch (op->type) {
- case GRPC_SEND_METADATA:
- extract_and_annotate_method_tag(op, calld, chand);
- break;
- case GRPC_RECV_FINISH:
- /* Should we stop timing the rpc here? */
- break;
- default:
- break;
+ if (op->send_ops) {
+ extract_and_annotate_method_tag(op->send_ops, calld, chand);
}
- /* Always pass control up or down the stack depending on op->dir */
+}
+
+static void client_start_transport_op(grpc_call_element* elem,
+ grpc_transport_op* op) {
+ call_data* calld = elem->call_data;
+ GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
+ client_mutate_op(elem, op);
grpc_call_next_op(elem, op);
}
-static void server_call_op(grpc_call_element* elem,
- grpc_call_element* from_elem, grpc_call_op* op) {
+static void server_on_done_recv(void* ptr, int success) {
+ grpc_call_element* elem = ptr;
call_data* calld = elem->call_data;
channel_data* chand = elem->channel_data;
- GPR_ASSERT(calld != NULL);
- GPR_ASSERT(chand != NULL);
- GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
- switch (op->type) {
- case GRPC_RECV_METADATA:
- extract_and_annotate_method_tag(op, calld, chand);
- break;
- case GRPC_SEND_FINISH:
- /* Should we stop timing the rpc here? */
- break;
- default:
- break;
+ if (success) {
+ extract_and_annotate_method_tag(calld->recv_ops, calld, chand);
}
- /* Always pass control up or down the stack depending on op->dir */
+ calld->on_done_recv(calld->recv_user_data, success);
+}
+
+static void server_mutate_op(grpc_call_element* elem, grpc_transport_op* op) {
+ call_data* calld = elem->call_data;
+ if (op->recv_ops) {
+ /* substitute our callback for the op callback */
+ calld->recv_ops = op->recv_ops;
+ calld->on_done_recv = op->on_done_recv;
+ calld->recv_user_data = op->recv_user_data;
+ op->on_done_recv = server_on_done_recv;
+ op->recv_user_data = elem;
+ }
+}
+
+static void server_start_transport_op(grpc_call_element* elem,
+ grpc_transport_op* op) {
+ call_data* calld = elem->call_data;
+ GPR_ASSERT((calld->op_id.upper != 0) || (calld->op_id.lower != 0));
+ server_mutate_op(elem, op);
grpc_call_next_op(elem, op);
}
@@ -126,12 +144,14 @@ static void channel_op(grpc_channel_element* elem,
}
static void client_init_call_elem(grpc_call_element* elem,
- const void* server_transport_data) {
+ const void* server_transport_data,
+ grpc_transport_op* initial_op) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->op_id = census_tracing_start_op();
+ if (initial_op) client_mutate_op(elem, initial_op);
}
static void client_destroy_call_elem(grpc_call_element* elem) {
@@ -142,12 +162,14 @@ static void client_destroy_call_elem(grpc_call_element* elem) {
}
static void server_init_call_elem(grpc_call_element* elem,
- const void* server_transport_data) {
+ const void* server_transport_data,
+ grpc_transport_op* initial_op) {
call_data* d = elem->call_data;
GPR_ASSERT(d != NULL);
init_rpc_stats(&d->stats);
d->start_ts = gpr_now();
d->op_id = census_tracing_start_op();
+ if (initial_op) server_mutate_op(elem, initial_op);
}
static void server_destroy_call_elem(grpc_call_element* elem) {
@@ -178,11 +200,11 @@ static void destroy_channel_elem(grpc_channel_element* elem) {
}
const grpc_channel_filter grpc_client_census_filter = {
- client_call_op, channel_op, sizeof(call_data),
+ client_start_transport_op, channel_op, sizeof(call_data),
client_init_call_elem, client_destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "census-client"};
+ init_channel_elem, destroy_channel_elem, "census-client"};
const grpc_channel_filter grpc_server_census_filter = {
- server_call_op, channel_op, sizeof(call_data),
+ server_start_transport_op, channel_op, sizeof(call_data),
server_init_call_elem, server_destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "census-server"};
+ init_channel_elem, destroy_channel_elem, "census-server"};
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index 21df9771ce..311f4f08ce 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -35,6 +35,7 @@
#include <grpc/support/log.h>
#include <stdlib.h>
+#include <string.h>
int grpc_trace_channel = 0;
@@ -77,9 +78,9 @@ size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
return size;
}
-#define CHANNEL_ELEMS_FROM_STACK(stk) \
- ((grpc_channel_element *)( \
- (char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_channel_stack))))
+#define CHANNEL_ELEMS_FROM_STACK(stk) \
+ ((grpc_channel_element *)((char *)(stk) + ROUND_UP_TO_ALIGNMENT_SIZE( \
+ sizeof(grpc_channel_stack))))
#define CALL_ELEMS_FROM_STACK(stk) \
((grpc_call_element *)((char *)(stk) + \
@@ -147,6 +148,7 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack) {
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
+ grpc_transport_op *initial_op,
grpc_call_stack *call_stack) {
grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
size_t count = channel_stack->count;
@@ -164,7 +166,8 @@ void grpc_call_stack_init(grpc_channel_stack *channel_stack,
call_elems[i].filter = channel_elems[i].filter;
call_elems[i].channel_data = channel_elems[i].channel_data;
call_elems[i].call_data = user_data;
- call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data);
+ call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data,
+ initial_op);
user_data +=
ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
}
@@ -181,9 +184,9 @@ void grpc_call_stack_destroy(grpc_call_stack *stack) {
}
}
-void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) {
- grpc_call_element *next_elem = elem + op->dir;
- next_elem->filter->call_op(next_elem, elem, op);
+void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op) {
+ grpc_call_element *next_elem = elem + 1;
+ next_elem->filter->start_transport_op(next_elem, op);
}
void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
@@ -193,58 +196,24 @@ void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_channel_element *elem) {
- return (grpc_channel_stack *)((char *)(elem) -
- ROUND_UP_TO_ALIGNMENT_SIZE(
- sizeof(grpc_channel_stack)));
+ return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+ sizeof(grpc_channel_stack)));
}
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
- return (grpc_call_stack *)((char *)(elem) - ROUND_UP_TO_ALIGNMENT_SIZE(
- sizeof(grpc_call_stack)));
-}
-
-static void do_nothing(void *user_data, grpc_op_error error) {}
-
-void grpc_call_element_recv_metadata(grpc_call_element *cur_elem,
- grpc_mdelem *mdelem) {
- grpc_call_op metadata_op;
- metadata_op.type = GRPC_RECV_METADATA;
- metadata_op.dir = GRPC_CALL_UP;
- metadata_op.done_cb = do_nothing;
- metadata_op.user_data = NULL;
- metadata_op.flags = 0;
- metadata_op.data.metadata = mdelem;
- grpc_call_next_op(cur_elem, &metadata_op);
-}
-
-void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
- grpc_mdelem *mdelem) {
- grpc_call_op metadata_op;
- metadata_op.type = GRPC_SEND_METADATA;
- metadata_op.dir = GRPC_CALL_DOWN;
- metadata_op.done_cb = do_nothing;
- metadata_op.user_data = NULL;
- metadata_op.flags = 0;
- metadata_op.data.metadata = mdelem;
- grpc_call_next_op(cur_elem, &metadata_op);
+ return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+ sizeof(grpc_call_stack)));
}
void grpc_call_element_send_cancel(grpc_call_element *cur_elem) {
- grpc_call_op cancel_op;
- cancel_op.type = GRPC_CANCEL_OP;
- cancel_op.dir = GRPC_CALL_DOWN;
- cancel_op.done_cb = do_nothing;
- cancel_op.user_data = NULL;
- cancel_op.flags = 0;
- grpc_call_next_op(cur_elem, &cancel_op);
+ grpc_transport_op op;
+ memset(&op, 0, sizeof(op));
+ op.cancel_with_status = GRPC_STATUS_CANCELLED;
+ grpc_call_next_op(cur_elem, &op);
}
-void grpc_call_element_send_finish(grpc_call_element *cur_elem) {
- grpc_call_op finish_op;
- finish_op.type = GRPC_SEND_FINISH;
- finish_op.dir = GRPC_CALL_DOWN;
- finish_op.done_cb = do_nothing;
- finish_op.user_data = NULL;
- finish_op.flags = 0;
- grpc_call_next_op(cur_elem, &finish_op);
+void grpc_call_element_recv_status(grpc_call_element *cur_elem,
+ grpc_status_code status,
+ const char *message) {
+ abort();
}
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index ef1da7b33b..de0e4e4518 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -51,82 +51,11 @@
typedef struct grpc_channel_element grpc_channel_element;
typedef struct grpc_call_element grpc_call_element;
-/* Call operations - things that can be sent and received.
-
- Threading:
- SEND, RECV, and CANCEL ops can be active on a call at the same time, but
- only one SEND, one RECV, and one CANCEL can be active at a time.
-
- If state is shared between send/receive/cancel operations, it is up to
- filters to provide their own protection around that. */
-typedef enum {
- /* send metadata to the channels peer */
- GRPC_SEND_METADATA,
- /* send a deadline */
- GRPC_SEND_DEADLINE,
- /* start a connection (corresponds to start_invoke/accept) */
- GRPC_SEND_START,
- /* send a message to the channels peer */
- GRPC_SEND_MESSAGE,
- /* send a pre-formatted message to the channels peer */
- GRPC_SEND_PREFORMATTED_MESSAGE,
- /* send half-close to the channels peer */
- GRPC_SEND_FINISH,
- /* request that more data be allowed through flow control */
- GRPC_REQUEST_DATA,
- /* metadata was received from the channels peer */
- GRPC_RECV_METADATA,
- /* receive a deadline */
- GRPC_RECV_DEADLINE,
- /* the end of the first batch of metadata was received */
- GRPC_RECV_END_OF_INITIAL_METADATA,
- /* a message was received from the channels peer */
- GRPC_RECV_MESSAGE,
- /* half-close was received from the channels peer */
- GRPC_RECV_HALF_CLOSE,
- /* full close was received from the channels peer */
- GRPC_RECV_FINISH,
- /* the call has been abnormally terminated */
- GRPC_CANCEL_OP
-} grpc_call_op_type;
-
/* The direction of the call.
The values of the enums (1, -1) matter here - they are used to increment
or decrement a pointer to find the next element to call */
typedef enum { GRPC_CALL_DOWN = 1, GRPC_CALL_UP = -1 } grpc_call_dir;
-/* A single filterable operation to be performed on a call */
-typedef struct {
- /* The type of operation we're performing */
- grpc_call_op_type type;
- /* The directionality of this call - does the operation begin at the bottom
- of the stack and flow up, or does the operation start at the top of the
- stack and flow down through the filters. */
- grpc_call_dir dir;
-
- /* Flags associated with this call: see GRPC_WRITE_* in grpc.h */
- gpr_uint32 flags;
-
- /* Argument data, matching up with grpc_call_op_type names */
- union {
- struct {
- grpc_pollset *pollset;
- } start;
- grpc_byte_buffer *message;
- grpc_mdelem *metadata;
- gpr_timespec deadline;
- } data;
-
- /* Must be called when processing of this call-op is complete.
- Signature chosen to match transport flow control callbacks */
- void (*done_cb)(void *user_data, grpc_op_error error);
- /* User data to be passed into done_cb */
- void *user_data;
-} grpc_call_op;
-
-/* returns a string representation of op, that can be destroyed with gpr_free */
-char *grpc_call_op_string(grpc_call_op *op);
-
typedef enum {
/* send a goaway message to remote channels indicating that we are going
to disconnect in the future */
@@ -174,8 +103,7 @@ typedef struct {
typedef struct {
/* Called to eg. send/receive data on a call.
See grpc_call_next_op on how to call the next element in the stack */
- void (*call_op)(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op);
+ void (*start_transport_op)(grpc_call_element *elem, grpc_transport_op *op);
/* Called to handle channel level operations - e.g. new calls, or transport
closure.
See grpc_channel_next_op on how to call the next element in the stack */
@@ -193,7 +121,8 @@ typedef struct {
transport and is on the server. Most filters want to ignore this
argument.*/
void (*init_call_elem)(grpc_call_element *elem,
- const void *server_transport_data);
+ const void *server_transport_data,
+ grpc_transport_op *initial_op);
/* Destroy per call data.
The filter does not need to do any chaining */
void (*destroy_call_elem)(grpc_call_element *elem);
@@ -272,12 +201,13 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack);
server. */
void grpc_call_stack_init(grpc_channel_stack *channel_stack,
const void *transport_server_data,
+ grpc_transport_op *initial_op,
grpc_call_stack *call_stack);
/* Destroy a call stack */
void grpc_call_stack_destroy(grpc_call_stack *stack);
-/* Call the next operation (depending on call directionality) in a call stack */
-void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op);
+/* Call the next operation in a call stack */
+void grpc_call_next_op(grpc_call_element *elem, grpc_transport_op *op);
/* Call the next operation (depending on call directionality) in a channel
stack */
void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op);
@@ -289,18 +219,13 @@ grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem);
void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
- grpc_call_element *elem, grpc_call_op *op);
+ grpc_call_element *elem, grpc_transport_op *op);
-void grpc_call_element_send_metadata(grpc_call_element *cur_elem,
- grpc_mdelem *elem);
-void grpc_call_element_recv_metadata(grpc_call_element *cur_elem,
- grpc_mdelem *elem);
void grpc_call_element_send_cancel(grpc_call_element *cur_elem);
-void grpc_call_element_send_finish(grpc_call_element *cur_elem);
extern int grpc_trace_channel;
#define GRPC_CALL_LOG_OP(sev, elem, op) \
if (grpc_trace_channel) grpc_call_log_op(sev, elem, op)
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/channel/child_channel.c b/src/core/channel/child_channel.c
index 2cb03829c7..a2f3c54290 100644
--- a/src/core/channel/child_channel.c
+++ b/src/core/channel/child_channel.c
@@ -60,23 +60,11 @@ typedef struct {
gpr_uint8 sent_farewell;
} lb_channel_data;
-typedef struct {
- grpc_call_element *back;
- grpc_child_channel *channel;
-} lb_call_data;
-
-static void lb_call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- lb_call_data *calld = elem->call_data;
+typedef struct { grpc_child_channel *channel; } lb_call_data;
- switch (op->dir) {
- case GRPC_CALL_UP:
- calld->back->filter->call_op(calld->back, elem, op);
- break;
- case GRPC_CALL_DOWN:
- grpc_call_next_op(elem, op);
- break;
- }
+static void lb_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ grpc_call_next_op(elem, op);
}
/* Currently we assume all channel operations should just be pushed up. */
@@ -132,7 +120,8 @@ static void lb_channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void lb_init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {}
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {}
/* Destructor for call_data */
static void lb_destroy_call_elem(grpc_call_element *elem) {}
@@ -165,9 +154,10 @@ static void lb_destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_child_channel_top_filter = {
- lb_call_op, lb_channel_op, sizeof(lb_call_data),
- lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data),
- lb_init_channel_elem, lb_destroy_channel_elem, "child-channel", };
+ lb_start_transport_op, lb_channel_op, sizeof(lb_call_data),
+ lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data),
+ lb_init_channel_elem, lb_destroy_channel_elem, "child-channel",
+};
/* grpc_child_channel proper */
@@ -272,17 +262,17 @@ void grpc_child_channel_handle_op(grpc_child_channel *channel,
}
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
- grpc_call_element *parent) {
+ grpc_call_element *parent,
+ grpc_transport_op *initial_op) {
grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size);
grpc_call_element *lbelem;
lb_call_data *lbcalld;
lb_channel_data *lbchand;
- grpc_call_stack_init(channel, NULL, stk);
+ grpc_call_stack_init(channel, NULL, initial_op, stk);
lbelem = LINK_BACK_ELEM_FROM_CALL(stk);
lbchand = lbelem->channel_data;
lbcalld = lbelem->call_data;
- lbcalld->back = parent;
lbcalld->channel = channel;
gpr_mu_lock(&lbchand->mu);
diff --git a/src/core/channel/child_channel.h b/src/core/channel/child_channel.h
index 38695402ab..556a1c731c 100644
--- a/src/core/channel/child_channel.h
+++ b/src/core/channel/child_channel.h
@@ -57,8 +57,9 @@ void grpc_child_channel_destroy(grpc_child_channel *channel,
int wait_for_callbacks);
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
- grpc_call_element *parent);
+ grpc_call_element *parent,
+ grpc_transport_op *initial_op);
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call);
void grpc_child_call_destroy(grpc_child_call *call);
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */
+#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 9791f98be8..78f8d06d89 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -38,7 +38,6 @@
#include "src/core/channel/channel_args.h"
#include "src/core/channel/child_channel.h"
#include "src/core/channel/connected_channel.h"
-#include "src/core/channel/metadata_buffer.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
@@ -59,6 +58,7 @@ typedef struct {
/* the sending child (may be null) */
grpc_child_channel *active_child;
+ grpc_mdctx *mdctx;
/* calls waiting for a channel to be ready */
call_data **waiting_children;
@@ -70,9 +70,6 @@ typedef struct {
int transport_setup_initiated;
grpc_channel_args *args;
-
- /* metadata cache */
- grpc_mdelem *cancel_status;
} channel_data;
typedef enum {
@@ -87,19 +84,17 @@ struct call_data {
grpc_call_element *elem;
call_state state;
- grpc_metadata_buffer pending_metadata;
gpr_timespec deadline;
union {
struct {
/* our child call stack */
grpc_child_call *child_call;
} active;
+ grpc_transport_op waiting_op;
struct {
- void (*on_complete)(void *user_data, grpc_op_error error);
- void *on_complete_user_data;
- gpr_uint32 start_flags;
- grpc_pollset *pollset;
- } waiting;
+ grpc_linked_mdelem status;
+ grpc_linked_mdelem details;
+ } cancelled;
} s;
};
@@ -113,89 +108,23 @@ static int prepare_activate(grpc_call_element *elem,
calld->state = CALL_ACTIVE;
/* create a child call */
- calld->s.active.child_call = grpc_child_channel_create_call(on_child, elem);
+ /* TODO(ctiller): pass the waiting op down here */
+ calld->s.active.child_call =
+ grpc_child_channel_create_call(on_child, elem, NULL);
return 1;
}
-static void do_nothing(void *ignored, grpc_op_error error) {}
-
-static void complete_activate(grpc_call_element *elem, grpc_call_op *op) {
+static void complete_activate(grpc_call_element *elem, grpc_transport_op *op) {
call_data *calld = elem->call_data;
grpc_call_element *child_elem =
grpc_child_call_get_top_element(calld->s.active.child_call);
GPR_ASSERT(calld->state == CALL_ACTIVE);
- /* sending buffered metadata down the stack before the start call */
- grpc_metadata_buffer_flush(&calld->pending_metadata, child_elem);
-
- if (gpr_time_cmp(calld->deadline, gpr_inf_future) != 0) {
- grpc_call_op dop;
- dop.type = GRPC_SEND_DEADLINE;
- dop.dir = GRPC_CALL_DOWN;
- dop.flags = 0;
- dop.data.deadline = calld->deadline;
- dop.done_cb = do_nothing;
- dop.user_data = NULL;
- child_elem->filter->call_op(child_elem, elem, &dop);
- }
-
/* continue the start call down the stack, this nees to happen after metadata
are flushed*/
- child_elem->filter->call_op(child_elem, elem, op);
-}
-
-static void start_rpc(grpc_call_element *elem, grpc_call_op *op) {
- call_data *calld = elem->call_data;
- channel_data *chand = elem->channel_data;
- gpr_mu_lock(&chand->mu);
- if (calld->state == CALL_CANCELLED) {
- gpr_mu_unlock(&chand->mu);
- op->done_cb(op->user_data, GRPC_OP_ERROR);
- return;
- }
- GPR_ASSERT(calld->state == CALL_CREATED);
- calld->state = CALL_WAITING;
- if (chand->active_child) {
- /* channel is connected - use the connected stack */
- if (prepare_activate(elem, chand->active_child)) {
- gpr_mu_unlock(&chand->mu);
- /* activate the request (pass it down) outside the lock */
- complete_activate(elem, op);
- } else {
- gpr_mu_unlock(&chand->mu);
- }
- } else {
- /* check to see if we should initiate a connection (if we're not already),
- but don't do so until outside the lock to avoid re-entrancy problems if
- the callback is immediate */
- int initiate_transport_setup = 0;
- if (!chand->transport_setup_initiated) {
- chand->transport_setup_initiated = 1;
- initiate_transport_setup = 1;
- }
- /* add this call to the waiting set to be resumed once we have a child
- channel stack, growing the waiting set if needed */
- if (chand->waiting_child_count == chand->waiting_child_capacity) {
- chand->waiting_child_capacity =
- GPR_MAX(chand->waiting_child_capacity * 2, 8);
- chand->waiting_children =
- gpr_realloc(chand->waiting_children,
- chand->waiting_child_capacity * sizeof(call_data *));
- }
- calld->s.waiting.on_complete = op->done_cb;
- calld->s.waiting.on_complete_user_data = op->user_data;
- calld->s.waiting.start_flags = op->flags;
- calld->s.waiting.pollset = op->data.start.pollset;
- chand->waiting_children[chand->waiting_child_count++] = calld;
- gpr_mu_unlock(&chand->mu);
-
- /* finally initiate transport setup if needed */
- if (initiate_transport_setup) {
- grpc_transport_setup_initiate(chand->transport_setup);
- }
- }
+ child_elem->filter->start_transport_op(child_elem, op);
}
static void remove_waiting_child(channel_data *chand, call_data *calld) {
@@ -210,94 +139,128 @@ static void remove_waiting_child(channel_data *chand, call_data *calld) {
chand->waiting_child_count = new_count;
}
-static void send_up_cancelled_ops(grpc_call_element *elem) {
- grpc_call_op finish_op;
+static void handle_op_after_cancellation(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
- /* send up a synthesized status */
- finish_op.type = GRPC_RECV_METADATA;
- finish_op.dir = GRPC_CALL_UP;
- finish_op.flags = 0;
- finish_op.data.metadata = grpc_mdelem_ref(chand->cancel_status);
- finish_op.done_cb = do_nothing;
- finish_op.user_data = NULL;
- grpc_call_next_op(elem, &finish_op);
- /* send up a finish */
- finish_op.type = GRPC_RECV_FINISH;
- finish_op.dir = GRPC_CALL_UP;
- finish_op.flags = 0;
- finish_op.done_cb = do_nothing;
- finish_op.user_data = NULL;
- grpc_call_next_op(elem, &finish_op);
+ if (op->send_ops) {
+ op->on_done_send(op->send_user_data, 0);
+ }
+ if (op->recv_ops) {
+ char status[GPR_LTOA_MIN_BUFSIZE];
+ grpc_metadata_batch mdb;
+ gpr_ltoa(GRPC_STATUS_CANCELLED, status);
+ calld->s.cancelled.status.md =
+ grpc_mdelem_from_strings(chand->mdctx, "grpc-status", status);
+ calld->s.cancelled.details.md =
+ grpc_mdelem_from_strings(chand->mdctx, "grpc-message", "Cancelled");
+ calld->s.cancelled.status.prev = calld->s.cancelled.details.next = NULL;
+ calld->s.cancelled.status.next = &calld->s.cancelled.details;
+ calld->s.cancelled.details.prev = &calld->s.cancelled.status;
+ mdb.list.head = &calld->s.cancelled.status;
+ mdb.list.tail = &calld->s.cancelled.details;
+ mdb.garbage.head = mdb.garbage.tail = NULL;
+ mdb.deadline = gpr_inf_future;
+ grpc_sopb_add_metadata(op->recv_ops, mdb);
+ *op->recv_state = GRPC_STREAM_CLOSED;
+ op->on_done_recv(op->recv_user_data, 1);
+ }
}
-static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) {
+static void cc_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
grpc_call_element *child_elem;
+ grpc_transport_op waiting_op;
+ GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+ GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
gpr_mu_lock(&chand->mu);
switch (calld->state) {
case CALL_ACTIVE:
child_elem = grpc_child_call_get_top_element(calld->s.active.child_call);
gpr_mu_unlock(&chand->mu);
- child_elem->filter->call_op(child_elem, elem, op);
- return; /* early out */
- case CALL_WAITING:
- remove_waiting_child(chand, calld);
- calld->state = CALL_CANCELLED;
- gpr_mu_unlock(&chand->mu);
- send_up_cancelled_ops(elem);
- calld->s.waiting.on_complete(calld->s.waiting.on_complete_user_data,
- GRPC_OP_ERROR);
- return; /* early out */
- case CALL_CREATED:
- calld->state = CALL_CANCELLED;
- gpr_mu_unlock(&chand->mu);
- send_up_cancelled_ops(elem);
- return; /* early out */
- case CALL_CANCELLED:
- gpr_mu_unlock(&chand->mu);
- return; /* early out */
- }
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
-}
-
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- call_data *calld = elem->call_data;
- GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
- GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-
- switch (op->type) {
- case GRPC_SEND_METADATA:
- grpc_metadata_buffer_queue(&calld->pending_metadata, op);
- break;
- case GRPC_SEND_DEADLINE:
- calld->deadline = op->data.deadline;
- op->done_cb(op->user_data, GRPC_OP_OK);
- break;
- case GRPC_SEND_START:
- /* filter out the start event to find which child to send on */
- start_rpc(elem, op);
+ child_elem->filter->start_transport_op(child_elem, op);
break;
- case GRPC_CANCEL_OP:
- cancel_rpc(elem, op);
+ case CALL_CREATED:
+ if (op->cancel_with_status != GRPC_STATUS_OK) {
+ calld->state = CALL_CANCELLED;
+ gpr_mu_unlock(&chand->mu);
+ handle_op_after_cancellation(elem, op);
+ } else {
+ calld->state = CALL_WAITING;
+ if (chand->active_child) {
+ /* channel is connected - use the connected stack */
+ if (prepare_activate(elem, chand->active_child)) {
+ gpr_mu_unlock(&chand->mu);
+ /* activate the request (pass it down) outside the lock */
+ complete_activate(elem, op);
+ } else {
+ gpr_mu_unlock(&chand->mu);
+ }
+ } else {
+ /* check to see if we should initiate a connection (if we're not
+ already),
+ but don't do so until outside the lock to avoid re-entrancy
+ problems if
+ the callback is immediate */
+ int initiate_transport_setup = 0;
+ if (!chand->transport_setup_initiated) {
+ chand->transport_setup_initiated = 1;
+ initiate_transport_setup = 1;
+ }
+ /* add this call to the waiting set to be resumed once we have a child
+ channel stack, growing the waiting set if needed */
+ if (chand->waiting_child_count == chand->waiting_child_capacity) {
+ chand->waiting_child_capacity =
+ GPR_MAX(chand->waiting_child_capacity * 2, 8);
+ chand->waiting_children = gpr_realloc(
+ chand->waiting_children,
+ chand->waiting_child_capacity * sizeof(call_data *));
+ }
+ calld->s.waiting_op = *op;
+ chand->waiting_children[chand->waiting_child_count++] = calld;
+ gpr_mu_unlock(&chand->mu);
+
+ /* finally initiate transport setup if needed */
+ if (initiate_transport_setup) {
+ grpc_transport_setup_initiate(chand->transport_setup);
+ }
+ }
+ }
break;
- case GRPC_SEND_MESSAGE:
- case GRPC_SEND_FINISH:
- case GRPC_REQUEST_DATA:
- if (calld->state == CALL_ACTIVE) {
- grpc_call_element *child_elem =
- grpc_child_call_get_top_element(calld->s.active.child_call);
- child_elem->filter->call_op(child_elem, elem, op);
+ case CALL_WAITING:
+ if (op->cancel_with_status != GRPC_STATUS_OK) {
+ waiting_op = calld->s.waiting_op;
+ remove_waiting_child(chand, calld);
+ calld->state = CALL_CANCELLED;
+ gpr_mu_unlock(&chand->mu);
+ handle_op_after_cancellation(elem, &waiting_op);
+ handle_op_after_cancellation(elem, op);
} else {
- op->done_cb(op->user_data, GRPC_OP_ERROR);
+ GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) !=
+ (op->send_ops == NULL));
+ GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) !=
+ (op->recv_ops == NULL));
+ if (op->send_ops) {
+ calld->s.waiting_op.send_ops = op->send_ops;
+ calld->s.waiting_op.is_last_send = op->is_last_send;
+ calld->s.waiting_op.on_done_send = op->on_done_send;
+ calld->s.waiting_op.send_user_data = op->send_user_data;
+ }
+ if (op->recv_ops) {
+ calld->s.waiting_op.recv_ops = op->recv_ops;
+ calld->s.waiting_op.recv_state = op->recv_state;
+ calld->s.waiting_op.on_done_recv = op->on_done_recv;
+ calld->s.waiting_op.recv_user_data = op->recv_user_data;
+ }
+ gpr_mu_unlock(&chand->mu);
}
break;
- default:
- GPR_ASSERT(op->dir == GRPC_CALL_UP);
- grpc_call_next_op(elem, op);
+ case CALL_CANCELLED:
+ gpr_mu_unlock(&chand->mu);
+ handle_op_after_cancellation(elem, op);
break;
}
}
@@ -382,39 +345,33 @@ static void channel_op(grpc_channel_element *elem,
}
}
-static void error_bad_on_complete(void *arg, grpc_op_error error) {
- gpr_log(GPR_ERROR,
- "Waiting finished but not started? Bad on_complete callback");
- abort();
-}
-
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
call_data *calld = elem->call_data;
+ /* TODO(ctiller): is there something useful we can do here? */
+ GPR_ASSERT(initial_op == NULL);
+
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GPR_ASSERT(server_transport_data == NULL);
calld->elem = elem;
calld->state = CALL_CREATED;
calld->deadline = gpr_inf_future;
- calld->s.waiting.on_complete = error_bad_on_complete;
- calld->s.waiting.on_complete_user_data = NULL;
- grpc_metadata_buffer_init(&calld->pending_metadata);
}
/* Destructor for call_data */
static void destroy_call_elem(grpc_call_element *elem) {
call_data *calld = elem->call_data;
- /* if the metadata buffer is not flushed, destroy it here. */
- grpc_metadata_buffer_destroy(&calld->pending_metadata, GRPC_OP_OK);
/* if the call got activated, we need to destroy the child stack also, and
remove it from the in-flight requests tracked by the child_entry we
picked */
if (calld->state == CALL_ACTIVE) {
grpc_child_call_destroy(calld->s.active.child_call);
}
+ GPR_ASSERT(calld->state != CALL_WAITING);
}
/* Constructor for channel_data */
@@ -423,7 +380,6 @@ static void init_channel_elem(grpc_channel_element *elem,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
channel_data *chand = elem->channel_data;
- char temp[GPR_LTOA_MIN_BUFSIZE];
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
@@ -437,10 +393,7 @@ static void init_channel_elem(grpc_channel_element *elem,
chand->transport_setup = NULL;
chand->transport_setup_initiated = 0;
chand->args = grpc_channel_args_copy(args);
-
- gpr_ltoa(GRPC_STATUS_CANCELLED, temp);
- chand->cancel_status =
- grpc_mdelem_from_strings(metadata_context, "grpc-status", temp);
+ chand->mdctx = metadata_context;
}
/* Destructor for channel_data */
@@ -455,7 +408,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
grpc_channel_args_destroy(chand->args);
- grpc_mdelem_unref(chand->cancel_status);
gpr_mu_destroy(&chand->mu);
GPR_ASSERT(chand->waiting_child_count == 0);
@@ -463,9 +415,10 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_client_channel_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "client-channel", };
+ cc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "client-channel",
+};
grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_stack *channel_stack, grpc_transport *transport,
@@ -481,7 +434,7 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
call_data **waiting_children;
size_t waiting_child_count;
size_t i;
- grpc_call_op *call_ops;
+ grpc_transport_op *call_ops;
/* build the child filter stack */
child_filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_child_filters);
@@ -517,19 +470,13 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
chand->waiting_child_count = 0;
chand->waiting_child_capacity = 0;
- call_ops = gpr_malloc(sizeof(grpc_call_op) * waiting_child_count);
+ call_ops = gpr_malloc(sizeof(*call_ops) * waiting_child_count);
for (i = 0; i < waiting_child_count; i++) {
- call_ops[i].type = GRPC_SEND_START;
- call_ops[i].dir = GRPC_CALL_DOWN;
- call_ops[i].flags = waiting_children[i]->s.waiting.start_flags;
- call_ops[i].done_cb = waiting_children[i]->s.waiting.on_complete;
- call_ops[i].user_data =
- waiting_children[i]->s.waiting.on_complete_user_data;
- call_ops[i].data.start.pollset = waiting_children[i]->s.waiting.pollset;
+ call_ops[i] = waiting_children[i]->s.waiting_op;
if (!prepare_activate(waiting_children[i]->elem, chand->active_child)) {
waiting_children[i] = NULL;
- call_ops[i].done_cb(call_ops[i].user_data, GRPC_OP_ERROR);
+ grpc_transport_op_finish_with_failure(&call_ops[i]);
}
}
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 62611e08f3..14dda88698 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -45,26 +45,12 @@
#include <grpc/support/slice_buffer.h>
#define MAX_BUFFER_LENGTH 8192
-/* the protobuf library will (by default) start warning at 100megs */
-#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
typedef struct connected_channel_channel_data {
grpc_transport *transport;
- gpr_uint32 max_message_length;
} channel_data;
-typedef struct connected_channel_call_data {
- grpc_call_element *elem;
- grpc_stream_op_buffer outgoing_sopb;
-
- gpr_uint32 max_message_length;
- gpr_uint32 incoming_message_length;
- gpr_uint8 reading_message;
- gpr_uint8 got_metadata_boundary;
- gpr_uint8 got_read_close;
- gpr_slice_buffer incoming_message;
- gpr_uint32 outgoing_buffer_length_estimate;
-} call_data;
+typedef struct connected_channel_call_data { void *unused; } call_data;
/* We perform a small hack to locate transport data alongside the connected
channel data in call allocations, to allow everything to be pulled in minimal
@@ -73,98 +59,17 @@ typedef struct connected_channel_call_data {
#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
(((call_data *)(transport_stream)) - 1)
-/* Copy the contents of a byte buffer into stream ops */
-static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
- grpc_stream_op_buffer *sopb) {
- size_t i;
-
- switch (byte_buffer->type) {
- case GRPC_BB_SLICE_BUFFER:
- for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
- gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
- gpr_slice_ref(slice);
- grpc_sopb_add_slice(sopb, slice);
- }
- break;
- }
-}
-
-/* Flush queued stream operations onto the transport */
-static void end_bufferable_op(grpc_call_op *op, channel_data *chand,
- call_data *calld, int is_last) {
- size_t nops;
-
- if (op->flags & GRPC_WRITE_BUFFER_HINT) {
- if (calld->outgoing_buffer_length_estimate < MAX_BUFFER_LENGTH) {
- op->done_cb(op->user_data, GRPC_OP_OK);
- return;
- }
- }
-
- calld->outgoing_buffer_length_estimate = 0;
- grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb, op->user_data);
-
- nops = calld->outgoing_sopb.nops;
- calld->outgoing_sopb.nops = 0;
- grpc_transport_send_batch(chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- calld->outgoing_sopb.ops, nops, is_last);
-}
-
/* Intercept a call operation and either push it directly up or translate it
into transport stream operations */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
+static void con_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- switch (op->type) {
- case GRPC_SEND_METADATA:
- grpc_sopb_add_metadata(&calld->outgoing_sopb, op->data.metadata);
- grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
- op->user_data);
- break;
- case GRPC_SEND_DEADLINE:
- grpc_sopb_add_deadline(&calld->outgoing_sopb, op->data.deadline);
- grpc_sopb_add_flow_ctl_cb(&calld->outgoing_sopb, op->done_cb,
- op->user_data);
- break;
- case GRPC_SEND_START:
- grpc_transport_add_to_pollset(chand->transport, op->data.start.pollset);
- grpc_sopb_add_metadata_boundary(&calld->outgoing_sopb);
- end_bufferable_op(op, chand, calld, 0);
- break;
- case GRPC_SEND_MESSAGE:
- grpc_sopb_add_begin_message(&calld->outgoing_sopb,
- grpc_byte_buffer_length(op->data.message),
- op->flags);
- /* fall-through */
- case GRPC_SEND_PREFORMATTED_MESSAGE:
- copy_byte_buffer_to_stream_ops(op->data.message, &calld->outgoing_sopb);
- calld->outgoing_buffer_length_estimate +=
- (5 + grpc_byte_buffer_length(op->data.message));
- end_bufferable_op(op, chand, calld, 0);
- break;
- case GRPC_SEND_FINISH:
- end_bufferable_op(op, chand, calld, 1);
- break;
- case GRPC_REQUEST_DATA:
- /* re-arm window updates if they were disarmed by finish_message */
- grpc_transport_set_allow_window_updates(
- chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 1);
- break;
- case GRPC_CANCEL_OP:
- grpc_transport_abort_stream(chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- GRPC_STATUS_CANCELLED);
- break;
- default:
- GPR_ASSERT(op->dir == GRPC_CALL_UP);
- grpc_call_next_op(elem, op);
- break;
- }
+ grpc_transport_perform_op(chand->transport,
+ TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
}
/* Currently we assume all channel operations should just be pushed up. */
@@ -190,24 +95,16 @@ static void channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
int r;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
- calld->elem = elem;
- grpc_sopb_init(&calld->outgoing_sopb);
-
- calld->reading_message = 0;
- calld->got_metadata_boundary = 0;
- calld->got_read_close = 0;
- calld->outgoing_buffer_length_estimate = 0;
- calld->max_message_length = chand->max_message_length;
- gpr_slice_buffer_init(&calld->incoming_message);
r = grpc_transport_init_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- server_transport_data);
+ server_transport_data, initial_op);
GPR_ASSERT(r == 0);
}
@@ -216,8 +113,6 @@ static void destroy_call_elem(grpc_call_element *elem) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
- grpc_sopb_destroy(&calld->outgoing_sopb);
- gpr_slice_buffer_destroy(&calld->incoming_message);
grpc_transport_destroy_stream(chand->transport,
TRANSPORT_STREAM_FROM_CALL_DATA(calld));
}
@@ -227,28 +122,10 @@ static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
channel_data *cd = (channel_data *)elem->channel_data;
- size_t i;
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
cd->transport = NULL;
-
- cd->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
- if (args) {
- for (i = 0; i < args->num_args; i++) {
- if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
- if (args->args[i].type != GRPC_ARG_INTEGER) {
- gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
- GRPC_ARG_MAX_MESSAGE_LENGTH);
- } else if (args->args[i].value.integer < 0) {
- gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
- GRPC_ARG_MAX_MESSAGE_LENGTH);
- } else {
- cd->max_message_length = args->args[i].value.integer;
- }
- }
- }
- }
}
/* Destructor for channel_data */
@@ -259,14 +136,10 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_connected_channel_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "connected", };
-
-static gpr_slice alloc_recv_buffer(void *user_data, grpc_transport *transport,
- grpc_stream *stream, size_t size_hint) {
- return gpr_slice_malloc(size_hint);
-}
+ con_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "connected",
+};
/* Transport callback to accept a new stream... calls up to handle it */
static void accept_stream(void *user_data, grpc_transport *transport,
@@ -285,183 +158,6 @@ static void accept_stream(void *user_data, grpc_transport *transport,
channel_op(elem, NULL, &op);
}
-static void recv_error(channel_data *chand, call_data *calld, int line,
- const char *message) {
- gpr_log_message(__FILE__, line, GPR_LOG_SEVERITY_ERROR, message);
-
- if (chand->transport) {
- grpc_transport_abort_stream(chand->transport,
- TRANSPORT_STREAM_FROM_CALL_DATA(calld),
- GRPC_STATUS_INVALID_ARGUMENT);
- }
-}
-
-static void do_nothing(void *calldata, grpc_op_error error) {}
-
-static void finish_message(channel_data *chand, call_data *calld) {
- grpc_call_element *elem = calld->elem;
- grpc_call_op call_op;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- /* if we got all the bytes for this message, call up the stack */
- call_op.type = GRPC_RECV_MESSAGE;
- call_op.done_cb = do_nothing;
- /* TODO(ctiller): this could be a lot faster if coded directly */
- call_op.data.message = grpc_byte_buffer_create(
- calld->incoming_message.slices, calld->incoming_message.count);
- gpr_slice_buffer_reset_and_unref(&calld->incoming_message);
-
- /* disable window updates until we get a request more from above */
- grpc_transport_set_allow_window_updates(
- chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), 0);
-
- GPR_ASSERT(calld->incoming_message.count == 0);
- calld->reading_message = 0;
- grpc_call_next_op(elem, &call_op);
-}
-
-/* Handle incoming stream ops from the transport, translating them into
- call_ops to pass up the call stack */
-static void recv_batch(void *user_data, grpc_transport *transport,
- grpc_stream *stream, grpc_stream_op *ops,
- size_t ops_count, grpc_stream_state final_state) {
- call_data *calld = CALL_DATA_FROM_TRANSPORT_STREAM(stream);
- grpc_call_element *elem = calld->elem;
- channel_data *chand = elem->channel_data;
- grpc_stream_op *stream_op;
- grpc_call_op call_op;
- size_t i;
- gpr_uint32 length;
-
- GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-
- for (i = 0; i < ops_count; i++) {
- stream_op = ops + i;
- switch (stream_op->type) {
- case GRPC_OP_FLOW_CTL_CB:
- gpr_log(GPR_ERROR,
- "should not receive flow control ops from transport");
- abort();
- break;
- case GRPC_NO_OP:
- break;
- case GRPC_OP_METADATA:
- call_op.type = GRPC_RECV_METADATA;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- call_op.data.metadata = stream_op->data.metadata;
- call_op.done_cb = do_nothing;
- call_op.user_data = NULL;
- grpc_call_next_op(elem, &call_op);
- break;
- case GRPC_OP_DEADLINE:
- call_op.type = GRPC_RECV_DEADLINE;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- call_op.data.deadline = stream_op->data.deadline;
- call_op.done_cb = do_nothing;
- call_op.user_data = NULL;
- grpc_call_next_op(elem, &call_op);
- break;
- case GRPC_OP_METADATA_BOUNDARY:
- if (!calld->got_metadata_boundary) {
- calld->got_metadata_boundary = 1;
- call_op.type = GRPC_RECV_END_OF_INITIAL_METADATA;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- call_op.done_cb = do_nothing;
- call_op.user_data = NULL;
- grpc_call_next_op(elem, &call_op);
- }
- break;
- case GRPC_OP_BEGIN_MESSAGE:
- /* can't begin a message when we're still reading a message */
- if (calld->reading_message) {
- char *message = NULL;
- gpr_asprintf(&message,
- "Message terminated early; read %d bytes, expected %d",
- (int)calld->incoming_message.length,
- (int)calld->incoming_message_length);
- recv_error(chand, calld, __LINE__, message);
- gpr_free(message);
- return;
- }
- /* stash away parameters, and prepare for incoming slices */
- length = stream_op->data.begin_message.length;
- if (length > calld->max_message_length) {
- char *message = NULL;
- gpr_asprintf(
- &message,
- "Maximum message length of %d exceeded by a message of length %d",
- calld->max_message_length, length);
- recv_error(chand, calld, __LINE__, message);
- gpr_free(message);
- } else if (length > 0) {
- calld->reading_message = 1;
- calld->incoming_message_length = length;
- } else {
- finish_message(chand, calld);
- }
- break;
- case GRPC_OP_SLICE:
- if (GPR_SLICE_LENGTH(stream_op->data.slice) == 0) {
- gpr_slice_unref(stream_op->data.slice);
- break;
- }
- /* we have to be reading a message to know what to do here */
- if (!calld->reading_message) {
- recv_error(chand, calld, __LINE__,
- "Received payload data while not reading a message");
- return;
- }
- /* append the slice to the incoming buffer */
- gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
- if (calld->incoming_message.length > calld->incoming_message_length) {
- /* if we got too many bytes, complain */
- char *message = NULL;
- gpr_asprintf(&message,
- "Receiving message overflow; read %d bytes, expected %d",
- (int)calld->incoming_message.length,
- (int)calld->incoming_message_length);
- recv_error(chand, calld, __LINE__, message);
- gpr_free(message);
- return;
- } else if (calld->incoming_message.length ==
- calld->incoming_message_length) {
- finish_message(chand, calld);
- }
- }
- }
- /* if the stream closed, then call up the stack to let it know */
- if (!calld->got_read_close && (final_state == GRPC_STREAM_RECV_CLOSED ||
- final_state == GRPC_STREAM_CLOSED)) {
- calld->got_read_close = 1;
- if (calld->reading_message) {
- char *message = NULL;
- gpr_asprintf(&message,
- "Last message truncated; read %d bytes, expected %d",
- (int)calld->incoming_message.length,
- (int)calld->incoming_message_length);
- recv_error(chand, calld, __LINE__, message);
- gpr_free(message);
- }
- call_op.type = GRPC_RECV_HALF_CLOSE;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- call_op.done_cb = do_nothing;
- call_op.user_data = NULL;
- grpc_call_next_op(elem, &call_op);
- }
- if (final_state == GRPC_STREAM_CLOSED) {
- call_op.type = GRPC_RECV_FINISH;
- call_op.dir = GRPC_CALL_UP;
- call_op.flags = 0;
- call_op.done_cb = do_nothing;
- call_op.user_data = NULL;
- grpc_call_next_op(elem, &call_op);
- }
-}
-
static void transport_goaway(void *user_data, grpc_transport *transport,
grpc_status_code status, gpr_slice debug) {
/* transport got goaway ==> call up and handle it */
@@ -494,8 +190,8 @@ static void transport_closed(void *user_data, grpc_transport *transport) {
}
const grpc_transport_callbacks connected_channel_transport_callbacks = {
- alloc_recv_buffer, accept_stream, recv_batch,
- transport_goaway, transport_closed, };
+ accept_stream, transport_goaway, transport_closed,
+};
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport) {
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 3ccc39b717..9805f325a6 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -35,7 +35,16 @@
#include <grpc/support/log.h>
typedef struct call_data {
- int sent_headers;
+ grpc_linked_mdelem method;
+ grpc_linked_mdelem scheme;
+ grpc_linked_mdelem te_trailers;
+ grpc_linked_mdelem content_type;
+ int sent_initial_metadata;
+
+ int got_initial_metadata;
+ grpc_stream_op_buffer *recv_ops;
+ void (*on_done_recv)(void *user_data, int success);
+ void *recv_user_data;
} call_data;
typedef struct channel_data {
@@ -49,62 +58,78 @@ typedef struct channel_data {
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
-/* Called either:
- - in response to an API call (or similar) from above, to send something
- - a network event (or similar) from below, to receive something
- op contains type and call direction information, in addition to the data
- that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
+static grpc_mdelem *client_filter(void *user_data, grpc_mdelem *md) {
+ grpc_call_element *elem = user_data;
channel_data *channeld = elem->channel_data;
- GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+ if (md == channeld->status) {
+ return NULL;
+ } else if (md->key == channeld->status->key) {
+ grpc_call_element_send_cancel(elem);
+ return NULL;
+ }
+ return md;
+}
- ignore_unused(calld);
+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);
+ }
+ }
+ calld->on_done_recv(calld->recv_user_data, success);
+}
- switch (op->type) {
- case GRPC_SEND_METADATA:
- if (!calld->sent_headers) {
- /* Send : prefixed headers, which have to be before any application
- * layer headers. */
- calld->sent_headers = 1;
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method));
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme));
- }
- grpc_call_next_op(elem, op);
- break;
- case GRPC_SEND_START:
- if (!calld->sent_headers) {
- /* Send : prefixed headers, if we haven't already */
- calld->sent_headers = 1;
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->method));
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->scheme));
- }
- /* Send non : prefixed headers */
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->te_trailers));
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(channeld->content_type));
- grpc_call_next_op(elem, op);
- break;
- case GRPC_RECV_METADATA:
- if (op->data.metadata == channeld->status) {
- grpc_mdelem_unref(op->data.metadata);
- op->done_cb(op->user_data, GRPC_OP_OK);
- } else if (op->data.metadata->key == channeld->status->key) {
- grpc_mdelem_unref(op->data.metadata);
- op->done_cb(op->user_data, GRPC_OP_OK);
- grpc_call_element_send_cancel(elem);
- } else {
- grpc_call_next_op(elem, op);
- }
- break;
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_call_next_op(elem, op);
+static void hc_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+ /* grab pointers to our data from the call element */
+ call_data *calld = elem->call_data;
+ channel_data *channeld = elem->channel_data;
+ size_t i;
+ if (op->send_ops && !calld->sent_initial_metadata) {
+ size_t nops = op->send_ops->nops;
+ grpc_stream_op *ops = op->send_ops->ops;
+ for (i = 0; i < nops; i++) {
+ grpc_stream_op *op = &ops[i];
+ if (op->type != GRPC_OP_METADATA) continue;
+ calld->sent_initial_metadata = 1;
+ /* Send : prefixed headers, which have to be before any application
+ layer headers. */
+ grpc_metadata_batch_add_head(&op->data.metadata, &calld->method,
+ grpc_mdelem_ref(channeld->method));
+ grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme,
+ grpc_mdelem_ref(channeld->scheme));
+ grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers,
+ grpc_mdelem_ref(channeld->te_trailers));
+ grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type,
+ grpc_mdelem_ref(channeld->content_type));
break;
+ }
+ }
+
+ if (op->recv_ops && !calld->got_initial_metadata) {
+ /* substitute our callback for the higher callback */
+ calld->recv_ops = op->recv_ops;
+ calld->on_done_recv = op->on_done_recv;
+ calld->recv_user_data = op->recv_user_data;
+ op->on_done_recv = hc_on_recv;
+ op->recv_user_data = elem;
}
}
+static void hc_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+ hc_mutate_op(elem, op);
+ grpc_call_next_op(elem, op);
+}
+
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
@@ -124,15 +149,12 @@ static void channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
- /* grab pointers to our data from the call element */
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-
- /* initialize members */
- calld->sent_headers = 0;
+ calld->sent_initial_metadata = 0;
+ calld->got_initial_metadata = 0;
+ if (initial_op) hc_mutate_op(elem, initial_op);
}
/* Destructor for call_data */
@@ -194,6 +216,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_http_client_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "http-client"};
+ hc_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "http-client"};
diff --git a/src/core/channel/http_filter.c b/src/core/channel/http_filter.c
deleted file mode 100644
index 453a0422d8..0000000000
--- a/src/core/channel/http_filter.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/http_filter.h"
-#include <grpc/support/log.h>
-
-typedef struct call_data {
- int unused; /* C89 requires at least one struct element */
-} call_data;
-
-typedef struct channel_data {
- int unused; /* C89 requires at least one struct element */
-} channel_data;
-
-/* used to silence 'variable not used' warnings */
-static void ignore_unused(void *ignored) {}
-
-/* Called either:
- - in response to an API call (or similar) from above, to send something
- - a network event (or similar) from below, to receive something
- op contains type and call direction information, in addition to the data
- that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
- GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-
- ignore_unused(calld);
- ignore_unused(channeld);
-
- switch (op->type) {
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_call_next_op(elem, op);
- break;
- }
-}
-
-/* Called on special channel events, such as disconnection or new incoming
- calls on the server */
-static void channel_op(grpc_channel_element *elem,
- grpc_channel_element *from_elem, grpc_channel_op *op) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-
- switch (op->type) {
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_channel_next_op(elem, op);
- break;
- }
-}
-
-/* Constructor for call_data */
-static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- /* initialize members */
- calld->unused = channeld->unused;
-}
-
-/* Destructor for call_data */
-static void destroy_call_elem(grpc_call_element *elem) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(calld);
- ignore_unused(channeld);
-}
-
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_channel_element *elem,
- const grpc_channel_args *args, grpc_mdctx *mdctx,
- int is_first, int is_last) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- /* The first and the last filters tend to be implemented differently to
- handle the case that there's no 'next' filter to call on the up or down
- path */
- GPR_ASSERT(!is_first);
- GPR_ASSERT(!is_last);
-
- /* initialize members */
- channeld->unused = 0;
-}
-
-/* Destructor for channel data */
-static void destroy_channel_elem(grpc_channel_element *elem) {
- /* grab pointers to our data from the channel element */
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-}
-
-const grpc_channel_filter grpc_http_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "http"};
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index f565cbf3ae..1f64df68e3 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -38,25 +38,22 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-typedef enum { NOT_RECEIVED, POST, GET } known_method_type;
-
-typedef struct {
- grpc_mdelem *path;
- grpc_mdelem *content_type;
- grpc_byte_buffer *content;
-} gettable;
-
typedef struct call_data {
- known_method_type seen_method;
+ gpr_uint8 got_initial_metadata;
+ gpr_uint8 seen_path;
+ gpr_uint8 seen_post;
gpr_uint8 sent_status;
gpr_uint8 seen_scheme;
gpr_uint8 seen_te_trailers;
- grpc_mdelem *path;
+ grpc_linked_mdelem status;
+
+ grpc_stream_op_buffer *recv_ops;
+ void (*on_done_recv)(void *user_data, int success);
+ void *recv_user_data;
} call_data;
typedef struct channel_data {
grpc_mdelem *te_trailers;
- grpc_mdelem *method_get;
grpc_mdelem *method_post;
grpc_mdelem *http_scheme;
grpc_mdelem *https_scheme;
@@ -70,148 +67,100 @@ typedef struct channel_data {
grpc_mdstr *host_key;
grpc_mdctx *mdctx;
-
- size_t gettable_count;
- gettable *gettables;
} channel_data;
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
-/* Handle 'GET': not technically grpc, so probably a web browser hitting
- us */
-static void payload_done(void *elem, grpc_op_error error) {
- if (error == GRPC_OP_OK) {
- grpc_call_element_send_finish(elem);
- }
-}
-
-static void handle_get(grpc_call_element *elem) {
+static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
+ grpc_call_element *elem = user_data;
channel_data *channeld = elem->channel_data;
call_data *calld = elem->call_data;
- grpc_call_op op;
- size_t i;
- for (i = 0; i < channeld->gettable_count; i++) {
- if (channeld->gettables[i].path == calld->path) {
- grpc_call_element_send_metadata(elem,
- grpc_mdelem_ref(channeld->status_ok));
- grpc_call_element_send_metadata(
- elem, grpc_mdelem_ref(channeld->gettables[i].content_type));
- op.type = GRPC_SEND_PREFORMATTED_MESSAGE;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.data.message = channeld->gettables[i].content;
- op.done_cb = payload_done;
- op.user_data = elem;
- grpc_call_next_op(elem, &op);
+ /* Check if it is one of the headers we care about. */
+ if (md == channeld->te_trailers || md == channeld->method_post ||
+ md == channeld->http_scheme || md == channeld->https_scheme ||
+ md == channeld->grpc_scheme || md == channeld->content_type) {
+ /* swallow it */
+ if (md == channeld->method_post) {
+ calld->seen_post = 1;
+ } else if (md->key == channeld->http_scheme->key) {
+ calld->seen_scheme = 1;
+ } else if (md == channeld->te_trailers) {
+ calld->seen_te_trailers = 1;
}
+ /* TODO(klempner): Track that we've seen all the headers we should
+ require */
+ return NULL;
+ } else if (md->key == channeld->content_type->key) {
+ if (strncmp(grpc_mdstr_as_c_string(md->value), "application/grpc+", 17) ==
+ 0) {
+ /* Although the C implementation doesn't (currently) generate them,
+ any custom +-suffix is explicitly valid. */
+ /* TODO(klempner): We should consider preallocating common values such
+ as +proto or +json, or at least stashing them if we see them. */
+ /* TODO(klempner): Should we be surfacing this to application code? */
+ } else {
+ /* TODO(klempner): We're currently allowing this, but we shouldn't
+ see it without a proxy so log for now. */
+ gpr_log(GPR_INFO, "Unexpected content-type %s",
+ channeld->content_type->key);
+ }
+ return NULL;
+ } else if (md->key == channeld->te_trailers->key ||
+ md->key == channeld->method_post->key ||
+ md->key == channeld->http_scheme->key ||
+ md->key == channeld->content_type->key) {
+ gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
+ grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
+ /* swallow it and error everything out. */
+ /* TODO(klempner): We ought to generate more descriptive error messages
+ on the wire here. */
+ grpc_call_element_send_cancel(elem);
+ return NULL;
+ } else if (md->key == channeld->path_key) {
+ if (calld->seen_path) {
+ gpr_log(GPR_ERROR, "Received :path twice");
+ return NULL;
+ }
+ calld->seen_path = 1;
+ return md;
+ } else if (md->key == channeld->host_key) {
+ /* translate host to :authority since :authority may be
+ omitted */
+ grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
+ channeld->mdctx, grpc_mdstr_ref(channeld->authority_key),
+ grpc_mdstr_ref(md->value));
+ grpc_mdelem_unref(md);
+ return authority;
+ } else {
+ return md;
}
- grpc_call_element_send_metadata(elem,
- grpc_mdelem_ref(channeld->status_not_found));
- grpc_call_element_send_finish(elem);
}
-/* Called either:
- - in response to an API call (or similar) from above, to send something
- - a network event (or similar) from below, to receive something
- op contains type and call direction information, in addition to the data
- that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- /* grab pointers to our data from the call element */
+static void hs_on_recv(void *user_data, int success) {
+ grpc_call_element *elem = user_data;
call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
- GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-
- switch (op->type) {
- case GRPC_RECV_METADATA:
- /* Check if it is one of the headers we care about. */
- if (op->data.metadata == channeld->te_trailers ||
- op->data.metadata == channeld->method_get ||
- op->data.metadata == channeld->method_post ||
- op->data.metadata == channeld->http_scheme ||
- op->data.metadata == channeld->https_scheme ||
- op->data.metadata == channeld->grpc_scheme ||
- op->data.metadata == channeld->content_type) {
- /* swallow it */
- if (op->data.metadata == channeld->method_get) {
- calld->seen_method = GET;
- } else if (op->data.metadata == channeld->method_post) {
- calld->seen_method = POST;
- } else if (op->data.metadata->key == channeld->http_scheme->key) {
- calld->seen_scheme = 1;
- } else if (op->data.metadata == channeld->te_trailers) {
- calld->seen_te_trailers = 1;
- }
- /* TODO(klempner): Track that we've seen all the headers we should
- require */
- grpc_mdelem_unref(op->data.metadata);
- op->done_cb(op->user_data, GRPC_OP_OK);
- } else if (op->data.metadata->key == channeld->content_type->key) {
- if (strncmp(grpc_mdstr_as_c_string(op->data.metadata->value),
- "application/grpc+", 17) == 0) {
- /* Although the C implementation doesn't (currently) generate them,
- any
- custom +-suffix is explicitly valid. */
- /* TODO(klempner): We should consider preallocating common values such
- as +proto or +json, or at least stashing them if we see them. */
- /* TODO(klempner): Should we be surfacing this to application code? */
- } else {
- /* TODO(klempner): We're currently allowing this, but we shouldn't
- see it without a proxy so log for now. */
- gpr_log(GPR_INFO, "Unexpected content-type %s",
- channeld->content_type->key);
- }
- grpc_mdelem_unref(op->data.metadata);
- op->done_cb(op->user_data, GRPC_OP_OK);
- } else if (op->data.metadata->key == channeld->te_trailers->key ||
- op->data.metadata->key == channeld->method_post->key ||
- op->data.metadata->key == channeld->http_scheme->key ||
- op->data.metadata->key == channeld->content_type->key) {
- gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
- grpc_mdstr_as_c_string(op->data.metadata->key),
- grpc_mdstr_as_c_string(op->data.metadata->value));
- /* swallow it and error everything out. */
- /* TODO(klempner): We ought to generate more descriptive error messages
- on the wire here. */
- grpc_mdelem_unref(op->data.metadata);
- op->done_cb(op->user_data, GRPC_OP_OK);
- grpc_call_element_send_cancel(elem);
- } else if (op->data.metadata->key == channeld->path_key) {
- if (calld->path != NULL) {
- gpr_log(GPR_ERROR, "Received :path twice");
- grpc_mdelem_unref(calld->path);
- }
- calld->path = op->data.metadata;
- op->done_cb(op->user_data, GRPC_OP_OK);
- } else if (op->data.metadata->key == channeld->host_key) {
- /* translate host to :authority since :authority may be
- omitted */
- grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
- channeld->mdctx, channeld->authority_key, op->data.metadata->value);
- grpc_mdelem_unref(op->data.metadata);
- op->data.metadata = authority;
- /* pass the event up */
- grpc_call_next_op(elem, op);
- } else {
- /* pass the event up */
- grpc_call_next_op(elem, op);
- }
- break;
- case GRPC_RECV_END_OF_INITIAL_METADATA:
+ 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, server_filter, elem);
/* Have we seen the required http2 transport headers?
(:method, :scheme, content-type, with :path and :authority covered
at the channel level right now) */
- if (calld->seen_method == POST && calld->seen_scheme &&
- calld->seen_te_trailers && calld->path) {
- grpc_call_element_recv_metadata(elem, calld->path);
- calld->path = NULL;
- grpc_call_next_op(elem, op);
- } else if (calld->seen_method == GET) {
- handle_get(elem);
+ if (calld->seen_post && calld->seen_scheme && calld->seen_te_trailers &&
+ calld->seen_path) {
+ /* do nothing */
} else {
- if (calld->seen_method == NOT_RECEIVED) {
+ if (!calld->seen_path) {
+ gpr_log(GPR_ERROR, "Missing :path header");
+ }
+ if (!calld->seen_post) {
gpr_log(GPR_ERROR, "Missing :method header");
}
if (!calld->seen_scheme) {
@@ -221,29 +170,50 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
gpr_log(GPR_ERROR, "Missing te trailers header");
}
/* Error this call out */
- op->done_cb(op->user_data, GRPC_OP_OK);
+ success = 0;
grpc_call_element_send_cancel(elem);
}
+ }
+ }
+ calld->on_done_recv(calld->recv_user_data, success);
+}
+
+static void hs_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+ /* grab pointers to our data from the call element */
+ call_data *calld = elem->call_data;
+ channel_data *channeld = elem->channel_data;
+ size_t i;
+
+ if (op->send_ops && !calld->sent_status) {
+ size_t nops = op->send_ops->nops;
+ grpc_stream_op *ops = op->send_ops->ops;
+ for (i = 0; i < nops; i++) {
+ grpc_stream_op *op = &ops[i];
+ if (op->type != GRPC_OP_METADATA) continue;
+ calld->sent_status = 1;
+ grpc_metadata_batch_add_head(&op->data.metadata, &calld->status,
+ grpc_mdelem_ref(channeld->status_ok));
break;
- case GRPC_SEND_START:
- case GRPC_SEND_METADATA:
- /* If we haven't sent status 200 yet, we need to so so because it needs to
- come before any non : prefixed metadata. */
- if (!calld->sent_status) {
- calld->sent_status = 1;
- /* status is reffed by grpc_call_element_send_metadata */
- grpc_call_element_send_metadata(elem,
- grpc_mdelem_ref(channeld->status_ok));
- }
- grpc_call_next_op(elem, op);
- break;
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_call_next_op(elem, op);
- break;
+ }
+ }
+
+ if (op->recv_ops && !calld->got_initial_metadata) {
+ /* substitute our callback for the higher callback */
+ calld->recv_ops = op->recv_ops;
+ calld->on_done_recv = op->on_done_recv;
+ calld->recv_user_data = op->recv_user_data;
+ op->on_done_recv = hs_on_recv;
+ op->recv_user_data = elem;
}
}
+static void hs_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+ hs_mutate_op(elem, op);
+ grpc_call_next_op(elem, op);
+}
+
/* Called on special channel events, such as disconnection or new incoming
calls on the server */
static void channel_op(grpc_channel_element *elem,
@@ -263,41 +233,22 @@ static void channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-
/* initialize members */
- calld->path = NULL;
- calld->sent_status = 0;
- calld->seen_scheme = 0;
- calld->seen_method = NOT_RECEIVED;
- calld->seen_te_trailers = 0;
+ memset(calld, 0, sizeof(*calld));
+ if (initial_op) hs_mutate_op(elem, initial_op);
}
/* Destructor for call_data */
-static void destroy_call_elem(grpc_call_element *elem) {
- /* grab pointers to our data from the call element */
- call_data *calld = elem->call_data;
- channel_data *channeld = elem->channel_data;
-
- ignore_unused(channeld);
-
- if (calld->path) {
- grpc_mdelem_unref(calld->path);
- }
-}
+static void destroy_call_elem(grpc_call_element *elem) {}
/* Constructor for channel_data */
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
- size_t i;
- size_t gettable_capacity = 0;
-
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
@@ -313,7 +264,6 @@ static void init_channel_elem(grpc_channel_element *elem,
channeld->status_not_found =
grpc_mdelem_from_strings(mdctx, ":status", "404");
channeld->method_post = grpc_mdelem_from_strings(mdctx, ":method", "POST");
- channeld->method_get = grpc_mdelem_from_strings(mdctx, ":method", "GET");
channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
@@ -324,51 +274,17 @@ static void init_channel_elem(grpc_channel_element *elem,
grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
channeld->mdctx = mdctx;
-
- /* initialize http download support */
- channeld->gettable_count = 0;
- channeld->gettables = NULL;
- for (i = 0; i < args->num_args; i++) {
- if (0 == strcmp(args->args[i].key, GRPC_ARG_SERVE_OVER_HTTP)) {
- gettable *g;
- gpr_slice slice;
- grpc_http_server_page *p = args->args[i].value.pointer.p;
- if (channeld->gettable_count == gettable_capacity) {
- gettable_capacity =
- GPR_MAX(gettable_capacity * 3 / 2, gettable_capacity + 1);
- channeld->gettables = gpr_realloc(channeld->gettables,
- gettable_capacity * sizeof(gettable));
- }
- g = &channeld->gettables[channeld->gettable_count++];
- g->path = grpc_mdelem_from_strings(mdctx, ":path", p->path);
- g->content_type =
- grpc_mdelem_from_strings(mdctx, "content-type", p->content_type);
- slice = gpr_slice_from_copied_string(p->content);
- g->content = grpc_byte_buffer_create(&slice, 1);
- gpr_slice_unref(slice);
- }
- }
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
- size_t i;
-
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
- for (i = 0; i < channeld->gettable_count; i++) {
- grpc_mdelem_unref(channeld->gettables[i].path);
- grpc_mdelem_unref(channeld->gettables[i].content_type);
- grpc_byte_buffer_destroy(channeld->gettables[i].content);
- }
- gpr_free(channeld->gettables);
-
grpc_mdelem_unref(channeld->te_trailers);
grpc_mdelem_unref(channeld->status_ok);
grpc_mdelem_unref(channeld->status_not_found);
grpc_mdelem_unref(channeld->method_post);
- grpc_mdelem_unref(channeld->method_get);
grpc_mdelem_unref(channeld->http_scheme);
grpc_mdelem_unref(channeld->https_scheme);
grpc_mdelem_unref(channeld->grpc_scheme);
@@ -379,6 +295,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_http_server_filter = {
- call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
- sizeof(channel_data), init_channel_elem, destroy_channel_elem,
- "http-server"};
+ hs_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "http-server"};
diff --git a/src/core/channel/metadata_buffer.c b/src/core/channel/metadata_buffer.c
deleted file mode 100644
index eac852e4a4..0000000000
--- a/src/core/channel/metadata_buffer.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/channel/metadata_buffer.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-#include <string.h>
-
-#define INITIAL_ELEM_CAP 8
-
-/* One queued call; we track offsets to string data in a shared buffer to
- reduce allocations. See grpc_metadata_buffer_impl for the memory use
- strategy */
-typedef struct {
- grpc_mdelem *md;
- void (*cb)(void *user_data, grpc_op_error error);
- void *user_data;
- gpr_uint32 flags;
-} qelem;
-
-/* Memory layout:
-
- grpc_metadata_buffer_impl
- followed by an array of qelem */
-struct grpc_metadata_buffer_impl {
- /* number of elements in q */
- size_t elems;
- /* capacity of q */
- size_t elem_cap;
-};
-
-#define ELEMS(buffer) ((qelem *)((buffer) + 1))
-
-void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) {
- /* start buffer as NULL, indicating no elements */
- *buffer = NULL;
-}
-
-void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
- grpc_op_error error) {
- size_t i;
- qelem *qe;
- if (*buffer) {
- for (i = 0; i < (*buffer)->elems; i++) {
- qe = &ELEMS(*buffer)[i];
- grpc_mdelem_unref(qe->md);
- qe->cb(qe->user_data, error);
- }
- gpr_free(*buffer);
- }
-}
-
-void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer,
- grpc_call_op *op) {
- grpc_metadata_buffer_impl *impl = *buffer;
- qelem *qe;
- size_t bytes;
-
- GPR_ASSERT(op->type == GRPC_SEND_METADATA || op->type == GRPC_RECV_METADATA);
-
- if (!impl) {
- /* this is the first element: allocate enough space to hold the
- header object and the initial element capacity of qelems */
- bytes =
- sizeof(grpc_metadata_buffer_impl) + INITIAL_ELEM_CAP * sizeof(qelem);
- impl = gpr_malloc(bytes);
- /* initialize the header object */
- impl->elems = 0;
- impl->elem_cap = INITIAL_ELEM_CAP;
- } else if (impl->elems == impl->elem_cap) {
- /* more qelems than what we can deal with: grow by doubling size */
- impl->elem_cap *= 2;
- bytes = sizeof(grpc_metadata_buffer_impl) + impl->elem_cap * sizeof(qelem);
- impl = gpr_realloc(impl, bytes);
- }
-
- /* append an element to the queue */
- qe = &ELEMS(impl)[impl->elems];
- impl->elems++;
-
- qe->md = op->data.metadata;
- qe->cb = op->done_cb;
- qe->user_data = op->user_data;
- qe->flags = op->flags;
-
- /* header object may have changed location: store it back */
- *buffer = impl;
-}
-
-void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
- grpc_call_element *elem) {
- grpc_metadata_buffer_impl *impl = *buffer;
- grpc_call_op op;
- qelem *qe;
- size_t i;
-
- if (!impl) {
- /* nothing to send */
- return;
- }
-
- /* construct call_op's, and push them down the stack */
- op.type = GRPC_SEND_METADATA;
- op.dir = GRPC_CALL_DOWN;
- for (i = 0; i < impl->elems; i++) {
- qe = &ELEMS(impl)[i];
- op.done_cb = qe->cb;
- op.user_data = qe->user_data;
- op.flags = qe->flags;
- op.data.metadata = qe->md;
- grpc_call_next_op(elem, &op);
- }
-
- /* free data structures and reset to NULL: we can only flush once */
- gpr_free(impl);
- *buffer = NULL;
-}
diff --git a/src/core/channel/metadata_buffer.h b/src/core/channel/metadata_buffer.h
deleted file mode 100644
index b7cc5170d1..0000000000
--- a/src/core/channel/metadata_buffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H
-
-#include "src/core/channel/channel_stack.h"
-
-/* Utility code to buffer GRPC_SEND_METADATA calls and pass them down the stack
- all at once at some otherwise-determined time. Useful for implementing
- filters that want to queue metadata until a START event chooses some
- underlying filter stack to send an rpc on. */
-
-/* Clients should declare a member of grpc_metadata_buffer. This may at some
- point become a typedef for a struct, but for now a pointer suffices */
-typedef struct grpc_metadata_buffer_impl grpc_metadata_buffer_impl;
-typedef grpc_metadata_buffer_impl *grpc_metadata_buffer;
-
-/* Initializes the metadata buffer. Allocates no memory. */
-void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer);
-/* Destroy the metadata buffer. */
-void grpc_metadata_buffer_destroy(grpc_metadata_buffer *buffer,
- grpc_op_error error);
-/* Append a call to the end of a metadata buffer: may allocate memory */
-void grpc_metadata_buffer_queue(grpc_metadata_buffer *buffer, grpc_call_op *op);
-/* Flush all queued operations from the metadata buffer to the element below
- self */
-void grpc_metadata_buffer_flush(grpc_metadata_buffer *buffer,
- grpc_call_element *self);
-/* Count the number of queued elements in the buffer. */
-size_t grpc_metadata_buffer_count(const grpc_metadata_buffer *buffer);
-/* Extract elements as a grpc_metadata*, for presentation to applications.
- The returned buffer must be freed with
- grpc_metadata_buffer_cleanup_elements.
- Clears the metadata buffer (this is a one-shot operation) */
-grpc_metadata *grpc_metadata_buffer_extract_elements(
- grpc_metadata_buffer *buffer);
-void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error);
-
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_METADATA_BUFFER_H */
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
index d987fa2bc1..1d2be716d7 100644
--- a/src/core/channel/noop_filter.c
+++ b/src/core/channel/noop_filter.c
@@ -45,13 +45,7 @@ typedef struct channel_data {
/* used to silence 'variable not used' warnings */
static void ignore_unused(void *ignored) {}
-/* Called either:
- - in response to an API call (or similar) from above, to send something
- - a network event (or similar) from below, to receive something
- op contains type and call direction information, in addition to the data
- that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
+static void noop_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
@@ -59,12 +53,20 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
ignore_unused(calld);
ignore_unused(channeld);
- switch (op->type) {
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_call_next_op(elem, op);
- break;
- }
+ /* do nothing */
+}
+
+/* Called either:
+ - in response to an API call (or similar) from above, to send something
+ - a network event (or similar) from below, to receive something
+ op contains type and call direction information, in addition to the data
+ that is being sent or received. */
+static void noop_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ noop_mutate_op(elem, op);
+
+ /* pass control down the stack */
+ grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
@@ -86,13 +88,16 @@ static void channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
/* initialize members */
calld->unused = channeld->unused;
+
+ if (initial_op) noop_mutate_op(elem, initial_op);
}
/* Destructor for call_data */
@@ -131,6 +136,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_no_op_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "no-op"};
+ noop_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "no-op"};
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index d2cf09a8df..fe7ea6a86b 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -40,9 +40,8 @@
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h"
#include "src/core/httpcli/format_request.h"
-#include "src/core/httpcli/httpcli_security_context.h"
+#include "src/core/httpcli/httpcli_security_connector.h"
#include "src/core/httpcli/parser.h"
-#include "src/core/security/security_context.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
@@ -180,7 +179,7 @@ static void on_connected(void *arg, grpc_endpoint *tcp) {
}
req->ep = tcp;
if (req->use_ssl) {
- grpc_channel_security_context *ctx = NULL;
+ grpc_channel_security_connector *sc = NULL;
const unsigned char *pem_root_certs = NULL;
size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
if (pem_root_certs == NULL || pem_root_certs_size == 0) {
@@ -188,12 +187,12 @@ static void on_connected(void *arg, grpc_endpoint *tcp) {
finish(req, 0);
return;
}
- GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create(
- pem_root_certs, pem_root_certs_size, req->host, &ctx) ==
+ GPR_ASSERT(grpc_httpcli_ssl_channel_security_connector_create(
+ pem_root_certs, pem_root_certs_size, req->host, &sc) ==
GRPC_SECURITY_OK);
- grpc_setup_secure_transport(&ctx->base, tcp, on_secure_transport_setup_done,
+ grpc_setup_secure_transport(&sc->base, tcp, on_secure_transport_setup_done,
req);
- grpc_security_context_unref(&ctx->base);
+ grpc_security_connector_unref(&sc->base);
} else {
start_write(req);
}
diff --git a/src/core/httpcli/httpcli_security_context.c b/src/core/httpcli/httpcli_security_connector.c
index e97752bbe1..6eed5eaf12 100644
--- a/src/core/httpcli/httpcli_security_context.c
+++ b/src/core/httpcli/httpcli_security_connector.c
@@ -31,7 +31,7 @@
*
*/
-#include "src/core/httpcli/httpcli_security_context.h"
+#include "src/core/httpcli/httpcli_security_connector.h"
#include <string.h>
@@ -42,25 +42,25 @@
#include "src/core/tsi/ssl_transport_security.h"
typedef struct {
- grpc_channel_security_context base;
+ grpc_channel_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory;
char *secure_peer_name;
-} grpc_httpcli_ssl_channel_security_context;
+} grpc_httpcli_ssl_channel_security_connector;
-static void httpcli_ssl_destroy(grpc_security_context *ctx) {
- grpc_httpcli_ssl_channel_security_context *c =
- (grpc_httpcli_ssl_channel_security_context *)ctx;
+static void httpcli_ssl_destroy(grpc_security_connector *sc) {
+ grpc_httpcli_ssl_channel_security_connector *c =
+ (grpc_httpcli_ssl_channel_security_connector *)sc;
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
- gpr_free(ctx);
+ gpr_free(sc);
}
static grpc_security_status httpcli_ssl_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
- grpc_httpcli_ssl_channel_security_context *c =
- (grpc_httpcli_ssl_channel_security_context *)ctx;
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
+ grpc_httpcli_ssl_channel_security_connector *c =
+ (grpc_httpcli_ssl_channel_security_connector *)sc;
tsi_result result = TSI_OK;
if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
result = tsi_ssl_handshaker_factory_create_handshaker(
@@ -73,12 +73,12 @@ static grpc_security_status httpcli_ssl_create_handshaker(
return GRPC_SECURITY_OK;
}
-static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx,
+static grpc_security_status httpcli_ssl_check_peer(grpc_security_connector *sc,
tsi_peer peer,
grpc_security_check_cb cb,
void *user_data) {
- grpc_httpcli_ssl_channel_security_context *c =
- (grpc_httpcli_ssl_channel_security_context *)ctx;
+ grpc_httpcli_ssl_channel_security_connector *c =
+ (grpc_httpcli_ssl_channel_security_connector *)sc;
grpc_security_status status = GRPC_SECURITY_OK;
/* Check the peer name. */
@@ -92,14 +92,14 @@ static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx,
return status;
}
-static grpc_security_context_vtable httpcli_ssl_vtable = {
+static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_create_handshaker, httpcli_ssl_check_peer};
-grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+grpc_security_status grpc_httpcli_ssl_channel_security_connector_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
- const char *secure_peer_name, grpc_channel_security_context **ctx) {
+ const char *secure_peer_name, grpc_channel_security_connector **sc) {
tsi_result result = TSI_OK;
- grpc_httpcli_ssl_channel_security_context *c;
+ grpc_httpcli_ssl_channel_security_connector *c;
if (secure_peer_name != NULL && pem_root_certs == NULL) {
gpr_log(GPR_ERROR,
@@ -107,8 +107,8 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
return GRPC_SECURITY_ERROR;
}
- c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_context));
- memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_context));
+ c = gpr_malloc(sizeof(grpc_httpcli_ssl_channel_security_connector));
+ memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
@@ -123,9 +123,9 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
httpcli_ssl_destroy(&c->base.base);
- *ctx = NULL;
+ *sc = NULL;
return GRPC_SECURITY_ERROR;
}
- *ctx = &c->base;
+ *sc = &c->base;
return GRPC_SECURITY_OK;
}
diff --git a/src/core/httpcli/httpcli_security_context.h b/src/core/httpcli/httpcli_security_connector.h
index a776828a69..c50f25905e 100644
--- a/src/core/httpcli/httpcli_security_context.h
+++ b/src/core/httpcli/httpcli_security_connector.h
@@ -31,13 +31,13 @@
*
*/
-#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H
-#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H
+#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H
+#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
-grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
+grpc_security_status grpc_httpcli_ssl_channel_security_connector_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
- const char *secure_peer_name, grpc_channel_security_context **ctx);
+ const char *secure_peer_name, grpc_channel_security_connector **sc);
-#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H */
+#endif /* GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H */
diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c
index f4decda98a..7b2a62060c 100644
--- a/src/core/httpcli/parser.c
+++ b/src/core/httpcli/parser.c
@@ -177,6 +177,8 @@ static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
}
gpr_log(GPR_ERROR, "should never reach here");
abort();
+
+ return 0;
}
void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {
diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c
new file mode 100644
index 0000000000..d78b6ea957
--- /dev/null
+++ b/src/core/iomgr/endpoint_pair_windows.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/iomgr/endpoint_pair.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "src/core/iomgr/tcp_windows.h"
+#include "src/core/iomgr/socket_windows.h"
+#include <grpc/support/log.h>
+
+static void create_sockets(SOCKET sv[2]) {
+ SOCKET svr_sock = INVALID_SOCKET;
+ SOCKET lst_sock = INVALID_SOCKET;
+ SOCKET cli_sock = INVALID_SOCKET;
+ SOCKADDR_IN addr;
+ int addr_len;
+
+ lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ GPR_ASSERT(lst_sock != INVALID_SOCKET);
+
+ memset(&addr, 0, sizeof(addr));
+ GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR);
+ GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
+ GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) != SOCKET_ERROR);
+
+ cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+ GPR_ASSERT(cli_sock != INVALID_SOCKET);
+
+ GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL, NULL, NULL) == 0);
+ svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len);
+ GPR_ASSERT(svr_sock != INVALID_SOCKET);
+
+ closesocket(lst_sock);
+
+ sv[1] = cli_sock;
+ sv[0] = svr_sock;
+}
+
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) {
+ SOCKET sv[2];
+ grpc_endpoint_pair p;
+ create_sockets(sv);
+ p.client = grpc_tcp_create(grpc_winsocket_create(sv[1]));
+ p.server = grpc_tcp_create(grpc_winsocket_create(sv[0]));
+ return p;
+}
+
+#endif
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 8b019e8049..7968729353 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -52,10 +52,11 @@ 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 HANDLE g_iocp;
-static int do_iocp_work() {
+static void do_iocp_work() {
BOOL success;
DWORD bytes = 0;
DWORD flags = 0;
@@ -71,14 +72,13 @@ static int do_iocp_work() {
gpr_time_to_millis(wait_time));
if (!success && !overlapped) {
/* The deadline got attained. */
- return 0;
+ return;
}
GPR_ASSERT(completion_key && overlapped);
if (overlapped == &g_iocp_custom_overlap) {
if (completion_key == (ULONG_PTR) &g_iocp_kick_token) {
/* We were awoken from a kick. */
- gpr_log(GPR_DEBUG, "do_iocp_work - got a kick");
- return 1;
+ return;
}
gpr_log(GPR_ERROR, "Unknown custom completion key.");
abort();
@@ -86,10 +86,8 @@ static int do_iocp_work() {
socket = (grpc_winsocket*) completion_key;
if (overlapped == &socket->write_info.overlapped) {
- gpr_log(GPR_DEBUG, "do_iocp_work - got write packet");
info = &socket->write_info;
} else if (overlapped == &socket->read_info.overlapped) {
- gpr_log(GPR_DEBUG, "do_iocp_work - got read packet");
info = &socket->read_info;
} else {
gpr_log(GPR_ERROR, "Unknown IOCP operation");
@@ -97,8 +95,11 @@ static int do_iocp_work() {
}
success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
FALSE, &flags);
- gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s", bytes, flags,
- success ? "succeeded" : "failed");
+ if (socket->orphan) {
+ grpc_winsocket_destroy(socket);
+ gpr_atm_full_fetch_add(&g_orphans, -1);
+ return;
+ }
info->bytes_transfered = bytes;
info->wsa_error = success ? 0 : WSAGetLastError();
GPR_ASSERT(overlapped == &info->overlapped);
@@ -113,12 +114,10 @@ static int do_iocp_work() {
}
gpr_mu_unlock(&socket->state_mu);
if (f) f(opaque, 1);
-
- return 1;
}
static void iocp_loop(void *p) {
- while (!gpr_event_get(&g_shutdown_iocp)) {
+ while (gpr_atm_acq_load(&g_orphans) || !gpr_event_get(&g_shutdown_iocp)) {
grpc_maybe_call_delayed_callbacks(NULL, 1);
do_iocp_work();
}
@@ -138,13 +137,19 @@ void grpc_iocp_init(void) {
gpr_thd_new(&id, iocp_loop, NULL, NULL);
}
-void grpc_iocp_shutdown(void) {
+void grpc_iocp_kick(void) {
BOOL success;
- gpr_event_set(&g_shutdown_iocp, (void *)1);
+
success = PostQueuedCompletionStatus(g_iocp, 0,
(ULONG_PTR) &g_iocp_kick_token,
&g_iocp_custom_overlap);
GPR_ASSERT(success);
+}
+
+void grpc_iocp_shutdown(void) {
+ BOOL success;
+ gpr_event_set(&g_shutdown_iocp, (void *)1);
+ grpc_iocp_kick();
gpr_event_wait(&g_iocp_done, gpr_inf_future);
success = CloseHandle(g_iocp);
GPR_ASSERT(success);
@@ -166,6 +171,10 @@ void grpc_iocp_add_socket(grpc_winsocket *socket) {
GPR_ASSERT(ret == g_iocp);
}
+void grpc_iocp_socket_orphan(grpc_winsocket *socket) {
+ gpr_atm_full_fetch_add(&g_orphans, 1);
+}
+
static void socket_notify_on_iocp(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque,
grpc_winsocket_callback_info *info) {
@@ -175,11 +184,9 @@ static void socket_notify_on_iocp(grpc_winsocket *socket,
if (info->has_pending_iocp) {
run_now = 1;
info->has_pending_iocp = 0;
- gpr_log(GPR_DEBUG, "socket_notify_on_iocp - runs now");
} else {
info->cb = cb;
info->opaque = opaque;
- gpr_log(GPR_DEBUG, "socket_notify_on_iocp - queued");
}
gpr_mu_unlock(&socket->state_mu);
if (run_now) cb(opaque, 1);
@@ -187,13 +194,11 @@ static void socket_notify_on_iocp(grpc_winsocket *socket,
void grpc_socket_notify_on_write(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque) {
- gpr_log(GPR_DEBUG, "grpc_socket_notify_on_write");
socket_notify_on_iocp(socket, cb, opaque, &socket->write_info);
}
void grpc_socket_notify_on_read(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque) {
- gpr_log(GPR_DEBUG, "grpc_socket_notify_on_read");
socket_notify_on_iocp(socket, cb, opaque, &socket->read_info);
}
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 33133193a1..fa3f5eee10 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -42,6 +42,7 @@
void grpc_iocp_init(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 058685b295..d0e6706fbd 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -117,7 +117,16 @@ void grpc_iomgr_shutdown(void) {
gpr_mu_lock(&g_mu);
}
if (g_refs) {
- if (gpr_cv_wait(&g_rcv, &g_mu, shutdown_deadline) && g_cbs_head == NULL) {
+ int timeout = 0;
+ gpr_timespec short_deadline = gpr_time_add(gpr_now(),
+ gpr_time_from_millis(100));
+ while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
+ if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
+ timeout = 1;
+ break;
+ }
+ }
+ if (timeout) {
gpr_log(GPR_DEBUG,
"Failed to free %d iomgr objects before shutdown deadline: "
"memory leaks are likely",
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index 7570ff18c5..25b7cfda1a 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -172,6 +172,9 @@ static int multipoll_with_poll_pollset_maybe_work(
}
r = poll(h->pfds, h->pfd_count, timeout);
+
+ end_polling(pollset);
+
if (r < 0) {
if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
@@ -192,7 +195,6 @@ static int multipoll_with_poll_pollset_maybe_work(
}
}
grpc_pollset_kick_post_poll(&pollset->kick_state);
- end_polling(pollset);
gpr_mu_lock(&pollset->mu);
pollset->counter = 0;
@@ -201,7 +203,7 @@ static int multipoll_with_poll_pollset_maybe_work(
}
static void multipoll_with_poll_pollset_kick(grpc_pollset *p) {
- grpc_pollset_kick_kick(&p->kick_state);
+ grpc_pollset_force_kick(p);
}
static void multipoll_with_poll_pollset_destroy(grpc_pollset *pollset) {
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 0bb722e2b1..60d0dad6d8 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -47,9 +47,11 @@
#include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/socket_utils_posix.h"
+#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/thd.h>
+#include <grpc/support/tls.h>
#include <grpc/support/useful.h>
static grpc_pollset g_backup_pollset;
@@ -57,6 +59,8 @@ static int g_shutdown_backup_poller;
static gpr_event g_backup_poller_done;
static gpr_event g_backup_pollset_shutdown_done;
+GPR_TLS_DECL(g_current_thread_poller);
+
static void backup_poller(void *p) {
gpr_timespec delta = gpr_time_from_millis(100);
gpr_timespec last_poll = gpr_now();
@@ -76,17 +80,21 @@ static void backup_poller(void *p) {
}
void grpc_pollset_kick(grpc_pollset *p) {
- if (p->counter) {
+ if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p && p->counter) {
p->vtable->kick(p);
}
}
void grpc_pollset_force_kick(grpc_pollset *p) {
- grpc_pollset_kick_kick(&p->kick_state);
+ if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) {
+ grpc_pollset_kick_kick(&p->kick_state);
+ }
}
static void kick_using_pollset_kick(grpc_pollset *p) {
- grpc_pollset_kick_kick(&p->kick_state);
+ if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) {
+ grpc_pollset_kick_kick(&p->kick_state);
+ }
}
/* global state management */
@@ -96,6 +104,8 @@ grpc_pollset *grpc_backup_pollset(void) { return &g_backup_pollset; }
void grpc_pollset_global_init(void) {
gpr_thd_id id;
+ gpr_tls_init(&g_current_thread_poller);
+
/* Initialize kick fd state */
grpc_pollset_kick_global_init();
@@ -129,6 +139,8 @@ void grpc_pollset_global_shutdown(void) {
/* destroy the kick pipes */
grpc_pollset_kick_global_destroy();
+
+ gpr_tls_destroy(&g_current_thread_poller);
}
/* main interface */
@@ -161,8 +173,8 @@ void grpc_pollset_del_fd(grpc_pollset *pollset, grpc_fd *fd) {
int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
/* pollset->mu already held */
- gpr_timespec now;
- now = gpr_now();
+ gpr_timespec now = gpr_now();
+ int r;
if (gpr_time_cmp(now, deadline) > 0) {
return 0;
}
@@ -172,7 +184,10 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
if (grpc_alarm_check(&pollset->mu, now, &deadline)) {
return 1;
}
- return pollset->vtable->maybe_work(pollset, deadline, now, 1);
+ gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
+ r = pollset->vtable->maybe_work(pollset, deadline, now, 1);
+ gpr_tls_set(&g_current_thread_poller, 0);
+ return r;
}
void grpc_pollset_shutdown(grpc_pollset *pollset,
@@ -396,6 +411,10 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout);
+ GRPC_TIMER_MARK(POLL_FINISHED, r);
+
+ grpc_fd_end_poll(&fd_watcher);
+
if (r < 0) {
if (errno != EINTR) {
gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
@@ -415,7 +434,6 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
}
grpc_pollset_kick_post_poll(&pollset->kick_state);
- grpc_fd_end_poll(&fd_watcher);
gpr_mu_lock(&pollset->mu);
pollset->counter = 0;
diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c
index 877b3f35ed..9b416dfe8a 100644
--- a/src/core/iomgr/resolve_address_windows.c
+++ b/src/core/iomgr/resolve_address_windows.c
@@ -65,7 +65,6 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
int s;
size_t i;
grpc_resolved_addresses *addrs = NULL;
- const gpr_timespec start_time = gpr_now();
/* parse name, splitting it into host and port parts */
gpr_split_host_port(name, &host, &port);
@@ -107,18 +106,11 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
i++;
}
- /* Temporary logging, to help identify flakiness in dualstack_socket_test. */
{
- const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time);
- const int delay_ms =
- delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_MS;
- gpr_log(GPR_INFO, "logspam: getaddrinfo(%s, %s) resolved %d addrs in %dms:",
- host, port, addrs->naddrs, delay_ms);
for (i = 0; i < addrs->naddrs; i++) {
char *buf;
grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
0);
- gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf);
gpr_free(buf);
}
}
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index 99f38b0e03..91268c04e6 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -46,7 +46,6 @@
grpc_winsocket *grpc_winsocket_create(SOCKET socket) {
grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
- gpr_log(GPR_DEBUG, "grpc_winsocket_create");
memset(r, 0, sizeof(grpc_winsocket));
r->socket = socket;
gpr_mu_init(&r->state_mu);
@@ -55,21 +54,24 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket) {
return r;
}
-void shutdown_op(grpc_winsocket_callback_info *info) {
+static void shutdown_op(grpc_winsocket_callback_info *info) {
if (!info->cb) return;
grpc_iomgr_add_delayed_callback(info->cb, info->opaque, 0);
}
void grpc_winsocket_shutdown(grpc_winsocket *socket) {
- gpr_log(GPR_DEBUG, "grpc_winsocket_shutdown");
shutdown_op(&socket->read_info);
shutdown_op(&socket->write_info);
}
void grpc_winsocket_orphan(grpc_winsocket *socket) {
- gpr_log(GPR_DEBUG, "grpc_winsocket_orphan");
+ grpc_iocp_socket_orphan(socket);
+ socket->orphan = 1;
grpc_iomgr_unref();
closesocket(socket->socket);
+}
+
+void grpc_winsocket_destroy(grpc_winsocket *socket) {
gpr_mu_destroy(&socket->state_mu);
gpr_free(socket);
}
diff --git a/src/core/iomgr/socket_windows.h b/src/core/iomgr/socket_windows.h
index d4776ab10f..cbae91692c 100644
--- a/src/core/iomgr/socket_windows.h
+++ b/src/core/iomgr/socket_windows.h
@@ -57,12 +57,13 @@ typedef struct grpc_winsocket_callback_info {
typedef struct grpc_winsocket {
SOCKET socket;
- int added_to_iocp;
-
grpc_winsocket_callback_info write_info;
grpc_winsocket_callback_info read_info;
gpr_mu state_mu;
+
+ int added_to_iocp;
+ int orphan;
} grpc_winsocket;
/* Create a wrapped windows handle.
@@ -71,5 +72,6 @@ grpc_winsocket *grpc_winsocket_create(SOCKET socket);
void grpc_winsocket_shutdown(grpc_winsocket *socket);
void grpc_winsocket_orphan(grpc_winsocket *socket);
+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 181d89cb6d..00c8da601b 100644
--- a/src/core/iomgr/tcp_client_windows.c
+++ b/src/core/iomgr/tcp_client_windows.c
@@ -102,7 +102,6 @@ static void on_connect(void *acp, int success) {
gpr_free(utf8_message);
goto finish;
} else {
- gpr_log(GPR_DEBUG, "on_connect: connection established");
ep = grpc_tcp_create(ac->socket);
goto finish;
}
@@ -179,9 +178,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
info = &socket->write_info;
success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped);
- if (success) {
- gpr_log(GPR_DEBUG, "connected immediately - but we still go to sleep");
- } else {
+ if (!success) {
int error = WSAGetLastError();
if (error != ERROR_IO_PENDING) {
message = "ConnectEx failed: %s";
@@ -189,7 +186,6 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
}
}
- gpr_log(GPR_DEBUG, "grpc_tcp_client_connect: connection pending");
ac = gpr_malloc(sizeof(async_connect));
ac->cb = cb;
ac->cb_arg = arg;
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 597a2a62d3..86721e9c95 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -46,6 +46,7 @@
#include "src/core/support/string.h"
#include "src/core/debug/trace.h"
+#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
@@ -326,6 +327,7 @@ static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) {
gpr_slice *final_slices;
size_t final_nslices;
+ GRPC_TIMER_MARK(HANDLE_READ_BEGIN, 0);
slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
0);
@@ -348,9 +350,11 @@ static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) {
msg.msg_controllen = 0;
msg.msg_flags = 0;
+ GRPC_TIMER_MARK(RECVMSG_BEGIN, 0);
do {
read_bytes = recvmsg(tcp->fd, &msg, 0);
} while (read_bytes < 0 && errno == EINTR);
+ GRPC_TIMER_MARK(RECVMSG_END, 0);
if (read_bytes < allocated_bytes) {
/* TODO(klempner): Consider a second read first, in hopes of getting a
@@ -402,6 +406,7 @@ static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) {
++iov_size;
}
}
+ GRPC_TIMER_MARK(HANDLE_READ_END, 0);
}
static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb,
@@ -433,10 +438,12 @@ static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) {
msg.msg_controllen = 0;
msg.msg_flags = 0;
+ GRPC_TIMER_MARK(SENDMSG_BEGIN, 0);
do {
/* TODO(klempner): Cork if this is a partial write */
sent_length = sendmsg(tcp->fd, &msg, 0);
} while (sent_length < 0 && errno == EINTR);
+ GRPC_TIMER_MARK(SENDMSG_END, 0);
if (sent_length < 0) {
if (errno == EAGAIN) {
@@ -472,6 +479,7 @@ static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) {
return;
}
+ GRPC_TIMER_MARK(CB_WRITE_BEGIN, 0);
write_status = grpc_tcp_flush(tcp);
if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
@@ -487,6 +495,7 @@ static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) {
cb(tcp->write_user_data, cb_status);
grpc_tcp_unref(tcp);
}
+ GRPC_TIMER_MARK(CB_WRITE_END, 0);
}
static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
@@ -509,6 +518,7 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
}
}
+ GRPC_TIMER_MARK(WRITE_BEGIN, 0);
GPR_ASSERT(tcp->write_cb == NULL);
slice_state_init(&tcp->write_state, slices, nslices, nslices);
@@ -522,6 +532,7 @@ static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep,
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
}
+ GRPC_TIMER_MARK(WRITE_END, 0);
return status;
}
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 68ee85c5a7..66bb3ef701 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -71,6 +71,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
up when grpc_tcp_server_destroy is called. */
int grpc_tcp_server_get_fd(grpc_tcp_server *s, unsigned index);
-void grpc_tcp_server_destroy(grpc_tcp_server *server);
+void grpc_tcp_server_destroy(grpc_tcp_server *server,
+ void (*shutdown_done)(void *shutdown_done_arg),
+ void *shutdown_done_arg);
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
+#endif /* GRPC_INTERNAL_CORE_IOMGR_TCP_SERVER_H */
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 90b7eb451d..7e31f2d7a5 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -102,12 +102,18 @@ struct grpc_tcp_server {
gpr_cv cv;
/* active port count: how many ports are actually still listening */
- int active_ports;
+ size_t active_ports;
+ /* destroyed port count: how many ports are completely destroyed */
+ size_t destroyed_ports;
/* all listening ports */
server_port *ports;
size_t nports;
size_t port_capacity;
+
+ /* shutdown callback */
+ void (*shutdown_complete)(void *);
+ void *shutdown_complete_arg;
};
grpc_tcp_server *grpc_tcp_server_create(void) {
@@ -115,6 +121,7 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
gpr_mu_init(&s->mu);
gpr_cv_init(&s->cv);
s->active_ports = 0;
+ s->destroyed_ports = 0;
s->cb = NULL;
s->cb_arg = NULL;
s->ports = gpr_malloc(sizeof(server_port) * INIT_PORT_CAP);
@@ -123,29 +130,65 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
return s;
}
-void grpc_tcp_server_destroy(grpc_tcp_server *s) {
+static void finish_shutdown(grpc_tcp_server *s) {
+ s->shutdown_complete(s->shutdown_complete_arg);
+
+ gpr_mu_destroy(&s->mu);
+ gpr_cv_destroy(&s->cv);
+
+ gpr_free(s->ports);
+ gpr_free(s);
+}
+
+static void destroyed_port(void *server, int success) {
+ grpc_tcp_server *s = server;
+ gpr_mu_lock(&s->mu);
+ s->destroyed_ports++;
+ if (s->destroyed_ports == s->nports) {
+ gpr_mu_unlock(&s->mu);
+ finish_shutdown(s);
+ } else {
+ gpr_mu_unlock(&s->mu);
+ }
+}
+
+static void dont_care_about_shutdown_completion(void *ignored) {}
+
+void grpc_tcp_server_destroy(
+ grpc_tcp_server *s, void (*shutdown_complete)(void *shutdown_complete_arg),
+ void *shutdown_complete_arg) {
size_t i;
gpr_mu_lock(&s->mu);
+
+ s->shutdown_complete = shutdown_complete
+ ? shutdown_complete
+ : dont_care_about_shutdown_completion;
+ s->shutdown_complete_arg = shutdown_complete_arg;
+
/* shutdown all fd's */
for (i = 0; i < s->nports; i++) {
grpc_fd_shutdown(s->ports[i].emfd);
}
/* wait while that happens */
+ /* TODO(ctiller): make this asynchronous also */
while (s->active_ports) {
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
}
- gpr_mu_unlock(&s->mu);
/* delete ALL the things */
- for (i = 0; i < s->nports; i++) {
- server_port *sp = &s->ports[i];
- if (sp->addr.sockaddr.sa_family == AF_UNIX) {
- unlink_if_unix_domain_socket(&sp->addr.un);
+ if (s->nports) {
+ for (i = 0; i < s->nports; i++) {
+ server_port *sp = &s->ports[i];
+ if (sp->addr.sockaddr.sa_family == AF_UNIX) {
+ unlink_if_unix_domain_socket(&sp->addr.un);
+ }
+ grpc_fd_orphan(sp->emfd, destroyed_port, s);
}
- grpc_fd_orphan(sp->emfd, NULL, NULL);
+ gpr_mu_unlock(&s->mu);
+ } else {
+ gpr_mu_unlock(&s->mu);
+ finish_shutdown(s);
}
- gpr_free(s->ports);
- gpr_free(s);
}
/* get max listen queue size on linux */
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 0c3ab1dc91..fe92846a71 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -92,7 +92,9 @@ grpc_tcp_server *grpc_tcp_server_create(void) {
return s;
}
-void grpc_tcp_server_destroy(grpc_tcp_server *s) {
+void grpc_tcp_server_destroy(grpc_tcp_server *s,
+ void (*shutdown_done)(void *shutdown_done_arg),
+ void *shutdown_done_arg) {
size_t i;
gpr_mu_lock(&s->mu);
/* shutdown all fd's */
@@ -112,11 +114,15 @@ void grpc_tcp_server_destroy(grpc_tcp_server *s) {
}
gpr_free(s->ports);
gpr_free(s);
+
+ if (shutdown_done) {
+ shutdown_done(shutdown_done_arg);
+ }
}
/* Prepare a recently-created socket for listening. */
-static int prepare_socket(SOCKET sock,
- const struct sockaddr *addr, int addr_len) {
+static int prepare_socket(SOCKET sock, const struct sockaddr *addr,
+ int addr_len) {
struct sockaddr_storage sockname_temp;
socklen_t sockname_len;
@@ -147,15 +153,15 @@ static int prepare_socket(SOCKET sock,
}
sockname_len = sizeof(sockname_temp);
- if (getsockname(sock, (struct sockaddr *) &sockname_temp, &sockname_len)
- == SOCKET_ERROR) {
+ if (getsockname(sock, (struct sockaddr *)&sockname_temp, &sockname_len) ==
+ SOCKET_ERROR) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "getsockname: %s", utf8_message);
gpr_free(utf8_message);
goto error;
}
- return grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp);
+ return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
error:
if (sock != INVALID_SOCKET) closesocket(sock);
@@ -185,13 +191,13 @@ static void start_accept(server_port *port) {
goto failure;
}
+ /* TODO(jtattermusch): probably a race here, we regularly get use-after-free on server shutdown */
+ GPR_ASSERT(port->socket != (grpc_winsocket*)0xfeeefeee);
success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
addrlen, addrlen, &bytes_received,
&port->socket->read_info.overlapped);
- if (success) {
- gpr_log(GPR_DEBUG, "accepted immediately - but we still go to sleep");
- } else {
+ if (!success) {
int error = WSAGetLastError();
if (error != ERROR_IO_PENDING) {
message = "AcceptEx failed: %s";
@@ -221,19 +227,16 @@ static void on_accept(void *arg, int success) {
DWORD transfered_bytes = 0;
DWORD flags;
BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
- &transfered_bytes, FALSE,
- &flags);
+ &transfered_bytes, FALSE, &flags);
if (!wsa_success) {
char *utf8_message = gpr_format_message(WSAGetLastError());
gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
gpr_free(utf8_message);
closesocket(sock);
} else {
- gpr_log(GPR_DEBUG, "on_accept: accepted connection");
ep = grpc_tcp_create(grpc_winsocket_create(sock));
}
} else {
- gpr_log(GPR_DEBUG, "on_accept: shutting down");
closesocket(sock);
gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) {
@@ -243,7 +246,9 @@ static void on_accept(void *arg, int success) {
}
if (ep) sp->server->cb(sp->server->cb_arg, ep);
- start_accept(sp);
+ if (success) {
+ start_accept(sp);
+ }
}
static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
@@ -257,9 +262,9 @@ static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,
if (sock == INVALID_SOCKET) return -1;
- status = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
- &guid, sizeof(guid), &AcceptEx, sizeof(AcceptEx),
- &ioctl_num_bytes, NULL, NULL);
+ status =
+ WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
+ &AcceptEx, sizeof(AcceptEx), &ioctl_num_bytes, NULL, NULL);
if (status != 0) {
char *utf8_message = gpr_format_message(WSAGetLastError());
@@ -307,9 +312,8 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
for (i = 0; i < s->nports; i++) {
sockname_len = sizeof(sockname_temp);
if (0 == getsockname(s->ports[i].socket->socket,
- (struct sockaddr *) &sockname_temp,
- &sockname_len)) {
- port = grpc_sockaddr_get_port((struct sockaddr *) &sockname_temp);
+ (struct sockaddr *)&sockname_temp, &sockname_len)) {
+ port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
if (port > 0) {
allocated_addr = malloc(addr_len);
memcpy(allocated_addr, addr, addr_len);
@@ -330,7 +334,7 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
if (grpc_sockaddr_is_wildcard(addr, &port)) {
grpc_sockaddr_make_wildcard6(port, &wildcard);
- addr = (struct sockaddr *) &wildcard;
+ addr = (struct sockaddr *)&wildcard;
addr_len = sizeof(wildcard);
}
@@ -369,4 +373,4 @@ void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset **pollset,
gpr_mu_unlock(&s->mu);
}
-#endif /* GPR_WINSOCK_SOCKET */
+#endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index ec5496e7ee..71534eaa3d 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -93,14 +93,11 @@ typedef struct grpc_tcp {
} grpc_tcp;
static void tcp_ref(grpc_tcp *tcp) {
- gpr_log(GPR_DEBUG, "tcp_ref");
gpr_ref(&tcp->refcount);
}
static void tcp_unref(grpc_tcp *tcp) {
- gpr_log(GPR_DEBUG, "tcp_unref");
if (gpr_unref(&tcp->refcount)) {
- gpr_log(GPR_DEBUG, "tcp_unref: destroying");
gpr_slice_buffer_destroy(&tcp->write_slices);
grpc_winsocket_orphan(tcp->socket);
gpr_free(tcp);
@@ -126,24 +123,20 @@ static void on_read(void *tcpp, int success) {
return;
}
- gpr_log(GPR_DEBUG, "on_read");
tcp->outstanding_read = 0;
if (socket->read_info.wsa_error != 0) {
char *utf8_message = gpr_format_message(info->wsa_error);
- __debugbreak();
gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
gpr_free(utf8_message);
status = GRPC_ENDPOINT_CB_ERROR;
} else {
if (info->bytes_transfered != 0) {
sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
- gpr_log(GPR_DEBUG, "on_read: calling callback");
status = GRPC_ENDPOINT_CB_OK;
slice = &sub;
nslices = 1;
} else {
- gpr_log(GPR_DEBUG, "on_read: closed socket");
gpr_slice_unref(tcp->read_slice);
status = GRPC_ENDPOINT_CB_EOF;
}
@@ -174,27 +167,22 @@ static void win_notify_on_read(grpc_endpoint *ep,
buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);
- gpr_log(GPR_DEBUG, "win_notify_on_read: calling WSARecv without overlap");
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
if (info->wsa_error != WSAEWOULDBLOCK) {
- gpr_log(GPR_DEBUG, "got response immediately, calling on_read");
info->bytes_transfered = bytes_read;
/* This might heavily recurse. */
on_read(tcp, 1);
return;
}
- gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSARecv with overlap");
-
memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
&info->overlapped, NULL);
if (status == 0) {
- gpr_log(GPR_DEBUG, "got response immediately, but we're going to sleep");
grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
return;
}
@@ -213,7 +201,6 @@ static void win_notify_on_read(grpc_endpoint *ep,
return;
}
- gpr_log(GPR_DEBUG, "waiting on the IO completion port now");
grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
}
@@ -227,8 +214,6 @@ static void on_write(void *tcpp, int success) {
GPR_ASSERT(tcp->outstanding_write);
- gpr_log(GPR_DEBUG, "on_write");
-
if (!success) {
tcp_unref(tcp);
cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
@@ -265,13 +250,9 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
WSABUF *allocated = NULL;
WSABUF *buffers = local_buffers;
- GPR_ASSERT(nslices != 0);
- GPR_ASSERT(GPR_SLICE_LENGTH(slices[0]) != 0);
GPR_ASSERT(!tcp->outstanding_write);
tcp_ref(tcp);
- gpr_log(GPR_DEBUG, "win_write");
-
tcp->outstanding_write = 1;
tcp->write_cb = cb;
tcp->write_user_data = arg;
@@ -287,14 +268,12 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
}
- gpr_log(GPR_DEBUG, "win_write: calling WSASend without overlap");
status = WSASend(socket->socket, buffers, tcp->write_slices.count,
&bytes_sent, 0, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError();
if (info->wsa_error != WSAEWOULDBLOCK) {
grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
- gpr_log(GPR_DEBUG, "got response immediately, cleaning up and leaving");
if (status == 0) {
ret = GRPC_ENDPOINT_WRITE_DONE;
GPR_ASSERT(bytes_sent == tcp->write_slices.length);
@@ -310,8 +289,6 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
return ret;
}
- gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSASend with overlap");
-
memset(&socket->write_info, 0, sizeof(OVERLAPPED));
status = WSASend(socket->socket, buffers, tcp->write_slices.count,
&bytes_sent, 0, &socket->write_info.overlapped, NULL);
@@ -329,9 +306,6 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
tcp_unref(tcp);
return GRPC_ENDPOINT_WRITE_ERROR;
}
- gpr_log(GPR_DEBUG, "win_write: got pending op");
- } else {
- gpr_log(GPR_DEBUG, "wrote data immediately - but we're going to sleep");
}
grpc_socket_notify_on_write(socket, on_write, tcp);
@@ -340,19 +314,16 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_tcp *tcp = (grpc_tcp *) ep;
- gpr_log(GPR_DEBUG, "win_add_to_pollset");
grpc_iocp_add_socket(tcp->socket);
}
static void win_shutdown(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *) ep;
- gpr_log(GPR_DEBUG, "win_shutdown");
grpc_winsocket_shutdown(tcp->socket);
}
static void win_destroy(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *) ep;
- gpr_log(GPR_DEBUG, "win_destroy");
tcp_unref(tcp);
}
diff --git a/src/core/profiling/timers.c b/src/core/profiling/timers.c
new file mode 100644
index 0000000000..bd1700ffd8
--- /dev/null
+++ b/src/core/profiling/timers.c
@@ -0,0 +1,141 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifdef GRPC_LATENCY_PROFILER
+
+#include "src/core/profiling/timers.h"
+#include "src/core/profiling/timers_preciseclock.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <stdio.h>
+
+typedef struct grpc_timer_entry {
+ grpc_precise_clock tm;
+ gpr_thd_id thd;
+ const char* tag;
+ void* id;
+ const char* file;
+ int line;
+} grpc_timer_entry;
+
+struct grpc_timers_log {
+ gpr_mu mu;
+ grpc_timer_entry* log;
+ int num_entries;
+ int capacity;
+ int capacity_limit;
+ FILE* fp;
+};
+
+grpc_timers_log* grpc_timers_log_global = NULL;
+
+grpc_timers_log* grpc_timers_log_create(int capacity_limit, FILE* dump) {
+ grpc_timers_log* log = gpr_malloc(sizeof(*log));
+
+ /* TODO (vpai): Allow allocation below limit */
+ log->log = gpr_malloc(capacity_limit * sizeof(*log->log));
+
+ /* TODO (vpai): Improve concurrency, do per-thread logging? */
+ gpr_mu_init(&log->mu);
+
+ log->num_entries = 0;
+ log->capacity = log->capacity_limit = capacity_limit;
+
+ log->fp = dump;
+
+ return log;
+}
+
+static void log_report_locked(grpc_timers_log* log) {
+ FILE* fp = log->fp;
+ int i;
+ for (i = 0; i < log->num_entries; i++) {
+ grpc_timer_entry* entry = &(log->log[i]);
+ fprintf(fp, "GRPC_LAT_PROF ");
+ grpc_precise_clock_print(&entry->tm, fp);
+ fprintf(fp, " %p %s %p %s %d\n", (void*)(gpr_intptr)entry->thd, entry->tag, entry->id, entry->file,
+ entry->line);
+ }
+
+ /* Now clear out the log */
+ log->num_entries = 0;
+}
+
+void grpc_timers_log_destroy(grpc_timers_log* log) {
+ gpr_mu_lock(&log->mu);
+ log_report_locked(log);
+ gpr_mu_unlock(&log->mu);
+
+ gpr_free(log->log);
+ gpr_mu_destroy(&log->mu);
+
+ gpr_free(log);
+}
+
+void grpc_timers_log_add(grpc_timers_log* log, const char* tag, void* id,
+ const char* file, int line) {
+ grpc_timer_entry* entry;
+
+ /* TODO (vpai) : Improve concurrency */
+ gpr_mu_lock(&log->mu);
+ if (log->num_entries == log->capacity_limit) {
+ log_report_locked(log);
+ }
+
+ entry = &log->log[log->num_entries++];
+
+ grpc_precise_clock_now(&entry->tm);
+ entry->tag = tag;
+ entry->id = id;
+ entry->file = file;
+ entry->line = line;
+ entry->thd = gpr_thd_currentid();
+
+ gpr_mu_unlock(&log->mu);
+}
+
+void grpc_timers_log_global_init(void) {
+ grpc_timers_log_global = grpc_timers_log_create(100000, stdout);
+}
+
+void grpc_timers_log_global_destroy(void) {
+ grpc_timers_log_destroy(grpc_timers_log_global);
+}
+#else /* !GRPC_LATENCY_PROFILER */
+void grpc_timers_log_global_init(void) {}
+void grpc_timers_log_global_destroy(void) {}
+#endif /* GRPC_LATENCY_PROFILER */
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
new file mode 100644
index 0000000000..1a6b9ffac9
--- /dev/null
+++ b/src/core/profiling/timers.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_PROFILING_TIMERS_H
+#define GRPC_CORE_PROFILING_TIMERS_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef GRPC_LATENCY_PROFILER
+
+typedef struct grpc_timers_log grpc_timers_log;
+
+grpc_timers_log* grpc_timers_log_create(int capacity_limit, FILE* dump);
+void grpc_timers_log_add(grpc_timers_log*, const char* tag, void* id,
+ const char* file, int line);
+void grpc_timers_log_destroy(grpc_timers_log *);
+
+extern grpc_timers_log *grpc_timers_log_global;
+
+#define GRPC_TIMER_MARK(x, s) \
+ grpc_timers_log_add(grpc_timers_log_global, #x, ((void *)(gpr_intptr)(s)), \
+ __FILE__, __LINE__)
+
+#else /* !GRPC_LATENCY_PROFILER */
+#define GRPC_TIMER_MARK(x, s) \
+ do { \
+ } while (0)
+#endif /* GRPC_LATENCY_PROFILER */
+
+void grpc_timers_log_global_init(void);
+void grpc_timers_log_global_destroy(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_PROFILING_TIMERS_H */
diff --git a/src/ruby/ext/grpc/rb_metadata.h b/src/core/profiling/timers_preciseclock.h
index 251072f658..bf4a0eab8a 100644
--- a/src/ruby/ext/grpc/rb_metadata.h
+++ b/src/core/profiling/timers_preciseclock.h
@@ -31,23 +31,26 @@
*
*/
-#ifndef GRPC_RB_METADATA_H_
-#define GRPC_RB_METADATA_H_
+#ifndef GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H
+#define GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H
-#include <grpc/grpc.h>
-#include <ruby.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
-/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
-extern VALUE rb_cMetadata;
+typedef struct grpc_precise_clock grpc_precise_clock;
-/* grpc_rb_metadata_create_with_mark creates a grpc_rb_metadata with a ruby mark
- * object that will be kept alive while the metadata is alive. */
-extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata* md);
+#ifdef GRPC_TIMERS_RDTSC
+#error RDTSC timers not currently supported
+#else
+struct grpc_precise_clock {
+ gpr_timespec clock;
+};
+static void grpc_precise_clock_now(grpc_precise_clock* clk) {
+ clk->clock = gpr_now();
+}
+static void grpc_precise_clock_print(const grpc_precise_clock* clk, FILE* fp) {
+ fprintf(fp, "%ld.%09d", clk->clock.tv_sec, clk->clock.tv_nsec);
+}
+#endif /* GRPC_TIMERS_RDTSC */
-/* Gets the wrapped metadata from the ruby wrapper */
-grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v);
-
-/* Initializes the Metadata class. */
-void Init_grpc_metadata();
-
-#endif /* GRPC_RB_METADATA_H_ */
+#endif /* GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H */
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 5fc6d2717f..2322c12aa5 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -40,21 +40,26 @@
#include "src/core/support/string.h"
#include "src/core/channel/channel_stack.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h"
#include "src/core/surface/call.h"
+#define MAX_CREDENTIALS_METADATA_COUNT 4
+
/* We can have a per-call credentials. */
typedef struct {
grpc_credentials *creds;
grpc_mdstr *host;
grpc_mdstr *method;
- grpc_call_op op;
+ grpc_transport_op op;
+ size_t op_md_idx;
+ int sent_initial_metadata;
+ grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT];
} call_data;
/* We can have a per-channel credentials. */
typedef struct {
- grpc_channel_security_context *security_context;
+ grpc_channel_security_connector *security_connector;
grpc_mdctx *md_ctx;
grpc_mdstr *authority_string;
grpc_mdstr *path_string;
@@ -62,42 +67,23 @@ typedef struct {
grpc_mdstr *status_key;
} channel_data;
-static void do_nothing(void *ignored, grpc_op_error error) {}
-
-static void bubbleup_error(grpc_call_element *elem, const char *error_msg) {
- grpc_call_op finish_op;
- channel_data *channeld = elem->channel_data;
- char status[GPR_LTOA_MIN_BUFSIZE];
-
- gpr_log(GPR_ERROR, "%s", error_msg);
- finish_op.type = GRPC_RECV_METADATA;
- finish_op.dir = GRPC_CALL_UP;
- finish_op.flags = 0;
- finish_op.data.metadata = grpc_mdelem_from_metadata_strings(
- channeld->md_ctx, grpc_mdstr_ref(channeld->error_msg_key),
- grpc_mdstr_from_string(channeld->md_ctx, error_msg));
- finish_op.done_cb = do_nothing;
- finish_op.user_data = NULL;
- grpc_call_next_op(elem, &finish_op);
-
- gpr_ltoa(GRPC_STATUS_UNAUTHENTICATED, status);
- finish_op.data.metadata = grpc_mdelem_from_metadata_strings(
- channeld->md_ctx, grpc_mdstr_ref(channeld->status_key),
- grpc_mdstr_from_string(channeld->md_ctx, status));
- grpc_call_next_op(elem, &finish_op);
-
- grpc_call_element_send_cancel(elem);
-}
-
static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
size_t num_md,
grpc_credentials_status status) {
grpc_call_element *elem = (grpc_call_element *)user_data;
+ call_data *calld = elem->call_data;
+ grpc_transport_op *op = &calld->op;
+ grpc_metadata_batch *mdb;
size_t i;
+ GPR_ASSERT(num_md <= MAX_CREDENTIALS_METADATA_COUNT);
+ GPR_ASSERT(op->send_ops && op->send_ops->nops > calld->op_md_idx &&
+ op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA);
+ mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata;
for (i = 0; i < num_md; i++) {
- grpc_call_element_send_metadata(elem, grpc_mdelem_ref(md_elems[i]));
+ grpc_metadata_batch_add_tail(mdb, &calld->md_links[i],
+ grpc_mdelem_ref(md_elems[i]));
}
- grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
+ grpc_call_next_op(elem, op);
}
static char *build_service_url(const char *url_scheme, call_data *calld) {
@@ -120,13 +106,14 @@ static char *build_service_url(const char *url_scheme, call_data *calld) {
return service_url;
}
-static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
+static void send_security_metadata(grpc_call_element *elem,
+ grpc_transport_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
grpc_credentials *channel_creds =
- channeld->security_context->request_metadata_creds;
+ channeld->security_connector->request_metadata_creds;
/* TODO(jboeuf):
Decide on the policy in this case:
- populate both channel and call?
@@ -138,7 +125,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
if (channel_creds != NULL &&
grpc_credentials_has_request_metadata(channel_creds)) {
char *service_url =
- build_service_url(channeld->security_context->base.url_scheme, calld);
+ build_service_url(channeld->security_connector->base.url_scheme, calld);
calld->op = *op; /* Copy op (originates from the caller's stack). */
grpc_credentials_get_request_metadata(channel_creds, service_url,
on_credentials_metadata, elem);
@@ -151,6 +138,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
static void on_host_checked(void *user_data, grpc_security_status status) {
grpc_call_element *elem = (grpc_call_element *)user_data;
call_data *calld = elem->call_data;
+ channel_data *chand = elem->channel_data;
if (status == GRPC_SECURITY_OK) {
send_security_metadata(elem, &calld->op);
@@ -158,9 +146,11 @@ static void on_host_checked(void *user_data, grpc_security_status status) {
char *error_msg;
gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
grpc_mdstr_as_c_string(calld->host));
- bubbleup_error(elem, error_msg);
+ grpc_transport_op_add_cancellation(
+ &calld->op, GRPC_STATUS_UNAUTHENTICATED,
+ grpc_mdstr_from_string(chand->md_ctx, error_msg));
gpr_free(error_msg);
- calld->op.done_cb(calld->op.user_data, GRPC_OP_ERROR);
+ grpc_call_next_op(elem, &calld->op);
}
}
@@ -169,53 +159,62 @@ static void on_host_checked(void *user_data, grpc_security_status status) {
- a network event (or similar) from below, to receive something
op contains type and call direction information, in addition to the data
that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
+static void auth_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
/* grab pointers to our data from the call element */
call_data *calld = elem->call_data;
channel_data *channeld = elem->channel_data;
+ grpc_linked_mdelem *l;
+ size_t i;
- switch (op->type) {
- case GRPC_SEND_METADATA:
- /* Pointer comparison is OK for md_elems created from the same context. */
- if (op->data.metadata->key == channeld->authority_string) {
- if (calld->host != NULL) grpc_mdstr_unref(calld->host);
- calld->host = grpc_mdstr_ref(op->data.metadata->value);
- } else if (op->data.metadata->key == channeld->path_string) {
- if (calld->method != NULL) grpc_mdstr_unref(calld->method);
- calld->method = grpc_mdstr_ref(op->data.metadata->value);
+ if (op->send_ops && !calld->sent_initial_metadata) {
+ size_t nops = op->send_ops->nops;
+ grpc_stream_op *ops = op->send_ops->ops;
+ for (i = 0; i < nops; i++) {
+ grpc_stream_op *sop = &ops[i];
+ if (sop->type != GRPC_OP_METADATA) continue;
+ calld->op_md_idx = i;
+ calld->sent_initial_metadata = 1;
+ for (l = sop->data.metadata.list.head; l != NULL; l = l->next) {
+ grpc_mdelem *md = l->md;
+ /* Pointer comparison is OK for md_elems created from the same context.
+ */
+ if (md->key == channeld->authority_string) {
+ if (calld->host != NULL) grpc_mdstr_unref(calld->host);
+ calld->host = grpc_mdstr_ref(md->value);
+ } else if (md->key == channeld->path_string) {
+ if (calld->method != NULL) grpc_mdstr_unref(calld->method);
+ calld->method = grpc_mdstr_ref(md->value);
+ }
}
- grpc_call_next_op(elem, op);
- break;
-
- case GRPC_SEND_START:
if (calld->host != NULL) {
grpc_security_status status;
const char *call_host = grpc_mdstr_as_c_string(calld->host);
calld->op = *op; /* Copy op (originates from the caller's stack). */
- status = grpc_channel_security_context_check_call_host(
- channeld->security_context, call_host, on_host_checked, elem);
+ status = grpc_channel_security_connector_check_call_host(
+ channeld->security_connector, call_host, on_host_checked, elem);
if (status != GRPC_SECURITY_OK) {
if (status == GRPC_SECURITY_ERROR) {
char *error_msg;
gpr_asprintf(&error_msg,
"Invalid host %s set in :authority metadata.",
call_host);
- bubbleup_error(elem, error_msg);
+ grpc_transport_op_add_cancellation(
+ &calld->op, GRPC_STATUS_UNAUTHENTICATED,
+ grpc_mdstr_from_string(channeld->md_ctx, error_msg));
gpr_free(error_msg);
- op->done_cb(op->user_data, GRPC_OP_ERROR);
+ grpc_call_next_op(elem, &calld->op);
}
- break;
+ return; /* early exit */
}
}
send_security_metadata(elem, op);
- break;
-
- default:
- /* pass control up or down the stack depending on op->dir */
- grpc_call_next_op(elem, op);
- break;
+ return; /* early exit */
+ }
}
+
+ /* pass control up or down the stack */
+ grpc_call_next_op(elem, op);
}
/* Called on special channel events, such as disconnection or new incoming
@@ -227,13 +226,17 @@ static void channel_op(grpc_channel_element *elem,
/* Constructor for call_data */
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
/* TODO(jboeuf):
Find a way to pass-in the credentials from the caller here. */
call_data *calld = elem->call_data;
calld->creds = NULL;
calld->host = NULL;
calld->method = NULL;
+ calld->sent_initial_metadata = 0;
+
+ GPR_ASSERT(!initial_op || !initial_op->send_ops);
}
/* Destructor for call_data */
@@ -255,7 +258,7 @@ static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
- grpc_security_context *ctx = grpc_find_security_context_in_args(args);
+ grpc_security_connector *ctx = grpc_find_security_connector_in_args(args);
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
@@ -268,23 +271,24 @@ static void init_channel_elem(grpc_channel_element *elem,
/* initialize members */
GPR_ASSERT(ctx->is_client_side);
- channeld->security_context =
- (grpc_channel_security_context *)grpc_security_context_ref(ctx);
+ channeld->security_connector =
+ (grpc_channel_security_connector *)grpc_security_connector_ref(ctx);
channeld->md_ctx = metadata_context;
channeld->authority_string =
grpc_mdstr_from_string(channeld->md_ctx, ":authority");
channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
channeld->error_msg_key =
grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
- channeld->status_key = grpc_mdstr_from_string(channeld->md_ctx, "grpc-status");
+ channeld->status_key =
+ grpc_mdstr_from_string(channeld->md_ctx, "grpc-status");
}
/* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data;
- grpc_channel_security_context *ctx = channeld->security_context;
- if (ctx != NULL) grpc_security_context_unref(&ctx->base);
+ grpc_channel_security_connector *ctx = channeld->security_connector;
+ if (ctx != NULL) grpc_security_connector_unref(&ctx->base);
if (channeld->authority_string != NULL) {
grpc_mdstr_unref(channeld->authority_string);
}
@@ -300,6 +304,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_client_auth_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "auth"};
+ auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "auth"};
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 698e099134..f6366f0750 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -36,11 +36,14 @@
#include <string.h>
#include <stdio.h>
+#include "src/core/channel/channel_args.h"
+#include "src/core/channel/http_client_filter.h"
#include "src/core/json/json.h"
#include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h"
#include "src/core/support/string.h"
+
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
@@ -111,11 +114,49 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
}
+grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
+ grpc_credentials *creds) {
+ grpc_mdctx *mdctx = NULL;
+ if (creds != NULL && creds->vtable->get_metadata_context != NULL) {
+ mdctx = creds->vtable->get_metadata_context(creds);
+ }
+ if (mdctx == NULL) {
+ return grpc_mdctx_create();
+ } else {
+ grpc_mdctx_ref(mdctx);
+ return mdctx;
+ }
+}
+
+grpc_security_status grpc_credentials_create_security_connector(
+ grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+ *new_args = NULL;
+ if (creds == NULL || creds->vtable->create_security_connector == NULL ||
+ grpc_credentials_has_request_metadata_only(creds)) {
+ gpr_log(GPR_ERROR,
+ "Invalid credentials for creating a security connector.");
+ return GRPC_SECURITY_ERROR;
+ }
+ return creds->vtable->create_security_connector(
+ creds, target, args, request_metadata_creds, sc, new_args);
+}
+
void grpc_server_credentials_release(grpc_server_credentials *creds) {
if (creds == NULL) return;
creds->vtable->destroy(creds);
}
+grpc_security_status grpc_server_credentials_create_security_connector(
+ grpc_server_credentials *creds, grpc_security_connector **sc) {
+ if (creds == NULL || creds->vtable->create_security_connector == NULL) {
+ gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
+ return GRPC_SECURITY_ERROR;
+ }
+ return creds->vtable->create_security_connector(creds, sc);
+}
+
/* -- Ssl credentials. -- */
typedef struct {
@@ -167,31 +208,53 @@ static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
return 0;
}
-static grpc_credentials_vtable ssl_vtable = {
- ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
-
-static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
+static grpc_mdctx *ssl_get_metadata_context(grpc_credentials *creds) {
+ return NULL;
+}
-const grpc_ssl_config *grpc_ssl_credentials_get_config(
- const grpc_credentials *creds) {
- if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
- return NULL;
- } else {
- grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
- return &c->config;
+static grpc_security_status ssl_create_security_connector(
+ grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+ grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
+ grpc_security_status status = GRPC_SECURITY_OK;
+ size_t i = 0;
+ const char *overridden_target_name = NULL;
+ grpc_arg arg;
+
+ for (i = 0; args && i < args->num_args; i++) {
+ grpc_arg *arg = &args->args[i];
+ if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
+ arg->type == GRPC_ARG_STRING) {
+ overridden_target_name = arg->value.string;
+ break;
+ }
}
+ status = grpc_ssl_channel_security_connector_create(
+ request_metadata_creds, &c->config, target, overridden_target_name, sc);
+ if (status != GRPC_SECURITY_OK) {
+ return status;
+ }
+ arg.type = GRPC_ARG_STRING;
+ arg.key = GRPC_ARG_HTTP2_SCHEME;
+ arg.value.string = "https";
+ *new_args = grpc_channel_args_copy_and_add(args, &arg);
+ return status;
}
-const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
- const grpc_server_credentials *creds) {
- if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
- return NULL;
- } else {
- grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
- return &c->config;
- }
+static grpc_security_status ssl_server_create_security_connector(
+ grpc_server_credentials *creds, grpc_security_connector **sc) {
+ grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
+ return grpc_ssl_server_security_connector_create(&c->config, sc);
}
+static grpc_credentials_vtable ssl_vtable = {
+ ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only,
+ ssl_get_metadata_context, NULL, ssl_create_security_connector};
+
+static grpc_server_credentials_vtable ssl_server_vtable = {
+ ssl_server_destroy, ssl_server_create_security_connector};
+
static void ssl_copy_key_material(const char *input, unsigned char **output,
size_t *output_size) {
*output_size = strlen(input);
@@ -371,9 +434,14 @@ static void jwt_get_request_metadata(grpc_credentials *creds,
}
}
+static grpc_mdctx *jwt_get_metadata_context(grpc_credentials *creds) {
+ grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
+ return c->md_ctx;
+}
+
static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
- jwt_get_request_metadata};
+ jwt_get_metadata_context, jwt_get_request_metadata, NULL};
grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) {
@@ -585,12 +653,20 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
c->fetch_func = fetch_func;
}
+static grpc_mdctx *oauth2_token_fetcher_get_metadata_context(
+ grpc_credentials *creds) {
+ grpc_oauth2_token_fetcher_credentials *c =
+ (grpc_oauth2_token_fetcher_credentials *)creds;
+ return c->md_ctx;
+}
+
/* -- ComputeEngine credentials. -- */
static grpc_credentials_vtable compute_engine_vtable = {
oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only,
- oauth2_token_fetcher_get_request_metadata};
+ oauth2_token_fetcher_get_metadata_context,
+ oauth2_token_fetcher_get_request_metadata, NULL};
static void compute_engine_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req,
@@ -633,7 +709,8 @@ static void service_account_destroy(grpc_credentials *creds) {
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};
+ oauth2_token_fetcher_get_metadata_context,
+ oauth2_token_fetcher_get_request_metadata, NULL};
static void service_account_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req,
@@ -706,7 +783,8 @@ static void refresh_token_destroy(grpc_credentials *creds) {
static grpc_credentials_vtable refresh_token_vtable = {
refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only,
- oauth2_token_fetcher_get_request_metadata};
+ oauth2_token_fetcher_get_metadata_context,
+ oauth2_token_fetcher_get_request_metadata, NULL};
static void refresh_token_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req,
@@ -801,9 +879,15 @@ static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
}
}
+static grpc_mdctx *fake_oauth2_get_metadata_context(grpc_credentials *creds) {
+ grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
+ return c->md_ctx;
+}
+
static grpc_credentials_vtable fake_oauth2_vtable = {
fake_oauth2_destroy, fake_oauth2_has_request_metadata,
- fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
+ fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context,
+ fake_oauth2_get_request_metadata, NULL};
grpc_credentials *grpc_fake_oauth2_credentials_create(
const char *token_md_value, int is_async) {
@@ -842,14 +926,38 @@ static int fake_transport_security_has_request_metadata_only(
return 0;
}
+static grpc_mdctx *fake_transport_security_get_metadata_context(
+ grpc_credentials *c) {
+ return NULL;
+}
+
+static grpc_security_status
+fake_transport_security_create_security_connector(
+ grpc_credentials *c, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+ *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1);
+ return GRPC_SECURITY_OK;
+}
+
+static grpc_security_status
+fake_transport_security_server_create_security_connector(
+ grpc_server_credentials *c, grpc_security_connector **sc) {
+ *sc = grpc_fake_server_security_connector_create();
+ return GRPC_SECURITY_OK;
+}
+
static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
fake_transport_security_credentials_destroy,
fake_transport_security_has_request_metadata,
- fake_transport_security_has_request_metadata_only, NULL};
+ fake_transport_security_has_request_metadata_only,
+ fake_transport_security_get_metadata_context, 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_destroy,
+ fake_transport_security_server_create_security_connector};
grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
@@ -874,6 +982,7 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
+ grpc_credentials *connector_creds;
} grpc_composite_credentials;
typedef struct {
@@ -995,9 +1104,43 @@ static void composite_get_request_metadata(grpc_credentials *creds,
GPR_ASSERT(0); /* Should have exited before. */
}
+static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) {
+ grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
+ grpc_mdctx *ctx = NULL;
+ size_t i;
+ for (i = 0; i < c->inner.num_creds; i++) {
+ grpc_credentials *inner_creds = c->inner.creds_array[i];
+ grpc_mdctx *inner_ctx = NULL;
+ if (inner_creds->vtable->get_metadata_context != NULL) {
+ inner_ctx = inner_creds->vtable->get_metadata_context(inner_creds);
+ }
+ if (inner_ctx) {
+ GPR_ASSERT(ctx == NULL &&
+ "can only have one metadata context per composite credential");
+ ctx = inner_ctx;
+ }
+ }
+ return ctx;
+}
+
+static grpc_security_status composite_create_security_connector(
+ grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+ grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
+ if (c->connector_creds == NULL) {
+ gpr_log(GPR_ERROR,
+ "Cannot create security connector, missing connector credentials.");
+ return GRPC_SECURITY_ERROR;
+ }
+ return grpc_credentials_create_security_connector(c->connector_creds, target,
+ args, creds, sc, new_args);
+}
+
static grpc_credentials_vtable composite_credentials_vtable = {
composite_destroy, composite_has_request_metadata,
- composite_has_request_metadata_only, composite_get_request_metadata};
+ composite_has_request_metadata_only, composite_get_metadata_context,
+ composite_get_request_metadata, composite_create_security_connector};
static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
grpc_credentials_array result;
@@ -1013,6 +1156,7 @@ static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
grpc_credentials *creds2) {
size_t i;
+ size_t creds_array_byte_size;
grpc_credentials_array creds1_array;
grpc_credentials_array creds2_array;
grpc_composite_credentials *c;
@@ -1026,16 +1170,39 @@ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
creds1_array = get_creds_array(&creds1);
creds2_array = get_creds_array(&creds2);
c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
- c->inner.creds_array =
- gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *));
+ creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
+ c->inner.creds_array = gpr_malloc(creds_array_byte_size);
+ memset(c->inner.creds_array, 0, creds_array_byte_size);
for (i = 0; i < creds1_array.num_creds; i++) {
- c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]);
+ grpc_credentials *cur_creds = creds1_array.creds_array[i];
+ if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
+ if (c->connector_creds == NULL) {
+ c->connector_creds = cur_creds;
+ } else {
+ gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
+ goto fail;
+ }
+ }
+ c->inner.creds_array[i] = grpc_credentials_ref(cur_creds);
}
for (i = 0; i < creds2_array.num_creds; i++) {
+ grpc_credentials *cur_creds = creds2_array.creds_array[i];
+ if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
+ if (c->connector_creds == NULL) {
+ c->connector_creds = cur_creds;
+ } else {
+ gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
+ goto fail;
+ }
+ }
c->inner.creds_array[i + creds1_array.num_creds] =
- grpc_credentials_ref(creds2_array.creds_array[i]);
+ grpc_credentials_ref(cur_creds);
}
return &c->base;
+
+fail:
+ grpc_credentials_unref(&c->base);
+ return NULL;
}
const grpc_credentials_array *grpc_composite_credentials_get_credentials(
@@ -1102,9 +1269,14 @@ static void iam_get_request_metadata(grpc_credentials *creds,
cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK);
}
+static grpc_mdctx *iam_get_metadata_context(grpc_credentials *creds) {
+ grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
+ return c->md_ctx;
+}
+
static grpc_credentials_vtable iam_vtable = {
iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
- iam_get_request_metadata};
+ iam_get_metadata_context, iam_get_request_metadata, NULL};
grpc_credentials *grpc_iam_credentials_create(const char *token,
const char *authority_selector) {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 0f70670ced..87c773e49a 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -39,6 +39,8 @@
#include <grpc/grpc_security.h>
#include <grpc/support/sync.h>
+#include "src/core/security/security_connector.h"
+
struct grpc_httpcli_response;
/* --- Constants. --- */
@@ -94,10 +96,16 @@ typedef struct {
void (*destroy)(grpc_credentials *c);
int (*has_request_metadata)(const grpc_credentials *c);
int (*has_request_metadata_only)(const grpc_credentials *c);
+ grpc_mdctx *(*get_metadata_context)(grpc_credentials *c);
void (*get_request_metadata)(grpc_credentials *c,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data);
+ grpc_security_status (*create_security_connector)(
+ grpc_credentials *c, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+
} grpc_credentials_vtable;
struct grpc_credentials {
@@ -114,17 +122,20 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
const char *service_url,
grpc_credentials_metadata_cb cb,
void *user_data);
-typedef struct {
- unsigned char *pem_private_key;
- size_t pem_private_key_size;
- unsigned char *pem_cert_chain;
- size_t pem_cert_chain_size;
- unsigned char *pem_root_certs;
- size_t pem_root_certs_size;
-} grpc_ssl_config;
-const grpc_ssl_config *grpc_ssl_credentials_get_config(
- const grpc_credentials *ssl_creds);
+/* Gets the mdctx from the credentials and increase the refcount if it exists,
+ otherwise, create a new one. */
+grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
+ grpc_credentials *creds);
+
+/* Creates a security connector for the channel. May also create new channel
+ args for the channel to be used in place of the passed in const args if
+ returned non NULL. In that case the caller is responsible for destroying
+ new_args after channel creation. */
+grpc_security_status grpc_credentials_create_security_connector(
+ grpc_credentials *creds, const char *target, const grpc_channel_args *args,
+ grpc_credentials *request_metadata_creds,
+ grpc_channel_security_connector **sc, grpc_channel_args **new_args);
typedef struct {
grpc_credentials **creds_array;
@@ -156,6 +167,8 @@ grpc_credentials *grpc_fake_oauth2_credentials_create(
typedef struct {
void (*destroy)(grpc_server_credentials *c);
+ grpc_security_status (*create_security_connector)(
+ grpc_server_credentials *c, grpc_security_connector **sc);
} grpc_server_credentials_vtable;
struct grpc_server_credentials {
@@ -163,17 +176,7 @@ struct grpc_server_credentials {
const char *type;
};
-typedef struct {
- unsigned char **pem_private_keys;
- size_t *pem_private_keys_sizes;
- unsigned char **pem_cert_chains;
- size_t *pem_cert_chains_sizes;
- size_t num_key_cert_pairs;
- unsigned char *pem_root_certs;
- size_t pem_root_certs_size;
-} grpc_ssl_server_config;
-
-const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
- const grpc_server_credentials *ssl_creds);
+grpc_security_status grpc_server_credentials_create_security_connector(
+ grpc_server_credentials *creds, grpc_security_connector **sc);
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index ebea70dad2..0e4b9fc9d3 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -127,7 +127,7 @@ static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
gpr_slice creds_data;
int file_ok = 0;
if (creds_path == NULL) return NULL;
- creds_data = gpr_load_file(creds_path, &file_ok);
+ creds_data = gpr_load_file(creds_path, 1, &file_ok);
gpr_free(creds_path);
if (file_ok) {
result = grpc_jwt_credentials_create(
@@ -145,7 +145,7 @@ static grpc_credentials *create_refresh_token_creds_from_path(
gpr_slice creds_data;
int file_ok = 0;
if (creds_path == NULL) return NULL;
- creds_data = gpr_load_file(creds_path, &file_ok);
+ creds_data = gpr_load_file(creds_path, 1, &file_ok);
gpr_free(creds_path);
if (file_ok) {
result = grpc_refresh_token_credentials_create(
@@ -163,7 +163,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
gpr_mu_lock(&g_mu);
if (default_credentials != NULL) {
- result = default_credentials;
+ result = grpc_credentials_ref(default_credentials);
serving_cached_credentials = 1;
goto end;
}
diff --git a/src/core/security/secure_transport_setup.c b/src/core/security/secure_transport_setup.c
index f57d22109c..3e1db9a12d 100644
--- a/src/core/security/secure_transport_setup.c
+++ b/src/core/security/secure_transport_setup.c
@@ -43,7 +43,7 @@
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
typedef struct {
- grpc_security_context *ctx;
+ grpc_security_connector *connector;
tsi_handshaker *handshaker;
unsigned char *handshake_buffer;
size_t handshake_buffer_size;
@@ -74,7 +74,7 @@ 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);
- grpc_security_context_unref(s->ctx);
+ grpc_security_connector_unref(s->connector);
gpr_free(s);
}
@@ -112,8 +112,8 @@ static void check_peer(grpc_secure_transport_setup *s) {
secure_transport_setup_done(s, 0);
return;
}
- peer_status =
- grpc_security_context_check_peer(s->ctx, peer, on_peer_checked, s);
+ peer_status = grpc_security_connector_check_peer(s->connector, peer,
+ on_peer_checked, s);
if (peer_status == GRPC_SECURITY_ERROR) {
gpr_log(GPR_ERROR, "Peer check failed.");
secure_transport_setup_done(s, 0);
@@ -262,7 +262,7 @@ static void on_handshake_data_sent_to_peer(void *setup,
}
}
-void grpc_setup_secure_transport(grpc_security_context *ctx,
+void grpc_setup_secure_transport(grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint,
grpc_secure_transport_setup_done_cb cb,
void *user_data) {
@@ -270,12 +270,12 @@ void grpc_setup_secure_transport(grpc_security_context *ctx,
grpc_secure_transport_setup *s =
gpr_malloc(sizeof(grpc_secure_transport_setup));
memset(s, 0, sizeof(grpc_secure_transport_setup));
- result = grpc_security_context_create_handshaker(ctx, &s->handshaker);
+ result = grpc_security_connector_create_handshaker(connector, &s->handshaker);
if (result != GRPC_SECURITY_OK) {
secure_transport_setup_done(s, 0);
return;
}
- s->ctx = grpc_security_context_ref(ctx);
+ s->connector = grpc_security_connector_ref(connector);
s->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
s->endpoint = nonsecure_endpoint;
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
index e1f8ed7830..58701c461d 100644
--- a/src/core/security/secure_transport_setup.h
+++ b/src/core/security/secure_transport_setup.h
@@ -35,7 +35,7 @@
#define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H
#include "src/core/iomgr/endpoint.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
/* --- Secure transport setup --- */
@@ -45,7 +45,7 @@ typedef void (*grpc_secure_transport_setup_done_cb)(
grpc_endpoint *secure_endpoint);
/* Calls the callback upon completion. */
-void grpc_setup_secure_transport(grpc_security_context *ctx,
+void grpc_setup_secure_transport(grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint,
grpc_secure_transport_setup_done_cb cb,
void *user_data);
diff --git a/src/core/security/security_context.c b/src/core/security/security_connector.c
index e180cad52b..dbd79c5b22 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_connector.c
@@ -31,12 +31,10 @@
*
*/
-#include "src/core/security/security_context.h"
+#include "src/core/security/security_connector.h"
#include <string.h>
-#include "src/core/channel/channel_args.h"
-#include "src/core/channel/http_client_filter.h"
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.h"
#include "src/core/support/env.h"
@@ -56,7 +54,8 @@
#ifndef INSTALL_PREFIX
static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
#else
-static const char *installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem";
+static const char *installed_roots_path =
+ INSTALL_PREFIX "/share/grpc/roots.pem";
#endif
/* -- Cipher suites. -- */
@@ -82,75 +81,77 @@ static const char *ssl_cipher_suites(void) {
/* -- Common methods. -- */
-grpc_security_status grpc_security_context_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
- if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
- return ctx->vtable->create_handshaker(ctx, handshaker);
+grpc_security_status grpc_security_connector_create_handshaker(
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
+ if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
+ return sc->vtable->create_handshaker(sc, handshaker);
}
-grpc_security_status grpc_security_context_check_peer(
- grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb,
+grpc_security_status grpc_security_connector_check_peer(
+ grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
void *user_data) {
- if (ctx == NULL) {
+ if (sc == NULL) {
tsi_peer_destruct(&peer);
return GRPC_SECURITY_ERROR;
}
- return ctx->vtable->check_peer(ctx, peer, cb, user_data);
+ return sc->vtable->check_peer(sc, peer, cb, user_data);
}
-grpc_security_status grpc_channel_security_context_check_call_host(
- grpc_channel_security_context *ctx, const char *host,
+grpc_security_status grpc_channel_security_connector_check_call_host(
+ grpc_channel_security_connector *sc, const char *host,
grpc_security_check_cb cb, void *user_data) {
- if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR;
- return ctx->check_call_host(ctx, host, cb, user_data);
+ if (sc == NULL || sc->check_call_host == NULL) return GRPC_SECURITY_ERROR;
+ return sc->check_call_host(sc, host, cb, user_data);
}
-void grpc_security_context_unref(grpc_security_context *ctx) {
- if (ctx == NULL) return;
- if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx);
+void grpc_security_connector_unref(grpc_security_connector *sc) {
+ if (sc == NULL) return;
+ if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
}
-grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) {
- if (ctx == NULL) return NULL;
- gpr_ref(&ctx->refcount);
- return ctx;
+grpc_security_connector *grpc_security_connector_ref(
+ grpc_security_connector *sc) {
+ if (sc == NULL) return NULL;
+ gpr_ref(&sc->refcount);
+ return sc;
}
-static void context_pointer_arg_destroy(void *p) {
- grpc_security_context_unref(p);
+static void connector_pointer_arg_destroy(void *p) {
+ grpc_security_connector_unref(p);
}
-static void *context_pointer_arg_copy(void *p) {
- return grpc_security_context_ref(p);
+static void *connector_pointer_arg_copy(void *p) {
+ return grpc_security_connector_ref(p);
}
-grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) {
grpc_arg result;
result.type = GRPC_ARG_POINTER;
- result.key = GRPC_SECURITY_CONTEXT_ARG;
- result.value.pointer.destroy = context_pointer_arg_destroy;
- result.value.pointer.copy = context_pointer_arg_copy;
- result.value.pointer.p = ctx;
+ result.key = GRPC_SECURITY_CONNECTOR_ARG;
+ result.value.pointer.destroy = connector_pointer_arg_destroy;
+ result.value.pointer.copy = connector_pointer_arg_copy;
+ result.value.pointer.p = sc;
return result;
}
-grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) {
- if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
+ if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
- GRPC_SECURITY_CONTEXT_ARG);
+ GRPC_SECURITY_CONNECTOR_ARG);
return NULL;
}
return arg->value.pointer.p;
}
-grpc_security_context *grpc_find_security_context_in_args(
+grpc_security_connector *grpc_find_security_connector_in_args(
const grpc_channel_args *args) {
size_t i;
if (args == NULL) return NULL;
for (i = 0; i < args->num_args; i++) {
- grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]);
- if (ctx != NULL) return ctx;
+ grpc_security_connector *sc =
+ grpc_security_connector_from_arg(&args->args[i]);
+ if (sc != NULL) return sc;
}
return NULL;
}
@@ -158,7 +159,7 @@ grpc_security_context *grpc_find_security_context_in_args(
static int check_request_metadata_creds(grpc_credentials *creds) {
if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
gpr_log(GPR_ERROR,
- "Incompatible credentials for channel security context: needs to "
+ "Incompatible credentials for channel security connector: needs to "
"set request metadata.");
return 0;
}
@@ -168,31 +169,31 @@ static int check_request_metadata_creds(grpc_credentials *creds) {
/* -- Fake implementation. -- */
typedef struct {
- grpc_channel_security_context base;
+ grpc_channel_security_connector base;
int call_host_check_is_async;
-} grpc_fake_channel_security_context;
+} grpc_fake_channel_security_connector;
-static void fake_channel_destroy(grpc_security_context *ctx) {
- grpc_channel_security_context *c = (grpc_channel_security_context *)ctx;
+static void fake_channel_destroy(grpc_security_connector *sc) {
+ grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_credentials_unref(c->request_metadata_creds);
- gpr_free(ctx);
+ gpr_free(sc);
}
-static void fake_server_destroy(grpc_security_context *ctx) { gpr_free(ctx); }
+static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
static grpc_security_status fake_channel_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
*handshaker = tsi_create_fake_handshaker(1);
return GRPC_SECURITY_OK;
}
static grpc_security_status fake_server_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
*handshaker = tsi_create_fake_handshaker(0);
return GRPC_SECURITY_OK;
}
-static grpc_security_status fake_check_peer(grpc_security_context *ctx,
+static grpc_security_status fake_check_peer(grpc_security_connector *sc,
tsi_peer peer,
grpc_security_check_cb cb,
void *user_data) {
@@ -228,10 +229,10 @@ end:
}
static grpc_security_status fake_channel_check_call_host(
- grpc_channel_security_context *ctx, const char *host,
+ grpc_channel_security_connector *sc, const char *host,
grpc_security_check_cb cb, void *user_data) {
- grpc_fake_channel_security_context *c =
- (grpc_fake_channel_security_context *)ctx;
+ grpc_fake_channel_security_connector *c =
+ (grpc_fake_channel_security_connector *)sc;
if (c->call_host_check_is_async) {
cb(user_data, GRPC_SECURITY_OK);
return GRPC_SECURITY_PENDING;
@@ -240,16 +241,16 @@ static grpc_security_status fake_channel_check_call_host(
}
}
-static grpc_security_context_vtable fake_channel_vtable = {
+static grpc_security_connector_vtable fake_channel_vtable = {
fake_channel_destroy, fake_channel_create_handshaker, fake_check_peer};
-static grpc_security_context_vtable fake_server_vtable = {
+static grpc_security_connector_vtable fake_server_vtable = {
fake_server_destroy, fake_server_create_handshaker, fake_check_peer};
-grpc_channel_security_context *grpc_fake_channel_security_context_create(
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
- grpc_fake_channel_security_context *c =
- gpr_malloc(sizeof(grpc_fake_channel_security_context));
+ grpc_fake_channel_security_connector *c =
+ gpr_malloc(sizeof(grpc_fake_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -261,8 +262,8 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create(
return &c->base;
}
-grpc_security_context *grpc_fake_server_security_context_create(void) {
- grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context));
+grpc_security_connector *grpc_fake_server_security_connector_create(void) {
+ grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
gpr_ref_init(&c->refcount, 1);
c->vtable = &fake_server_vtable;
c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@@ -272,21 +273,21 @@ grpc_security_context *grpc_fake_server_security_context_create(void) {
/* --- Ssl implementation. --- */
typedef struct {
- grpc_channel_security_context base;
+ grpc_channel_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory;
char *target_name;
char *overridden_target_name;
tsi_peer peer;
-} grpc_ssl_channel_security_context;
+} grpc_ssl_channel_security_connector;
typedef struct {
- grpc_security_context base;
+ grpc_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory;
-} grpc_ssl_server_security_context;
+} grpc_ssl_server_security_connector;
-static void ssl_channel_destroy(grpc_security_context *ctx) {
- grpc_ssl_channel_security_context *c =
- (grpc_ssl_channel_security_context *)ctx;
+static void ssl_channel_destroy(grpc_security_connector *sc) {
+ grpc_ssl_channel_security_connector *c =
+ (grpc_ssl_channel_security_connector *)sc;
grpc_credentials_unref(c->base.request_metadata_creds);
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
@@ -294,15 +295,16 @@ static void ssl_channel_destroy(grpc_security_context *ctx) {
if (c->target_name != NULL) gpr_free(c->target_name);
if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
tsi_peer_destruct(&c->peer);
- gpr_free(ctx);
+ gpr_free(sc);
}
-static void ssl_server_destroy(grpc_security_context *ctx) {
- grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
+static void ssl_server_destroy(grpc_security_connector *sc) {
+ grpc_ssl_server_security_connector *c =
+ (grpc_ssl_server_security_connector *)sc;
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
- gpr_free(ctx);
+ gpr_free(sc);
}
static grpc_security_status ssl_create_handshaker(
@@ -321,9 +323,9 @@ static grpc_security_status ssl_create_handshaker(
}
static grpc_security_status ssl_channel_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
- grpc_ssl_channel_security_context *c =
- (grpc_ssl_channel_security_context *)ctx;
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
+ grpc_ssl_channel_security_connector *c =
+ (grpc_ssl_channel_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 1,
c->overridden_target_name != NULL
? c->overridden_target_name
@@ -332,13 +334,13 @@ static grpc_security_status ssl_channel_create_handshaker(
}
static grpc_security_status ssl_server_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker) {
- grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
+ grpc_security_connector *sc, tsi_handshaker **handshaker) {
+ grpc_ssl_server_security_connector *c =
+ (grpc_ssl_server_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
}
-static int ssl_host_matches_name(const tsi_peer *peer,
- const char *peer_name) {
+static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
char *allocated_name = NULL;
int r;
@@ -349,7 +351,6 @@ static int ssl_host_matches_name(const tsi_peer *peer,
peer_name = allocated_name;
if (!peer_name) return 0;
}
-
r = tsi_ssl_peer_matches_name(peer, peer_name);
gpr_free(allocated_name);
return r;
@@ -375,8 +376,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
}
/* Check the peer name if specified. */
- if (peer_name != NULL &&
- !ssl_host_matches_name(peer, peer_name)) {
+ if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR;
}
@@ -384,12 +384,12 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
return GRPC_SECURITY_OK;
}
-static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
+static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc,
tsi_peer peer,
grpc_security_check_cb cb,
void *user_data) {
- grpc_ssl_channel_security_context *c =
- (grpc_ssl_channel_security_context *)ctx;
+ grpc_ssl_channel_security_connector *c =
+ (grpc_ssl_channel_security_connector *)sc;
grpc_security_status status;
tsi_peer_destruct(&c->peer);
c->peer = peer;
@@ -400,7 +400,7 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
return status;
}
-static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
+static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc,
tsi_peer peer,
grpc_security_check_cb cb,
void *user_data) {
@@ -411,10 +411,10 @@ static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
}
static grpc_security_status ssl_channel_check_call_host(
- grpc_channel_security_context *ctx, const char *host,
+ grpc_channel_security_connector *sc, const char *host,
grpc_security_check_cb cb, void *user_data) {
- grpc_ssl_channel_security_context *c =
- (grpc_ssl_channel_security_context *)ctx;
+ grpc_ssl_channel_security_connector *c =
+ (grpc_ssl_channel_security_connector *)sc;
if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK;
@@ -428,10 +428,10 @@ static grpc_security_status ssl_channel_check_call_host(
}
}
-static grpc_security_context_vtable ssl_channel_vtable = {
+static grpc_security_connector_vtable ssl_channel_vtable = {
ssl_channel_destroy, ssl_channel_create_handshaker, ssl_channel_check_peer};
-static grpc_security_context_vtable ssl_server_vtable = {
+static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
static gpr_slice default_pem_root_certs;
@@ -443,13 +443,13 @@ static void init_default_pem_root_certs(void) {
if (default_root_certs_path == NULL) {
default_pem_root_certs = gpr_empty_slice();
} else {
- default_pem_root_certs = gpr_load_file(default_root_certs_path, NULL);
+ default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL);
gpr_free(default_root_certs_path);
}
/* Fall back to installed certs if needed. */
if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) {
- default_pem_root_certs = gpr_load_file(installed_roots_path, NULL);
+ default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL);
}
}
@@ -462,17 +462,17 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
return GPR_SLICE_LENGTH(default_pem_root_certs);
}
-grpc_security_status grpc_ssl_channel_security_context_create(
+grpc_security_status grpc_ssl_channel_security_connector_create(
grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *target_name, const char *overridden_target_name,
- grpc_channel_security_context **ctx) {
+ grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK;
- grpc_ssl_channel_security_context *c;
+ grpc_ssl_channel_security_connector *c;
size_t i;
const unsigned char *pem_root_certs;
size_t pem_root_certs_size;
@@ -493,8 +493,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
goto error;
}
- c = gpr_malloc(sizeof(grpc_ssl_channel_security_context));
- memset(c, 0, sizeof(grpc_ssl_channel_security_context));
+ c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
+ memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable;
@@ -526,10 +526,10 @@ grpc_security_status grpc_ssl_channel_security_context_create(
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
ssl_channel_destroy(&c->base.base);
- *ctx = NULL;
+ *sc = NULL;
goto error;
}
- *ctx = &c->base;
+ *sc = &c->base;
gpr_free(alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK;
@@ -540,15 +540,15 @@ error:
return GRPC_SECURITY_ERROR;
}
-grpc_security_status grpc_ssl_server_security_context_create(
- const grpc_ssl_server_config *config, grpc_security_context **ctx) {
+grpc_security_status grpc_ssl_server_security_connector_create(
+ const grpc_ssl_server_config *config, grpc_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK;
- grpc_ssl_server_security_context *c;
+ grpc_ssl_server_security_connector *c;
size_t i;
for (i = 0; i < num_alpn_protocols; i++) {
@@ -562,8 +562,8 @@ grpc_security_status grpc_ssl_server_security_context_create(
gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
goto error;
}
- c = gpr_malloc(sizeof(grpc_ssl_server_security_context));
- memset(c, 0, sizeof(grpc_ssl_server_security_context));
+ c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
+ memset(c, 0, sizeof(grpc_ssl_server_security_connector));
gpr_ref_init(&c->base.refcount, 1);
c->base.url_scheme = GRPC_SSL_URL_SCHEME;
@@ -573,17 +573,17 @@ grpc_security_status grpc_ssl_server_security_context_create(
config->pem_private_keys_sizes,
(const unsigned char **)config->pem_cert_chains,
config->pem_cert_chains_sizes, config->num_key_cert_pairs,
- config->pem_root_certs, config->pem_root_certs_size,
- ssl_cipher_suites(), alpn_protocol_strings,
- alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
+ config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
+ alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols,
+ &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
ssl_server_destroy(&c->base);
- *ctx = NULL;
+ *sc = NULL;
goto error;
}
- *ctx = &c->base;
+ *sc = &c->base;
gpr_free(alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK;
@@ -594,83 +594,3 @@ error:
return GRPC_SECURITY_ERROR;
}
-/* -- High level objects. -- */
-
-grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
- grpc_credentials *request_metadata_creds,
- const char *target,
- const grpc_channel_args *args) {
- grpc_channel_security_context *ctx = NULL;
- grpc_channel *channel = NULL;
- grpc_security_status status = GRPC_SECURITY_OK;
- size_t i = 0;
- const char *overridden_target_name = NULL;
- grpc_arg arg;
- grpc_channel_args *new_args;
-
- for (i = 0; args && i < args->num_args; i++) {
- grpc_arg *arg = &args->args[i];
- if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
- arg->type == GRPC_ARG_STRING) {
- overridden_target_name = arg->value.string;
- break;
- }
- }
- status = grpc_ssl_channel_security_context_create(
- request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds),
- target, overridden_target_name, &ctx);
- if (status != GRPC_SECURITY_OK) {
- return grpc_lame_client_channel_create();
- }
- arg.type = GRPC_ARG_STRING;
- arg.key = GRPC_ARG_HTTP2_SCHEME;
- arg.value.string = "https";
- new_args = grpc_channel_args_copy_and_add(args, &arg);
- channel = grpc_secure_channel_create_internal(target, new_args, ctx);
- grpc_security_context_unref(&ctx->base);
- grpc_channel_args_destroy(new_args);
- return channel;
-}
-
-grpc_channel *grpc_fake_transport_security_channel_create(
- grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
- const char *target, const grpc_channel_args *args) {
- grpc_channel_security_context *ctx =
- grpc_fake_channel_security_context_create(request_metadata_creds, 1);
- grpc_channel *channel =
- grpc_secure_channel_create_internal(target, args, ctx);
- grpc_security_context_unref(&ctx->base);
- return channel;
-}
-
-grpc_channel *grpc_secure_channel_create_with_factories(
- const grpc_secure_channel_factory *factories, size_t num_factories,
- grpc_credentials *creds, const char *target,
- const grpc_channel_args *args) {
- size_t i;
- if (creds == NULL) {
- gpr_log(GPR_ERROR, "No credentials to create a secure channel.");
- return grpc_lame_client_channel_create();
- }
- if (grpc_credentials_has_request_metadata_only(creds)) {
- gpr_log(GPR_ERROR,
- "Credentials is insufficient to create a secure channel.");
- return grpc_lame_client_channel_create();
- }
-
- for (i = 0; i < num_factories; i++) {
- grpc_credentials *composite_creds = NULL;
- grpc_credentials *transport_security_creds = NULL;
- transport_security_creds = grpc_credentials_contains_type(
- creds, factories[i].creds_type, &composite_creds);
- if (transport_security_creds != NULL) {
- return factories[i].factory(transport_security_creds, composite_creds,
- target, args);
- }
- }
-
- gpr_log(GPR_ERROR,
- "Unknown credentials type %s for creating a secure channel.",
- creds->type);
- return grpc_lame_client_channel_create();
-}
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
new file mode 100644
index 0000000000..47abe05cff
--- /dev/null
+++ b/src/core/security/security_connector.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
+#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H
+
+#include <grpc/grpc_security.h>
+#include "src/core/iomgr/endpoint.h"
+#include "src/core/tsi/transport_security_interface.h"
+
+/* --- status enum. --- */
+
+typedef enum {
+ GRPC_SECURITY_OK = 0,
+ GRPC_SECURITY_PENDING,
+ GRPC_SECURITY_ERROR
+} grpc_security_status;
+
+/* --- URL schemes. --- */
+
+#define GRPC_SSL_URL_SCHEME "https"
+#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
+
+/* --- security_connector object. ---
+
+ A security connector object represents away to configure the underlying
+ transport security mechanism and check the resulting trusted peer. */
+
+typedef struct grpc_security_connector grpc_security_connector;
+
+#define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
+
+typedef void (*grpc_security_check_cb)(void *user_data,
+ grpc_security_status status);
+
+typedef struct {
+ void (*destroy)(grpc_security_connector *sc);
+ grpc_security_status (*create_handshaker)(grpc_security_connector *sc,
+ tsi_handshaker **handshaker);
+ grpc_security_status (*check_peer)(grpc_security_connector *sc, tsi_peer peer,
+ grpc_security_check_cb cb,
+ void *user_data);
+} grpc_security_connector_vtable;
+
+struct grpc_security_connector {
+ const grpc_security_connector_vtable *vtable;
+ gpr_refcount refcount;
+ int is_client_side;
+ const char *url_scheme;
+};
+
+/* Increments the refcount. */
+grpc_security_connector *grpc_security_connector_ref(
+ grpc_security_connector *sc);
+
+/* Decrements the refcount and destroys the object if it reaches 0. */
+void grpc_security_connector_unref(grpc_security_connector *sc);
+
+/* Handshake creation. */
+grpc_security_status grpc_security_connector_create_handshaker(
+ grpc_security_connector *sc, tsi_handshaker **handshaker);
+
+/* Check the peer.
+ Implementations can choose to check the peer either synchronously or
+ asynchronously. In the first case, a successful call will return
+ GRPC_SECURITY_OK. In the asynchronous case, the call will return
+ GRPC_SECURITY_PENDING unless an error is detected early on.
+ Ownership of the peer is transfered.
+*/
+grpc_security_status grpc_security_connector_check_peer(
+ grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
+ void *user_data);
+
+/* Util to encapsulate the connector in a channel arg. */
+grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
+
+/* Util to get the connector from a channel arg. */
+grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg);
+
+/* Util to find the connector from channel args. */
+grpc_security_connector *grpc_find_security_connector_in_args(
+ const grpc_channel_args *args);
+
+/* --- channel_security_connector object. ---
+
+ A channel security connector object represents away to configure the
+ underlying transport security mechanism on the client side. */
+
+typedef struct grpc_channel_security_connector grpc_channel_security_connector;
+
+struct grpc_channel_security_connector {
+ grpc_security_connector base; /* requires is_client_side to be non 0. */
+ grpc_credentials *request_metadata_creds;
+ grpc_security_status (*check_call_host)(grpc_channel_security_connector *sc,
+ const char *host,
+ grpc_security_check_cb cb,
+ void *user_data);
+};
+
+/* Checks that the host that will be set for a call is acceptable.
+ Implementations can choose do the check either synchronously or
+ asynchronously. In the first case, a successful call will return
+ GRPC_SECURITY_OK. In the asynchronous case, the call will return
+ GRPC_SECURITY_PENDING unless an error is detected early on. */
+grpc_security_status grpc_channel_security_connector_check_call_host(
+ grpc_channel_security_connector *sc, const char *host,
+ grpc_security_check_cb cb, void *user_data);
+
+/* --- Creation security connectors. --- */
+
+/* For TESTING ONLY!
+ Creates a fake connector that emulates real channel security. */
+grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
+ grpc_credentials *request_metadata_creds, int call_host_check_is_async);
+
+/* For TESTING ONLY!
+ Creates a fake connector that emulates real server security. */
+grpc_security_connector *grpc_fake_server_security_connector_create(void);
+
+/* Config for ssl clients. */
+typedef struct {
+ unsigned char *pem_private_key;
+ size_t pem_private_key_size;
+ unsigned char *pem_cert_chain;
+ size_t pem_cert_chain_size;
+ unsigned char *pem_root_certs;
+ size_t pem_root_certs_size;
+} grpc_ssl_config;
+
+/* Creates an SSL channel_security_connector.
+ - request_metadata_creds is the credentials object which metadata
+ will be sent with each request. This parameter can be NULL.
+ - config is the SSL config to be used for the SSL channel establishment.
+ - is_client should be 0 for a server or a non-0 value for a client.
+ - secure_peer_name is the secure peer name that should be checked in
+ grpc_channel_security_connector_check_peer. This parameter may be NULL in
+ which case the peer name will not be checked. Note that if this parameter
+ is not NULL, then, pem_root_certs should not be NULL either.
+ - sc is a pointer on the connector to be created.
+ This function returns GRPC_SECURITY_OK in case of success or a
+ specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_channel_security_connector_create(
+ grpc_credentials *request_metadata_creds,
+ const grpc_ssl_config *config, const char *target_name,
+ const char *overridden_target_name, grpc_channel_security_connector **sc);
+
+/* Gets the default ssl roots. */
+size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
+
+/* Config for ssl servers. */
+typedef struct {
+ unsigned char **pem_private_keys;
+ size_t *pem_private_keys_sizes;
+ unsigned char **pem_cert_chains;
+ size_t *pem_cert_chains_sizes;
+ size_t num_key_cert_pairs;
+ unsigned char *pem_root_certs;
+ size_t pem_root_certs_size;
+} grpc_ssl_server_config;
+
+/* Creates an SSL server_security_connector.
+ - config is the SSL config to be used for the SSL channel establishment.
+ - sc is a pointer on the connector to be created.
+ This function returns GRPC_SECURITY_OK in case of success or a
+ specific error code otherwise.
+*/
+grpc_security_status grpc_ssl_server_security_connector_create(
+ const grpc_ssl_server_config *config, grpc_security_connector **sc);
+
+#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONNECTOR_H */
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
deleted file mode 100644
index 0b5821c3c0..0000000000
--- a/src/core/security/security_context.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H
-#define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H
-
-#include <grpc/grpc_security.h>
-#include "src/core/iomgr/endpoint.h"
-#include "src/core/security/credentials.h"
-#include "src/core/tsi/transport_security_interface.h"
-
-/* --- status enum. --- */
-
-typedef enum {
- GRPC_SECURITY_OK = 0,
- GRPC_SECURITY_PENDING,
- GRPC_SECURITY_ERROR
-} grpc_security_status;
-
-/* --- URL schemes. --- */
-
-#define GRPC_SSL_URL_SCHEME "https"
-#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security"
-
-/* --- security_context object. ---
-
- A security context object represents away to configure the underlying
- transport security mechanism and check the resulting trusted peer. */
-
-typedef struct grpc_security_context grpc_security_context;
-
-#define GRPC_SECURITY_CONTEXT_ARG "grpc.security_context"
-
-typedef void (*grpc_security_check_cb)(void *user_data,
- grpc_security_status status);
-
-typedef struct {
- void (*destroy)(grpc_security_context *ctx);
- grpc_security_status (*create_handshaker)(grpc_security_context *ctx,
- tsi_handshaker **handshaker);
- grpc_security_status (*check_peer)(grpc_security_context *ctx, tsi_peer peer,
- grpc_security_check_cb cb,
- void *user_data);
-} grpc_security_context_vtable;
-
-struct grpc_security_context {
- const grpc_security_context_vtable *vtable;
- gpr_refcount refcount;
- int is_client_side;
- const char *url_scheme;
-};
-
-/* Increments the refcount. */
-grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx);
-
-/* Decrements the refcount and destroys the object if it reaches 0. */
-void grpc_security_context_unref(grpc_security_context *ctx);
-
-/* Handshake creation. */
-grpc_security_status grpc_security_context_create_handshaker(
- grpc_security_context *ctx, tsi_handshaker **handshaker);
-
-/* Check the peer.
- Implementations can choose to check the peer either synchronously or
- asynchronously. In the first case, a successful call will return
- GRPC_SECURITY_OK. In the asynchronous case, the call will return
- GRPC_SECURITY_PENDING unless an error is detected early on.
- Ownership of the peer is transfered.
-*/
-grpc_security_status grpc_security_context_check_peer(
- grpc_security_context *ctx, tsi_peer peer,
- grpc_security_check_cb cb, void *user_data);
-
-/* Util to encapsulate the context in a channel arg. */
-grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx);
-
-/* Util to get the context from a channel arg. */
-grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg);
-
-/* Util to find the context from channel args. */
-grpc_security_context *grpc_find_security_context_in_args(
- const grpc_channel_args *args);
-
-/* --- channel_security_context object. ---
-
- A channel security context object represents away to configure the
- underlying transport security mechanism on the client side. */
-
-typedef struct grpc_channel_security_context grpc_channel_security_context;
-
-struct grpc_channel_security_context {
- grpc_security_context base; /* requires is_client_side to be non 0. */
- grpc_credentials *request_metadata_creds;
- grpc_security_status (*check_call_host)(
- grpc_channel_security_context *ctx, const char *host,
- grpc_security_check_cb cb, void *user_data);
-};
-
-/* Checks that the host that will be set for a call is acceptable.
- Implementations can choose do the check either synchronously or
- asynchronously. In the first case, a successful call will return
- GRPC_SECURITY_OK. In the asynchronous case, the call will return
- GRPC_SECURITY_PENDING unless an error is detected early on. */
-grpc_security_status grpc_channel_security_context_check_call_host(
- grpc_channel_security_context *ctx, const char *host,
- grpc_security_check_cb cb, void *user_data);
-
-/* --- Creation security contexts. --- */
-
-/* For TESTING ONLY!
- Creates a fake context that emulates real channel security. */
-grpc_channel_security_context *grpc_fake_channel_security_context_create(
- grpc_credentials *request_metadata_creds, int call_host_check_is_async);
-
-/* For TESTING ONLY!
- Creates a fake context that emulates real server security. */
-grpc_security_context *grpc_fake_server_security_context_create(void);
-
-/* Creates an SSL channel_security_context.
- - request_metadata_creds is the credentials object which metadata
- will be sent with each request. This parameter can be NULL.
- - config is the SSL config to be used for the SSL channel establishment.
- - is_client should be 0 for a server or a non-0 value for a client.
- - secure_peer_name is the secure peer name that should be checked in
- grpc_channel_security_context_check_peer. This parameter may be NULL in
- which case the peer name will not be checked. Note that if this parameter
- is not NULL, then, pem_root_certs should not be NULL either.
- - ctx is a pointer on the context to be created.
- This function returns GRPC_SECURITY_OK in case of success or a
- specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_channel_security_context_create(
- grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
- const char *target_name, const char *overridden_target_name,
- grpc_channel_security_context **ctx);
-
-/* Creates an SSL server_security_context.
- - config is the SSL config to be used for the SSL channel establishment.
- - ctx is a pointer on the context to be created.
- This function returns GRPC_SECURITY_OK in case of success or a
- specific error code otherwise.
-*/
-grpc_security_status grpc_ssl_server_security_context_create(
- const grpc_ssl_server_config *config, grpc_security_context **ctx);
-
-/* --- Creation of high level objects. --- */
-
-/* Secure client channel creation. */
-
-size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
-
-grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
- grpc_credentials *request_metadata_creds,
- const char *target,
- const grpc_channel_args *args);
-
-grpc_channel *grpc_fake_transport_security_channel_create(
- grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
- const char *target, const grpc_channel_args *args);
-
-grpc_channel *grpc_secure_channel_create_internal(
- const char *target, const grpc_channel_args *args,
- grpc_channel_security_context *ctx);
-
-typedef grpc_channel *(*grpc_secure_channel_factory_func)(
- grpc_credentials *transport_security_creds,
- grpc_credentials *request_metadata_creds, const char *target,
- const grpc_channel_args *args);
-
-typedef struct {
- const char *creds_type;
- grpc_secure_channel_factory_func factory;
-} grpc_secure_channel_factory;
-
-grpc_channel *grpc_secure_channel_create_with_factories(
- const grpc_secure_channel_factory *factories, size_t num_factories,
- grpc_credentials *creds, const char *target, const grpc_channel_args *args);
-
-/* Secure server creation. */
-
-grpc_server *grpc_secure_server_create_internal(grpc_completion_queue *cq,
- const grpc_channel_args *args,
- grpc_security_context *ctx);
-
-#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index c155b80b7e..db9d545c0e 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -35,12 +35,12 @@
#include <string.h>
-#include "src/core/channel/http_filter.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_server.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_connector.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h"
@@ -52,7 +52,7 @@
typedef struct grpc_server_secure_state {
grpc_server *server;
grpc_tcp_server *tcp;
- grpc_security_context *ctx;
+ grpc_security_connector *sc;
int is_shutdown;
gpr_mu mu;
gpr_refcount refcount;
@@ -64,7 +64,7 @@ static void state_ref(grpc_server_secure_state *state) {
static void state_unref(grpc_server_secure_state *state) {
if (gpr_unref(&state->refcount)) {
- grpc_security_context_unref(state->ctx);
+ grpc_security_connector_unref(state->sc);
gpr_free(state);
}
}
@@ -72,8 +72,8 @@ static void state_unref(grpc_server_secure_state *state) {
static grpc_transport_setup_result setup_transport(void *server,
grpc_transport *transport,
grpc_mdctx *mdctx) {
- static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter,
- &grpc_http_filter};
+ static grpc_channel_filter const *extra_filters[] = {
+ &grpc_http_server_filter};
return grpc_server_setup_transport(server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx);
}
@@ -85,10 +85,10 @@ static void on_secure_transport_setup_done(void *statep,
if (status == GRPC_SECURITY_OK) {
gpr_mu_lock(&state->mu);
if (!state->is_shutdown) {
- grpc_create_chttp2_transport(
- setup_transport, state->server,
- grpc_server_get_channel_args(state->server),
- secure_endpoint, NULL, 0, grpc_mdctx_create(), 0);
+ grpc_create_chttp2_transport(setup_transport, state->server,
+ grpc_server_get_channel_args(state->server),
+ secure_endpoint, NULL, 0,
+ grpc_mdctx_create(), 0);
} else {
/* We need to consume this here, because the server may already have gone
* away. */
@@ -104,7 +104,8 @@ static void on_secure_transport_setup_done(void *statep,
static void on_accept(void *statep, grpc_endpoint *tcp) {
grpc_server_secure_state *state = statep;
state_ref(state);
- grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, state);
+ grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done,
+ state);
}
/* Server callback: start listening on our ports */
@@ -120,12 +121,14 @@ static void destroy(grpc_server *server, void *statep) {
grpc_server_secure_state *state = statep;
gpr_mu_lock(&state->mu);
state->is_shutdown = 1;
- grpc_tcp_server_destroy(state->tcp);
+ grpc_tcp_server_destroy(state->tcp, grpc_server_listener_destroy_done,
+ server);
gpr_mu_unlock(&state->mu);
state_unref(state);
}
-int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_credentials *creds) {
+int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
+ grpc_server_credentials *creds) {
grpc_resolved_addresses *resolved = NULL;
grpc_tcp_server *tcp = NULL;
grpc_server_secure_state *state = NULL;
@@ -134,20 +137,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grp
int port_num = -1;
int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR;
- grpc_security_context *ctx = NULL;
+ grpc_security_connector *sc = NULL;
/* create security context */
if (creds == NULL) goto error;
-
- if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) {
- status = grpc_ssl_server_security_context_create(
- grpc_ssl_server_credentials_get_config(creds), &ctx);
- } else if (strcmp(creds->type,
- GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) {
- ctx = grpc_fake_server_security_context_create();
- status = GRPC_SECURITY_OK;
- }
-
+ status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR,
"Unable to create secure server with credentials of type %s.",
@@ -194,7 +188,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grp
state = gpr_malloc(sizeof(*state));
state->server = server;
state->tcp = tcp;
- state->ctx = ctx;
+ state->sc = sc;
state->is_shutdown = 0;
gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1);
@@ -206,14 +200,14 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grp
/* Error path: cleanup and return */
error:
- if (ctx) {
- grpc_security_context_unref(ctx);
+ if (sc) {
+ grpc_security_connector_unref(sc);
}
if (resolved) {
grpc_resolved_addresses_destroy(resolved);
}
if (tcp) {
- grpc_tcp_server_destroy(tcp);
+ grpc_tcp_server_destroy(tcp, NULL, NULL);
}
if (state) {
gpr_free(state);
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
index a19a0141d4..d2ed82e771 100644
--- a/src/core/support/alloc.c
+++ b/src/core/support/alloc.c
@@ -55,7 +55,7 @@ void *gpr_realloc(void *p, size_t size) {
}
void *gpr_malloc_aligned(size_t size, size_t alignment_log) {
- size_t alignment = 1 << alignment_log;
+ size_t alignment = ((size_t)1) << alignment_log;
size_t extra = alignment - 1 + sizeof(void *);
void *p = gpr_malloc(size + extra);
void **ret = (void **)(((gpr_uintptr)p + extra) & ~(alignment - 1));
diff --git a/src/core/support/file.c b/src/core/support/file.c
index 70100b7e9b..3a4ac6f2f0 100644
--- a/src/core/support/file.c
+++ b/src/core/support/file.c
@@ -41,13 +41,14 @@
#include "src/core/support/string.h"
-gpr_slice gpr_load_file(const char *filename, int *success) {
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+ int *success) {
unsigned char *contents = NULL;
size_t contents_size = 0;
- unsigned char buf[4096];
char *error_msg = NULL;
gpr_slice result = gpr_empty_slice();
FILE *file = fopen(filename, "rb");
+ size_t bytes_read = 0;
if (file == NULL) {
gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename,
@@ -55,27 +56,22 @@ gpr_slice gpr_load_file(const char *filename, int *success) {
GPR_ASSERT(error_msg != NULL);
goto end;
}
-
- while (1) {
- size_t bytes_read = fread(buf, 1, sizeof(buf), file);
- if (bytes_read > 0) {
- contents = gpr_realloc(contents, contents_size + bytes_read);
- memcpy(contents + contents_size, buf, bytes_read);
- contents_size += bytes_read;
- }
- if (bytes_read < sizeof(buf)) {
- if (ferror(file)) {
- gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
- strerror(errno), filename);
- GPR_ASSERT(error_msg != NULL);
- goto end;
- } else {
- GPR_ASSERT(feof(file));
- break;
- }
- }
+ fseek(file, 0, SEEK_END);
+ contents_size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
+ bytes_read = fread(contents, 1, contents_size, file);
+ if (bytes_read < contents_size) {
+ GPR_ASSERT(ferror(file));
+ gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
+ strerror(errno), filename);
+ GPR_ASSERT(error_msg != NULL);
+ goto end;
}
if (success != NULL) *success = 1;
+ if (add_null_terminator) {
+ contents[contents_size++] = 0;
+ }
result = gpr_slice_new(contents, contents_size, gpr_free);
end:
diff --git a/src/core/support/file.h b/src/core/support/file.h
index ee6ca7b230..1dafe390e3 100644
--- a/src/core/support/file.h
+++ b/src/core/support/file.h
@@ -44,9 +44,11 @@ extern "C" {
/* File utility functions */
-/* Loads the content of a file into a slice. The success parameter, if not NULL,
+/* Loads the content of a file into a slice. add_null_terminator will add
+ a NULL terminator if non-zero. The success parameter, if not NULL,
will be set to 1 in case of success and 0 in case of failure. */
-gpr_slice gpr_load_file(const char *filename, int *success);
+gpr_slice gpr_load_file(const char *filename, int add_null_terminator,
+ int *success);
/* Creates a temporary file from a prefix.
If tmp_filename is not NULL, *tmp_filename is assigned the name of the
diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c
index ed344b43e8..673affde71 100644
--- a/src/core/support/histogram.c
+++ b/src/core/support/histogram.c
@@ -76,7 +76,7 @@ static size_t bucket_for_unchecked(gpr_histogram *h, double x) {
/* bounds checked version of the above */
static size_t bucket_for(gpr_histogram *h, double x) {
- size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 0, h->max_possible));
+ size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible));
GPR_ASSERT(bucket < h->num_buckets);
return bucket;
}
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index b280e4bd02..3b1daa07c5 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -38,21 +38,34 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-/* initial allocation size (# of slices) */
-#define INITIAL_CAPACITY 4
-/* grow a buffer; requires INITIAL_CAPACITY > 1 */
+/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
#define GROW(x) (3 * (x) / 2)
+static void maybe_embiggen(gpr_slice_buffer *sb) {
+ if (sb->count == sb->capacity) {
+ sb->capacity = GROW(sb->capacity);
+ GPR_ASSERT(sb->capacity > sb->count);
+ if (sb->slices == sb->inlined) {
+ sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
+ memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
+ } else {
+ sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+ }
+ }
+}
+
void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
sb->count = 0;
sb->length = 0;
- sb->capacity = INITIAL_CAPACITY;
- sb->slices = gpr_malloc(sizeof(gpr_slice) * INITIAL_CAPACITY);
+ sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
+ sb->slices = sb->inlined;
}
void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
gpr_slice_buffer_reset_and_unref(sb);
- gpr_free(sb->slices);
+ if (sb->slices != sb->inlined) {
+ gpr_free(sb->slices);
+ }
}
gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned n) {
@@ -71,11 +84,7 @@ gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned n) {
return out;
add_new:
- if (sb->count == sb->capacity) {
- sb->capacity = GROW(sb->capacity);
- GPR_ASSERT(sb->capacity > sb->count);
- sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
- }
+ maybe_embiggen(sb);
back = &sb->slices[sb->count];
sb->count++;
back->refcount = NULL;
@@ -85,11 +94,7 @@ add_new:
size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
size_t out = sb->count;
- if (out == sb->capacity) {
- sb->capacity = GROW(sb->capacity);
- GPR_ASSERT(sb->capacity > sb->count);
- sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
- }
+ maybe_embiggen(sb);
sb->slices[out] = s;
sb->length += GPR_SLICE_LENGTH(s);
sb->count = out + 1;
@@ -116,12 +121,7 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
memcpy(back->data.inlined.bytes + back->data.inlined.length,
s.data.inlined.bytes, cp1);
back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
- if (n == sb->capacity) {
- sb->capacity = GROW(sb->capacity);
- GPR_ASSERT(sb->capacity > sb->count);
- sb->slices =
- gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
- }
+ maybe_embiggen(sb);
back = &sb->slices[n];
sb->count = n + 1;
back->refcount = NULL;
@@ -160,3 +160,16 @@ void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
sb->count = 0;
sb->length = 0;
}
+
+void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
+ gpr_slice_buffer temp = *a;
+ *a = *b;
+ *b = temp;
+
+ if (a->slices == b->inlined) {
+ a->slices = a->inlined;
+ }
+ if (b->slices == a->inlined) {
+ b->slices = b->inlined;
+ }
+}
diff --git a/src/core/security/factories.c b/src/core/support/thd.c
index 02267d5545..ec308f3119 100644
--- a/src/core/security/factories.c
+++ b/src/core/support/thd.c
@@ -31,22 +31,36 @@
*
*/
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include "src/core/security/credentials.h"
-#include "src/core/security/security_context.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/useful.h>
-
-grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
- const char *target,
- const grpc_channel_args *args) {
- grpc_secure_channel_factory factories[] = {
- {GRPC_CREDENTIALS_TYPE_SSL, grpc_ssl_channel_create},
- {GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY,
- grpc_fake_transport_security_channel_create}};
- return grpc_secure_channel_create_with_factories(
- factories, GPR_ARRAY_SIZE(factories), creds, target, args);
+/* Posix implementation for gpr threads. */
+
+#include <memory.h>
+
+#include <grpc/support/thd.h>
+
+enum {
+ GPR_THD_JOINABLE = 1
+};
+
+gpr_thd_options gpr_thd_options_default(void) {
+ gpr_thd_options options;
+ memset(&options, 0, sizeof(options));
+ return options;
+}
+
+void gpr_thd_options_set_detached(gpr_thd_options *options) {
+ options->flags &= ~GPR_THD_JOINABLE;
+}
+
+void gpr_thd_options_set_joinable(gpr_thd_options *options) {
+ options->flags |= GPR_THD_JOINABLE;
+}
+
+int gpr_thd_options_is_detached(const gpr_thd_options *options) {
+ if (!options) return 1;
+ return (options->flags & GPR_THD_JOINABLE) == 0;
+}
+
+int gpr_thd_options_is_joinable(const gpr_thd_options *options) {
+ if (!options) return 0;
+ return (options->flags & GPR_THD_JOINABLE) == GPR_THD_JOINABLE;
}
diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c
index f50ea58335..fa4eb50556 100644
--- a/src/core/support/thd_posix.c
+++ b/src/core/support/thd_posix.c
@@ -68,7 +68,11 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
a->arg = arg;
GPR_ASSERT(pthread_attr_init(&attr) == 0);
- GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+ if (gpr_thd_options_is_detached(options)) {
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0);
+ } else {
+ GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) == 0);
+ }
thread_started = (pthread_create(&p, &attr, &thread_body, a) == 0);
GPR_ASSERT(pthread_attr_destroy(&attr) == 0);
if (!thread_started) {
@@ -78,14 +82,12 @@ int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
return thread_started;
}
-gpr_thd_options gpr_thd_options_default(void) {
- gpr_thd_options options;
- memset(&options, 0, sizeof(options));
- return options;
-}
-
gpr_thd_id gpr_thd_currentid(void) {
return (gpr_thd_id)pthread_self();
}
+void gpr_thd_join(gpr_thd_id t) {
+ pthread_join((pthread_t)t, NULL);
+}
+
#endif /* GPR_POSIX_SYNC */
diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c
index 347cad57e3..3cc798293a 100644
--- a/src/core/support/thd_win32.c
+++ b/src/core/support/thd_win32.c
@@ -31,7 +31,7 @@
*
*/
-/* Posix implementation for gpr threads. */
+/* Windows implementation for gpr threads. */
#include <grpc/support/port_platform.h>
@@ -40,47 +40,81 @@
#include <windows.h>
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include <grpc/support/thd.h>
-struct thd_arg {
+#if defined(_MSC_VER)
+#define thread_local __declspec(thread)
+#elif defined(__GNUC__)
+#define thread_local __thread
+#else
+#error "Unknown compiler - please file a bug report"
+#endif
+
+struct thd_info {
void (*body)(void *arg); /* body of a thread */
void *arg; /* argument to a thread */
+ HANDLE join_event; /* if joinable, the join event */
+ int joinable; /* true if not detached */
};
+static thread_local struct thd_info *g_thd_info;
+
+/* Destroys a thread info */
+static void destroy_thread(struct thd_info *t) {
+ if (t->joinable) CloseHandle(t->join_event);
+ gpr_free(t);
+}
+
/* Body of every thread started via gpr_thd_new. */
static DWORD WINAPI thread_body(void *v) {
- struct thd_arg a = *(struct thd_arg *)v;
- gpr_free(v);
- (*a.body)(a.arg);
+ g_thd_info = (struct thd_info *)v;
+ g_thd_info->body(g_thd_info->arg);
+ if (g_thd_info->joinable) {
+ BOOL ret = SetEvent(g_thd_info->join_event);
+ GPR_ASSERT(ret);
+ } else {
+ destroy_thread(g_thd_info);
+ }
return 0;
}
int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
const gpr_thd_options *options) {
HANDLE handle;
- DWORD thread_id;
- struct thd_arg *a = gpr_malloc(sizeof(*a));
- a->body = thd_body;
- a->arg = arg;
+ struct thd_info *info = gpr_malloc(sizeof(*info));
+ info->body = thd_body;
+ info->arg = arg;
*t = 0;
- handle = CreateThread(NULL, 64 * 1024, thread_body, a, 0, &thread_id);
+ if (gpr_thd_options_is_joinable(options)) {
+ info->joinable = 1;
+ info->join_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (info->join_event == NULL) {
+ gpr_free(info);
+ return 0;
+ }
+ } else {
+ info->joinable = 0;
+ }
+ handle = CreateThread(NULL, 64 * 1024, thread_body, info, 0, NULL);
if (handle == NULL) {
- gpr_free(a);
+ destroy_thread(info);
} else {
- CloseHandle(handle); /* threads are "detached" */
+ *t = (gpr_thd_id)info;
+ CloseHandle(handle);
}
- *t = (gpr_thd_id)thread_id;
return handle != NULL;
}
-gpr_thd_options gpr_thd_options_default(void) {
- gpr_thd_options options;
- memset(&options, 0, sizeof(options));
- return options;
+gpr_thd_id gpr_thd_currentid(void) {
+ return (gpr_thd_id)g_thd_info;
}
-gpr_thd_id gpr_thd_currentid(void) {
- return (gpr_thd_id)GetCurrentThreadId();
+void gpr_thd_join(gpr_thd_id t) {
+ struct thd_info *info = (struct thd_info *)t;
+ DWORD ret = WaitForSingleObject(info->join_event, INFINITE);
+ GPR_ASSERT(ret == WAIT_OBJECT_0);
+ destroy_thread(info);
}
#endif /* GPR_WIN32 */
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index f221cb5790..f4443b5c2d 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -39,6 +39,7 @@
#include <grpc/support/time.h>
#include <sys/timeb.h>
+#include <windows.h>
gpr_timespec gpr_now(void) {
gpr_timespec now_tv;
@@ -49,4 +50,23 @@ gpr_timespec gpr_now(void) {
return now_tv;
}
+void gpr_sleep_until(gpr_timespec until) {
+ gpr_timespec now;
+ gpr_timespec delta;
+ DWORD sleep_millis;
+
+ for (;;) {
+ /* We could simplify by using clock_nanosleep instead, but it might be
+ * slightly less portable. */
+ now = gpr_now();
+ if (gpr_time_cmp(until, now) <= 0) {
+ return;
+ }
+
+ delta = gpr_time_sub(until, now);
+ sleep_millis = (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+ Sleep(sleep_millis);
+ }
+}
+
#endif /* GPR_WIN32 */
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index cfce943794..6ca1b4e9a1 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -33,7 +33,6 @@
#include "src/core/surface/call.h"
#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/metadata_buffer.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/support/string.h"
#include "src/core/surface/byte_buffer_queue.h"
@@ -41,6 +40,7 @@
#include "src/core/surface/completion_queue.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -68,8 +68,10 @@ typedef struct {
} completed_request;
/* See request_set in grpc_call below for a description */
-#define REQSET_EMPTY 255
-#define REQSET_DONE 254
+#define REQSET_EMPTY 'X'
+#define REQSET_DONE 'Y'
+
+#define MAX_SEND_INITIAL_METADATA_COUNT 3
typedef struct {
/* Overall status of the operation: starts OK, may degrade to
@@ -79,9 +81,9 @@ typedef struct {
grpc_ioreq_completion_func on_complete;
void *user_data;
/* a bit mask of which request ops are needed (1u << opid) */
- gpr_uint32 need_mask;
+ gpr_uint16 need_mask;
/* a bit mask of which request ops are now completed */
- gpr_uint32 complete_mask;
+ gpr_uint16 complete_mask;
} reqinfo_master;
/* Status data for a request can come from several sources; this
@@ -92,6 +94,8 @@ typedef enum {
/* Status came from the application layer overriding whatever
the wire says */
STATUS_FROM_API_OVERRIDE = 0,
+ /* Status was created by some internal channel stack operation */
+ STATUS_FROM_CORE,
/* Status came from 'the wire' - or somewhere below the surface
layer */
STATUS_FROM_WIRE,
@@ -140,12 +144,17 @@ struct grpc_call {
gpr_uint8 have_alarm;
/* are we currently performing a send operation */
gpr_uint8 sending;
+ /* are we currently performing a recv operation */
+ gpr_uint8 receiving;
/* are we currently completing requests */
gpr_uint8 completing;
/* pairs with completed_requests */
gpr_uint8 num_completed_requests;
- /* flag that we need to request more data */
- gpr_uint8 need_more_data;
+ /* are we currently reading a message? */
+ gpr_uint8 reading_message;
+ /* flags with bits corresponding to write states allowing us to determine
+ what was sent */
+ gpr_uint16 last_send_contains;
/* Active ioreqs.
request_set and request_data contain one element per active ioreq
@@ -204,12 +213,25 @@ struct grpc_call {
/* Call refcount - to keep the call alive during asynchronous operations */
gpr_refcount internal_refcount;
+ grpc_linked_mdelem send_initial_metadata[MAX_SEND_INITIAL_METADATA_COUNT];
+ grpc_linked_mdelem status_link;
+ grpc_linked_mdelem details_link;
+ size_t send_initial_metadata_count;
+ gpr_timespec send_deadline;
+
+ grpc_stream_op_buffer send_ops;
+ grpc_stream_op_buffer recv_ops;
+ grpc_stream_state recv_state;
+
+ gpr_slice_buffer incoming_message;
+ gpr_uint32 incoming_message_length;
+
/* Data that the legacy api needs to track. To be deleted at some point
soon */
legacy_state *legacy_state;
};
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call)+1))
+#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
#define CALL_ELEM_FROM_CALL(call, idx) \
grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
@@ -224,12 +246,22 @@ struct grpc_call {
} while (0)
static void do_nothing(void *ignored, grpc_op_error also_ignored) {}
-static send_action choose_send_action(grpc_call *call);
-static void enact_send_action(grpc_call *call, send_action sa);
+static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline);
+static void call_on_done_recv(void *call, int success);
+static void call_on_done_send(void *call, int success);
+static int fill_send_ops(grpc_call *call, grpc_transport_op *op);
+static void execute_op(grpc_call *call, grpc_transport_op *op);
+static void recv_metadata(grpc_call *call, grpc_metadata_batch *metadata);
+static void finish_read_ops(grpc_call *call);
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_mdelem **add_initial_metadata,
+ size_t add_initial_metadata_count,
+ gpr_timespec send_deadline) {
size_t i;
+ grpc_transport_op initial_op;
+ grpc_transport_op *initial_op_ptr = NULL;
grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
grpc_call *call =
gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
@@ -245,13 +277,36 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
call->request_set[GRPC_IOREQ_SEND_TRAILING_METADATA] = REQSET_DONE;
call->request_set[GRPC_IOREQ_SEND_STATUS] = REQSET_DONE;
}
+ GPR_ASSERT(add_initial_metadata_count < MAX_SEND_INITIAL_METADATA_COUNT);
+ for (i = 0; i < add_initial_metadata_count; i++) {
+ call->send_initial_metadata[i].md = add_initial_metadata[i];
+ }
+ call->send_initial_metadata_count = add_initial_metadata_count;
+ call->send_deadline = send_deadline;
grpc_channel_internal_ref(channel);
call->metadata_context = grpc_channel_get_metadata_context(channel);
- /* one ref is dropped in response to destroy, the other in
- stream_closed */
- gpr_ref_init(&call->internal_refcount, 2);
- grpc_call_stack_init(channel_stack, server_transport_data,
+ grpc_sopb_init(&call->send_ops);
+ grpc_sopb_init(&call->recv_ops);
+ gpr_slice_buffer_init(&call->incoming_message);
+ /* dropped in destroy */
+ gpr_ref_init(&call->internal_refcount, 1);
+ /* server hack: start reads immediately so we can get initial metadata.
+ TODO(ctiller): figure out a cleaner solution */
+ if (!call->is_client) {
+ memset(&initial_op, 0, sizeof(initial_op));
+ initial_op.recv_ops = &call->recv_ops;
+ initial_op.recv_state = &call->recv_state;
+ initial_op.on_done_recv = call_on_done_recv;
+ initial_op.recv_user_data = call;
+ call->receiving = 1;
+ GRPC_CALL_INTERNAL_REF(call, "receiving");
+ initial_op_ptr = &initial_op;
+ }
+ grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr,
CALL_STACK_FROM_CALL(call));
+ if (gpr_time_cmp(send_deadline, gpr_inf_future) != 0) {
+ set_deadline_alarm(call, send_deadline);
+ }
return call;
}
@@ -264,7 +319,15 @@ grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call) {
return call->cq;
}
-void grpc_call_internal_ref(grpc_call *c) { gpr_ref(&c->internal_refcount); }
+#ifdef GRPC_CALL_REF_COUNT_DEBUG
+void grpc_call_internal_ref(grpc_call *c, const char *reason) {
+ gpr_log(GPR_DEBUG, "CALL: ref %p %d -> %d [%s]", c,
+ c->internal_refcount.count, c->internal_refcount.count + 1, reason);
+#else
+void grpc_call_internal_ref(grpc_call *c) {
+#endif
+ gpr_ref(&c->internal_refcount);
+}
static void destroy_call(void *call, int ignored_success) {
size_t i;
@@ -284,14 +347,27 @@ static void destroy_call(void *call, int ignored_success) {
for (i = 0; i < GPR_ARRAY_SIZE(c->buffered_metadata); i++) {
gpr_free(c->buffered_metadata[i].metadata);
}
+ for (i = 0; i < c->send_initial_metadata_count; i++) {
+ grpc_mdelem_unref(c->send_initial_metadata[i].md);
+ }
+ grpc_sopb_destroy(&c->send_ops);
+ grpc_sopb_destroy(&c->recv_ops);
if (c->legacy_state) {
destroy_legacy_state(c->legacy_state);
}
grpc_bbq_destroy(&c->incoming_queue);
+ gpr_slice_buffer_destroy(&c->incoming_message);
gpr_free(c);
}
+#ifdef GRPC_CALL_REF_COUNT_DEBUG
+void grpc_call_internal_unref(grpc_call *c, const char *reason,
+ int allow_immediate_deletion) {
+ gpr_log(GPR_DEBUG, "CALL: unref %p %d -> %d [%s]", c,
+ c->internal_refcount.count, c->internal_refcount.count - 1, reason);
+#else
void grpc_call_internal_unref(grpc_call *c, int allow_immediate_deletion) {
+#endif
if (gpr_unref(&c->internal_refcount)) {
if (allow_immediate_deletion) {
destroy_call(c, 1);
@@ -333,19 +409,6 @@ static grpc_call_error bind_cq(grpc_call *call, grpc_completion_queue *cq) {
return GRPC_CALL_OK;
}
-static void request_more_data(grpc_call *call) {
- grpc_call_op op;
-
- /* call down */
- op.type = GRPC_REQUEST_DATA;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.done_cb = do_nothing;
- op.user_data = NULL;
-
- grpc_call_execute_op(call, &op);
-}
-
static int is_op_live(grpc_call *call, grpc_ioreq_op op) {
gpr_uint8 set = call->request_set[op];
reqinfo_master *master;
@@ -356,17 +419,43 @@ static int is_op_live(grpc_call *call, grpc_ioreq_op op) {
static void lock(grpc_call *call) { gpr_mu_lock(&call->mu); }
+static int need_more_data(grpc_call *call) {
+ return is_op_live(call, GRPC_IOREQ_RECV_INITIAL_METADATA) ||
+ is_op_live(call, GRPC_IOREQ_RECV_MESSAGE) ||
+ is_op_live(call, GRPC_IOREQ_RECV_TRAILING_METADATA) ||
+ is_op_live(call, GRPC_IOREQ_RECV_STATUS) ||
+ is_op_live(call, GRPC_IOREQ_RECV_STATUS_DETAILS) ||
+ (is_op_live(call, GRPC_IOREQ_RECV_CLOSE) &&
+ grpc_bbq_empty(&call->incoming_queue)) ||
+ (call->write_state == WRITE_STATE_INITIAL && !call->is_client &&
+ call->read_state != READ_STATE_STREAM_CLOSED);
+}
+
static void unlock(grpc_call *call) {
- send_action sa = SEND_NOTHING;
+ grpc_transport_op op;
completed_request completed_requests[GRPC_IOREQ_OP_COUNT];
int completing_requests = 0;
- int need_more_data =
- call->need_more_data &&
- (call->write_state >= WRITE_STATE_STARTED || !call->is_client);
+ int start_op = 0;
int i;
- if (need_more_data) {
- call->need_more_data = 0;
+ memset(&op, 0, sizeof(op));
+
+ 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;
+ op.recv_user_data = call;
+ call->receiving = 1;
+ GRPC_CALL_INTERNAL_REF(call, "receiving");
+ start_op = 1;
+ }
+
+ if (!call->sending) {
+ if (fill_send_ops(call, &op)) {
+ call->sending = 1;
+ GRPC_CALL_INTERNAL_REF(call, "sending");
+ start_op = 1;
+ }
}
if (!call->completing && call->num_completed_requests != 0) {
@@ -375,25 +464,13 @@ static void unlock(grpc_call *call) {
sizeof(completed_requests));
call->num_completed_requests = 0;
call->completing = 1;
- grpc_call_internal_ref(call);
- }
-
- if (!call->sending) {
- sa = choose_send_action(call);
- if (sa != SEND_NOTHING) {
- call->sending = 1;
- grpc_call_internal_ref(call);
- }
+ GRPC_CALL_INTERNAL_REF(call, "completing");
}
gpr_mu_unlock(&call->mu);
- if (need_more_data) {
- request_more_data(call);
- }
-
- if (sa != SEND_NOTHING) {
- enact_send_action(call, sa);
+ if (start_op) {
+ execute_op(call, &op);
}
if (completing_requests > 0) {
@@ -404,7 +481,7 @@ static void unlock(grpc_call *call) {
lock(call);
call->completing = 0;
unlock(call);
- grpc_call_internal_unref(call, 0);
+ GRPC_CALL_INTERNAL_UNREF(call, "completing", 0);
}
}
@@ -468,7 +545,6 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
master->complete_mask |= 1u << op;
if (status != GRPC_OP_OK) {
master->status = status;
- master->complete_mask = master->need_mask;
}
if (master->complete_mask == master->need_mask) {
for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
@@ -527,160 +603,267 @@ static void finish_ioreq_op(grpc_call *call, grpc_ioreq_op op,
}
}
-static void finish_send_op(grpc_call *call, grpc_ioreq_op op, write_state ws,
- grpc_op_error error) {
+static void call_on_done_send(void *pc, int success) {
+ grpc_call *call = pc;
+ grpc_op_error error = success ? GRPC_OP_OK : GRPC_OP_ERROR;
lock(call);
- finish_ioreq_op(call, op, error);
+ if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) {
+ finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, error);
+ }
+ if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_MESSAGE)) {
+ finish_ioreq_op(call, GRPC_IOREQ_SEND_MESSAGE, error);
+ }
+ if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_CLOSE)) {
+ finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, error);
+ finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, error);
+ finish_ioreq_op(call, GRPC_IOREQ_SEND_CLOSE, GRPC_OP_OK);
+ }
+ call->last_send_contains = 0;
call->sending = 0;
- call->write_state = ws;
unlock(call);
- grpc_call_internal_unref(call, 0);
+ GRPC_CALL_INTERNAL_UNREF(call, "sending", 0);
}
-static void finish_write_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_MESSAGE, WRITE_STATE_STARTED, error);
+static void finish_message(grpc_call *call) {
+ /* TODO(ctiller): this could be a lot faster if coded directly */
+ grpc_byte_buffer *byte_buffer = grpc_byte_buffer_create(
+ call->incoming_message.slices, call->incoming_message.count);
+ gpr_slice_buffer_reset_and_unref(&call->incoming_message);
+
+ grpc_bbq_push(&call->incoming_queue, byte_buffer);
+
+ GPR_ASSERT(call->incoming_message.count == 0);
+ call->reading_message = 0;
}
-static void finish_finish_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_CLOSE, WRITE_STATE_WRITE_CLOSED, error);
+static int begin_message(grpc_call *call, grpc_begin_message msg) {
+ /* can't begin a message when we're still reading a message */
+ if (call->reading_message) {
+ char *message = NULL;
+ gpr_asprintf(
+ &message, "Message terminated early; read %d bytes, expected %d",
+ (int)call->incoming_message.length, (int)call->incoming_message_length);
+ grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
+ gpr_free(message);
+ return 0;
+ }
+ /* stash away parameters, and prepare for incoming slices */
+ if (msg.length > grpc_channel_get_max_message_length(call->channel)) {
+ char *message = NULL;
+ gpr_asprintf(
+ &message,
+ "Maximum message length of %d exceeded by a message of length %d",
+ grpc_channel_get_max_message_length(call->channel), msg.length);
+ grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
+ gpr_free(message);
+ return 0;
+ } else if (msg.length > 0) {
+ call->reading_message = 1;
+ call->incoming_message_length = msg.length;
+ return 1;
+ } else {
+ finish_message(call);
+ return 1;
+ }
}
-static void finish_start_step(void *pc, grpc_op_error error) {
- finish_send_op(pc, GRPC_IOREQ_SEND_INITIAL_METADATA, WRITE_STATE_STARTED,
- error);
+static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
+ if (GPR_SLICE_LENGTH(slice) == 0) {
+ gpr_slice_unref(slice);
+ return 1;
+ }
+ /* we have to be reading a message to know what to do here */
+ if (!call->reading_message) {
+ grpc_call_cancel_with_status(
+ call, GRPC_STATUS_INVALID_ARGUMENT,
+ "Received payload data while not reading a message");
+ return 0;
+ }
+ /* append the slice to the incoming buffer */
+ gpr_slice_buffer_add(&call->incoming_message, slice);
+ if (call->incoming_message.length > call->incoming_message_length) {
+ /* if we got too many bytes, complain */
+ char *message = NULL;
+ gpr_asprintf(
+ &message, "Receiving message overflow; read %d bytes, expected %d",
+ (int)call->incoming_message.length, (int)call->incoming_message_length);
+ grpc_call_cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT, message);
+ gpr_free(message);
+ return 0;
+ } else if (call->incoming_message.length == call->incoming_message_length) {
+ finish_message(call);
+ return 1;
+ } else {
+ return 1;
+ }
}
-static send_action choose_send_action(grpc_call *call) {
- switch (call->write_state) {
- case WRITE_STATE_INITIAL:
- if (is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) {
- if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE) ||
- is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
- return SEND_BUFFERED_INITIAL_METADATA;
- } else {
- return SEND_INITIAL_METADATA;
- }
- }
- return SEND_NOTHING;
- case WRITE_STATE_STARTED:
- if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) {
- if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
- return SEND_BUFFERED_MESSAGE;
- } else {
- return SEND_MESSAGE;
- }
- } else if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
- finish_ioreq_op(call, GRPC_IOREQ_SEND_TRAILING_METADATA, GRPC_OP_OK);
- finish_ioreq_op(call, GRPC_IOREQ_SEND_STATUS, GRPC_OP_OK);
- if (call->is_client) {
- return SEND_FINISH;
- } else {
- return SEND_TRAILING_METADATA_AND_FINISH;
- }
+static void call_on_done_recv(void *pc, int success) {
+ grpc_call *call = pc;
+ size_t i;
+ lock(call);
+ call->receiving = 0;
+ if (success) {
+ for (i = 0; success && i < call->recv_ops.nops; i++) {
+ grpc_stream_op *op = &call->recv_ops.ops[i];
+ switch (op->type) {
+ case GRPC_NO_OP:
+ break;
+ case GRPC_OP_METADATA:
+ recv_metadata(call, &op->data.metadata);
+ break;
+ case GRPC_OP_BEGIN_MESSAGE:
+ success = begin_message(call, op->data.begin_message);
+ break;
+ case GRPC_OP_SLICE:
+ success = add_slice_to_message(call, op->data.slice);
+ break;
}
- return SEND_NOTHING;
- case WRITE_STATE_WRITE_CLOSED:
- return SEND_NOTHING;
+ }
+ if (call->recv_state == GRPC_STREAM_RECV_CLOSED) {
+ GPR_ASSERT(call->read_state <= READ_STATE_READ_CLOSED);
+ call->read_state = READ_STATE_READ_CLOSED;
+ }
+ if (call->recv_state == GRPC_STREAM_CLOSED) {
+ GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED);
+ call->read_state = READ_STATE_STREAM_CLOSED;
+ }
+ finish_read_ops(call);
+ } else {
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_MESSAGE, GRPC_OP_ERROR);
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS, GRPC_OP_ERROR);
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_CLOSE, GRPC_OP_ERROR);
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_TRAILING_METADATA, GRPC_OP_ERROR);
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_INITIAL_METADATA, GRPC_OP_ERROR);
+ finish_ioreq_op(call, GRPC_IOREQ_RECV_STATUS_DETAILS, GRPC_OP_ERROR);
+ }
+ call->recv_ops.nops = 0;
+ unlock(call);
+
+ GRPC_CALL_INTERNAL_UNREF(call, "receiving", 0);
+}
+
+static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count,
+ grpc_metadata *metadata) {
+ size_t i;
+ grpc_mdelem_list out;
+ if (count == 0) {
+ out.head = out.tail = NULL;
+ return out;
+ }
+ for (i = 0; i < count; i++) {
+ grpc_metadata *md = &metadata[i];
+ grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1];
+ grpc_metadata *prev_md = (i == 0) ? NULL : &metadata[i - 1];
+ grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
+ GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
+ l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key,
+ (const gpr_uint8 *)md->value,
+ md->value_length);
+ l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL;
+ l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- return SEND_NOTHING;
+ out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data);
+ out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data);
+ return out;
}
-static void send_metadata(grpc_call *call, grpc_mdelem *elem) {
- grpc_call_op op;
- op.type = GRPC_SEND_METADATA;
- op.dir = GRPC_CALL_DOWN;
- op.flags = GRPC_WRITE_BUFFER_HINT;
- op.data.metadata = elem;
- op.done_cb = do_nothing;
- op.user_data = NULL;
- grpc_call_execute_op(call, &op);
+/* Copy the contents of a byte buffer into stream ops */
+static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
+ grpc_stream_op_buffer *sopb) {
+ size_t i;
+
+ switch (byte_buffer->type) {
+ case GRPC_BB_SLICE_BUFFER:
+ for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
+ gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
+ gpr_slice_ref(slice);
+ grpc_sopb_add_slice(sopb, slice);
+ }
+ break;
+ }
}
-static void enact_send_action(grpc_call *call, send_action sa) {
+static int fill_send_ops(grpc_call *call, grpc_transport_op *op) {
grpc_ioreq_data data;
- grpc_call_op op;
+ grpc_metadata_batch mdb;
size_t i;
- gpr_uint32 flags = 0;
char status_str[GPR_LTOA_MIN_BUFSIZE];
+ GPR_ASSERT(op->send_ops == NULL);
- switch (sa) {
- case SEND_NOTHING:
- abort();
- break;
- case SEND_BUFFERED_INITIAL_METADATA:
- flags |= GRPC_WRITE_BUFFER_HINT;
- /* fallthrough */
- case SEND_INITIAL_METADATA:
+ switch (call->write_state) {
+ case WRITE_STATE_INITIAL:
+ if (!is_op_live(call, GRPC_IOREQ_SEND_INITIAL_METADATA)) {
+ break;
+ }
data = call->request_data[GRPC_IOREQ_SEND_INITIAL_METADATA];
- for (i = 0; i < data.send_metadata.count; i++) {
- const grpc_metadata *md = &data.send_metadata.metadata[i];
- send_metadata(call,
- grpc_mdelem_from_string_and_buffer(
- call->metadata_context, md->key,
- (const gpr_uint8 *)md->value, md->value_length));
+ mdb.list = chain_metadata_from_app(call, data.send_metadata.count,
+ data.send_metadata.metadata);
+ mdb.garbage.head = mdb.garbage.tail = NULL;
+ mdb.deadline = call->send_deadline;
+ for (i = 0; i < call->send_initial_metadata_count; i++) {
+ grpc_metadata_batch_link_head(&mdb, &call->send_initial_metadata[i]);
}
- op.type = GRPC_SEND_START;
- op.dir = GRPC_CALL_DOWN;
- op.flags = flags;
- op.data.start.pollset = grpc_cq_pollset(call->cq);
- op.done_cb = finish_start_step;
- op.user_data = call;
- grpc_call_execute_op(call, &op);
- break;
- case SEND_BUFFERED_MESSAGE:
- flags |= GRPC_WRITE_BUFFER_HINT;
- /* fallthrough */
- case SEND_MESSAGE:
- data = call->request_data[GRPC_IOREQ_SEND_MESSAGE];
- op.type = GRPC_SEND_MESSAGE;
- op.dir = GRPC_CALL_DOWN;
- op.flags = flags;
- op.data.message = data.send_message;
- op.done_cb = finish_write_step;
- op.user_data = call;
- grpc_call_execute_op(call, &op);
- break;
- case SEND_TRAILING_METADATA_AND_FINISH:
- /* send trailing metadata */
- data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA];
- for (i = 0; i < data.send_metadata.count; i++) {
- const grpc_metadata *md = &data.send_metadata.metadata[i];
- send_metadata(call,
- grpc_mdelem_from_string_and_buffer(
- call->metadata_context, md->key,
- (const gpr_uint8 *)md->value, md->value_length));
+ grpc_sopb_add_metadata(&call->send_ops, mdb);
+ op->send_ops = &call->send_ops;
+ op->bind_pollset = grpc_cq_pollset(call->cq);
+ call->last_send_contains |= 1 << GRPC_IOREQ_SEND_INITIAL_METADATA;
+ call->write_state = WRITE_STATE_STARTED;
+ call->send_initial_metadata_count = 0;
+ /* fall through intended */
+ case WRITE_STATE_STARTED:
+ if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) {
+ data = call->request_data[GRPC_IOREQ_SEND_MESSAGE];
+ grpc_sopb_add_begin_message(
+ &call->send_ops, grpc_byte_buffer_length(data.send_message), 0);
+ copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops);
+ op->send_ops = &call->send_ops;
+ call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE;
}
- /* send status */
- /* TODO(ctiller): cache common status values */
- data = call->request_data[GRPC_IOREQ_SEND_STATUS];
- gpr_ltoa(data.send_status.code, status_str);
- send_metadata(
- call,
- grpc_mdelem_from_metadata_strings(
- call->metadata_context,
- grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)),
- grpc_mdstr_from_string(call->metadata_context, status_str)));
- if (data.send_status.details) {
- send_metadata(
- call,
- grpc_mdelem_from_metadata_strings(
- call->metadata_context,
- grpc_mdstr_ref(grpc_channel_get_message_string(call->channel)),
- grpc_mdstr_from_string(call->metadata_context,
- data.send_status.details)));
+ if (is_op_live(call, GRPC_IOREQ_SEND_CLOSE)) {
+ op->is_last_send = 1;
+ op->send_ops = &call->send_ops;
+ call->last_send_contains |= 1 << GRPC_IOREQ_SEND_CLOSE;
+ call->write_state = WRITE_STATE_WRITE_CLOSED;
+ if (!call->is_client) {
+ /* send trailing metadata */
+ data = call->request_data[GRPC_IOREQ_SEND_TRAILING_METADATA];
+ mdb.list = chain_metadata_from_app(call, data.send_metadata.count,
+ data.send_metadata.metadata);
+ mdb.garbage.head = mdb.garbage.tail = NULL;
+ mdb.deadline = gpr_inf_future;
+ /* send status */
+ /* TODO(ctiller): cache common status values */
+ data = call->request_data[GRPC_IOREQ_SEND_STATUS];
+ gpr_ltoa(data.send_status.code, status_str);
+ grpc_metadata_batch_add_tail(
+ &mdb, &call->status_link,
+ grpc_mdelem_from_metadata_strings(
+ call->metadata_context,
+ grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)),
+ grpc_mdstr_from_string(call->metadata_context, status_str)));
+ if (data.send_status.details) {
+ grpc_metadata_batch_add_tail(
+ &mdb, &call->details_link,
+ grpc_mdelem_from_metadata_strings(
+ call->metadata_context,
+ grpc_mdstr_ref(
+ grpc_channel_get_message_string(call->channel)),
+ grpc_mdstr_from_string(call->metadata_context,
+ data.send_status.details)));
+ }
+ grpc_sopb_add_metadata(&call->send_ops, mdb);
+ }
}
- /* fallthrough: see choose_send_action for details */
- case SEND_FINISH:
- op.type = GRPC_SEND_FINISH;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.done_cb = finish_finish_step;
- op.user_data = call;
- grpc_call_execute_op(call, &op);
break;
+ case WRITE_STATE_WRITE_CLOSED:
+ break;
+ }
+ if (op->send_ops) {
+ op->on_done_send = call_on_done_send;
+ op->send_user_data = call;
}
+ return op->send_ops != NULL;
}
static grpc_call_error start_ioreq_error(grpc_call *call,
@@ -789,10 +972,6 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
master->on_complete = completion;
master->user_data = user_data;
- if (have_ops & (1u << GRPC_IOREQ_RECV_MESSAGE)) {
- call->need_more_data = 1;
- }
-
finish_read_ops(call);
early_out_write_ops(call);
@@ -819,43 +998,37 @@ void grpc_call_destroy(grpc_call *c) {
cancel = c->read_state != READ_STATE_STREAM_CLOSED;
unlock(c);
if (cancel) grpc_call_cancel(c);
- grpc_call_internal_unref(c, 1);
+ GRPC_CALL_INTERNAL_UNREF(c, "destroy", 1);
}
-grpc_call_error grpc_call_cancel(grpc_call *c) {
- grpc_call_element *elem;
- grpc_call_op op;
-
- op.type = GRPC_CANCEL_OP;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.done_cb = do_nothing;
- op.user_data = NULL;
-
- elem = CALL_ELEM_FROM_CALL(c, 0);
- elem->filter->call_op(elem, NULL, &op);
-
- return GRPC_CALL_OK;
+grpc_call_error grpc_call_cancel(grpc_call *call) {
+ return grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED, "Cancelled");
}
grpc_call_error grpc_call_cancel_with_status(grpc_call *c,
grpc_status_code status,
const char *description) {
+ grpc_transport_op op;
grpc_mdstr *details =
description ? grpc_mdstr_from_string(c->metadata_context, description)
: NULL;
+ memset(&op, 0, sizeof(op));
+ op.cancel_with_status = status;
+
lock(c);
set_status_code(c, STATUS_FROM_API_OVERRIDE, status);
set_status_details(c, STATUS_FROM_API_OVERRIDE, details);
unlock(c);
- return grpc_call_cancel(c);
+
+ execute_op(c, &op);
+
+ return GRPC_CALL_OK;
}
-void grpc_call_execute_op(grpc_call *call, grpc_call_op *op) {
+static void execute_op(grpc_call *call, grpc_transport_op *op) {
grpc_call_element *elem;
- GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
elem = CALL_ELEM_FROM_CALL(call, 0);
- elem->filter->call_op(elem, NULL, op);
+ elem->filter->start_transport_op(elem, op);
}
grpc_call *grpc_call_from_top_element(grpc_call_element *elem) {
@@ -872,38 +1045,20 @@ static void call_alarm(void *arg, int success) {
grpc_call_cancel(call);
}
}
- grpc_call_internal_unref(call, 1);
+ GRPC_CALL_INTERNAL_UNREF(call, "alarm", 1);
}
-void grpc_call_set_deadline(grpc_call_element *elem, gpr_timespec deadline) {
- grpc_call *call = CALL_FROM_TOP_ELEM(elem);
-
+static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) {
if (call->have_alarm) {
gpr_log(GPR_ERROR, "Attempt to set deadline alarm twice");
+ assert(0);
+ return;
}
- grpc_call_internal_ref(call);
+ GRPC_CALL_INTERNAL_REF(call, "alarm");
call->have_alarm = 1;
grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
}
-static void set_read_state(grpc_call *call, read_state state) {
- lock(call);
- GPR_ASSERT(call->read_state < state);
- call->read_state = state;
- finish_read_ops(call);
- unlock(call);
-}
-
-void grpc_call_read_closed(grpc_call_element *elem) {
- set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED);
-}
-
-void grpc_call_stream_closed(grpc_call_element *elem) {
- grpc_call *call = CALL_FROM_TOP_ELEM(elem);
- set_read_state(call, READ_STATE_STREAM_CLOSED);
- grpc_call_internal_unref(call, 0);
-}
-
/* we offset status by a small amount when storing it into transport metadata
as metadata cannot store a 0 value (which is used as OK for grpc_status_codes
*/
@@ -914,7 +1069,7 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
gpr_uint32 status;
void *user_data = grpc_mdelem_get_user_data(md, destroy_status);
if (user_data) {
- status = ((gpr_uint32)(gpr_intptr) user_data) - STATUS_OFFSET;
+ status = ((gpr_uint32)(gpr_intptr)user_data) - STATUS_OFFSET;
} else {
if (!gpr_parse_bytes_to_uint32(grpc_mdstr_as_c_string(md->value),
GPR_SLICE_LENGTH(md->value->slice),
@@ -927,61 +1082,65 @@ static gpr_uint32 decode_status(grpc_mdelem *md) {
return status;
}
-void grpc_call_recv_message(grpc_call_element *elem,
- grpc_byte_buffer *byte_buffer) {
- grpc_call *call = CALL_FROM_TOP_ELEM(elem);
- lock(call);
- grpc_bbq_push(&call->incoming_queue, byte_buffer);
- finish_read_ops(call);
- unlock(call);
-}
-
-void grpc_call_recv_metadata(grpc_call_element *elem, grpc_mdelem *md) {
- grpc_call *call = CALL_FROM_TOP_ELEM(elem);
- grpc_mdstr *key = md->key;
+static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
+ grpc_linked_mdelem *l;
grpc_metadata_array *dest;
grpc_metadata *mdusr;
-
- lock(call);
- if (key == grpc_channel_get_status_string(call->channel)) {
- set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
- grpc_mdelem_unref(md);
- } else if (key == grpc_channel_get_message_string(call->channel)) {
- set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
- grpc_mdelem_unref(md);
- } else {
- dest = &call->buffered_metadata[call->read_state >=
- READ_STATE_GOT_INITIAL_METADATA];
- if (dest->count == dest->capacity) {
- dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
- dest->metadata =
- gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
- }
- mdusr = &dest->metadata[dest->count++];
- mdusr->key = grpc_mdstr_as_c_string(md->key);
- mdusr->value = grpc_mdstr_as_c_string(md->value);
- mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice);
- if (call->owned_metadata_count == call->owned_metadata_capacity) {
- call->owned_metadata_capacity = GPR_MAX(
- call->owned_metadata_capacity + 8, call->owned_metadata_capacity * 2);
- call->owned_metadata =
- gpr_realloc(call->owned_metadata,
- sizeof(grpc_mdelem *) * call->owned_metadata_capacity);
+ int is_trailing;
+ grpc_mdctx *mdctx = call->metadata_context;
+
+ is_trailing = call->read_state >= READ_STATE_GOT_INITIAL_METADATA;
+ for (l = md->list.head; l != NULL; l = l->next) {
+ grpc_mdelem *md = l->md;
+ grpc_mdstr *key = md->key;
+ if (key == grpc_channel_get_status_string(call->channel)) {
+ set_status_code(call, STATUS_FROM_WIRE, decode_status(md));
+ } else if (key == grpc_channel_get_message_string(call->channel)) {
+ set_status_details(call, STATUS_FROM_WIRE, grpc_mdstr_ref(md->value));
+ } else {
+ dest = &call->buffered_metadata[is_trailing];
+ if (dest->count == dest->capacity) {
+ dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
+ dest->metadata =
+ gpr_realloc(dest->metadata, sizeof(grpc_metadata) * dest->capacity);
+ }
+ mdusr = &dest->metadata[dest->count++];
+ mdusr->key = grpc_mdstr_as_c_string(md->key);
+ mdusr->value = grpc_mdstr_as_c_string(md->value);
+ mdusr->value_length = GPR_SLICE_LENGTH(md->value->slice);
+ if (call->owned_metadata_count == call->owned_metadata_capacity) {
+ call->owned_metadata_capacity =
+ GPR_MAX(call->owned_metadata_capacity + 8,
+ call->owned_metadata_capacity * 2);
+ call->owned_metadata =
+ gpr_realloc(call->owned_metadata,
+ sizeof(grpc_mdelem *) * call->owned_metadata_capacity);
+ }
+ call->owned_metadata[call->owned_metadata_count++] = md;
+ l->md = 0;
}
- call->owned_metadata[call->owned_metadata_count++] = md;
}
- unlock(call);
+ if (gpr_time_cmp(md->deadline, gpr_inf_future) != 0) {
+ set_deadline_alarm(call, md->deadline);
+ }
+ if (!is_trailing) {
+ call->read_state = READ_STATE_GOT_INITIAL_METADATA;
+ }
+
+ grpc_mdctx_lock(mdctx);
+ for (l = md->list.head; l; l = l->next) {
+ if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+ }
+ for (l = md->garbage.head; l; l = l->next) {
+ grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+ }
+ grpc_mdctx_unlock(mdctx);
}
grpc_call_stack *grpc_call_get_call_stack(grpc_call *call) {
return CALL_STACK_FROM_CALL(call);
}
-void grpc_call_initial_metadata_complete(grpc_call_element *surface_element) {
- grpc_call *call = grpc_call_from_top_element(surface_element);
- set_read_state(call, READ_STATE_GOT_INITIAL_METADATA);
-}
-
/*
* BATCH API IMPLEMENTATION
*/
@@ -1006,6 +1165,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
const grpc_op *op;
grpc_ioreq *req;
+ GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
+
if (nops == 0) {
grpc_cq_begin_op(call->cq, call, GRPC_OP_COMPLETE);
grpc_cq_end_op_complete(call->cq, tag, call, do_nothing, NULL, GRPC_OP_OK);
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index cb81cb52c2..2d4c7f61e3 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -35,7 +35,6 @@
#define GRPC_INTERNAL_CORE_SURFACE_CALL_H
#include "src/core/channel/channel_stack.h"
-#include "src/core/channel/metadata_buffer.h"
#include <grpc/grpc.h>
/* Primitive operation types - grpc_op's get rewritten into these */
@@ -67,7 +66,7 @@ typedef union {
} recv_status_details;
struct {
size_t count;
- const grpc_metadata *metadata;
+ grpc_metadata *metadata;
} send_metadata;
grpc_byte_buffer *send_message;
struct {
@@ -86,37 +85,42 @@ typedef void (*grpc_ioreq_completion_func)(grpc_call *call,
void *user_data);
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
- const void *server_transport_data);
+ const void *server_transport_data,
+ grpc_mdelem **add_initial_metadata,
+ size_t add_initial_metadata_count,
+ gpr_timespec send_deadline);
void grpc_call_set_completion_queue(grpc_call *call, grpc_completion_queue *cq);
grpc_completion_queue *grpc_call_get_completion_queue(grpc_call *call);
+#ifdef GRPC_CALL_REF_COUNT_DEBUG
+void grpc_call_internal_ref(grpc_call *call, const char *reason);
+void grpc_call_internal_unref(grpc_call *call, const char *reason, int allow_immediate_deletion);
+#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call, reason)
+#define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) grpc_call_internal_unref(call, reason, allow_immediate_deletion)
+#else
void grpc_call_internal_ref(grpc_call *call);
void grpc_call_internal_unref(grpc_call *call, int allow_immediate_deletion);
+#define GRPC_CALL_INTERNAL_REF(call, reason) grpc_call_internal_ref(call)
+#define GRPC_CALL_INTERNAL_UNREF(call, reason, allow_immediate_deletion) grpc_call_internal_unref(call, allow_immediate_deletion)
+#endif
-/* Helpers for grpc_client, grpc_server filters to publish received data to
- the completion queue/surface layer */
-void grpc_call_recv_metadata(grpc_call_element *surface_element,
- grpc_mdelem *md);
-void grpc_call_recv_message(grpc_call_element *surface_element,
- grpc_byte_buffer *message);
-void grpc_call_read_closed(grpc_call_element *surface_element);
-void grpc_call_stream_closed(grpc_call_element *surface_element);
-
-void grpc_call_execute_op(grpc_call *call, grpc_call_op *op);
grpc_call_error grpc_call_start_ioreq_and_call_back(
grpc_call *call, const grpc_ioreq *reqs, size_t nreqs,
grpc_ioreq_completion_func on_complete, void *user_data);
-/* Called when it's known that the initial batch of metadata is complete */
-void grpc_call_initial_metadata_complete(grpc_call_element *surface_element);
-
-void grpc_call_set_deadline(grpc_call_element *surface_element,
- gpr_timespec deadline);
-
grpc_call_stack *grpc_call_get_call_stack(grpc_call *call);
/* Given the top call_element, get the call object. */
grpc_call *grpc_call_from_top_element(grpc_call_element *surface_element);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */
+extern int grpc_trace_batch;
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+ grpc_call *call, const grpc_op *ops, size_t nops,
+ void *tag);
+
+#define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
+ if (grpc_trace_batch) grpc_call_log_batch(sev, call, ops, nops, tag)
+
+#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_H */
diff --git a/src/core/surface/call_log_batch.c b/src/core/surface/call_log_batch.c
new file mode 100644
index 0000000000..a33583a12d
--- /dev/null
+++ b/src/core/surface/call_log_batch.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/surface/call.h"
+
+#include "src/core/support/string.h"
+#include <grpc/support/alloc.h>
+
+int grpc_trace_batch = 0;
+
+static void add_metadata(gpr_strvec *b, const grpc_metadata *md, size_t count) {
+ size_t i;
+ for(i = 0; i < count; i++) {
+ gpr_strvec_add(b, gpr_strdup("\nkey="));
+ gpr_strvec_add(b, gpr_strdup(md[i].key));
+
+ gpr_strvec_add(b, gpr_strdup(" value="));
+ gpr_strvec_add(b, gpr_hexdump(md[i].value, md[i].value_length,
+ GPR_HEXDUMP_PLAINTEXT));
+ }
+}
+
+char *grpc_op_string(const grpc_op *op) {
+ char *tmp;
+ char *out;
+
+ gpr_strvec b;
+ gpr_strvec_init(&b);
+
+ switch (op->op) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ gpr_strvec_add(&b, gpr_strdup("SEND_INITIAL_METADATA"));
+ add_metadata(&b, op->data.send_initial_metadata.metadata,
+ op->data.send_initial_metadata.count);
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ gpr_asprintf(&tmp, "SEND_MESSAGE ptr=%p", op->data.send_message);
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ gpr_strvec_add(&b, gpr_strdup("SEND_CLOSE_FROM_CLIENT"));
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ gpr_asprintf(&tmp, "SEND_STATUS_FROM_SERVER status=%d details=%s",
+ op->data.send_status_from_server.status,
+ op->data.send_status_from_server.status_details);
+ gpr_strvec_add(&b, tmp);
+ add_metadata(&b, op->data.send_status_from_server.trailing_metadata,
+ op->data.send_status_from_server.trailing_metadata_count);
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ gpr_asprintf(&tmp, "RECV_INITIAL_METADATA ptr=%p",
+ op->data.recv_initial_metadata);
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ gpr_asprintf(&tmp, "RECV_MESSAGE ptr=%p", op->data.recv_message);
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ gpr_asprintf(&tmp,
+ "RECV_STATUS_ON_CLIENT metadata=%p status=%p details=%p",
+ op->data.recv_status_on_client.trailing_metadata,
+ op->data.recv_status_on_client.status,
+ op->data.recv_status_on_client.status_details);
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ gpr_asprintf(&tmp, "RECV_CLOSE_ON_SERVER cancelled=%p",
+ op->data.recv_close_on_server.cancelled);
+ gpr_strvec_add(&b, tmp);
+ }
+ out = gpr_strvec_flatten(&b, NULL);
+ gpr_strvec_destroy(&b);
+
+ return out;
+}
+
+void grpc_call_log_batch(char *file, int line, gpr_log_severity severity,
+ grpc_call *call, const grpc_op *ops, size_t nops,
+ void *tag) {
+ char *tmp;
+ size_t i;
+ gpr_log(file, line, severity,
+ "grpc_call_start_batch(%p, %p, %d, 0x%x)", call, ops, nops, tag);
+ for(i = 0; i < nops; i++) {
+ tmp = grpc_op_string(&ops[i]);
+ gpr_log(file, line, severity, "ops[%d]: %s", i, tmp);
+ gpr_free(tmp);
+ }
+}
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index e764a3b9af..78f9144c19 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -43,30 +43,46 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+typedef struct registered_call {
+ grpc_mdelem *path;
+ grpc_mdelem *authority;
+ struct registered_call *next;
+} registered_call;
+
struct grpc_channel {
int is_client;
gpr_refcount refs;
+ gpr_uint32 max_message_length;
grpc_mdctx *metadata_context;
grpc_mdstr *grpc_status_string;
grpc_mdstr *grpc_message_string;
grpc_mdstr *path_string;
grpc_mdstr *authority_string;
+
+ gpr_mu registered_call_mu;
+ registered_call *registered_calls;
};
-#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
-#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) (((grpc_channel *)(channel_stack)) - 1)
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
+#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \
+ (((grpc_channel *)(channel_stack)) - 1)
#define CHANNEL_FROM_TOP_ELEM(top_elem) \
CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
+/* the protobuf library will (by default) start warning at 100megs */
+#define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
+
grpc_channel *grpc_channel_create_from_filters(
const grpc_channel_filter **filters, size_t num_filters,
const grpc_channel_args *args, grpc_mdctx *mdctx, int is_client) {
+ size_t i;
size_t size =
sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
grpc_channel *channel = gpr_malloc(size);
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client;
- /* decremented by grpc_channel_destroy, and grpc_client_channel_closed if is_client */
+ /* decremented by grpc_channel_destroy, and grpc_client_channel_closed if
+ * is_client */
gpr_ref_init(&channel->refs, 1 + is_client);
channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
@@ -75,59 +91,41 @@ grpc_channel *grpc_channel_create_from_filters(
channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel));
+ gpr_mu_init(&channel->registered_call_mu);
+ channel->registered_calls = NULL;
+
+ channel->max_message_length = DEFAULT_MAX_MESSAGE_LENGTH;
+ if (args) {
+ for (i = 0; i < args->num_args; i++) {
+ if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_MESSAGE_LENGTH)) {
+ if (args->args[i].type != GRPC_ARG_INTEGER) {
+ gpr_log(GPR_ERROR, "%s ignored: it must be an integer",
+ GRPC_ARG_MAX_MESSAGE_LENGTH);
+ } else if (args->args[i].value.integer < 0) {
+ gpr_log(GPR_ERROR, "%s ignored: it must be >= 0",
+ GRPC_ARG_MAX_MESSAGE_LENGTH);
+ } else {
+ channel->max_message_length = args->args[i].value.integer;
+ }
+ }
+ }
+ }
+
return channel;
}
-static void do_nothing(void *ignored, grpc_op_error error) {}
+static grpc_call *grpc_channel_create_call_internal(
+ grpc_channel *channel, grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
+ grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
+ grpc_mdelem *send_metadata[2];
-grpc_call *grpc_channel_create_call(grpc_channel *channel,
- grpc_completion_queue *cq,
- const char *method, const char *host,
- gpr_timespec absolute_deadline) {
- grpc_call *call;
- grpc_mdelem *path_mdelem;
- grpc_mdelem *authority_mdelem;
- grpc_call_op op;
-
- if (!channel->is_client) {
- gpr_log(GPR_ERROR, "Cannot create a call on the server.");
- return NULL;
- }
-
- call = grpc_call_create(channel, cq, NULL);
+ GPR_ASSERT(channel->is_client);
- /* Add :path and :authority headers. */
- /* TODO(klempner): Consider optimizing this by stashing mdelems for common
- values of method and host. */
- path_mdelem = grpc_mdelem_from_metadata_strings(
- channel->metadata_context, grpc_mdstr_ref(channel->path_string),
- grpc_mdstr_from_string(channel->metadata_context, method));
- op.type = GRPC_SEND_METADATA;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.data.metadata = path_mdelem;
- op.done_cb = do_nothing;
- op.user_data = NULL;
- grpc_call_execute_op(call, &op);
-
- grpc_mdstr_ref(channel->authority_string);
- authority_mdelem = grpc_mdelem_from_metadata_strings(
- channel->metadata_context, channel->authority_string,
- grpc_mdstr_from_string(channel->metadata_context, host));
- op.data.metadata = authority_mdelem;
- grpc_call_execute_op(call, &op);
-
- if (0 != gpr_time_cmp(absolute_deadline, gpr_inf_future)) {
- op.type = GRPC_SEND_DEADLINE;
- op.dir = GRPC_CALL_DOWN;
- op.flags = 0;
- op.data.deadline = absolute_deadline;
- op.done_cb = do_nothing;
- op.user_data = NULL;
- grpc_call_execute_op(call, &op);
- }
+ send_metadata[0] = path_mdelem;
+ send_metadata[1] = authority_mdelem;
- return call;
+ return grpc_call_create(channel, cq, NULL, send_metadata,
+ GPR_ARRAY_SIZE(send_metadata), deadline);
}
grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
@@ -137,6 +135,46 @@ grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
absolute_deadline);
}
+grpc_call *grpc_channel_create_call(grpc_channel *channel,
+ grpc_completion_queue *cq,
+ const char *method, const char *host,
+ gpr_timespec deadline) {
+ return grpc_channel_create_call_internal(
+ channel, cq,
+ grpc_mdelem_from_metadata_strings(
+ channel->metadata_context, grpc_mdstr_ref(channel->path_string),
+ grpc_mdstr_from_string(channel->metadata_context, method)),
+ grpc_mdelem_from_metadata_strings(
+ channel->metadata_context, grpc_mdstr_ref(channel->authority_string),
+ grpc_mdstr_from_string(channel->metadata_context, host)),
+ deadline);
+}
+
+void *grpc_channel_register_call(grpc_channel *channel, const char *method,
+ const char *host) {
+ registered_call *rc = gpr_malloc(sizeof(registered_call));
+ rc->path = grpc_mdelem_from_metadata_strings(
+ channel->metadata_context, grpc_mdstr_ref(channel->path_string),
+ grpc_mdstr_from_string(channel->metadata_context, method));
+ rc->authority = grpc_mdelem_from_metadata_strings(
+ channel->metadata_context, grpc_mdstr_ref(channel->authority_string),
+ grpc_mdstr_from_string(channel->metadata_context, host));
+ gpr_mu_lock(&channel->registered_call_mu);
+ rc->next = channel->registered_calls;
+ channel->registered_calls = rc;
+ gpr_mu_unlock(&channel->registered_call_mu);
+ return rc;
+}
+
+grpc_call *grpc_channel_create_registered_call(
+ grpc_channel *channel, grpc_completion_queue *completion_queue,
+ void *registered_call_handle, gpr_timespec deadline) {
+ registered_call *rc = registered_call_handle;
+ return grpc_channel_create_call_internal(
+ channel, completion_queue, grpc_mdelem_ref(rc->path),
+ grpc_mdelem_ref(rc->authority), deadline);
+}
+
void grpc_channel_internal_ref(grpc_channel *channel) {
gpr_ref(&channel->refs);
}
@@ -148,7 +186,15 @@ static void destroy_channel(void *p, int ok) {
grpc_mdstr_unref(channel->grpc_message_string);
grpc_mdstr_unref(channel->path_string);
grpc_mdstr_unref(channel->authority_string);
+ while (channel->registered_calls) {
+ registered_call *rc = channel->registered_calls;
+ channel->registered_calls = rc->next;
+ grpc_mdelem_unref(rc->path);
+ grpc_mdelem_unref(rc->authority);
+ gpr_free(rc);
+ }
grpc_mdctx_unref(channel->metadata_context);
+ gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel);
}
@@ -196,3 +242,7 @@ grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel) {
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel) {
return channel->grpc_message_string;
}
+
+gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel) {
+ return channel->max_message_length;
+}
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index d3e51185ee..388be35711 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -44,10 +44,11 @@ grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
grpc_mdctx *grpc_channel_get_metadata_context(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_status_string(grpc_channel *channel);
grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
+gpr_uint32 grpc_channel_get_max_message_length(grpc_channel *channel);
void grpc_client_channel_closed(grpc_channel_element *elem);
void grpc_channel_internal_ref(grpc_channel *channel);
void grpc_channel_internal_unref(grpc_channel *channel);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 3104b1d00d..daa8d3a7c6 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -44,7 +44,6 @@
#include "src/core/channel/client_setup.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_client_filter.h"
-#include "src/core/channel/http_filter.h"
#include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h"
@@ -176,8 +175,8 @@ static void done_setup(void *sp) {
static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_transport *transport,
grpc_mdctx *mdctx) {
- static grpc_channel_filter const *extra_filters[] = {&grpc_http_client_filter,
- &grpc_http_filter};
+ static grpc_channel_filter const *extra_filters[] = {
+ &grpc_http_client_filter};
return grpc_client_channel_transport_setup_complete(
channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
mdctx);
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
index 4d54865d16..8ac4dd1e0e 100644
--- a/src/core/surface/client.c
+++ b/src/core/surface/client.c
@@ -39,46 +39,14 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-typedef struct {
- void *unused;
-} call_data;
+typedef struct { void *unused; } call_data;
-typedef struct {
- void *unused;
-} channel_data;
+typedef struct { void *unused; } channel_data;
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
+static void client_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-
- switch (op->type) {
- case GRPC_SEND_DEADLINE:
- grpc_call_set_deadline(elem, op->data.deadline);
- grpc_call_next_op(elem, op);
- break;
- case GRPC_RECV_METADATA:
- grpc_call_recv_metadata(elem, op->data.metadata);
- break;
- case GRPC_RECV_DEADLINE:
- gpr_log(GPR_ERROR, "Deadline received by client (ignored)");
- break;
- case GRPC_RECV_MESSAGE:
- grpc_call_recv_message(elem, op->data.message);
- op->done_cb(op->user_data, GRPC_OP_OK);
- break;
- case GRPC_RECV_HALF_CLOSE:
- grpc_call_read_closed(elem);
- break;
- case GRPC_RECV_FINISH:
- grpc_call_stream_closed(elem);
- break;
- case GRPC_RECV_END_OF_INITIAL_METADATA:
- grpc_call_initial_metadata_complete(elem);
- break;
- default:
- GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
- grpc_call_next_op(elem, op);
- }
+ grpc_call_next_op(elem, op);
}
static void channel_op(grpc_channel_element *elem,
@@ -100,7 +68,8 @@ static void channel_op(grpc_channel_element *elem,
}
static void init_call_elem(grpc_call_element *elem,
- const void *transport_server_data) {}
+ const void *transport_server_data,
+ grpc_transport_op *initial_op) {}
static void destroy_call_elem(grpc_call_element *elem) {}
@@ -114,6 +83,7 @@ static void init_channel_elem(grpc_channel_element *elem,
static void destroy_channel_elem(grpc_channel_element *elem) {}
const grpc_channel_filter grpc_client_surface_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "client", };
+ client_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "client",
+};
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 6a1d83ce5d..c1c97af337 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -67,6 +67,8 @@ struct grpc_completion_queue {
/* When refs drops to zero, we are in shutdown mode, and will be destroyable
once all queued events are drained */
gpr_refcount refs;
+ /* Once owning_refs drops to zero, we will destroy the cq */
+ gpr_refcount owning_refs;
/* the set of low level i/o things that concern this cq */
grpc_pollset pollset;
/* 0 initially, 1 once we've begun shutting down */
@@ -91,11 +93,29 @@ grpc_completion_queue *grpc_completion_queue_create(void) {
memset(cc, 0, sizeof(*cc));
/* Initial ref is dropped by grpc_completion_queue_shutdown */
gpr_ref_init(&cc->refs, 1);
+ gpr_ref_init(&cc->owning_refs, 1);
grpc_pollset_init(&cc->pollset);
cc->allow_polling = 1;
return cc;
}
+void grpc_cq_internal_ref(grpc_completion_queue *cc) {
+ gpr_ref(&cc->owning_refs);
+}
+
+static void on_pollset_destroy_done(void *arg) {
+ grpc_completion_queue *cc = arg;
+ grpc_pollset_destroy(&cc->pollset);
+ gpr_free(cc);
+}
+
+void grpc_cq_internal_unref(grpc_completion_queue *cc) {
+ if (gpr_unref(&cc->owning_refs)) {
+ GPR_ASSERT(cc->queue == NULL);
+ grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
+ }
+}
+
void grpc_completion_queue_dont_poll_test_only(grpc_completion_queue *cc) {
cc->allow_polling = 0;
}
@@ -135,7 +155,7 @@ static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call,
grpc_completion_type type) {
gpr_ref(&cc->refs);
- if (call) grpc_call_internal_ref(call);
+ if (call) GRPC_CALL_INTERNAL_REF(call, "cq");
#ifndef NDEBUG
gpr_atm_no_barrier_fetch_add(&cc->pending_op_count[type], 1);
#endif
@@ -394,22 +414,15 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
}
}
-static void on_pollset_destroy_done(void *arg) {
- grpc_completion_queue *cc = arg;
- grpc_pollset_destroy(&cc->pollset);
- gpr_free(cc);
-}
-
void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
- GPR_ASSERT(cc->queue == NULL);
- grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
+ grpc_cq_internal_unref(cc);
}
void grpc_event_finish(grpc_event *base) {
event *ev = (event *)base;
ev->on_finish(ev->on_finish_user_data, GRPC_OP_OK);
if (ev->base.call) {
- grpc_call_internal_unref(ev->base.call, 1);
+ GRPC_CALL_INTERNAL_UNREF(ev->base.call, "cq", 1);
}
gpr_free(ev);
}
@@ -432,3 +445,11 @@ void grpc_cq_dump_pending_ops(grpc_completion_queue *cc) {
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
return &cc->pollset;
}
+
+void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) {
+ gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+ grpc_pollset_kick(&cc->pollset);
+ grpc_pollset_work(&cc->pollset,
+ gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+ gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+}
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 3054264cad..41024cda14 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -43,6 +43,9 @@
grpc_event_finish */
typedef void (*grpc_event_finish_func)(void *user_data, grpc_op_error error);
+void grpc_cq_internal_ref(grpc_completion_queue *cc);
+void grpc_cq_internal_unref(grpc_completion_queue *cc);
+
/* Flag that an operation is beginning: the completion channel will not finish
shutdown until a corrensponding grpc_cq_end_* call is made */
void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call,
@@ -114,4 +117,6 @@ void grpc_cq_dump_pending_ops(grpc_completion_queue *cc);
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
+void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc);
+
+#endif /* GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index e48c4202e5..5a119a47cc 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -32,10 +32,12 @@
*/
#include <grpc/grpc.h>
-#include "src/core/iomgr/iomgr.h"
+#include "src/core/channel/channel_stack.h"
#include "src/core/debug/trace.h"
+#include "src/core/iomgr/iomgr.h"
#include "src/core/statistics/census_interface.h"
-#include "src/core/channel/channel_stack.h"
+#include "src/core/profiling/timers.h"
+#include "src/core/surface/call.h"
#include "src/core/surface/init.h"
#include "src/core/surface/surface_trace.h"
#include "src/core/transport/chttp2_transport.h"
@@ -57,10 +59,12 @@ void grpc_init(void) {
grpc_register_tracer("channel", &grpc_trace_channel);
grpc_register_tracer("surface", &grpc_surface_trace);
grpc_register_tracer("http", &grpc_http_trace);
+ grpc_register_tracer("batch", &grpc_trace_batch);
grpc_security_pre_init();
- grpc_tracer_init("GRPC_TRACE");
grpc_iomgr_init();
+ grpc_tracer_init("GRPC_TRACE");
census_init();
+ grpc_timers_log_global_init();
}
gpr_mu_unlock(&g_init_mu);
}
@@ -70,6 +74,7 @@ void grpc_shutdown(void) {
if (--g_initializations == 0) {
grpc_iomgr_shutdown();
census_shutdown();
+ grpc_timers_log_global_destroy();
}
gpr_mu_unlock(&g_init_mu);
}
@@ -82,4 +87,3 @@ int grpc_is_initialized(void) {
gpr_mu_unlock(&g_init_mu);
return r;
}
-
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index b40c48381f..3186292a02 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -43,33 +43,39 @@
#include <grpc/support/log.h>
typedef struct {
- void *unused;
+ grpc_linked_mdelem status;
+ grpc_linked_mdelem details;
} call_data;
-typedef struct {
- grpc_mdelem *status;
- grpc_mdelem *message;
-} channel_data;
+typedef struct { grpc_mdctx *mdctx; } channel_data;
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
- grpc_call_op *op) {
- channel_data *channeld = elem->channel_data;
+static void lame_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ call_data *calld = elem->call_data;
+ channel_data *chand = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-
- switch (op->type) {
- case GRPC_SEND_START:
- grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->status));
- grpc_call_recv_metadata(elem, grpc_mdelem_ref(channeld->message));
- grpc_call_stream_closed(elem);
- break;
- case GRPC_SEND_METADATA:
- grpc_mdelem_unref(op->data.metadata);
- break;
- default:
- break;
+ if (op->send_ops) {
+ op->on_done_send(op->send_user_data, 0);
+ }
+ if (op->recv_ops) {
+ char tmp[GPR_LTOA_MIN_BUFSIZE];
+ grpc_metadata_batch mdb;
+ gpr_ltoa(GRPC_STATUS_UNKNOWN, tmp);
+ calld->status.md =
+ grpc_mdelem_from_strings(chand->mdctx, "grpc-status", tmp);
+ calld->details.md = grpc_mdelem_from_strings(chand->mdctx, "grpc-message",
+ "Rpc sent on a lame channel.");
+ calld->status.prev = calld->details.next = NULL;
+ calld->status.next = &calld->details;
+ calld->details.prev = &calld->status;
+ mdb.list.head = &calld->status;
+ mdb.list.tail = &calld->details;
+ mdb.garbage.head = mdb.garbage.tail = NULL;
+ mdb.deadline = gpr_inf_future;
+ grpc_sopb_add_metadata(op->recv_ops, mdb);
+ *op->recv_state = GRPC_STREAM_CLOSED;
+ op->on_done_recv(op->recv_user_data, 1);
}
-
- op->done_cb(op->user_data, GRPC_OP_ERROR);
}
static void channel_op(grpc_channel_element *elem,
@@ -87,36 +93,31 @@ static void channel_op(grpc_channel_element *elem,
}
static void init_call_elem(grpc_call_element *elem,
- const void *transport_server_data) {}
+ const void *transport_server_data,
+ grpc_transport_op *initial_op) {
+ if (initial_op) {
+ grpc_transport_op_finish_with_failure(initial_op);
+ }
+}
static void destroy_call_elem(grpc_call_element *elem) {}
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
- channel_data *channeld = elem->channel_data;
- char status[12];
-
+ channel_data *chand = elem->channel_data;
GPR_ASSERT(is_first);
GPR_ASSERT(is_last);
-
- channeld->message = grpc_mdelem_from_strings(mdctx, "grpc-message",
- "Rpc sent on a lame channel.");
- gpr_ltoa(GRPC_STATUS_UNKNOWN, status);
- channeld->status = grpc_mdelem_from_strings(mdctx, "grpc-status", status);
+ chand->mdctx = mdctx;
}
-static void destroy_channel_elem(grpc_channel_element *elem) {
- channel_data *channeld = elem->channel_data;
-
- grpc_mdelem_unref(channeld->message);
- grpc_mdelem_unref(channeld->status);
-}
+static void destroy_channel_elem(grpc_channel_element *elem) {}
static const grpc_channel_filter lame_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "lame-client", };
+ lame_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "lame-client",
+};
grpc_channel *grpc_lame_client_channel_create(void) {
static const grpc_channel_filter *filters[] = {&lame_filter};
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 8e56868d42..3e331293b5 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -44,11 +44,10 @@
#include "src/core/channel/client_setup.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_client_filter.h"
-#include "src/core/channel/http_filter.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h"
#include "src/core/security/auth.h"
-#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
@@ -74,7 +73,7 @@ typedef struct {
} request;
struct setup {
- grpc_channel_security_context *security_context;
+ grpc_channel_security_connector *security_connector;
const char *target;
grpc_transport_setup_callback setup_callback;
void *setup_user_data;
@@ -130,7 +129,7 @@ static void on_connect(void *rp, grpc_endpoint *tcp) {
return;
}
} else {
- grpc_setup_secure_transport(&r->setup->security_context->base, tcp,
+ grpc_setup_secure_transport(&r->setup->security_connector->base, tcp,
on_secure_transport_setup_done, r);
}
}
@@ -185,7 +184,7 @@ static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
static void done_setup(void *sp) {
setup *s = sp;
gpr_free((void *)s->target);
- grpc_security_context_unref(&s->security_context->base);
+ grpc_security_connector_unref(&s->security_connector->base);
gpr_free(s);
}
@@ -193,7 +192,7 @@ static grpc_transport_setup_result complete_setup(void *channel_stack,
grpc_transport *transport,
grpc_mdctx *mdctx) {
static grpc_channel_filter const *extra_filters[] = {
- &grpc_client_auth_filter, &grpc_http_client_filter, &grpc_http_filter};
+ &grpc_client_auth_filter, &grpc_http_client_filter};
return grpc_client_channel_transport_setup_complete(
channel_stack, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters),
mdctx);
@@ -203,24 +202,37 @@ static grpc_transport_setup_result complete_setup(void *channel_stack,
Asynchronously: - resolve target
- connect to it (trying alternatives as presented)
- perform handshakes */
-grpc_channel *grpc_secure_channel_create_internal(
- const char *target, const grpc_channel_args *args,
- grpc_channel_security_context *context) {
+grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+ const char *target,
+ const grpc_channel_args *args) {
setup *s;
grpc_channel *channel;
- grpc_arg context_arg;
+ grpc_arg connector_arg;
grpc_channel_args *args_copy;
- grpc_mdctx *mdctx = grpc_mdctx_create();
+ grpc_channel_args *new_args_from_connector;
+ grpc_channel_security_connector *connector;
+ grpc_mdctx *mdctx;
#define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS];
int n = 0;
- if (grpc_find_security_context_in_args(args) != 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();
+ }
+
+ if (grpc_credentials_create_security_connector(
+ creds, target, args, NULL, &connector, &new_args_from_connector) !=
+ GRPC_SECURITY_OK) {
+ return grpc_lame_client_channel_create();
}
+ mdctx = grpc_credentials_get_or_create_metadata_context(creds);
s = gpr_malloc(sizeof(setup));
- context_arg = grpc_security_context_to_arg(&context->base);
- args_copy = grpc_channel_args_copy_and_add(args, &context_arg);
+ connector_arg = grpc_security_connector_to_arg(&connector->base);
+ args_copy = grpc_channel_args_copy_and_add(
+ new_args_from_connector != NULL ? new_args_from_connector : args,
+ &connector_arg);
filters[n++] = &grpc_client_surface_filter;
if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter;
@@ -229,13 +241,14 @@ grpc_channel *grpc_secure_channel_create_internal(
GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
grpc_channel_args_destroy(args_copy);
+ if (new_args_from_connector != NULL) {
+ grpc_channel_args_destroy(new_args_from_connector);
+ }
s->target = gpr_strdup(target);
s->setup_callback = complete_setup;
s->setup_user_data = grpc_channel_get_channel_stack(channel);
- s->security_context =
- (grpc_channel_security_context *)grpc_security_context_ref(
- &context->base);
+ s->security_connector = connector;
grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
args, mdctx, initiate_setup, done_setup,
s);
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 424734c54c..83caefcbc6 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -137,6 +137,7 @@ struct grpc_server {
size_t cq_count;
gpr_mu mu;
+ gpr_cv cv;
registered_method *registered_methods;
requested_call_array requested_calls;
@@ -149,6 +150,7 @@ struct grpc_server {
channel_data root_channel_data;
listener *listeners;
+ int listeners_destroyed;
gpr_refcount internal_refcount;
};
@@ -171,13 +173,19 @@ struct call_data {
grpc_call *call;
call_state state;
- gpr_timespec deadline;
grpc_mdstr *path;
grpc_mdstr *host;
+ gpr_timespec deadline;
+ int got_initial_metadata;
legacy_data *legacy;
grpc_completion_queue *cq_new;
+ grpc_stream_op_buffer *recv_ops;
+ grpc_stream_state *recv_state;
+ void (*on_done_recv)(void *user_data, int success);
+ void *recv_user_data;
+
call_data **root[CALL_LIST_COUNT];
call_link links[CALL_LIST_COUNT];
};
@@ -260,9 +268,11 @@ static void server_ref(grpc_server *server) {
static void server_unref(grpc_server *server) {
registered_method *rm;
+ size_t i;
if (gpr_unref(&server->internal_refcount)) {
grpc_channel_args_destroy(server->channel_args);
gpr_mu_destroy(&server->mu);
+ gpr_cv_destroy(&server->cv);
gpr_free(server->channel_filters);
requested_call_array_destroy(&server->requested_calls);
while ((rm = server->registered_methods) != NULL) {
@@ -272,6 +282,9 @@ static void server_unref(grpc_server *server) {
requested_call_array_destroy(&rm->requested);
gpr_free(rm);
}
+ for (i = 0; i < server->cq_count; i++) {
+ grpc_cq_internal_unref(server->cqs[i]);
+ }
gpr_free(server->cqs);
gpr_free(server->pollsets);
gpr_free(server->shutdown_tags);
@@ -368,88 +381,89 @@ static void kill_zombie(void *elem, int success) {
grpc_call_destroy(grpc_call_from_top_element(elem));
}
-static void stream_closed(grpc_call_element *elem) {
- call_data *calld = elem->call_data;
+static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
+ grpc_call_element *elem = user_data;
channel_data *chand = elem->channel_data;
- gpr_mu_lock(&chand->server->mu);
- switch (calld->state) {
- case ACTIVATED:
- break;
- case PENDING:
- call_list_remove(calld, PENDING_START);
- /* fallthrough intended */
- case NOT_STARTED:
- calld->state = ZOMBIED;
- grpc_iomgr_add_callback(kill_zombie, elem);
- break;
- case ZOMBIED:
- break;
+ call_data *calld = elem->call_data;
+ if (md->key == chand->path_key) {
+ calld->path = grpc_mdstr_ref(md->value);
+ return NULL;
+ } else if (md->key == chand->authority_key) {
+ calld->host = grpc_mdstr_ref(md->value);
+ return NULL;
}
- gpr_mu_unlock(&chand->server->mu);
- grpc_call_stream_closed(elem);
+ return md;
}
-static void read_closed(grpc_call_element *elem) {
+static void server_on_recv(void *ptr, int success) {
+ grpc_call_element *elem = ptr;
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
- gpr_mu_lock(&chand->server->mu);
- switch (calld->state) {
- case ACTIVATED:
- case PENDING:
- grpc_call_read_closed(elem);
- break;
- case NOT_STARTED:
- calld->state = ZOMBIED;
- grpc_iomgr_add_callback(kill_zombie, elem);
- break;
- case ZOMBIED:
- break;
- }
- gpr_mu_unlock(&chand->server->mu);
-}
-static void call_op(grpc_call_element *elem, grpc_call_element *from_elemn,
- grpc_call_op *op) {
- channel_data *chand = elem->channel_data;
- call_data *calld = elem->call_data;
- grpc_mdelem *md;
- GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- switch (op->type) {
- case GRPC_RECV_METADATA:
- md = op->data.metadata;
- if (md->key == chand->path_key) {
- calld->path = grpc_mdstr_ref(md->value);
- grpc_mdelem_unref(md);
- } else if (md->key == chand->authority_key) {
- calld->host = grpc_mdstr_ref(md->value);
- grpc_mdelem_unref(md);
- } else {
- grpc_call_recv_metadata(elem, md);
+ if (success && !calld->got_initial_metadata) {
+ 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;
+ grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem);
+ if (0 != gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future)) {
+ calld->deadline = op->data.metadata.deadline;
}
- break;
- case GRPC_RECV_END_OF_INITIAL_METADATA:
+ calld->got_initial_metadata = 1;
start_new_rpc(elem);
- grpc_call_initial_metadata_complete(elem);
- break;
- case GRPC_RECV_MESSAGE:
- grpc_call_recv_message(elem, op->data.message);
- op->done_cb(op->user_data, GRPC_OP_OK);
break;
- case GRPC_RECV_HALF_CLOSE:
- read_closed(elem);
+ }
+ }
+
+ switch (*calld->recv_state) {
+ case GRPC_STREAM_OPEN:
break;
- case GRPC_RECV_FINISH:
- stream_closed(elem);
+ case GRPC_STREAM_SEND_CLOSED:
break;
- case GRPC_RECV_DEADLINE:
- grpc_call_set_deadline(elem, op->data.deadline);
- ((call_data *)elem->call_data)->deadline = op->data.deadline;
+ case GRPC_STREAM_RECV_CLOSED:
+ gpr_mu_lock(&chand->server->mu);
+ if (calld->state == NOT_STARTED) {
+ calld->state = ZOMBIED;
+ grpc_iomgr_add_callback(kill_zombie, elem);
+ }
+ gpr_mu_unlock(&chand->server->mu);
break;
- default:
- GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
- grpc_call_next_op(elem, op);
+ case GRPC_STREAM_CLOSED:
+ gpr_mu_lock(&chand->server->mu);
+ if (calld->state == NOT_STARTED) {
+ calld->state = ZOMBIED;
+ grpc_iomgr_add_callback(kill_zombie, elem);
+ } else if (calld->state == PENDING) {
+ call_list_remove(calld, PENDING_START);
+ }
+ gpr_mu_unlock(&chand->server->mu);
break;
}
+
+ calld->on_done_recv(calld->recv_user_data, success);
+}
+
+static void server_mutate_op(grpc_call_element *elem, grpc_transport_op *op) {
+ call_data *calld = elem->call_data;
+
+ if (op->recv_ops) {
+ /* substitute our callback for the higher callback */
+ calld->recv_ops = op->recv_ops;
+ calld->recv_state = op->recv_state;
+ calld->on_done_recv = op->on_done_recv;
+ calld->recv_user_data = op->recv_user_data;
+ op->on_done_recv = server_on_recv;
+ op->recv_user_data = elem;
+ }
+}
+
+static void server_start_transport_op(grpc_call_element *elem,
+ grpc_transport_op *op) {
+ GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+ server_mutate_op(elem, op);
+ grpc_call_next_op(elem, op);
}
static void channel_op(grpc_channel_element *elem,
@@ -461,7 +475,8 @@ static void channel_op(grpc_channel_element *elem,
case GRPC_ACCEPT_CALL:
/* create a call */
grpc_call_create(chand->channel, NULL,
- op->data.accept_call.transport_server_data);
+ op->data.accept_call.transport_server_data, NULL, 0,
+ gpr_inf_future);
break;
case GRPC_TRANSPORT_CLOSED:
/* if the transport is closed for a server channel, we destroy the
@@ -499,7 +514,8 @@ static void shutdown_channel(channel_data *chand) {
}
static void init_call_elem(grpc_call_element *elem,
- const void *server_transport_data) {
+ const void *server_transport_data,
+ grpc_transport_op *initial_op) {
call_data *calld = elem->call_data;
channel_data *chand = elem->channel_data;
memset(calld, 0, sizeof(call_data));
@@ -511,6 +527,8 @@ static void init_call_elem(grpc_call_element *elem,
gpr_mu_unlock(&chand->server->mu);
server_ref(chand->server);
+
+ if (initial_op) server_mutate_op(elem, initial_op);
}
static void destroy_call_elem(grpc_call_element *elem) {
@@ -589,9 +607,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
static const grpc_channel_filter server_surface_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "server",
+ server_start_transport_op, channel_op, sizeof(call_data), init_call_elem,
+ destroy_call_elem, sizeof(channel_data), init_channel_elem,
+ destroy_channel_elem, "server",
};
static void addcq(grpc_server *server, grpc_completion_queue *cq) {
@@ -599,6 +617,7 @@ static void addcq(grpc_server *server, grpc_completion_queue *cq) {
for (i = 0; i < server->cq_count; i++) {
if (server->cqs[i] == cq) return;
}
+ grpc_cq_internal_ref(cq);
n = server->cq_count++;
server->cqs = gpr_realloc(server->cqs,
server->cq_count * sizeof(grpc_completion_queue *));
@@ -620,6 +639,7 @@ grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq,
if (cq) addcq(server, cq);
gpr_mu_init(&server->mu);
+ gpr_cv_init(&server->cv);
server->unregistered_cq = cq;
/* decremented by grpc_server_destroy */
@@ -733,7 +753,8 @@ grpc_transport_setup_result grpc_server_setup_transport(
channel = grpc_channel_create_from_filters(filters, num_filters,
s->channel_args, mdctx, 0);
chand = (channel_data *)grpc_channel_stack_element(
- grpc_channel_get_channel_stack(channel), 0)->channel_data;
+ grpc_channel_get_channel_stack(channel), 0)
+ ->channel_data;
chand->server = s;
server_ref(s);
chand->channel = channel;
@@ -754,7 +775,7 @@ grpc_transport_setup_result grpc_server_setup_transport(
method = grpc_mdstr_from_string(mdctx, rm->method);
hash = GRPC_MDSTR_KV_HASH(host ? host->hash : 0, method->hash);
for (probes = 0; chand->registered_methods[(hash + probes) % slots]
- .server_registered_method != NULL;
+ .server_registered_method != NULL;
probes++)
;
if (probes > max_probes) max_probes = probes;
@@ -781,6 +802,15 @@ grpc_transport_setup_result grpc_server_setup_transport(
return result;
}
+static int num_listeners(grpc_server *server) {
+ listener *l;
+ int n = 0;
+ for (l = server->listeners; l; l = l->next) {
+ n++;
+ }
+ return n;
+}
+
static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
void *shutdown_tag) {
listener *l;
@@ -878,11 +908,6 @@ static void shutdown_internal(grpc_server *server, gpr_uint8 have_shutdown_tag,
for (l = server->listeners; l; l = l->next) {
l->destroy(server, l->arg);
}
- while (server->listeners) {
- l = server->listeners;
- server->listeners = l->next;
- gpr_free(l);
- }
}
void grpc_server_shutdown(grpc_server *server) {
@@ -893,8 +918,20 @@ void grpc_server_shutdown_and_notify(grpc_server *server, void *tag) {
shutdown_internal(server, 1, tag);
}
+void grpc_server_listener_destroy_done(void *s) {
+ grpc_server *server = s;
+ gpr_mu_lock(&server->mu);
+ server->listeners_destroyed++;
+ gpr_cv_signal(&server->cv);
+ gpr_mu_unlock(&server->mu);
+}
+
void grpc_server_destroy(grpc_server *server) {
channel_data *c;
+ listener *l;
+ size_t i;
+ call_data *calld;
+
gpr_mu_lock(&server->mu);
if (!server->shutdown) {
gpr_mu_unlock(&server->mu);
@@ -902,6 +939,32 @@ void grpc_server_destroy(grpc_server *server) {
gpr_mu_lock(&server->mu);
}
+ while (server->listeners_destroyed != num_listeners(server)) {
+ for (i = 0; i < server->cq_count; i++) {
+ gpr_mu_unlock(&server->mu);
+ grpc_cq_hack_spin_pollset(server->cqs[i]);
+ gpr_mu_lock(&server->mu);
+ }
+
+ gpr_cv_wait(&server->cv, &server->mu,
+ gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+ }
+
+ while (server->listeners) {
+ l = server->listeners;
+ server->listeners = l->next;
+ gpr_free(l);
+ }
+
+ while ((calld = call_list_remove_head(&server->lists[PENDING_START],
+ PENDING_START)) != NULL) {
+ gpr_log(GPR_DEBUG, "server destroys call %p", calld->call);
+ calld->state = ZOMBIED;
+ grpc_iomgr_add_callback(
+ kill_zombie,
+ grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
+ }
+
for (c = server->root_channel_data.next; c != &server->root_channel_data;
c = c->next) {
shutdown_channel(c);
@@ -1048,6 +1111,7 @@ static void begin_call(grpc_server *server, call_data *calld,
&rc->data.batch.details->host_capacity, calld->host);
cpstr(&rc->data.batch.details->method,
&rc->data.batch.details->method_capacity, calld->path);
+ rc->data.batch.details->deadline = calld->deadline;
grpc_call_set_completion_queue(calld->call, rc->data.batch.cq_bind);
*rc->data.batch.call = calld->call;
r->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
@@ -1073,7 +1137,7 @@ static void begin_call(grpc_server *server, call_data *calld,
break;
}
- grpc_call_internal_ref(calld->call);
+ GRPC_CALL_INTERNAL_REF(calld->call, "server");
grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish,
rc->tag);
}
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index e33f69b8c7..2cfa38fa43 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -48,9 +48,12 @@ grpc_server *grpc_server_create_from_filters(grpc_completion_queue *cq,
and when it shuts down, it will call destroy */
void grpc_server_add_listener(grpc_server *server, void *listener,
void (*start)(grpc_server *server, void *arg,
- grpc_pollset **pollsets, size_t npollsets),
+ grpc_pollset **pollsets,
+ size_t npollsets),
void (*destroy)(grpc_server *server, void *arg));
+void grpc_server_listener_destroy_done(void *server);
+
/* Setup a transport - creates a channel stack, binds the transport to the
server */
grpc_transport_setup_result grpc_server_setup_transport(
@@ -60,4 +63,4 @@ grpc_transport_setup_result grpc_server_setup_transport(
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
-#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */
+#endif /* GRPC_INTERNAL_CORE_SURFACE_SERVER_H */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 27434b39e2..7b5c2f227b 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -33,7 +33,6 @@
#include <grpc/grpc.h>
-#include "src/core/channel/http_filter.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_server.h"
@@ -46,8 +45,8 @@
static grpc_transport_setup_result setup_transport(void *server,
grpc_transport *transport,
grpc_mdctx *mdctx) {
- static grpc_channel_filter const *extra_filters[] = {&grpc_http_server_filter,
- &grpc_http_filter};
+ static grpc_channel_filter const *extra_filters[] = {
+ &grpc_http_server_filter};
return grpc_server_setup_transport(server, transport, extra_filters,
GPR_ARRAY_SIZE(extra_filters), mdctx);
}
@@ -66,7 +65,8 @@ static void new_transport(void *server, grpc_endpoint *tcp) {
}
/* Server callback: start listening on our ports */
-static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size_t pollset_count) {
+static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets,
+ size_t pollset_count) {
grpc_tcp_server *tcp = tcpp;
grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server);
}
@@ -75,7 +75,7 @@ static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets, size
callbacks) */
static void destroy(grpc_server *server, void *tcpp) {
grpc_tcp_server *tcp = tcpp;
- grpc_tcp_server_destroy(tcp);
+ grpc_tcp_server_destroy(tcp, grpc_server_listener_destroy_done, server);
}
int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
@@ -131,7 +131,7 @@ error:
grpc_resolved_addresses_destroy(resolved);
}
if (tcp) {
- grpc_tcp_server_destroy(tcp);
+ grpc_tcp_server_destroy(tcp, NULL, NULL);
}
return 0;
}
diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h
index fbb941969e..ac76c4cc9c 100644
--- a/src/core/transport/chttp2/frame.h
+++ b/src/core/transport/chttp2/frame.h
@@ -54,6 +54,7 @@ typedef struct {
gpr_uint8 process_ping_reply;
gpr_uint8 goaway;
+ gpr_int64 initial_window_update;
gpr_uint32 window_update;
gpr_uint32 goaway_last_stream_index;
gpr_uint32 goaway_error;
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
index 8d3250c34f..2ffce730d5 100644
--- a/src/core/transport/chttp2/frame_settings.c
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -218,6 +218,14 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
return GRPC_CHTTP2_CONNECTION_ERROR;
}
}
+ if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
+ parser->incoming_settings[parser->id] != parser->value) {
+ state->initial_window_update =
+ (gpr_int64)parser->value -
+ parser->incoming_settings[parser->id];
+ gpr_log(GPR_DEBUG, "adding %d for initial_window change",
+ (int)state->initial_window_update);
+ }
parser->incoming_settings[parser->id] = parser->value;
if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id,
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 79cce553fa..cf1e66bf8b 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -43,7 +43,7 @@
#include "src/core/transport/chttp2/timeout_encoding.h"
#include "src/core/transport/chttp2/varint.h"
-#define HASH_FRAGMENT_1(x) ((x) & 255)
+#define HASH_FRAGMENT_1(x) ((x)&255)
#define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
#define HASH_FRAGMENT_3(x) ((x >> 16) & 255)
#define HASH_FRAGMENT_4(x) ((x >> 24) & 255)
@@ -171,13 +171,15 @@ static gpr_uint8 *add_tiny_header_data(framer_state *st, int len) {
return gpr_slice_buffer_tiny_add(st->output, len);
}
-static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
+/* add an element to the decoder table: returns metadata element to unref */
+static grpc_mdelem *add_elem(grpc_chttp2_hpack_compressor *c,
+ grpc_mdelem *elem) {
gpr_uint32 key_hash = elem->key->hash;
gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
gpr_uint32 new_index = c->tail_remote_index + c->table_elems + 1;
gpr_uint32 elem_size = 32 + GPR_SLICE_LENGTH(elem->key->slice) +
GPR_SLICE_LENGTH(elem->value->slice);
- int drop_ref;
+ grpc_mdelem *elem_to_unref;
/* Reserve space for this element in the remote table: if this overflows
the current table, drop elements until it fits, matching the decompressor
@@ -204,34 +206,32 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == elem) {
/* already there: update with new index */
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- drop_ref = 1;
+ elem_to_unref = elem;
} else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem) {
/* already there (cuckoo): update with new index */
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
- drop_ref = 1;
+ elem_to_unref = elem;
} else if (c->entries_elems[HASH_FRAGMENT_2(elem_hash)] == NULL) {
/* not there, but a free element: add */
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- drop_ref = 0;
+ elem_to_unref = NULL;
} else if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == NULL) {
/* not there (cuckoo), but a free element: add */
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
- drop_ref = 0;
+ elem_to_unref = NULL;
} else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
/* not there: replace oldest */
- grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
+ elem_to_unref = c->entries_elems[HASH_FRAGMENT_2(elem_hash)];
c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = elem;
c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
- drop_ref = 0;
} else {
/* not there: replace oldest */
- grpc_mdelem_unref(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
+ elem_to_unref = c->entries_elems[HASH_FRAGMENT_3(elem_hash)];
c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = elem;
c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
- drop_ref = 0;
}
/* do exactly the same for the key (so we can find by that again too) */
@@ -257,9 +257,7 @@ static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
}
- if (drop_ref) {
- grpc_mdelem_unref(elem);
- }
+ return elem_to_unref;
}
static void emit_indexed(grpc_chttp2_hpack_compressor *c, gpr_uint32 index,
@@ -348,9 +346,9 @@ static gpr_uint32 dynidx(grpc_chttp2_hpack_compressor *c, gpr_uint32 index) {
c->table_elems - index;
}
-/* encode an mdelem, taking ownership of it */
-static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
- framer_state *st) {
+/* encode an mdelem; returns metadata element to unref */
+static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
+ grpc_mdelem *elem, framer_state *st) {
gpr_uint32 key_hash = elem->key->hash;
gpr_uint32 elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
size_t decoder_space_usage;
@@ -366,8 +364,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
/* HIT: complete element (first cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_2(elem_hash)]),
st);
- grpc_mdelem_unref(elem);
- return;
+ return elem;
}
if (c->entries_elems[HASH_FRAGMENT_3(elem_hash)] == elem &&
@@ -375,8 +372,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
/* HIT: complete element (second cuckoo hash) */
emit_indexed(c, dynidx(c, c->indices_elems[HASH_FRAGMENT_3(elem_hash)]),
st);
- grpc_mdelem_unref(elem);
- return;
+ return elem;
}
/* should this elem be in the table? */
@@ -394,12 +390,12 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
- add_elem(c, elem);
+ return add_elem(c, elem);
} else {
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
- grpc_mdelem_unref(elem);
+ return elem;
}
- return;
+ abort();
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
@@ -408,23 +404,24 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
/* HIT: key (first cuckoo hash) */
if (should_add_elem) {
emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
- add_elem(c, elem);
+ return add_elem(c, elem);
} else {
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
- grpc_mdelem_unref(elem);
+ return elem;
}
- return;
+ abort();
}
/* no elem, key in the table... fall back to literal emission */
if (should_add_elem) {
emit_lithdr_incidx_v(c, elem, st);
- add_elem(c, elem);
+ return add_elem(c, elem);
} else {
emit_lithdr_noidx_v(c, elem, st);
- grpc_mdelem_unref(elem);
+ return elem;
}
+ abort();
}
#define STRLEN_LIT(x) (sizeof(x) - 1)
@@ -433,11 +430,13 @@ static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
framer_state *st) {
char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
+ grpc_mdelem *mdelem;
grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
- hpack_enc(c, grpc_mdelem_from_metadata_strings(
- c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
- grpc_mdstr_from_string(c->mdctx, timeout_str)),
- st);
+ mdelem = grpc_mdelem_from_metadata_strings(
+ c->mdctx, grpc_mdstr_ref(c->timeout_key_str),
+ grpc_mdstr_from_string(c->mdctx, timeout_str));
+ mdelem = hpack_enc(c, mdelem, st);
+ if (mdelem) grpc_mdelem_unref(mdelem);
}
gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id) {
@@ -480,10 +479,8 @@ gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
/* skip */
curop++;
break;
- case GRPC_OP_FLOW_CTL_CB:
- case GRPC_OP_DEADLINE:
case GRPC_OP_METADATA:
- case GRPC_OP_METADATA_BOUNDARY:
+ grpc_metadata_batch_assert_ok(&op->data.metadata);
/* these just get copied as they don't impact the number of flow
controlled bytes */
grpc_sopb_append(outops, op, 1);
@@ -530,6 +527,12 @@ exit_loop:
*inops_count -= curop;
memmove(inops, inops + curop, *inops_count * sizeof(grpc_stream_op));
+ for (curop = 0; curop < *inops_count; curop++) {
+ if (inops[curop].type == GRPC_OP_METADATA) {
+ grpc_metadata_batch_assert_ok(&inops[curop].data.metadata);
+ }
+ }
+
return flow_controlled_bytes_taken;
}
@@ -542,6 +545,10 @@ void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
grpc_stream_op *op;
gpr_uint32 max_take_size;
gpr_uint32 curop = 0;
+ gpr_uint32 unref_op;
+ grpc_mdctx *mdctx = compressor->mdctx;
+ grpc_linked_mdelem *l;
+ int need_unref = 0;
GPR_ASSERT(stream_id != 0);
@@ -559,19 +566,20 @@ void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
GPR_ERROR,
"These stream ops should be filtered out by grpc_chttp2_preencode");
abort();
- case GRPC_OP_FLOW_CTL_CB:
- op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
- curop++;
- break;
case GRPC_OP_METADATA:
- hpack_enc(compressor, op->data.metadata, &st);
- curop++;
- break;
- case GRPC_OP_DEADLINE:
- deadline_enc(compressor, op->data.deadline, &st);
- curop++;
- break;
- case GRPC_OP_METADATA_BOUNDARY:
+ /* Encode a metadata batch; store the returned values, representing
+ a metadata element that needs to be unreffed back into the metadata
+ slot. THIS MAY NOT BE THE SAME ELEMENT (if a decoder table slot got
+ updated). After this loop, we'll do a batch unref of elements. */
+ need_unref |= op->data.metadata.garbage.head != NULL;
+ grpc_metadata_batch_assert_ok(&op->data.metadata);
+ for (l = op->data.metadata.list.head; l; l = l->next) {
+ l->md = hpack_enc(compressor, l->md, &st);
+ need_unref |= l->md != NULL;
+ }
+ if (gpr_time_cmp(op->data.metadata.deadline, gpr_inf_future) != 0) {
+ deadline_enc(compressor, op->data.metadata.deadline, &st);
+ }
ensure_frame_type(&st, HEADER, 0);
finish_frame(&st, 1, 0);
st.last_was_header = 0; /* force a new header frame */
@@ -601,4 +609,19 @@ void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
begin_frame(&st, DATA);
}
finish_frame(&st, 1, eof);
+
+ if (need_unref) {
+ grpc_mdctx_lock(mdctx);
+ for (unref_op = 0; unref_op < curop; unref_op++) {
+ op = &ops[unref_op];
+ if (op->type != GRPC_OP_METADATA) continue;
+ for (l = op->data.metadata.list.head; l; l = l->next) {
+ if (l->md) grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+ }
+ for (l = op->data.metadata.garbage.head; l; l = l->next) {
+ grpc_mdctx_locked_mdelem_unref(mdctx, l->md);
+ }
+ }
+ grpc_mdctx_unlock(mdctx);
+ }
}
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 2b15b2a812..3ae693176e 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -68,10 +68,10 @@ int grpc_http_trace = 0;
typedef struct transport transport;
typedef struct stream stream;
-#define IF_TRACING(stmt) \
- if (!(grpc_http_trace)) \
- ; \
- else \
+#define IF_TRACING(stmt) \
+ if (!(grpc_http_trace)) \
+ ; \
+ else \
stmt
/* streams are kept in various linked lists depending on what things need to
@@ -91,10 +91,9 @@ typedef enum {
/* streams that are waiting to start because there are too many concurrent
streams on the connection */
WAITING_FOR_CONCURRENCY,
- /* streams that want to callback the application */
- PENDING_CALLBACKS,
- /* streams that *ARE* calling back to the application */
- EXECUTING_CALLBACKS,
+ /* streams that have finished reading: we wait until unlock to coalesce
+ all changes into one callback */
+ FINISHED_READ_OP,
STREAM_LIST_COUNT /* must be last */
} stream_list_id;
@@ -141,6 +140,12 @@ typedef enum {
DTS_FRAME
} deframe_transport_state;
+typedef enum {
+ WRITE_STATE_OPEN,
+ WRITE_STATE_QUEUED_CLOSE,
+ WRITE_STATE_SENT_CLOSE
+} WRITE_STATE;
+
typedef struct {
stream *head;
stream *tail;
@@ -182,6 +187,18 @@ typedef struct {
gpr_slice debug;
} pending_goaway;
+typedef struct {
+ void (*cb)(void *user_data, int success);
+ void *user_data;
+ int success;
+} op_closure;
+
+typedef struct {
+ op_closure *callbacks;
+ size_t count;
+ size_t capacity;
+} op_closure_array;
+
struct transport {
grpc_transport base; /* must be first */
const grpc_transport_callbacks *cb;
@@ -202,6 +219,10 @@ struct transport {
gpr_uint8 closed;
error_state error_state;
+ /* queued callbacks */
+ op_closure_array pending_callbacks;
+ op_closure_array executing_callbacks;
+
/* stream indexing */
gpr_uint32 next_stream_id;
gpr_uint32 last_incoming_stream_id;
@@ -276,24 +297,34 @@ struct transport {
struct stream {
gpr_uint32 id;
- gpr_uint32 outgoing_window;
gpr_uint32 incoming_window;
+ gpr_int64 outgoing_window;
/* when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */
- gpr_uint8 queued_write_closed;
- gpr_uint8 sending_write_closed;
- gpr_uint8 sent_write_closed;
+ WRITE_STATE write_state;
+ gpr_uint8 send_closed;
gpr_uint8 read_closed;
gpr_uint8 cancelled;
- gpr_uint8 allow_window_updates;
- gpr_uint8 published_close;
+
+ op_closure send_done_closure;
+ op_closure recv_done_closure;
stream_link links[STREAM_LIST_COUNT];
gpr_uint8 included[STREAM_LIST_COUNT];
+ /* incoming metadata */
+ grpc_linked_mdelem *incoming_metadata;
+ size_t incoming_metadata_count;
+ size_t incoming_metadata_capacity;
+ grpc_linked_mdelem *old_incoming_metadata;
+ gpr_timespec incoming_deadline;
+
/* sops from application */
- grpc_stream_op_buffer outgoing_sopb;
+ grpc_stream_op_buffer *outgoing_sopb;
+ grpc_stream_op_buffer *incoming_sopb;
+ grpc_stream_state *publish_state;
+ grpc_stream_state published_state;
/* sops that have passed flow control to be written */
grpc_stream_op_buffer writing_sopb;
@@ -331,7 +362,8 @@ static void cancel_stream_id(transport *t, gpr_uint32 id,
grpc_chttp2_error_code error_code, int send_rst);
static void cancel_stream(transport *t, stream *s,
grpc_status_code local_status,
- grpc_chttp2_error_code error_code, int send_rst);
+ grpc_chttp2_error_code error_code,
+ grpc_mdstr *optional_message, int send_rst);
static void finalize_cancellations(transport *t);
static stream *lookup_stream(transport *t, gpr_uint32 id);
static void remove_from_stream_map(transport *t, stream *s);
@@ -342,6 +374,14 @@ static void become_skip_parser(transport *t);
static void recv_data(void *tp, gpr_slice *slices, size_t nslices,
grpc_endpoint_cb_status error);
+static void schedule_cb(transport *t, op_closure closure, int success);
+static void maybe_finish_read(transport *t, stream *s);
+static void maybe_join_window_updates(transport *t, stream *s);
+static void finish_reads(transport *t);
+static void add_to_pollset_locked(transport *t, grpc_pollset *pollset);
+static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op);
+static void add_metadata_batch(transport *t, stream *s);
+
/*
* CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/
@@ -381,6 +421,9 @@ static void destruct_transport(transport *t) {
}
gpr_free(t->pings);
+ gpr_free(t->pending_callbacks.callbacks);
+ gpr_free(t->executing_callbacks.callbacks);
+
for (i = 0; i < t->num_pending_goaways; i++) {
gpr_slice_unref(t->pending_goaways[i].debug);
}
@@ -410,6 +453,8 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
GPR_ASSERT(strlen(CLIENT_CONNECT_STRING) == CLIENT_CONNECT_STRLEN);
+ memset(t, 0, sizeof(*t));
+
t->base.vtable = &vtable;
t->ep = ep;
/* one ref is for destroy, the other for when ep becomes NULL */
@@ -421,27 +466,16 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
t->str_grpc_timeout =
grpc_mdstr_from_string(t->metadata_context, "grpc-timeout");
t->reading = 1;
- t->writing = 0;
t->error_state = ERROR_STATE_NONE;
t->next_stream_id = is_client ? 1 : 2;
- t->last_incoming_stream_id = 0;
- t->destroying = 0;
- t->closed = 0;
t->is_client = is_client;
t->outgoing_window = DEFAULT_WINDOW;
t->incoming_window = DEFAULT_WINDOW;
t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
t->deframe_state = is_client ? DTS_FH_0 : DTS_CLIENT_PREFIX_0;
- t->expect_continuation_stream_id = 0;
- t->pings = NULL;
- t->ping_count = 0;
- t->ping_capacity = 0;
t->ping_counter = gpr_now().tv_nsec;
grpc_chttp2_hpack_compressor_init(&t->hpack_compressor, mdctx);
grpc_chttp2_goaway_parser_init(&t->goaway_parser);
- t->pending_goaways = NULL;
- t->num_pending_goaways = 0;
- t->cap_pending_goaways = 0;
gpr_slice_buffer_init(&t->outbuf);
gpr_slice_buffer_init(&t->qbuf);
grpc_sopb_init(&t->nuke_later_sopb);
@@ -456,7 +490,6 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
needed.
TODO(ctiller): tune this */
grpc_chttp2_stream_map_init(&t->stream_map, 8);
- memset(&t->lists, 0, sizeof(t->lists));
/* copy in initial settings to all setting sets */
for (i = 0; i < NUM_SETTING_SETS; i++) {
@@ -497,7 +530,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
gpr_mu_lock(&t->mu);
t->calling_back = 1;
- ref_transport(t);
+ ref_transport(t); /* matches unref at end of this function */
gpr_mu_unlock(&t->mu);
sr = setup(arg, &t->base, t->metadata_context);
@@ -509,7 +542,7 @@ static void init_transport(transport *t, grpc_transport_setup_callback setup,
if (t->destroying) gpr_cv_signal(&t->cv);
unlock(t);
- ref_transport(t);
+ ref_transport(t); /* matches unref inside recv_data */
recv_data(t, slices, nslices, GRPC_ENDPOINT_CB_OK);
unref_transport(t);
@@ -567,17 +600,20 @@ static void goaway(grpc_transport *gt, grpc_status_code status,
}
static int init_stream(grpc_transport *gt, grpc_stream *gs,
- const void *server_data) {
+ const void *server_data, grpc_transport_op *initial_op) {
transport *t = (transport *)gt;
stream *s = (stream *)gs;
+ memset(s, 0, sizeof(*s));
+
ref_transport(t);
if (!server_data) {
lock(t);
s->id = 0;
} else {
- s->id = (gpr_uint32)(gpr_uintptr) server_data;
+ /* already locked */
+ s->id = (gpr_uint32)(gpr_uintptr)server_data;
t->incoming_stream = s;
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
}
@@ -586,20 +622,13 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
s->incoming_window =
t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->queued_write_closed = 0;
- s->sending_write_closed = 0;
- s->sent_write_closed = 0;
- s->read_closed = 0;
- s->cancelled = 0;
- s->allow_window_updates = 0;
- s->published_close = 0;
- memset(&s->links, 0, sizeof(s->links));
- memset(&s->included, 0, sizeof(s->included));
- grpc_sopb_init(&s->outgoing_sopb);
+ s->incoming_deadline = gpr_inf_future;
grpc_sopb_init(&s->writing_sopb);
grpc_sopb_init(&s->callback_sopb);
grpc_chttp2_data_parser_init(&s->parser);
+ if (initial_op) perform_op_locked(t, s, initial_op);
+
if (!server_data) {
unlock(t);
}
@@ -632,10 +661,16 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
gpr_mu_unlock(&t->mu);
- grpc_sopb_destroy(&s->outgoing_sopb);
+ GPR_ASSERT(s->outgoing_sopb == NULL);
+ GPR_ASSERT(s->incoming_sopb == NULL);
grpc_sopb_destroy(&s->writing_sopb);
grpc_sopb_destroy(&s->callback_sopb);
grpc_chttp2_data_parser_destroy(&s->parser);
+ for (i = 0; i < s->incoming_metadata_count; i++) {
+ grpc_mdelem_unref(s->incoming_metadata[i].md);
+ }
+ gpr_free(s->incoming_metadata);
+ gpr_free(s->old_incoming_metadata);
unref_transport(t);
}
@@ -698,7 +733,6 @@ static void stream_list_add_tail(transport *t, stream *s, stream_list_id id) {
}
static void stream_list_join(transport *t, stream *s, stream_list_id id) {
- if (id == PENDING_CALLBACKS) GPR_ASSERT(t->cb != NULL || t->error_state == ERROR_STATE_NONE);
if (s->included[id]) {
return;
}
@@ -707,6 +741,8 @@ static void stream_list_join(transport *t, stream *s, stream_list_id id) {
static void remove_from_stream_map(transport *t, stream *s) {
if (s->id == 0) return;
+ IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Removing stream %d",
+ t->is_client ? "CLI" : "SVR", s->id));
if (grpc_chttp2_stream_map_delete(&t->stream_map, s->id)) {
maybe_start_some_streams(t);
}
@@ -751,6 +787,8 @@ static void unlock(transport *t) {
finalize_cancellations(t);
}
+ finish_reads(t);
+
/* gather any callbacks that need to be made */
if (!t->calling_back && cb) {
perform_callbacks = prepare_callbacks(t);
@@ -760,7 +798,7 @@ static void unlock(transport *t) {
if (t->error_state == ERROR_STATE_SEEN && !t->writing) {
call_closed = 1;
t->calling_back = 1;
- t->cb = NULL; /* no more callbacks */
+ t->cb = NULL; /* no more callbacks */
t->error_state = ERROR_STATE_NOTIFIED;
}
if (t->num_pending_goaways) {
@@ -782,8 +820,7 @@ static void unlock(transport *t) {
/* perform some callbacks if necessary */
for (i = 0; i < num_goaways; i++) {
- cb->goaway(t->cb_user_data, &t->base, goaways[i].status,
- goaways[i].debug);
+ cb->goaway(t->cb_user_data, &t->base, goaways[i].status, goaways[i].debug);
}
if (perform_callbacks) {
@@ -834,13 +871,10 @@ static void push_setting(transport *t, grpc_chttp2_setting_id id,
static int prepare_write(transport *t) {
stream *s;
- gpr_slice_buffer tempbuf;
gpr_uint32 window_delta;
/* simple writes are queued to qbuf, and flushed here */
- tempbuf = t->qbuf;
- t->qbuf = t->outbuf;
- t->outbuf = tempbuf;
+ gpr_slice_buffer_swap(&t->qbuf, &t->outbuf);
GPR_ASSERT(t->qbuf.count == 0);
if (t->dirtied_local_settings && !t->sent_local_settings) {
@@ -855,23 +889,27 @@ static int prepare_write(transport *t) {
/* for each stream that's become writable, frame it's data (according to
available window sizes) and add to the output buffer */
- while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE))) {
+ while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE)) &&
+ s->outgoing_window > 0) {
window_delta = grpc_chttp2_preencode(
- s->outgoing_sopb.ops, &s->outgoing_sopb.nops,
+ s->outgoing_sopb->ops, &s->outgoing_sopb->nops,
GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
t->outgoing_window -= window_delta;
s->outgoing_window -= window_delta;
- s->sending_write_closed =
- s->queued_write_closed && s->outgoing_sopb.nops == 0;
- if (s->writing_sopb.nops > 0 || s->sending_write_closed) {
+ if (s->write_state == WRITE_STATE_QUEUED_CLOSE &&
+ s->outgoing_sopb->nops == 0) {
+ s->send_closed = 1;
+ }
+ if (s->writing_sopb.nops > 0 || s->send_closed) {
stream_list_join(t, s, WRITING);
}
- /* if there are still writes to do and the stream still has window
- available, then schedule a further write */
- if (s->outgoing_sopb.nops && s->outgoing_window) {
- GPR_ASSERT(!t->outgoing_window);
+ /* we should either exhaust window or have no ops left, but not both */
+ if (s->outgoing_sopb->nops == 0) {
+ s->outgoing_sopb = NULL;
+ schedule_cb(t, s->send_done_closure, 1);
+ } else if (s->outgoing_window) {
stream_list_add_tail(t, s, WRITABLE);
}
}
@@ -904,10 +942,9 @@ static void finalize_outbuf(transport *t) {
while ((s = stream_list_remove_head(t, WRITING))) {
grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops,
- s->sending_write_closed, s->id, &t->hpack_compressor,
- &t->outbuf);
+ s->send_closed, s->id, &t->hpack_compressor, &t->outbuf);
s->writing_sopb.nops = 0;
- if (s->sending_write_closed) {
+ if (s->send_closed) {
stream_list_join(t, s, WRITTEN_CLOSED);
}
}
@@ -921,8 +958,10 @@ static void finish_write_common(transport *t, int success) {
drop_connection(t);
}
while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) {
- s->sent_write_closed = 1;
- if (!s->cancelled) stream_list_join(t, s, PENDING_CALLBACKS);
+ s->write_state = WRITE_STATE_SENT_CLOSE;
+ if (1||!s->cancelled) {
+ maybe_finish_read(t, s);
+ }
}
t->outbuf.count = 0;
t->outbuf.length = 0;
@@ -972,6 +1011,9 @@ static void maybe_start_some_streams(transport *t) {
stream *s = stream_list_remove_head(t, WAITING_FOR_CONCURRENCY);
if (!s) break;
+ IF_TRACING(gpr_log(GPR_DEBUG, "HTTP:%s: Allocating new stream %p to id %d",
+ t->is_client ? "CLI" : "SVR", s, t->next_stream_id));
+
GPR_ASSERT(s->id == 0);
s->id = t->next_stream_id;
t->next_stream_id += 2;
@@ -980,43 +1022,63 @@ static void maybe_start_some_streams(transport *t) {
}
}
-static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops,
- size_t ops_count, int is_last) {
- transport *t = (transport *)gt;
- stream *s = (stream *)gs;
-
- lock(t);
-
- if (is_last) {
- s->queued_write_closed = 1;
- }
- if (!s->cancelled) {
- grpc_sopb_append(&s->outgoing_sopb, ops, ops_count);
- if (s->id == 0) {
- stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
- maybe_start_some_streams(t);
+static void perform_op_locked(transport *t, stream *s, grpc_transport_op *op) {
+ if (op->cancel_with_status != GRPC_STATUS_OK) {
+ cancel_stream(
+ t, s, op->cancel_with_status,
+ grpc_chttp2_grpc_status_to_http2_error(op->cancel_with_status),
+ op->cancel_message, 1);
+ }
+
+ if (op->send_ops) {
+ GPR_ASSERT(s->outgoing_sopb == NULL);
+ s->send_done_closure.cb = op->on_done_send;
+ s->send_done_closure.user_data = op->send_user_data;
+ if (!s->cancelled) {
+ s->outgoing_sopb = op->send_ops;
+ if (op->is_last_send && s->write_state == WRITE_STATE_OPEN) {
+ s->write_state = WRITE_STATE_QUEUED_CLOSE;
+ }
+ if (s->id == 0) {
+ IF_TRACING(gpr_log(GPR_DEBUG,
+ "HTTP:%s: New stream %p waiting for concurrency",
+ t->is_client ? "CLI" : "SVR", s));
+ stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
+ maybe_start_some_streams(t);
+ } else if (s->outgoing_window > 0) {
+ stream_list_join(t, s, WRITABLE);
+ }
} else {
- stream_list_join(t, s, WRITABLE);
+ schedule_nuke_sopb(t, op->send_ops);
+ schedule_cb(t, s->send_done_closure, 0);
}
- } else {
- grpc_sopb_append(&t->nuke_later_sopb, ops, ops_count);
}
- if (is_last && s->outgoing_sopb.nops == 0 && s->read_closed &&
- !s->published_close) {
- stream_list_join(t, s, PENDING_CALLBACKS);
+
+ if (op->recv_ops) {
+ GPR_ASSERT(s->incoming_sopb == NULL);
+ s->recv_done_closure.cb = op->on_done_recv;
+ s->recv_done_closure.user_data = op->recv_user_data;
+ s->incoming_sopb = op->recv_ops;
+ s->incoming_sopb->nops = 0;
+ s->publish_state = op->recv_state;
+ gpr_free(s->old_incoming_metadata);
+ s->old_incoming_metadata = NULL;
+ maybe_finish_read(t, s);
+ maybe_join_window_updates(t, s);
}
- unlock(t);
+ if (op->bind_pollset) {
+ add_to_pollset_locked(t, op->bind_pollset);
+ }
}
-static void abort_stream(grpc_transport *gt, grpc_stream *gs,
- grpc_status_code status) {
+static void perform_op(grpc_transport *gt, grpc_stream *gs,
+ grpc_transport_op *op) {
transport *t = (transport *)gt;
stream *s = (stream *)gs;
lock(t);
- cancel_stream(t, s, status, grpc_chttp2_grpc_status_to_http2_error(status),
- 1);
+ perform_op_locked(t, s, op);
unlock(t);
}
@@ -1055,35 +1117,70 @@ static void finalize_cancellations(transport *t) {
while ((s = stream_list_remove_head(t, CANCELLED))) {
s->read_closed = 1;
- s->sent_write_closed = 1;
- stream_list_join(t, s, PENDING_CALLBACKS);
+ s->write_state = WRITE_STATE_SENT_CLOSE;
+ maybe_finish_read(t, s);
+ }
+}
+
+static void add_incoming_metadata(transport *t, stream *s, grpc_mdelem *elem) {
+ if (s->incoming_metadata_capacity == s->incoming_metadata_count) {
+ s->incoming_metadata_capacity =
+ GPR_MAX(8, 2 * s->incoming_metadata_capacity);
+ s->incoming_metadata =
+ gpr_realloc(s->incoming_metadata, sizeof(*s->incoming_metadata) *
+ s->incoming_metadata_capacity);
}
+ s->incoming_metadata[s->incoming_metadata_count++].md = elem;
}
static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_status_code local_status,
grpc_chttp2_error_code error_code,
- int send_rst) {
+ grpc_mdstr *optional_message, int send_rst) {
int had_outgoing;
char buffer[GPR_LTOA_MIN_BUFSIZE];
if (s) {
/* clear out any unreported input & output: nobody cares anymore */
- had_outgoing = s->outgoing_sopb.nops != 0;
+ had_outgoing = s->outgoing_sopb && s->outgoing_sopb->nops != 0;
schedule_nuke_sopb(t, &s->parser.incoming_sopb);
- schedule_nuke_sopb(t, &s->outgoing_sopb);
+ if (s->outgoing_sopb) {
+ schedule_nuke_sopb(t, s->outgoing_sopb);
+ s->outgoing_sopb = NULL;
+ stream_list_remove(t, s, WRITABLE);
+ schedule_cb(t, s->send_done_closure, 0);
+ }
if (s->cancelled) {
send_rst = 0;
- } else if (!s->read_closed || !s->sent_write_closed || had_outgoing) {
+ } else if (!s->read_closed || s->write_state != WRITE_STATE_SENT_CLOSE ||
+ had_outgoing) {
s->cancelled = 1;
stream_list_join(t, s, CANCELLED);
gpr_ltoa(local_status, buffer);
- grpc_sopb_add_metadata(
- &s->parser.incoming_sopb,
+ add_incoming_metadata(
+ t, s,
grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
-
- stream_list_join(t, s, PENDING_CALLBACKS);
+ if (!optional_message) {
+ switch (local_status) {
+ case GRPC_STATUS_CANCELLED:
+ add_incoming_metadata(
+ t, s, grpc_mdelem_from_strings(t->metadata_context,
+ "grpc-message", "Cancelled"));
+ break;
+ default:
+ break;
+ }
+ } else {
+ add_incoming_metadata(
+ t, s,
+ grpc_mdelem_from_metadata_strings(
+ t->metadata_context,
+ grpc_mdstr_from_string(t->metadata_context, "grpc-message"),
+ grpc_mdstr_ref(optional_message)));
+ }
+ add_metadata_batch(t, s);
+ maybe_finish_read(t, s);
}
}
if (!id) send_rst = 0;
@@ -1091,24 +1188,29 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
gpr_slice_buffer_add(&t->qbuf,
grpc_chttp2_rst_stream_create(id, error_code));
}
+ if (optional_message) {
+ grpc_mdstr_unref(optional_message);
+ }
}
static void cancel_stream_id(transport *t, gpr_uint32 id,
grpc_status_code local_status,
grpc_chttp2_error_code error_code, int send_rst) {
cancel_stream_inner(t, lookup_stream(t, id), id, local_status, error_code,
- send_rst);
+ NULL, send_rst);
}
static void cancel_stream(transport *t, stream *s,
grpc_status_code local_status,
- grpc_chttp2_error_code error_code, int send_rst) {
- cancel_stream_inner(t, s, s->id, local_status, error_code, send_rst);
+ grpc_chttp2_error_code error_code,
+ grpc_mdstr *optional_message, int send_rst) {
+ cancel_stream_inner(t, s, s->id, local_status, error_code, optional_message,
+ send_rst);
}
static void cancel_stream_cb(void *user_data, gpr_uint32 id, void *stream) {
cancel_stream(user_data, stream, GRPC_STATUS_UNAVAILABLE,
- GRPC_CHTTP2_INTERNAL_ERROR, 0);
+ GRPC_CHTTP2_INTERNAL_ERROR, NULL, 0);
}
static void end_all_the_calls(transport *t) {
@@ -1122,8 +1224,14 @@ static void drop_connection(transport *t) {
end_all_the_calls(t);
}
+static void maybe_finish_read(transport *t, stream *s) {
+ if (s->incoming_sopb) {
+ stream_list_join(t, s, FINISHED_READ_OP);
+ }
+}
+
static void maybe_join_window_updates(transport *t, stream *s) {
- if (s->allow_window_updates &&
+ if (s->incoming_sopb != NULL &&
s->incoming_window <
t->settings[LOCAL_SETTINGS]
[GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] *
@@ -1132,21 +1240,6 @@ static void maybe_join_window_updates(transport *t, stream *s) {
}
}
-static void set_allow_window_updates(grpc_transport *tp, grpc_stream *sp,
- int allow) {
- transport *t = (transport *)tp;
- stream *s = (stream *)sp;
-
- lock(t);
- s->allow_window_updates = allow;
- if (allow) {
- maybe_join_window_updates(t, s);
- } else {
- stream_list_remove(t, s, WINDOW_UPDATE);
- }
- unlock(t);
-}
-
static grpc_chttp2_parse_error update_incoming_window(transport *t, stream *s) {
if (t->incoming_frame_size > t->incoming_window) {
gpr_log(GPR_ERROR, "frame of size %d overflows incoming window of %d",
@@ -1220,7 +1313,7 @@ static int init_data_frame_parser(transport *t) {
case GRPC_CHTTP2_STREAM_ERROR:
cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
GRPC_CHTTP2_INTERNAL_ERROR),
- GRPC_CHTTP2_INTERNAL_ERROR, 1);
+ GRPC_CHTTP2_INTERNAL_ERROR, NULL, 1);
return init_skip_frame(t, 0);
case GRPC_CHTTP2_CONNECTION_ERROR:
drop_connection(t);
@@ -1239,11 +1332,10 @@ static void on_header(void *tp, grpc_mdelem *md) {
GPR_ASSERT(s);
- IF_TRACING(gpr_log(GPR_INFO, "HTTP:%d:HDR: %s: %s", s->id,
- grpc_mdstr_as_c_string(md->key),
- grpc_mdstr_as_c_string(md->value)));
+ IF_TRACING(gpr_log(
+ GPR_INFO, "HTTP:%d:%s:HDR: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
+ grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
- stream_list_join(t, s, PENDING_CALLBACKS);
if (md->key == t->str_grpc_timeout) {
gpr_timespec *cached_timeout = grpc_mdelem_get_user_data(md, free_timeout);
if (!cached_timeout) {
@@ -1257,12 +1349,12 @@ static void on_header(void *tp, grpc_mdelem *md) {
}
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
- grpc_sopb_add_deadline(&s->parser.incoming_sopb,
- gpr_time_add(gpr_now(), *cached_timeout));
+ s->incoming_deadline = gpr_time_add(gpr_now(), *cached_timeout);
grpc_mdelem_unref(md);
} else {
- grpc_sopb_add_metadata(&s->parser.incoming_sopb, md);
+ add_incoming_metadata(t, s, md);
}
+ maybe_finish_read(t, s);
}
static int init_header_frame_parser(transport *t, int is_continuation) {
@@ -1300,13 +1392,16 @@ static int init_header_frame_parser(transport *t, int is_continuation) {
gpr_log(GPR_ERROR,
"ignoring out of order new stream request on server; last stream "
"id=%d, new stream id=%d",
- t->last_incoming_stream_id, t->incoming_stream);
+ t->last_incoming_stream_id, t->incoming_stream_id);
+ return init_skip_frame(t, 1);
+ } else if ((t->incoming_stream_id & 1) == 0) {
+ gpr_log(GPR_ERROR, "ignoring stream with non-client generated index %d", t->incoming_stream_id);
return init_skip_frame(t, 1);
}
t->incoming_stream = NULL;
/* if stream is accepted, we set incoming_stream in init_stream */
t->cb->accept_stream(t->cb_user_data, &t->base,
- (void *)(gpr_uintptr) t->incoming_stream_id);
+ (void *)(gpr_uintptr)t->incoming_stream_id);
s = t->incoming_stream;
if (!s) {
gpr_log(GPR_ERROR, "stream not accepted");
@@ -1433,8 +1528,24 @@ static int init_frame_parser(transport *t) {
}
}
-static int is_window_update_legal(gpr_uint32 window_update, gpr_uint32 window) {
- return window_update < MAX_WINDOW - window;
+static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
+ return window + window_update < MAX_WINDOW;
+}
+
+static void add_metadata_batch(transport *t, stream *s) {
+ grpc_metadata_batch b;
+
+ b.list.head = NULL;
+ /* Store away the last element of the list, so that in patch_metadata_ops
+ we can reconstitute the list.
+ We can't do list building here as later incoming metadata may reallocate
+ the underlying array. */
+ b.list.tail = (void*)(gpr_intptr)s->incoming_metadata_count;
+ b.garbage.head = b.garbage.tail = NULL;
+ b.deadline = s->incoming_deadline;
+ s->incoming_deadline = gpr_inf_future;
+
+ grpc_sopb_add_metadata(&s->parser.incoming_sopb, b);
}
static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
@@ -1445,15 +1556,14 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
case GRPC_CHTTP2_PARSE_OK:
if (st.end_of_stream) {
t->incoming_stream->read_closed = 1;
- stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+ maybe_finish_read(t, t->incoming_stream);
}
if (st.need_flush_reads) {
- stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+ maybe_finish_read(t, t->incoming_stream);
}
if (st.metadata_boundary) {
- grpc_sopb_add_metadata_boundary(
- &t->incoming_stream->parser.incoming_sopb);
- stream_list_join(t, t->incoming_stream, PENDING_CALLBACKS);
+ add_metadata_batch(t, t->incoming_stream);
+ maybe_finish_read(t, t->incoming_stream);
}
if (st.ack_settings) {
gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
@@ -1488,21 +1598,33 @@ static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
}
}
}
+ if (st.initial_window_update) {
+ for (i = 0; i < t->stream_map.count; i++) {
+ stream *s = (stream *)(t->stream_map.values[i]);
+ int was_window_empty = s->outgoing_window <= 0;
+ s->outgoing_window += st.initial_window_update;
+ if (was_window_empty && s->outgoing_window > 0 && s->outgoing_sopb &&
+ s->outgoing_sopb->nops > 0) {
+ stream_list_join(t, s, WRITABLE);
+ }
+ }
+ }
if (st.window_update) {
if (t->incoming_stream_id) {
/* if there was a stream id, this is for some stream */
stream *s = lookup_stream(t, t->incoming_stream_id);
if (s) {
- int was_window_empty = s->outgoing_window == 0;
+ int was_window_empty = s->outgoing_window <= 0;
if (!is_window_update_legal(st.window_update, s->outgoing_window)) {
cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
GRPC_CHTTP2_FLOW_CONTROL_ERROR),
- GRPC_CHTTP2_FLOW_CONTROL_ERROR, 1);
+ GRPC_CHTTP2_FLOW_CONTROL_ERROR, NULL, 1);
} else {
s->outgoing_window += st.window_update;
/* if this window update makes outgoing ops writable again,
flag that */
- if (was_window_empty && s->outgoing_sopb.nops) {
+ if (was_window_empty && s->outgoing_sopb &&
+ s->outgoing_sopb->nops > 0) {
stream_list_join(t, s, WRITABLE);
}
}
@@ -1571,8 +1693,8 @@ static int process_read(transport *t, gpr_slice slice) {
"Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
"at byte %d",
CLIENT_CONNECT_STRING[t->deframe_state],
- (int)(gpr_uint8) CLIENT_CONNECT_STRING[t->deframe_state],
- *cur, (int)*cur, t->deframe_state);
+ (int)(gpr_uint8)CLIENT_CONNECT_STRING[t->deframe_state], *cur,
+ (int)*cur, t->deframe_state);
drop_connection(t);
return 0;
}
@@ -1710,6 +1832,8 @@ static int process_read(transport *t, gpr_slice slice) {
gpr_log(GPR_ERROR, "should never reach here");
abort();
+
+ return 0;
}
/* tcp read callback */
@@ -1762,50 +1886,135 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed,
return GRPC_STREAM_OPEN;
}
-static int prepare_callbacks(transport *t) {
+static void patch_metadata_ops(stream *s) {
+ grpc_stream_op *ops = s->incoming_sopb->ops;
+ size_t nops = s->incoming_sopb->nops;
+ size_t i;
+ size_t j;
+ size_t mdidx = 0;
+ size_t last_mdidx;
+ int found_metadata = 0;
+
+ /* rework the array of metadata into a linked list, making use
+ of the breadcrumbs we left in metadata batches during
+ add_metadata_batch */
+ for (i = 0; i < nops; i++) {
+ grpc_stream_op *op = &ops[i];
+ if (op->type != GRPC_OP_METADATA) continue;
+ found_metadata = 1;
+ /* we left a breadcrumb indicating where the end of this list is,
+ and since we add sequentially, we know from the end of the last
+ segment where this segment begins */
+ last_mdidx = (size_t)(gpr_intptr)(op->data.metadata.list.tail);
+ GPR_ASSERT(last_mdidx > mdidx);
+ GPR_ASSERT(last_mdidx <= s->incoming_metadata_count);
+ /* turn the array into a doubly linked list */
+ op->data.metadata.list.head = &s->incoming_metadata[mdidx];
+ op->data.metadata.list.tail = &s->incoming_metadata[last_mdidx - 1];
+ for (j = mdidx + 1; j < last_mdidx; j++) {
+ s->incoming_metadata[j].prev = &s->incoming_metadata[j-1];
+ s->incoming_metadata[j-1].next = &s->incoming_metadata[j];
+ }
+ s->incoming_metadata[mdidx].prev = NULL;
+ s->incoming_metadata[last_mdidx-1].next = NULL;
+ /* track where we're up to */
+ mdidx = last_mdidx;
+ }
+ if (found_metadata) {
+ s->old_incoming_metadata = s->incoming_metadata;
+ if (mdidx != s->incoming_metadata_count) {
+ /* we have a partially read metadata batch still in incoming_metadata */
+ size_t new_count = s->incoming_metadata_count - mdidx;
+ size_t copy_bytes = sizeof(*s->incoming_metadata) * new_count;
+ GPR_ASSERT(mdidx < s->incoming_metadata_count);
+ s->incoming_metadata = gpr_malloc(copy_bytes);
+ memcpy(s->old_incoming_metadata + mdidx, s->incoming_metadata, copy_bytes);
+ s->incoming_metadata_count = s->incoming_metadata_capacity = new_count;
+ } else {
+ s->incoming_metadata = NULL;
+ s->incoming_metadata_count = 0;
+ s->incoming_metadata_capacity = 0;
+ }
+ }
+}
+
+static void finish_reads(transport *t) {
stream *s;
- int n = 0;
- while ((s = stream_list_remove_head(t, PENDING_CALLBACKS))) {
- int execute = 1;
- grpc_sopb_swap(&s->parser.incoming_sopb, &s->callback_sopb);
-
- s->callback_state = compute_state(s->sent_write_closed, s->read_closed);
- if (s->callback_state == GRPC_STREAM_CLOSED) {
- remove_from_stream_map(t, s);
- if (s->published_close) {
- execute = 0;
+
+ while ((s = stream_list_remove_head(t, FINISHED_READ_OP)) != NULL) {
+ int publish = 0;
+ GPR_ASSERT(s->incoming_sopb);
+ *s->publish_state =
+ compute_state(s->write_state == WRITE_STATE_SENT_CLOSE, s->read_closed);
+ if (*s->publish_state != s->published_state) {
+ s->published_state = *s->publish_state;
+ publish = 1;
+ if (s->published_state == GRPC_STREAM_CLOSED) {
+ remove_from_stream_map(t, s);
}
- s->published_close = 1;
}
-
- if (execute) {
- stream_list_add_tail(t, s, EXECUTING_CALLBACKS);
- n = 1;
+ if (s->parser.incoming_sopb.nops > 0) {
+ grpc_sopb_swap(s->incoming_sopb, &s->parser.incoming_sopb);
+ publish = 1;
+ }
+ if (publish) {
+ if (s->incoming_metadata_count > 0) {
+ patch_metadata_ops(s);
+ }
+ s->incoming_sopb = NULL;
+ schedule_cb(t, s->recv_done_closure, 1);
}
}
- return n;
+
+}
+
+static void schedule_cb(transport *t, op_closure closure, int success) {
+ if (t->pending_callbacks.capacity == t->pending_callbacks.count) {
+ t->pending_callbacks.capacity =
+ GPR_MAX(t->pending_callbacks.capacity * 2, 8);
+ t->pending_callbacks.callbacks =
+ gpr_realloc(t->pending_callbacks.callbacks,
+ t->pending_callbacks.capacity *
+ sizeof(*t->pending_callbacks.callbacks));
+ }
+ closure.success = success;
+ t->pending_callbacks.callbacks[t->pending_callbacks.count++] = closure;
+}
+
+static int prepare_callbacks(transport *t) {
+ op_closure_array temp = t->pending_callbacks;
+ t->pending_callbacks = t->executing_callbacks;
+ t->executing_callbacks = temp;
+ return t->executing_callbacks.count > 0;
}
static void run_callbacks(transport *t, const grpc_transport_callbacks *cb) {
- stream *s;
- while ((s = stream_list_remove_head(t, EXECUTING_CALLBACKS))) {
- size_t nops = s->callback_sopb.nops;
- s->callback_sopb.nops = 0;
- cb->recv_batch(t->cb_user_data, &t->base, (grpc_stream *)s,
- s->callback_sopb.ops, nops, s->callback_state);
+ size_t i;
+ for (i = 0; i < t->executing_callbacks.count; i++) {
+ op_closure c = t->executing_callbacks.callbacks[i];
+ c.cb(c.user_data, c.success);
}
+ t->executing_callbacks.count = 0;
}
static void call_cb_closed(transport *t, const grpc_transport_callbacks *cb) {
cb->closed(t->cb_user_data, &t->base);
}
-static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) {
- transport *t = (transport *)gt;
- lock(t);
+/*
+ * POLLSET STUFF
+ */
+
+static void add_to_pollset_locked(transport *t, grpc_pollset *pollset) {
if (t->ep) {
grpc_endpoint_add_to_pollset(t->ep, pollset);
}
+}
+
+static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) {
+ transport *t = (transport *)gt;
+ lock(t);
+ add_to_pollset_locked(t, pollset);
unlock(t);
}
@@ -1814,8 +2023,8 @@ static void add_to_pollset(grpc_transport *gt, grpc_pollset *pollset) {
*/
static const grpc_transport_vtable vtable = {
- sizeof(stream), init_stream, send_batch, set_allow_window_updates,
- add_to_pollset, destroy_stream, abort_stream, goaway,
+ sizeof(stream), init_stream, perform_op,
+ add_to_pollset, destroy_stream, goaway,
close_transport, send_ping, destroy_transport};
void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 1c15716fad..74e94b2c24 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -34,10 +34,12 @@
#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/metadata.h"
+#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include "src/core/support/murmur_hash.h"
#include "src/core/transport/chttp2/bin_encoder.h"
@@ -68,11 +70,12 @@ typedef struct internal_metadata {
internal_string *key;
internal_string *value;
+ gpr_atm refcnt;
+
/* private only data */
void *user_data;
void (*destroy_user_data)(void *user_data);
- gpr_uint32 refs;
grpc_mdctx *context;
struct internal_metadata *bucket_next;
} internal_metadata;
@@ -97,7 +100,7 @@ static void internal_string_ref(internal_string *s);
static void internal_string_unref(internal_string *s);
static void discard_metadata(grpc_mdctx *ctx);
static void gc_mdtab(grpc_mdctx *ctx);
-static void metadata_context_destroy(grpc_mdctx *ctx);
+static void metadata_context_destroy_locked(grpc_mdctx *ctx);
static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
@@ -117,21 +120,20 @@ static void unlock(grpc_mdctx *ctx) {
if (ctx->refs == 0) {
/* uncomment if you're having trouble diagnosing an mdelem leak to make
things clearer (slows down destruction a lot, however) */
- /* gc_mdtab(ctx); */
+ gc_mdtab(ctx);
if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
discard_metadata(ctx);
}
if (ctx->strtab_count == 0) {
- gpr_mu_unlock(&ctx->mu);
- metadata_context_destroy(ctx);
+ metadata_context_destroy_locked(ctx);
return;
}
}
gpr_mu_unlock(&ctx->mu);
}
-static void ref_md(internal_metadata *md) {
- if (0 == md->refs++) {
+static void ref_md_locked(internal_metadata *md) {
+ if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
md->context->mdtab_free--;
}
}
@@ -169,7 +171,7 @@ static void discard_metadata(grpc_mdctx *ctx) {
for (i = 0; i < ctx->mdtab_capacity; i++) {
cur = ctx->mdtab[i];
while (cur) {
- GPR_ASSERT(cur->refs == 0);
+ GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
next = cur->bucket_next;
internal_string_unref(cur->key);
internal_string_unref(cur->value);
@@ -185,8 +187,7 @@ static void discard_metadata(grpc_mdctx *ctx) {
}
}
-static void metadata_context_destroy(grpc_mdctx *ctx) {
- gpr_mu_lock(&ctx->mu);
+static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
GPR_ASSERT(ctx->strtab_count == 0);
GPR_ASSERT(ctx->mdtab_count == 0);
GPR_ASSERT(ctx->mdtab_free == 0);
@@ -351,7 +352,7 @@ static void gc_mdtab(grpc_mdctx *ctx) {
prev_next = &ctx->mdtab[i];
for (md = ctx->mdtab[i]; md; md = next) {
next = md->bucket_next;
- if (md->refs == 0) {
+ if (gpr_atm_acq_load(&md->refcnt) == 0) {
internal_string_unref(md->key);
internal_string_unref(md->value);
if (md->user_data) {
@@ -417,7 +418,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
/* search for an existing pair */
for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
if (md->key == key && md->value == value) {
- ref_md(md);
+ ref_md_locked(md);
internal_string_unref(key);
internal_string_unref(value);
unlock(ctx);
@@ -427,7 +428,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
/* not found: create a new pair */
md = gpr_malloc(sizeof(internal_metadata));
- md->refs = 1;
+ gpr_atm_rel_store(&md->refcnt, 1);
md->context = ctx;
md->key = key;
md->value = value;
@@ -470,10 +471,12 @@ grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd) {
internal_metadata *md = (internal_metadata *)gmd;
- grpc_mdctx *ctx = md->context;
- lock(ctx);
- ref_md(md);
- unlock(ctx);
+ /* we can assume the ref count is >= 1 as the application is calling
+ this function - meaning that no adjustment to mdtab_free is necessary,
+ simplifying the logic here to be just an atomic increment */
+ /* use C assert to have this removed in opt builds */
+ assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+ gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
return gmd;
}
@@ -481,8 +484,8 @@ void grpc_mdelem_unref(grpc_mdelem *gmd) {
internal_metadata *md = (internal_metadata *)gmd;
grpc_mdctx *ctx = md->context;
lock(ctx);
- GPR_ASSERT(md->refs);
- if (0 == --md->refs) {
+ assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+ if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
ctx->mdtab_free++;
}
unlock(ctx);
@@ -552,3 +555,17 @@ gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
unlock(ctx);
return slice;
}
+
+void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); }
+
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *gmd) {
+ internal_metadata *md = (internal_metadata *)gmd;
+ grpc_mdctx *elem_ctx = md->context;
+ GPR_ASSERT(ctx == elem_ctx);
+ assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
+ if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
+ ctx->mdtab_free++;
+ }
+}
+
+void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); }
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index b8afbeb1e3..21b8ae2b78 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -135,6 +135,18 @@ void grpc_mdelem_unref(grpc_mdelem *md);
Does not promise that the returned string has no embedded nulls however. */
const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
+/* Batch mode metadata functions.
+ These API's have equivalents above, but allow taking the mdctx just once,
+ performing a bunch of work, and then leaving the mdctx. */
+
+/* Lock the metadata context: it's only safe to call _locked_ functions against
+ this context from the calling thread until grpc_mdctx_unlock is called */
+void grpc_mdctx_lock(grpc_mdctx *ctx);
+/* Unref a metadata element */
+void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *elem);
+/* Unlock the metadata context */
+void grpc_mdctx_unlock(grpc_mdctx *ctx);
+
#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index c30e3a27f1..e1a75adcb6 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -33,11 +33,11 @@
#include "src/core/transport/stream_op.h"
+#include <string.h>
+
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
-#include <string.h>
-
/* Exponential growth function: Given x, return a larger x.
Currently we grow by 1.5 times upon reallocation. */
#define GROW(x) (3 * (x) / 2)
@@ -79,14 +79,9 @@ void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
gpr_slice_unref(ops[i].data.slice);
break;
case GRPC_OP_METADATA:
- grpc_mdelem_unref(ops[i].data.metadata);
- break;
- case GRPC_OP_FLOW_CTL_CB:
- ops[i].data.flow_ctl_cb.cb(ops[i].data.flow_ctl_cb.arg, GRPC_OP_ERROR);
+ grpc_metadata_batch_destroy(&ops[i].data.metadata);
break;
case GRPC_NO_OP:
- case GRPC_OP_DEADLINE:
- case GRPC_OP_METADATA_BOUNDARY:
case GRPC_OP_BEGIN_MESSAGE:
break;
}
@@ -106,6 +101,7 @@ static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) {
static grpc_stream_op *add(grpc_stream_op_buffer *sopb) {
grpc_stream_op *out;
+ GPR_ASSERT(sopb->nops <= sopb->capacity);
if (sopb->nops == sopb->capacity) {
expandto(sopb, GROW(sopb->capacity));
}
@@ -126,22 +122,11 @@ void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
op->data.begin_message.flags = flags;
}
-void grpc_sopb_add_metadata_boundary(grpc_stream_op_buffer *sopb) {
- grpc_stream_op *op = add(sopb);
- op->type = GRPC_OP_METADATA_BOUNDARY;
-}
-
-void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_mdelem *md) {
+void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb,
+ grpc_metadata_batch b) {
grpc_stream_op *op = add(sopb);
op->type = GRPC_OP_METADATA;
- op->data.metadata = md;
-}
-
-void grpc_sopb_add_deadline(grpc_stream_op_buffer *sopb,
- gpr_timespec deadline) {
- grpc_stream_op *op = add(sopb);
- op->type = GRPC_OP_DEADLINE;
- op->data.deadline = deadline;
+ op->data.metadata = b;
}
void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) {
@@ -150,15 +135,6 @@ void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) {
op->data.slice = slice;
}
-void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
- void (*cb)(void *arg, grpc_op_error error),
- void *arg) {
- grpc_stream_op *op = add(sopb);
- op->type = GRPC_OP_FLOW_CTL_CB;
- op->data.flow_ctl_cb.cb = cb;
- op->data.flow_ctl_cb.arg = arg;
-}
-
void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
size_t nops) {
size_t orig_nops = sopb->nops;
@@ -171,3 +147,151 @@ void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops);
sopb->nops = new_nops;
}
+
+static void assert_valid_list(grpc_mdelem_list *list) {
+#ifndef NDEBUG
+ grpc_linked_mdelem *l;
+
+ GPR_ASSERT((list->head == NULL) == (list->tail == NULL));
+ if (!list->head) return;
+ GPR_ASSERT(list->head->prev == NULL);
+ GPR_ASSERT(list->tail->next == NULL);
+ GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
+
+ for (l = list->head; l; l = l->next) {
+ GPR_ASSERT(l->md);
+ GPR_ASSERT((l->prev == NULL) == (l == list->head));
+ GPR_ASSERT((l->next == NULL) == (l == list->tail));
+ if (l->next) GPR_ASSERT(l->next->prev == l);
+ if (l->prev) GPR_ASSERT(l->prev->next == l);
+ }
+#endif /* NDEBUG */
+}
+
+#ifndef NDEBUG
+void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd) {
+ assert_valid_list(&comd->list);
+ assert_valid_list(&comd->garbage);
+}
+#endif /* NDEBUG */
+
+void grpc_metadata_batch_init(grpc_metadata_batch *comd) {
+ comd->list.head = comd->list.tail = comd->garbage.head = comd->garbage.tail =
+ NULL;
+ comd->deadline = gpr_inf_future;
+}
+
+void grpc_metadata_batch_destroy(grpc_metadata_batch *comd) {
+ grpc_linked_mdelem *l;
+ for (l = comd->list.head; l; l = l->next) {
+ grpc_mdelem_unref(l->md);
+ }
+ for (l = comd->garbage.head; l; l = l->next) {
+ grpc_mdelem_unref(l->md);
+ }
+}
+
+void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem *elem_to_add) {
+ GPR_ASSERT(elem_to_add);
+ storage->md = elem_to_add;
+ grpc_metadata_batch_link_head(comd, storage);
+}
+
+static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
+ assert_valid_list(list);
+ GPR_ASSERT(storage->md);
+ storage->prev = NULL;
+ storage->next = list->head;
+ if (list->head != NULL) {
+ list->head->prev = storage;
+ } else {
+ list->tail = storage;
+ }
+ list->head = storage;
+ assert_valid_list(list);
+}
+
+void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage) {
+ link_head(&comd->list, storage);
+}
+
+void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem *elem_to_add) {
+ GPR_ASSERT(elem_to_add);
+ storage->md = elem_to_add;
+ grpc_metadata_batch_link_tail(comd, storage);
+}
+
+static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
+ assert_valid_list(list);
+ GPR_ASSERT(storage->md);
+ storage->prev = list->tail;
+ storage->next = NULL;
+ if (list->tail != NULL) {
+ list->tail->next = storage;
+ } else {
+ list->head = storage;
+ }
+ list->tail = storage;
+ assert_valid_list(list);
+}
+
+void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage) {
+ link_tail(&comd->list, storage);
+}
+
+void grpc_metadata_batch_merge(grpc_metadata_batch *target,
+ grpc_metadata_batch *add) {
+ grpc_linked_mdelem *l;
+ grpc_linked_mdelem *next;
+ for (l = add->list.head; l; l = next) {
+ next = l->next;
+ link_tail(&target->list, l);
+ }
+ for (l = add->garbage.head; l; l = next) {
+ next = l->next;
+ link_tail(&target->garbage, l);
+ }
+}
+
+void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
+ grpc_mdelem *(*filter)(void *user_data,
+ grpc_mdelem *elem),
+ void *user_data) {
+ grpc_linked_mdelem *l;
+ grpc_linked_mdelem *next;
+
+ assert_valid_list(&comd->list);
+ assert_valid_list(&comd->garbage);
+ for (l = comd->list.head; l; l = next) {
+ grpc_mdelem *orig = l->md;
+ grpc_mdelem *filt = filter(user_data, orig);
+ next = l->next;
+ if (filt == NULL) {
+ if (l->prev) {
+ l->prev->next = l->next;
+ }
+ if (l->next) {
+ l->next->prev = l->prev;
+ }
+ if (comd->list.head == l) {
+ comd->list.head = l->next;
+ }
+ if (comd->list.tail == l) {
+ comd->list.tail = l->prev;
+ }
+ assert_valid_list(&comd->list);
+ link_head(&comd->garbage, l);
+ } else if (filt != orig) {
+ grpc_mdelem_unref(orig);
+ l->md = filt;
+ }
+ }
+ assert_valid_list(&comd->list);
+ assert_valid_list(&comd->garbage);
+}
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index 2ffbcce87b..95497a3cc8 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -50,16 +50,12 @@ typedef enum grpc_stream_op_code {
Must be ignored by receivers */
GRPC_NO_OP,
GRPC_OP_METADATA,
- GRPC_OP_DEADLINE,
- GRPC_OP_METADATA_BOUNDARY,
/* Begin a message/metadata element/status - as defined by
grpc_message_type. */
GRPC_OP_BEGIN_MESSAGE,
/* Add a slice of data to the current message/metadata element/status.
Must not overflow the forward declared length. */
- GRPC_OP_SLICE,
- /* Call some function once this operation has passed flow control. */
- GRPC_OP_FLOW_CTL_CB
+ GRPC_OP_SLICE
} grpc_stream_op_code;
/* Arguments for GRPC_OP_BEGIN */
@@ -70,11 +66,52 @@ typedef struct grpc_begin_message {
gpr_uint32 flags;
} grpc_begin_message;
-/* Arguments for GRPC_OP_FLOW_CTL_CB */
-typedef struct grpc_flow_ctl_cb {
- void (*cb)(void *arg, grpc_op_error error);
- void *arg;
-} grpc_flow_ctl_cb;
+typedef struct grpc_linked_mdelem {
+ grpc_mdelem *md;
+ struct grpc_linked_mdelem *next;
+ struct grpc_linked_mdelem *prev;
+} grpc_linked_mdelem;
+
+typedef struct grpc_mdelem_list {
+ grpc_linked_mdelem *head;
+ grpc_linked_mdelem *tail;
+} grpc_mdelem_list;
+
+typedef struct grpc_metadata_batch {
+ grpc_mdelem_list list;
+ grpc_mdelem_list garbage;
+ gpr_timespec deadline;
+} grpc_metadata_batch;
+
+void grpc_metadata_batch_init(grpc_metadata_batch *comd);
+void grpc_metadata_batch_destroy(grpc_metadata_batch *comd);
+void grpc_metadata_batch_merge(grpc_metadata_batch *target,
+ grpc_metadata_batch *add);
+
+void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage);
+void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage);
+
+void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem *elem_to_add);
+void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
+ grpc_linked_mdelem *storage,
+ grpc_mdelem *elem_to_add);
+
+void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
+ grpc_mdelem *(*filter)(void *user_data,
+ grpc_mdelem *elem),
+ void *user_data);
+
+#ifndef NDEBUG
+void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd);
+#else
+#define grpc_metadata_batch_assert_ok(comd) \
+ do { \
+ } while (0)
+#endif
/* Represents a single operation performed on a stream/transport */
typedef struct grpc_stream_op {
@@ -84,10 +121,8 @@ typedef struct grpc_stream_op {
associated op-code */
union {
grpc_begin_message begin_message;
- grpc_mdelem *metadata;
- gpr_timespec deadline;
+ grpc_metadata_batch metadata;
gpr_slice slice;
- grpc_flow_ctl_cb flow_ctl_cb;
} data;
} grpc_stream_op;
@@ -118,17 +153,14 @@ void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb);
/* Append a GRPC_OP_BEGIN to a buffer */
void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
gpr_uint32 flags);
-void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb, grpc_mdelem *metadata);
-void grpc_sopb_add_deadline(grpc_stream_op_buffer *sopb, gpr_timespec deadline);
-void grpc_sopb_add_metadata_boundary(grpc_stream_op_buffer *sopb);
+void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb,
+ grpc_metadata_batch metadata);
/* Append a GRPC_SLICE to a buffer - does not ref/unref the slice */
void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice);
-/* Append a GRPC_OP_FLOW_CTL_CB to a buffer */
-void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
- void (*cb)(void *arg, grpc_op_error error),
- void *arg);
/* Append a buffer to a buffer - does not ref/unref any internal objects */
void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
size_t nops);
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */
+char *grpc_sopb_string(grpc_stream_op_buffer *sopb);
+
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_STREAM_OP_H */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
index ef0020dc58..d9a1319c42 100644
--- a/src/core/transport/transport.c
+++ b/src/core/transport/transport.c
@@ -52,18 +52,15 @@ void grpc_transport_destroy(grpc_transport *transport) {
}
int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
- const void *server_data) {
- return transport->vtable->init_stream(transport, stream, server_data);
+ const void *server_data,
+ grpc_transport_op *initial_op) {
+ return transport->vtable->init_stream(transport, stream, server_data,
+ initial_op);
}
-void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream,
- grpc_stream_op *ops, size_t nops, int is_last) {
- transport->vtable->send_batch(transport, stream, ops, nops, is_last);
-}
-
-void grpc_transport_set_allow_window_updates(grpc_transport *transport,
- grpc_stream *stream, int allow) {
- transport->vtable->set_allow_window_updates(transport, stream, allow);
+void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream,
+ grpc_transport_op *op) {
+ transport->vtable->perform_op(transport, stream, op);
}
void grpc_transport_add_to_pollset(grpc_transport *transport,
@@ -76,11 +73,6 @@ void grpc_transport_destroy_stream(grpc_transport *transport,
transport->vtable->destroy_stream(transport, stream);
}
-void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream,
- grpc_status_code status) {
- transport->vtable->abort_stream(transport, stream, status);
-}
-
void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
void *user_data) {
transport->vtable->ping(transport, cb, user_data);
@@ -93,3 +85,23 @@ void grpc_transport_setup_cancel(grpc_transport_setup *setup) {
void grpc_transport_setup_initiate(grpc_transport_setup *setup) {
setup->vtable->initiate(setup);
}
+
+void grpc_transport_op_finish_with_failure(grpc_transport_op *op) {
+ if (op->send_ops) {
+ op->on_done_send(op->send_user_data, 0);
+ }
+ if (op->recv_ops) {
+ op->on_done_recv(op->recv_user_data, 0);
+ }
+}
+
+void grpc_transport_op_add_cancellation(grpc_transport_op *op,
+ grpc_status_code status,
+ grpc_mdstr *message) {
+ if (op->cancel_with_status == GRPC_STATUS_OK) {
+ op->cancel_with_status = status;
+ op->cancel_message = message;
+ } else if (message) {
+ grpc_mdstr_unref(message);
+ }
+}
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index ce8c17c322..cdea0b9a0b 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -60,26 +60,26 @@ typedef enum grpc_stream_state {
GRPC_STREAM_CLOSED
} grpc_stream_state;
-/* Callbacks made from the transport to the upper layers of grpc. */
-struct grpc_transport_callbacks {
- /* Allocate a buffer to receive data into.
- It's safe to call grpc_slice_new() to do this, but performance minded
- proxies may want to carefully place data into optimal locations for
- transports.
- This function must return a valid, non-empty slice.
+/* Transport op: a set of operations to perform on a transport */
+typedef struct grpc_transport_op {
+ grpc_stream_op_buffer *send_ops;
+ int is_last_send;
+ void (*on_done_send)(void *user_data, int success);
+ void *send_user_data;
- Arguments:
- user_data - the transport user data set at transport creation time
- transport - the grpc_transport instance making this call
- stream - the grpc_stream instance the buffer will be used for, or
- NULL if this is not known
- size_hint - how big of a buffer would the transport optimally like?
- the actual returned buffer can be smaller or larger than
- size_hint as the implementation finds convenient */
- struct gpr_slice (*alloc_recv_buffer)(void *user_data,
- grpc_transport *transport,
- grpc_stream *stream, size_t size_hint);
+ grpc_stream_op_buffer *recv_ops;
+ grpc_stream_state *recv_state;
+ void (*on_done_recv)(void *user_data, int success);
+ void *recv_user_data;
+ grpc_pollset *bind_pollset;
+
+ grpc_status_code cancel_with_status;
+ grpc_mdstr *cancel_message;
+} grpc_transport_op;
+
+/* Callbacks made from the transport to the upper layers of grpc. */
+struct grpc_transport_callbacks {
/* Initialize a new stream on behalf of the transport.
Must result in a call to
grpc_transport_init_stream(transport, ..., request) in the same call
@@ -96,28 +96,6 @@ struct grpc_transport_callbacks {
void (*accept_stream)(void *user_data, grpc_transport *transport,
const void *server_data);
- /* Process a set of stream ops that have been received by the transport.
- Called by network threads, so must be careful not to block on network
- activity.
-
- If final_state == GRPC_STREAM_CLOSED, the upper layers should arrange to
- call grpc_transport_destroy_stream.
-
- Ownership of any objects contained in ops is transferred to the callee.
-
- Arguments:
- user_data - the transport user data set at transport creation time
- transport - the grpc_transport instance making this call
- stream - the stream this data was received for
- ops - stream operations that are part of this batch
- ops_count - the number of stream operations in this batch
- final_state - the state of the stream as of the final operation in this
- batch */
- void (*recv_batch)(void *user_data, grpc_transport *transport,
- grpc_stream *stream, grpc_stream_op *ops, size_t ops_count,
- grpc_stream_state final_state);
-
- /* The transport received a goaway */
void (*goaway)(void *user_data, grpc_transport *transport,
grpc_status_code status, gpr_slice debug);
@@ -139,7 +117,8 @@ size_t grpc_transport_stream_size(grpc_transport *transport);
server_data - either NULL for a client initiated stream, or a pointer
supplied from the accept_stream callback function */
int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
- const void *server_data);
+ const void *server_data,
+ grpc_transport_op *initial_op);
/* Destroy transport data for a stream.
@@ -154,20 +133,17 @@ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
void grpc_transport_destroy_stream(grpc_transport *transport,
grpc_stream *stream);
-/* Enable/disable incoming data for a stream.
+void grpc_transport_op_finish_with_failure(grpc_transport_op *op);
- This effectively disables new window becoming available for a given stream,
- but does not prevent existing window from being consumed by a sender: the
- caller must still be prepared to receive some additional data after this
- call.
+void grpc_transport_op_add_cancellation(grpc_transport_op *op,
+ grpc_status_code status,
+ grpc_mdstr *message);
- Arguments:
- transport - the transport on which to create this stream
- stream - the grpc_stream to destroy (memory is still owned by the
- caller, but any child memory must be cleaned up)
- allow - is it allowed that new window be opened up? */
-void grpc_transport_set_allow_window_updates(grpc_transport *transport,
- grpc_stream *stream, int allow);
+/* TODO(ctiller): remove this */
+void grpc_transport_add_to_pollset(grpc_transport *transport,
+ grpc_pollset *pollset);
+
+char *grpc_transport_op_string(grpc_transport_op *op);
/* Send a batch of operations on a transport
@@ -177,13 +153,9 @@ void grpc_transport_set_allow_window_updates(grpc_transport *transport,
transport - the transport on which to initiate the stream
stream - the stream on which to send the operations. This must be
non-NULL and previously initialized by the same transport.
- ops - an array of operations to apply to the stream - can be NULL
- if ops_count == 0.
- ops_count - the number of elements in ops
- is_last - is this the last batch of operations to be sent out */
-void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream,
- grpc_stream_op *ops, size_t ops_count,
- int is_last);
+ op - a grpc_transport_op specifying the op to perform */
+void grpc_transport_perform_op(grpc_transport *transport, grpc_stream *stream,
+ grpc_transport_op *op);
/* Send a ping on a transport
@@ -193,19 +165,6 @@ void grpc_transport_send_batch(grpc_transport *transport, grpc_stream *stream,
void grpc_transport_ping(grpc_transport *transport, void (*cb)(void *user_data),
void *user_data);
-/* Abort a stream
-
- Terminate reading and writing for a stream. A final recv_batch with no
- operations and final_state == GRPC_STREAM_CLOSED will be received locally,
- and no more data will be presented to the up-layer.
-
- TODO(ctiller): consider adding a HTTP/2 reason to this function. */
-void grpc_transport_abort_stream(grpc_transport *transport, grpc_stream *stream,
- grpc_status_code status);
-
-void grpc_transport_add_to_pollset(grpc_transport *transport,
- grpc_pollset *pollset);
-
/* Advise peer of pending connection termination. */
void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
gpr_slice debug_data);
@@ -254,4 +213,4 @@ void grpc_transport_setup_initiate(grpc_transport_setup *setup);
used as a destruction call by setup). */
void grpc_transport_setup_cancel(grpc_transport_setup *setup);
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
index ac275c7560..479e15338f 100644
--- a/src/core/transport/transport_impl.h
+++ b/src/core/transport/transport_impl.h
@@ -43,15 +43,11 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_init_stream */
int (*init_stream)(grpc_transport *self, grpc_stream *stream,
- const void *server_data);
+ const void *server_data, grpc_transport_op *initial_op);
/* implementation of grpc_transport_send_batch */
- void (*send_batch)(grpc_transport *self, grpc_stream *stream,
- grpc_stream_op *ops, size_t ops_count, int is_last);
-
- /* implementation of grpc_transport_set_allow_window_updates */
- void (*set_allow_window_updates)(grpc_transport *self, grpc_stream *stream,
- int allow);
+ void (*perform_op)(grpc_transport *self, grpc_stream *stream,
+ grpc_transport_op *op);
/* implementation of grpc_transport_add_to_pollset */
void (*add_to_pollset)(grpc_transport *self, grpc_pollset *pollset);
@@ -59,10 +55,6 @@ typedef struct grpc_transport_vtable {
/* implementation of grpc_transport_destroy_stream */
void (*destroy_stream)(grpc_transport *self, grpc_stream *stream);
- /* implementation of grpc_transport_abort_stream */
- void (*abort_stream)(grpc_transport *self, grpc_stream *stream,
- grpc_status_code status);
-
/* implementation of grpc_transport_goaway */
void (*goaway)(grpc_transport *self, grpc_status_code status,
gpr_slice debug_data);
@@ -84,4 +76,4 @@ struct grpc_transport {
const grpc_transport_vtable *vtable;
};
-#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */
+#endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_IMPL_H */
diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c
new file mode 100644
index 0000000000..7bbe8276c3
--- /dev/null
+++ b/src/core/transport/transport_op_string.c
@@ -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.
+ *
+ */
+
+#include "src/core/channel/channel_stack.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/support/string.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+/* These routines are here to facilitate debugging - they produce string
+ representations of various transport data structures */
+
+static void put_metadata(gpr_strvec *b, grpc_mdelem *md) {
+ gpr_strvec_add(b, gpr_strdup("key="));
+ gpr_strvec_add(
+ b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->key->slice),
+ GPR_SLICE_LENGTH(md->key->slice), GPR_HEXDUMP_PLAINTEXT));
+
+ gpr_strvec_add(b, gpr_strdup(" value="));
+ gpr_strvec_add(b, gpr_hexdump((char *)GPR_SLICE_START_PTR(md->value->slice),
+ GPR_SLICE_LENGTH(md->value->slice),
+ GPR_HEXDUMP_PLAINTEXT));
+}
+
+static void put_metadata_list(gpr_strvec *b, grpc_metadata_batch md) {
+ grpc_linked_mdelem *m;
+ for (m = md.list.head; m != NULL; m = m->next) {
+ if (m != md.list.head) gpr_strvec_add(b, gpr_strdup(", "));
+ put_metadata(b, m->md);
+ }
+ if (gpr_time_cmp(md.deadline, gpr_inf_future) != 0) {
+ char *tmp;
+ gpr_asprintf(&tmp, " deadline=%d.%09d", md.deadline.tv_sec,
+ md.deadline.tv_nsec);
+ gpr_strvec_add(b, tmp);
+ }
+}
+
+char *grpc_sopb_string(grpc_stream_op_buffer *sopb) {
+ char *out;
+ char *tmp;
+ size_t i;
+ gpr_strvec b;
+ gpr_strvec_init(&b);
+
+ for (i = 0; i < sopb->nops; i++) {
+ grpc_stream_op *op = &sopb->ops[i];
+ if (i > 0) gpr_strvec_add(&b, gpr_strdup(", "));
+ switch (op->type) {
+ case GRPC_NO_OP:
+ gpr_strvec_add(&b, gpr_strdup("NO_OP"));
+ break;
+ case GRPC_OP_BEGIN_MESSAGE:
+ gpr_asprintf(&tmp, "BEGIN_MESSAGE:%d", op->data.begin_message.length);
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_SLICE:
+ gpr_asprintf(&tmp, "SLICE:%d", GPR_SLICE_LENGTH(op->data.slice));
+ gpr_strvec_add(&b, tmp);
+ break;
+ case GRPC_OP_METADATA:
+ gpr_strvec_add(&b, gpr_strdup("METADATA{"));
+ put_metadata_list(&b, op->data.metadata);
+ gpr_strvec_add(&b, gpr_strdup("}"));
+ break;
+ }
+ }
+
+ out = gpr_strvec_flatten(&b, NULL);
+ gpr_strvec_destroy(&b);
+
+ return out;
+}
+
+char *grpc_transport_op_string(grpc_transport_op *op) {
+ char *tmp;
+ char *out;
+ int first = 1;
+
+ gpr_strvec b;
+ gpr_strvec_init(&b);
+
+ if (op->send_ops) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = 0;
+ gpr_strvec_add(&b, gpr_strdup("SEND"));
+ if (op->is_last_send) {
+ gpr_strvec_add(&b, gpr_strdup("_LAST"));
+ }
+ gpr_strvec_add(&b, gpr_strdup("["));
+ gpr_strvec_add(&b, grpc_sopb_string(op->send_ops));
+ gpr_strvec_add(&b, gpr_strdup("]"));
+ }
+
+ if (op->recv_ops) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = 0;
+ gpr_strvec_add(&b, gpr_strdup("RECV"));
+ }
+
+ if (op->bind_pollset) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = 0;
+ gpr_strvec_add(&b, gpr_strdup("BIND"));
+ }
+
+ if (op->cancel_with_status != GRPC_STATUS_OK) {
+ if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+ first = 0;
+ gpr_asprintf(&tmp, "CANCEL:%d", op->cancel_with_status);
+ gpr_strvec_add(&b, tmp);
+ if (op->cancel_message) {
+ gpr_asprintf(&tmp, ";msg='%s'",
+ grpc_mdstr_as_c_string(op->cancel_message));
+ gpr_strvec_add(&b, tmp);
+ }
+ }
+
+ out = gpr_strvec_flatten(&b, NULL);
+ gpr_strvec_destroy(&b);
+
+ return out;
+}
+
+void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
+ grpc_call_element *elem, grpc_transport_op *op) {
+ char *str = grpc_transport_op_string(op);
+ gpr_log(file, line, severity, "OP[%s:%p]: %s", elem->filter->name, elem, str);
+ gpr_free(str);
+}
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 33645ca8b8..b7c2859a1c 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -34,6 +34,7 @@
#include "src/core/tsi/ssl_transport_security.h"
#include <limits.h>
+#include <string.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
@@ -567,7 +568,8 @@ static tsi_result populate_ssl_context(
EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
- result = TSI_INTERNAL_ERROR;
+ EC_KEY_free(ecdh);
+ return TSI_INTERNAL_ERROR;
}
SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
EC_KEY_free(ecdh);
@@ -604,6 +606,7 @@ static tsi_result build_alpn_protocol_name_list(
unsigned char* current;
*protocol_name_list = NULL;
*protocol_name_list_length = 0;
+ if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
for (i = 0; i < num_alpn_protocols; i++) {
if (alpn_protocols_lengths[i] == 0) {
gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 5380d3a232..c541ddfb48 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -33,7 +33,6 @@
#include "src/cpp/client/channel.h"
-#include <chrono>
#include <memory>
#include <grpc/grpc.h>
@@ -41,6 +40,7 @@
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
+#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
@@ -60,12 +60,18 @@ Channel::~Channel() { grpc_channel_destroy(c_channel_); }
Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) {
- auto c_call = grpc_channel_create_call(c_channel_, cq->cq(), method.name(),
- context->authority().empty()
- ? target_.c_str()
- : context->authority().c_str(),
- context->RawDeadline());
- context->set_call(c_call);
+ auto c_call =
+ method.channel_tag()
+ ? grpc_channel_create_registered_call(c_channel_, cq->cq(),
+ method.channel_tag(),
+ context->raw_deadline())
+ : grpc_channel_create_call(c_channel_, cq->cq(), method.name(),
+ context->authority().empty()
+ ? target_.c_str()
+ : context->authority().c_str(),
+ context->raw_deadline());
+ GRPC_TIMER_MARK(CALL_CREATED, c_call);
+ context->set_call(c_call, shared_from_this());
return Call(c_call, this, cq);
}
@@ -73,9 +79,15 @@ void Channel::PerformOpsOnCall(CallOpBuffer* buf, Call* call) {
static const size_t MAX_OPS = 8;
size_t nops = MAX_OPS;
grpc_op ops[MAX_OPS];
+ GRPC_TIMER_MARK(PERFORM_OPS_BEGIN, call->call());
buf->FillOps(ops, &nops);
GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_batch(call->call(), ops, nops, buf));
+ GRPC_TIMER_MARK(PERFORM_OPS_END, call->call());
+}
+
+void* Channel::RegisterMethod(const char* method) {
+ return grpc_channel_register_call(c_channel_, method, target_.c_str());
}
} // namespace grpc
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index 3980eba237..cd239247c8 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -38,6 +38,7 @@
#include <grpc++/channel_interface.h>
#include <grpc++/config.h>
+#include <grpc++/impl/grpc_library.h>
struct grpc_channel;
@@ -49,11 +50,13 @@ class CompletionQueue;
class Credentials;
class StreamContextInterface;
-class Channel GRPC_FINAL : public ChannelInterface {
+class Channel GRPC_FINAL : public GrpcLibrary,
+ public ChannelInterface {
public:
Channel(const grpc::string& target, grpc_channel* c_channel);
~Channel() GRPC_OVERRIDE;
+ virtual void *RegisterMethod(const char *method) GRPC_OVERRIDE;
virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) GRPC_OVERRIDE;
virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE;
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index de9f8c7201..70c9cb4c3b 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -34,9 +34,7 @@
#include <grpc++/client_context.h>
#include <grpc/grpc.h>
-#include "src/cpp/util/time.h"
-
-using std::chrono::system_clock;
+#include <grpc++/time.h>
namespace grpc {
@@ -44,7 +42,7 @@ ClientContext::ClientContext()
: initial_metadata_received_(false),
call_(nullptr),
cq_(nullptr),
- absolute_deadline_(gpr_inf_future) {}
+ deadline_(gpr_inf_future) {}
ClientContext::~ClientContext() {
if (call_) {
@@ -64,15 +62,6 @@ ClientContext::~ClientContext() {
}
}
-void ClientContext::set_absolute_deadline(
- const system_clock::time_point& deadline) {
- Timepoint2Timespec(deadline, &absolute_deadline_);
-}
-
-system_clock::time_point ClientContext::absolute_deadline() {
- return Timespec2Timepoint(absolute_deadline_);
-}
-
void ClientContext::AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value) {
send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));
diff --git a/src/ruby/ext/grpc/rb_event.h b/src/cpp/client/generic_stub.cc
index 3105934b11..0c90578ae5 100644
--- a/src/ruby/ext/grpc/rb_event.h
+++ b/src/cpp/client/generic_stub.cc
@@ -31,23 +31,21 @@
*
*/
-#ifndef GRPC_RB_EVENT_H_
-#define GRPC_RB_EVENT_H_
+#include <grpc++/generic_stub.h>
-#include <ruby.h>
-#include <grpc/grpc.h>
+#include <grpc++/impl/rpc_method.h>
-/* rb_cEvent is the Event class whose instances proxy grpc_event. */
-extern VALUE rb_cEvent;
+namespace grpc {
-/* rb_cEventError is the ruby class that acts the exception thrown during rpc
- event processing. */
-extern VALUE rb_eEventError;
+// begin a call to a named method
+std::unique_ptr<GenericClientAsyncReaderWriter> GenericStub::Call(
+ ClientContext* context, const grpc::string& method, CompletionQueue* cq,
+ void* tag) {
+ return std::unique_ptr<GenericClientAsyncReaderWriter>(
+ new GenericClientAsyncReaderWriter(
+ channel_.get(), cq,
+ RpcMethod(method.c_str(), RpcMethod::BIDI_STREAMING, nullptr),
+ context, tag));
+}
-/* Used to create new ruby event objects */
-VALUE grpc_rb_new_event(grpc_event *ev);
-
-/* Initializes the Event and EventError classes. */
-void Init_grpc_event();
-
-#endif /* GRPC_RB_EVENT_H_ */
+} // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index f3ca430bd4..8945b038de 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -31,8 +31,6 @@
*
*/
-#include <string>
-
#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 e3c6637623..48bf7430b2 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,40 +31,23 @@
*
*/
-#include <string>
-
-#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
#include <grpc++/channel_arguments.h>
-#include <grpc++/config.h>
-#include <grpc++/credentials.h>
#include "src/cpp/client/channel.h"
+#include "src/cpp/client/secure_credentials.h"
namespace grpc {
-class SecureCredentials GRPC_FINAL : public Credentials {
- public:
- explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
- ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
- grpc_credentials* GetRawCreds() { return c_creds_; }
-
- std::shared_ptr<grpc::ChannelInterface> CreateChannel(
- const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE {
- grpc_channel_args channel_args;
- args.SetChannelArgs(&channel_args);
- return std::shared_ptr<ChannelInterface>(new Channel(
- args.GetSslTargetNameOverride().empty()
- ? target
- : args.GetSslTargetNameOverride(),
- grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
- }
-
- SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
-
- private:
- grpc_credentials* const c_creds_;
-};
+std::shared_ptr<grpc::ChannelInterface> SecureCredentials::CreateChannel(
+ const string& target, const grpc::ChannelArguments& args) {
+ grpc_channel_args channel_args;
+ args.SetChannelArgs(&channel_args);
+ return std::shared_ptr<ChannelInterface>(new Channel(
+ args.GetSslTargetNameOverride().empty() ? target
+ : args.GetSslTargetNameOverride(),
+ grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
+}
namespace {
std::unique_ptr<Credentials> WrapCredentials(grpc_credentials* creds) {
@@ -98,27 +81,27 @@ std::unique_ptr<Credentials> ComputeEngineCredentials() {
// Builds service account credentials.
std::unique_ptr<Credentials> ServiceAccountCredentials(
const grpc::string& json_key, const grpc::string& scope,
- std::chrono::seconds token_lifetime) {
- if (token_lifetime.count() <= 0) {
+ long token_lifetime_seconds) {
+ 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.count());
+ gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds);
return WrapCredentials(grpc_service_account_credentials_create(
json_key.c_str(), scope.c_str(), lifetime));
}
// Builds JWT credentials.
std::unique_ptr<Credentials> JWTCredentials(
- const grpc::string& json_key, std::chrono::seconds token_lifetime) {
- if (token_lifetime.count() <= 0) {
+ const grpc::string& json_key, long token_lifetime_seconds) {
+ if (token_lifetime_seconds <= 0) {
gpr_log(GPR_ERROR,
"Trying to create JWTCredentials with non-positive lifetime");
return WrapCredentials(nullptr);
}
- gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime.count());
+ gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds);
return WrapCredentials(
grpc_jwt_credentials_create(json_key.c_str(), lifetime));
}
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
new file mode 100644
index 0000000000..77d575813e
--- /dev/null
+++ b/src/cpp/client/secure_credentials.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/config.h>
+#include <grpc++/credentials.h>
+
+namespace grpc {
+
+class SecureCredentials GRPC_FINAL : public Credentials {
+ public:
+ explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
+ ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
+ grpc_credentials* GetRawCreds() { return c_creds_; }
+
+ std::shared_ptr<grpc::ChannelInterface> CreateChannel(
+ const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE;
+ SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
+
+ private:
+ grpc_credentials* const c_creds_;
+};
+
+} // namespace grpc
+
+#endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc
index 5c26a1ad7c..9878133331 100644
--- a/src/cpp/common/call.cc
+++ b/src/cpp/common/call.cc
@@ -38,6 +38,7 @@
#include <grpc++/client_context.h>
#include <grpc++/channel_interface.h>
+#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h"
namespace grpc {
@@ -60,7 +61,8 @@ CallOpBuffer::CallOpBuffer()
status_code_(GRPC_STATUS_OK),
status_details_(nullptr),
status_details_capacity_(0),
- send_status_(nullptr),
+ send_status_available_(false),
+ send_status_code_(GRPC_STATUS_OK),
trailing_metadata_count_(0),
trailing_metadata_(nullptr),
cancelled_buf_(0),
@@ -104,7 +106,9 @@ void CallOpBuffer::Reset(void* next_return_tag) {
status_code_ = GRPC_STATUS_OK;
- send_status_ = nullptr;
+ send_status_available_ = false;
+ send_status_code_ = GRPC_STATUS_OK;
+ send_status_details_.clear();
trailing_metadata_count_ = 0;
trailing_metadata_ = nullptr;
@@ -148,7 +152,7 @@ void FillMetadataMap(grpc_metadata_array* arr,
// TODO(yangg) handle duplicates?
metadata->insert(std::pair<grpc::string, grpc::string>(
arr->metadata[i].key,
- {arr->metadata[i].value, arr->metadata[i].value_length}));
+ grpc::string(arr->metadata[i].value, arr->metadata[i].value_length)));
}
grpc_metadata_array_destroy(arr);
grpc_metadata_array_init(arr);
@@ -186,6 +190,7 @@ void CallOpBuffer::AddRecvMessage(grpc::protobuf::Message* message) {
void CallOpBuffer::AddRecvMessage(ByteBuffer* message) {
recv_message_buffer_ = message;
+ recv_message_buffer_->Clear();
}
void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; }
@@ -207,7 +212,9 @@ void CallOpBuffer::AddServerSendStatus(
} else {
trailing_metadata_count_ = 0;
}
- send_status_ = &status;
+ send_status_available_ = true;
+ send_status_code_ = static_cast<grpc_status_code>(status.code());
+ send_status_details_ = status.details();
}
void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
@@ -225,11 +232,13 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
}
if (send_message_ || send_message_buffer_) {
if (send_message_) {
+ GRPC_TIMER_MARK(SER_PROTO_BEGIN, 0);
bool success = SerializeProto(*send_message_, &send_buf_);
if (!success) {
abort();
// TODO handle parse failure
}
+ GRPC_TIMER_MARK(SER_PROTO_END, 0);
} else {
send_buf_ = send_message_buffer_->buffer();
}
@@ -256,16 +265,15 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
&status_details_capacity_;
(*nops)++;
}
- if (send_status_) {
+ if (send_status_available_) {
ops[*nops].op = GRPC_OP_SEND_STATUS_FROM_SERVER;
ops[*nops].data.send_status_from_server.trailing_metadata_count =
trailing_metadata_count_;
ops[*nops].data.send_status_from_server.trailing_metadata =
trailing_metadata_;
- ops[*nops].data.send_status_from_server.status =
- static_cast<grpc_status_code>(send_status_->code());
+ ops[*nops].data.send_status_from_server.status = send_status_code_;
ops[*nops].data.send_status_from_server.status_details =
- send_status_->details().c_str();
+ send_status_details_.empty() ? nullptr : send_status_details_.c_str();
(*nops)++;
}
if (recv_closed_) {
@@ -302,8 +310,10 @@ bool CallOpBuffer::FinalizeResult(void** tag, bool* status) {
if (recv_buf_) {
got_message = *status;
if (recv_message_) {
+ GRPC_TIMER_MARK(DESER_PROTO_BEGIN, 0);
*status = *status && DeserializeProto(recv_buf_, recv_message_);
grpc_byte_buffer_destroy(recv_buf_);
+ GRPC_TIMER_MARK(DESER_PROTO_END, 0);
} else {
recv_message_buffer_->set_buffer(recv_buf_);
}
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index cea2d24831..07122db4a5 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -36,7 +36,7 @@
#include <grpc/grpc.h>
#include <grpc/support/log.h>
-#include "src/cpp/util/time.h"
+#include <grpc++/time.h>
namespace grpc {
@@ -77,13 +77,6 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal(
}
}
-CompletionQueue::NextStatus CompletionQueue::AsyncNext(
- void** tag, bool* ok, std::chrono::system_clock::time_point deadline) {
- gpr_timespec gpr_deadline;
- Timepoint2Timespec(deadline, &gpr_deadline);
- return AsyncNextInternal(tag, ok, gpr_deadline);
-}
-
bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
std::unique_ptr<grpc_event, EventDeleter> ev;
@@ -92,7 +85,8 @@ bool CompletionQueue::Pluck(CompletionQueueTag* tag) {
void* ignored = tag;
GPR_ASSERT(tag->FinalizeResult(&ignored, &ok));
GPR_ASSERT(ignored == tag);
- return ok;
+ // Ignore mutations by FinalizeResult: Pluck returns the C API status
+ return ev->data.op_complete == GRPC_OP_OK;
}
void CompletionQueue::TryPluck(CompletionQueueTag* tag) {
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
index 628822a338..e1f29452a4 100644
--- a/src/cpp/server/async_server_context.cc
+++ b/src/cpp/server/async_server_context.cc
@@ -68,9 +68,11 @@ bool AsyncServerContext::StartRead(grpc::protobuf::Message* request) {
bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
int flags) {
grpc_byte_buffer* buffer = nullptr;
+ GRPC_TIMER_MARK(SER_PROTO_BEGIN, call_->call());
if (!SerializeProto(response, &buffer)) {
return false;
}
+ GRPC_TIMER_MARK(SER_PROTO_END, call_->call());
grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
grpc_byte_buffer_destroy(buffer);
return err == GRPC_CALL_OK;
@@ -87,7 +89,9 @@ bool AsyncServerContext::StartWriteStatus(const Status& status) {
bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
GPR_ASSERT(request_);
+ GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_->call());
bool success = DeserializeProto(read_buffer, request_);
+ GRPC_TIMER_MARK(DESER_PROTO_END, call_->call());
request_ = nullptr;
return success;
}
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 88f7a9b1a9..3e262dd74f 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -31,37 +31,23 @@
*
*/
-#include <grpc/grpc_security.h>
-
-#include <grpc++/server_credentials.h>
+#include "src/cpp/server/secure_server_credentials.h"
namespace grpc {
-namespace {
-class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
- public:
- explicit SecureServerCredentials(grpc_server_credentials* creds)
- : creds_(creds) {}
- ~SecureServerCredentials() GRPC_OVERRIDE {
- grpc_server_credentials_release(creds_);
- }
-
- int AddPortToServer(const grpc::string& addr,
- grpc_server* server) GRPC_OVERRIDE {
- return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
- }
-
- private:
- grpc_server_credentials* const creds_;
-};
-} // namespace
+int SecureServerCredentials::AddPortToServer(
+ const grpc::string& addr, grpc_server* server) {
+ return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
+}
std::shared_ptr<ServerCredentials> SslServerCredentials(
const SslServerCredentialsOptions& options) {
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
- for (const auto& key_cert_pair : options.pem_key_cert_pairs) {
- pem_key_cert_pairs.push_back(
- {key_cert_pair.private_key.c_str(), key_cert_pair.cert_chain.c_str()});
+ for (auto key_cert_pair = options.pem_key_cert_pairs.begin();
+ key_cert_pair != options.pem_key_cert_pairs.end(); key_cert_pair++) {
+ grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(),
+ key_cert_pair->cert_chain.c_str()};
+ pem_key_cert_pairs.push_back(p);
}
grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h
new file mode 100644
index 0000000000..b9803f107e
--- /dev/null
+++ b/src/cpp/server/secure_server_credentials.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/server_credentials.h>
+
+namespace grpc {
+
+class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
+ public:
+ explicit SecureServerCredentials(grpc_server_credentials* creds)
+ : creds_(creds) {}
+ ~SecureServerCredentials() GRPC_OVERRIDE {
+ grpc_server_credentials_release(creds_);
+ }
+
+ int AddPortToServer(const grpc::string& addr,
+ grpc_server* server) GRPC_OVERRIDE;
+
+ private:
+ grpc_server_credentials* const creds_;
+};
+
+} // namespace grpc
+
+#endif // GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 5a4ca6915a..4694a3a7ff 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -45,9 +45,10 @@
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/thread_pool_interface.h>
+#include <grpc++/time.h>
+#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h"
-#include "src/cpp/util/time.h"
namespace grpc {
@@ -107,6 +108,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
request_payload_(mrd->request_payload_),
method_(mrd->method_) {
ctx_.call_ = mrd->call_;
+ ctx_.cq_ = &cq_;
GPR_ASSERT(mrd->in_flight_);
mrd->in_flight_ = false;
mrd->request_metadata_.count = 0;
@@ -122,10 +124,12 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
std::unique_ptr<grpc::protobuf::Message> req;
std::unique_ptr<grpc::protobuf::Message> res;
if (has_request_payload_) {
+ GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_.call());
req.reset(method_->AllocateRequestProto());
if (!DeserializeProto(request_payload_, req.get())) {
abort(); // for now
}
+ GRPC_TIMER_MARK(DESER_PROTO_END, call_.call());
}
if (has_response_payload_) {
res.reset(method_->AllocateResponseProto());
@@ -176,13 +180,14 @@ Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned)
: started_(false),
shutdown_(false),
num_running_cb_(0),
+ sync_methods_(new std::list<SyncRequest>),
server_(grpc_server_create(cq_.cq(), nullptr)),
thread_pool_(thread_pool),
thread_pool_owned_(thread_pool_owned) {}
Server::~Server() {
{
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
if (started_ && !shutdown_) {
lock.unlock();
Shutdown();
@@ -192,6 +197,7 @@ Server::~Server() {
if (thread_pool_owned_) {
delete thread_pool_;
}
+ delete sync_methods_;
}
bool Server::RegisterService(RpcService* service) {
@@ -204,7 +210,8 @@ bool Server::RegisterService(RpcService* service) {
method->name());
return false;
}
- sync_methods_.emplace_back(method, tag);
+ SyncRequest request(method, tag);
+ sync_methods_->emplace_back(request);
}
return true;
}
@@ -246,9 +253,9 @@ bool Server::Start() {
grpc_server_start(server_);
// Start processing rpcs.
- if (!sync_methods_.empty()) {
- for (auto& m : sync_methods_) {
- m.Request(server_);
+ if (!sync_methods_->empty()) {
+ for (auto m = sync_methods_->begin(); m != sync_methods_->end(); m++) {
+ m->Request(server_);
}
ScheduleCallback();
@@ -258,7 +265,7 @@ bool Server::Start() {
}
void Server::Shutdown() {
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
if (started_ && !shutdown_) {
shutdown_ = true;
grpc_server_shutdown(server_);
@@ -272,7 +279,7 @@ void Server::Shutdown() {
}
void Server::Wait() {
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
while (num_running_cb_ != 0) {
callback_cv_.wait(lock);
}
@@ -339,7 +346,9 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
bool orig_status = *status;
if (*status && request_) {
if (payload_) {
+ GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_);
*status = DeserializeProto(payload_, request_);
+ GRPC_TIMER_MARK(DESER_PROTO_END, call_);
} else {
*status = false;
}
@@ -347,7 +356,7 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
ServerContext* ctx = ctx_ ? ctx_ : generic_ctx_;
GPR_ASSERT(ctx);
if (*status) {
- ctx->deadline_ = Timespec2Timepoint(call_details_.deadline);
+ ctx->deadline_ = call_details_.deadline;
for (size_t i = 0; i < array_.count; i++) {
ctx->client_metadata_.insert(std::make_pair(
grpc::string(array_.metadata[i].key),
@@ -364,6 +373,7 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
}
}
ctx->call_ = call_;
+ ctx->cq_ = cq_;
Call call(call_, server_, cq_);
if (orig_status && call_) {
ctx->BeginCompletionOp(&call);
@@ -403,7 +413,7 @@ void Server::RequestAsyncGenericCall(GenericServerContext* context,
void Server::ScheduleCallback() {
{
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
num_running_cb_++;
}
thread_pool_->ScheduleCallback(std::bind(&Server::RunRpc, this));
@@ -424,7 +434,7 @@ void Server::RunRpc() {
}
{
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
num_running_cb_--;
if (shutdown_) {
callback_cv_.notify_all();
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 58bf9d937f..81cb0e6724 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -66,7 +66,8 @@ void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
void ServerBuilder::AddListeningPort(const grpc::string& addr,
std::shared_ptr<ServerCredentials> creds,
int* selected_port) {
- ports_.push_back(Port{addr, creds, selected_port});
+ Port port = {addr, creds, selected_port};
+ ports_.push_back(port);
}
void ServerBuilder::SetThreadPool(ThreadPoolInterface* thread_pool) {
@@ -86,24 +87,26 @@ std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
thread_pool_owned = true;
}
std::unique_ptr<Server> server(new Server(thread_pool_, thread_pool_owned));
- for (auto* service : services_) {
- if (!server->RegisterService(service)) {
+ for (auto service = services_.begin(); service != services_.end();
+ service++) {
+ if (!server->RegisterService(*service)) {
return nullptr;
}
}
- for (auto* service : async_services_) {
- if (!server->RegisterAsyncService(service)) {
+ for (auto service = async_services_.begin();
+ service != async_services_.end(); service++) {
+ if (!server->RegisterAsyncService(*service)) {
return nullptr;
}
}
if (generic_service_) {
server->RegisterAsyncGenericService(generic_service_);
}
- for (auto& port : ports_) {
- int r = server->AddListeningPort(port.addr, port.creds.get());
+ for (auto port = ports_.begin(); port != ports_.end(); port++) {
+ int r = server->AddListeningPort(port->addr, port->creds.get());
if (!r) return nullptr;
- if (port.selected_port != nullptr) {
- *port.selected_port = r;
+ if (port->selected_port != nullptr) {
+ *port->selected_port = r;
}
}
if (!server->Start()) {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index bb3c2d1405..6b5e41d0a8 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -33,12 +33,11 @@
#include <grpc++/server_context.h>
-#include <mutex>
-
-#include <grpc++/impl/call.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
-#include "src/cpp/util/time.h"
+#include <grpc++/impl/call.h>
+#include <grpc++/impl/sync.h>
+#include <grpc++/time.h>
namespace grpc {
@@ -57,14 +56,14 @@ class ServerContext::CompletionOp GRPC_FINAL : public CallOpBuffer {
void Unref();
private:
- std::mutex mu_;
+ grpc::mutex mu_;
int refs_;
bool finalized_;
bool cancelled_;
};
void ServerContext::CompletionOp::Unref() {
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
if (--refs_ == 0) {
lock.unlock();
delete this;
@@ -73,13 +72,13 @@ void ServerContext::CompletionOp::Unref() {
bool ServerContext::CompletionOp::CheckCancelled(CompletionQueue* cq) {
cq->TryPluck(this);
- std::lock_guard<std::mutex> g(mu_);
+ grpc::lock_guard<grpc::mutex> g(mu_);
return finalized_ ? cancelled_ : false;
}
bool ServerContext::CompletionOp::FinalizeResult(void** tag, bool* status) {
GPR_ASSERT(CallOpBuffer::FinalizeResult(tag, status));
- std::unique_lock<std::mutex> lock(mu_);
+ grpc::unique_lock<grpc::mutex> lock(mu_);
finalized_ = true;
if (!*status) cancelled_ = true;
if (--refs_ == 0) {
@@ -100,7 +99,7 @@ ServerContext::ServerContext()
ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
size_t metadata_count)
: completion_op_(nullptr),
- deadline_(Timespec2Timepoint(deadline)),
+ deadline_(deadline),
call_(nullptr),
cq_(nullptr),
sent_initial_metadata_(false) {
diff --git a/src/cpp/server/thread_pool.cc b/src/cpp/server/thread_pool.cc
index d3013b806c..e8d0e89ed2 100644
--- a/src/cpp/server/thread_pool.cc
+++ b/src/cpp/server/thread_pool.cc
@@ -31,48 +31,52 @@
*
*/
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
+
#include "src/cpp/server/thread_pool.h"
namespace grpc {
+void ThreadPool::ThreadFunc() {
+ for (;;) {
+ // Wait until work is available or we are shutting down.
+ grpc::unique_lock<grpc::mutex> lock(mu_);
+ if (!shutdown_ && callbacks_.empty()) {
+ cv_.wait(lock);
+ }
+ // Drain callbacks before considering shutdown to ensure all work
+ // gets completed.
+ if (!callbacks_.empty()) {
+ auto cb = callbacks_.front();
+ callbacks_.pop();
+ lock.unlock();
+ cb();
+ } else if (shutdown_) {
+ return;
+ }
+ }
+}
+
ThreadPool::ThreadPool(int num_threads) : shutdown_(false) {
for (int i = 0; i < num_threads; i++) {
- threads_.push_back(std::thread([this]() {
- for (;;) {
- // Wait until work is available or we are shutting down.
- auto have_work = [this]() { return shutdown_ || !callbacks_.empty(); };
- std::unique_lock<std::mutex> lock(mu_);
- if (!have_work()) {
- cv_.wait(lock, have_work);
- }
- // Drain callbacks before considering shutdown to ensure all work
- // gets completed.
- if (!callbacks_.empty()) {
- auto cb = callbacks_.front();
- callbacks_.pop();
- lock.unlock();
- cb();
- } else if (shutdown_) {
- return;
- }
- }
- }));
+ threads_.push_back(grpc::thread(&ThreadPool::ThreadFunc, this));
}
}
ThreadPool::~ThreadPool() {
{
- std::lock_guard<std::mutex> lock(mu_);
+ grpc::lock_guard<grpc::mutex> lock(mu_);
shutdown_ = true;
cv_.notify_all();
}
- for (auto& t : threads_) {
- t.join();
+ for (auto t = threads_.begin(); t != threads_.end(); t++) {
+ t->join();
}
}
void ThreadPool::ScheduleCallback(const std::function<void()>& callback) {
- std::lock_guard<std::mutex> lock(mu_);
+ grpc::lock_guard<grpc::mutex> lock(mu_);
callbacks_.push(callback);
cv_.notify_one();
}
diff --git a/src/cpp/server/thread_pool.h b/src/cpp/server/thread_pool.h
index 6225d82a0b..0f24d6e9b3 100644
--- a/src/cpp/server/thread_pool.h
+++ b/src/cpp/server/thread_pool.h
@@ -35,11 +35,11 @@
#define GRPC_INTERNAL_CPP_SERVER_THREAD_POOL_H
#include <grpc++/config.h>
+
+#include <grpc++/impl/sync.h>
+#include <grpc++/impl/thd.h>
#include <grpc++/thread_pool_interface.h>
-#include <condition_variable>
-#include <thread>
-#include <mutex>
#include <queue>
#include <vector>
@@ -53,11 +53,13 @@ class ThreadPool GRPC_FINAL : public ThreadPoolInterface {
void ScheduleCallback(const std::function<void()>& callback) GRPC_OVERRIDE;
private:
- std::mutex mu_;
- std::condition_variable cv_;
+ grpc::mutex mu_;
+ grpc::condition_variable cv_;
bool shutdown_;
std::queue<std::function<void()>> callbacks_;
- std::vector<std::thread> threads_;
+ std::vector<grpc::thread> threads_;
+
+ void ThreadFunc();
};
} // namespace grpc
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index f8d8eec065..ac2657472c 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -60,7 +60,6 @@ void ByteBuffer::Dump(std::vector<Slice>* slices) {
gpr_slice s;
while (grpc_byte_buffer_reader_next(reader, &s)) {
slices->push_back(Slice(s, Slice::STEAL_REF));
- gpr_slice_unref(s);
}
grpc_byte_buffer_reader_destroy(reader);
}
diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc
index 059ea72abf..1fef2a56de 100644
--- a/src/cpp/util/time.cc
+++ b/src/cpp/util/time.cc
@@ -31,9 +31,12 @@
*
*/
-#include "src/cpp/util/time.h"
+#include <grpc++/config.h>
+
+#ifndef GRPC_CXX0X_NO_CHRONO
#include <grpc/support/time.h>
+#include <grpc++/time.h>
using std::chrono::duration_cast;
using std::chrono::nanoseconds;
@@ -68,3 +71,5 @@ system_clock::time_point Timespec2Timepoint(gpr_timespec t) {
}
} // namespace grpc
+
+#endif // !GRPC_CXX0X_NO_CHRONO
diff --git a/src/csharp/Grpc.Auth/.gitignore b/src/csharp/Grpc.Auth/.gitignore
new file mode 100644
index 0000000000..c2dd664167
--- /dev/null
+++ b/src/csharp/Grpc.Auth/.gitignore
@@ -0,0 +1,3 @@
+bin
+obj
+*.nupkg
diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs
new file mode 100644
index 0000000000..36d43d3207
--- /dev/null
+++ b/src/csharp/Grpc.Auth/GoogleCredential.cs
@@ -0,0 +1,124 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+
+using Google.Apis.Auth.OAuth2;
+using Mono.Security.Cryptography;
+using Newtonsoft.Json.Linq;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Grpc.Auth
+{
+ // TODO(jtattermusch): Remove this class once possible.
+ /// <summary>
+ /// A temporary placeholder for Google credential from
+ /// Google Auth library for .NET. It emulates the usage pattern
+ /// for Usable auth.
+ /// </summary>
+ public class GoogleCredential
+ {
+ private const string GoogleApplicationCredentialsEnvName = "GOOGLE_APPLICATION_CREDENTIALS";
+ private const string ClientEmailFieldName = "client_email";
+ private const string PrivateKeyFieldName = "private_key";
+
+ private ServiceCredential credential;
+
+ private GoogleCredential(ServiceCredential credential)
+ {
+ this.credential = credential;
+ }
+
+ public static GoogleCredential GetApplicationDefault()
+ {
+ return new GoogleCredential(null);
+ }
+
+ public bool IsCreateScopedRequired
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public GoogleCredential CreateScoped(IEnumerable<string> scopes)
+ {
+ var credsPath = Environment.GetEnvironmentVariable(GoogleApplicationCredentialsEnvName);
+ if (credsPath == null)
+ {
+ // Default to ComputeCredentials if path to JSON key is not set.
+ // ComputeCredential is not scoped actually, but for our use case it's
+ // fine to treat is as such.
+ return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer()));
+ }
+
+ JObject o1 = JObject.Parse(File.ReadAllText(credsPath));
+ string clientEmail = o1.GetValue(ClientEmailFieldName).Value<string>();
+ string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value<string>();
+ var privateKey = ParsePrivateKeyFromString(privateKeyString);
+
+ var serviceCredential = new ServiceAccountCredential(
+ new ServiceAccountCredential.Initializer(clientEmail)
+ {
+ Scopes = scopes,
+ Key = privateKey
+ });
+ return new GoogleCredential(serviceCredential);
+ }
+
+ internal ServiceCredential InternalCredential
+ {
+ get
+ {
+ return credential;
+ }
+ }
+
+ private RSACryptoServiceProvider ParsePrivateKeyFromString(string base64PrivateKey)
+ {
+ // TODO(jtattermusch): temporary code to create RSACryptoServiceProvider.
+ base64PrivateKey = base64PrivateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("\n", "").Replace("-----END PRIVATE KEY-----", "");
+ PKCS8.PrivateKeyInfo PKI = new PKCS8.PrivateKeyInfo(Convert.FromBase64String(base64PrivateKey));
+ RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(PKI.GetBytes());
+ RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(key);
+ RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
+ rsa.ImportParameters(rsaParameters);
+ return rsa;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
new file mode 100644
index 0000000000..1931db5fd8
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>Grpc.Auth</RootNamespace>
+ <AssemblyName>Grpc.Auth</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="BouncyCastle.Crypto">
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth">
+ <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices">
+ <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core">
+ <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Mono.Security">
+ <HintPath>..\packages\Mono.Security.3.2.3.0\lib\net45\Mono.Security.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="GoogleCredential.cs" />
+ <Compile Include="OAuth2InterceptorFactory.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
+ <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+ </Target>
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
new file mode 100644
index 0000000000..ca384d1a6e
--- /dev/null
+++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
@@ -0,0 +1,104 @@
+#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.Security.Cryptography.X509Certificates;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Google.Apis.Auth.OAuth2;
+using Google.Apis.Util;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+ public static class OAuth2InterceptorFactory
+ {
+ /// <summary>
+ /// Creates OAuth2 interceptor.
+ /// </summary>
+ public static HeaderInterceptorDelegate Create(GoogleCredential googleCredential)
+ {
+ var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
+ return new HeaderInterceptorDelegate(interceptor.InterceptHeaders);
+ }
+
+ /// <summary>
+ /// Injects OAuth2 authorization header into initial metadata (= request headers).
+ /// </summary>
+ private class OAuth2Interceptor
+ {
+ private const string AuthorizationHeader = "Authorization";
+ private const string Schema = "Bearer";
+
+ private ServiceCredential credential;
+ private IClock clock;
+
+ public OAuth2Interceptor(ServiceCredential credential, IClock clock)
+ {
+ this.credential = credential;
+ this.clock = clock;
+ }
+
+ /// <summary>
+ /// Gets access token and requests refreshing it if is going to expire soon.
+ /// </summary>
+ /// <param name="cancellationToken"></param>
+ /// <returns></returns>
+ public string GetAccessToken(CancellationToken cancellationToken)
+ {
+ if (credential.Token == null || credential.Token.IsExpired(clock))
+ {
+ // TODO(jtattermusch): Parallel requests will spawn multiple requests to refresh the token once the token expires.
+ // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+ if (!credential.RequestAccessTokenAsync(cancellationToken).Result)
+ {
+ throw new InvalidOperationException("The access token has expired but we can't refresh it");
+ }
+ }
+ return credential.Token.AccessToken;
+ }
+
+ public void InterceptHeaders(Metadata.Builder headerBuilder)
+ {
+ var accessToken = GetAccessToken(CancellationToken.None);
+ headerBuilder.Add(new Metadata.MetadataEntry(AuthorizationHeader, Schema + " " + accessToken));
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..66b18d0ccf
--- /dev/null
+++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.Auth")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.2.*")]
+
+[assembly: InternalsVisibleTo("Grpc.Auth.Tests")] \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
new file mode 100644
index 0000000000..966b777192
--- /dev/null
+++ b/src/csharp/Grpc.Auth/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
new file mode 100644
index 0000000000..0816bdbad1
--- /dev/null
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
+ <package id="Mono.Security" version="3.2.3.0" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
index e4328806ad..e0f0474245 100644
--- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Core/.gitignore b/src/csharp/Grpc.Core/.gitignore
index 8d4a6c08a8..c2dd664167 100644
--- a/src/csharp/Grpc.Core/.gitignore
+++ b/src/csharp/Grpc.Core/.gitignore
@@ -1,2 +1,3 @@
bin
-obj \ No newline at end of file
+obj
+*.nupkg
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 78ba32b277..0b85392e15 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.props" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.props')" />
+ <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.props" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -10,6 +12,7 @@
<RootNamespace>Grpc.Core</RootNamespace>
<AssemblyName>Grpc.Core</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>8bb563fb</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -32,7 +35,7 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable">
- <HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -92,7 +95,7 @@
ignored, which gives us the desired effect. -->
<When Condition=" '$(OS)' != 'Unix' ">
<ItemGroup>
- <Content Include="..\..\..\vsprojects\vs2013\Debug\grpc_csharp_ext.dll">
+ <Content Include="..\..\..\vsprojects\Debug\grpc_csharp_ext.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
@@ -100,7 +103,16 @@
<Otherwise />
</Choose>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
- <ItemGroup>
- <Folder Include="Stub\" />
- </ItemGroup>
+ <ItemGroup />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.props'))" />
+ <Error Condition="!Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets'))" />
+ <Error Condition="!Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.props'))" />
+ <Error Condition="!Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets'))" />
+ </Target>
+ <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
+ <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index af8a8869ca..4865ead555 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<package >
+<package>
<metadata>
<id>Grpc.Core</id>
<title>gRPC Core</title>
@@ -7,7 +7,7 @@
<description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.
This is an experimental release, not ready to use.
</description>
- <version>0.1.0</version>
+ <version>0.2.1</version>
<authors>Google Inc.</authors>
<owners>jtattermusch</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
@@ -16,6 +16,10 @@
<releaseNotes>The first experimental release. Not ready to use.</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
+ <dependencies>
+ <dependency id="Microsoft.Bcl.Immutable" version="1.0.34" />
+ <dependency id="grpc.native.csharp_ext" version="0.6.0.0" />
+ </dependencies>
</metadata>
<files>
<file src="bin/Release/Grpc.Core.dll" target="lib/net45" />
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 14add60c72..c97a3bc2b1 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -33,6 +33,7 @@ using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Grpc.Core;
+using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
@@ -180,7 +181,7 @@ namespace Grpc.Core.Internal
private static void AssertCallOk(GRPCCallError callError)
{
- Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
+ Preconditions.CheckState(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
}
private static uint GetFlags(bool buffered)
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index a59da09822..8080643d8c 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -35,6 +35,7 @@ using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using Grpc.Core.Utils;
namespace Grpc.Core.Internal
{
@@ -105,9 +106,9 @@ namespace Grpc.Core.Internal
grpcsharp_server_shutdown_and_notify_CALLBACK(this, callback);
}
- public GRPCCallError RequestCall(CompletionQueueSafeHandle cq, CompletionCallbackDelegate callback)
+ public void RequestCall(CompletionQueueSafeHandle cq, CompletionCallbackDelegate callback)
{
- return grpcsharp_server_request_call(this, cq, callback);
+ AssertCallOk(grpcsharp_server_request_call(this, cq, callback));
}
protected override bool ReleaseHandle()
@@ -115,5 +116,10 @@ namespace Grpc.Core.Internal
grpcsharp_server_destroy(handle);
return true;
}
+
+ private static void AssertCallOk(GRPCCallError callError)
+ {
+ Preconditions.CheckState(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 168939cf8c..81218cb67e 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -9,6 +9,6 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]
diff --git a/src/csharp/Grpc.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs
index 433d87215e..c58578286b 100644
--- a/src/csharp/Grpc.Core/RpcException.cs
+++ b/src/csharp/Grpc.Core/RpcException.cs
@@ -42,7 +42,7 @@ namespace Grpc.Core
{
private readonly Status status;
- public RpcException(Status status)
+ public RpcException(Status status) : base(status.ToString())
{
this.status = status;
}
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index f086fa8beb..e686cdddef 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -38,27 +38,29 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Server is implemented only to be able to do
- /// in-process testing.
+ /// A gRPC server.
/// </summary>
public class Server
{
- // TODO: make sure the delegate doesn't get garbage collected while
+ // TODO(jtattermusch) : make sure the delegate doesn't get garbage collected while
// native callbacks are in the completion queue.
readonly ServerShutdownCallbackDelegate serverShutdownHandler;
readonly CompletionCallbackDelegate newServerRpcHandler;
- readonly BlockingCollection<NewRpcInfo> newRpcQueue = new BlockingCollection<NewRpcInfo>();
readonly ServerSafeHandle handle;
+ readonly object myLock = new object();
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
-
readonly TaskCompletionSource<object> shutdownTcs = new TaskCompletionSource<object>();
+ bool startRequested;
+ bool shutdownRequested;
+
public Server()
{
this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), IntPtr.Zero);
@@ -66,71 +68,81 @@ namespace Grpc.Core
this.serverShutdownHandler = HandleServerShutdown;
}
- // only call this before Start()
+ /// <summary>
+ /// Adds a service definition to the server. This is how you register
+ /// handlers for a service with the server.
+ /// Only call this before Start().
+ /// </summary>
public void AddServiceDefinition(ServerServiceDefinition serviceDefinition)
{
- foreach (var entry in serviceDefinition.CallHandlers)
+ lock (myLock)
{
- callHandlers.Add(entry.Key, entry.Value);
+ Preconditions.CheckState(!startRequested);
+ foreach (var entry in serviceDefinition.CallHandlers)
+ {
+ callHandlers.Add(entry.Key, entry.Value);
+ }
}
}
- // only call before Start()
+ /// <summary>
+ /// Add a non-secure port on which server should listen.
+ /// Only call this before Start().
+ /// </summary>
public int AddListeningPort(string addr)
{
- return handle.AddListeningPort(addr);
- }
-
- // only call before Start()
- public int AddListeningPort(string addr, ServerCredentials credentials)
- {
- using (var nativeCredentials = credentials.ToNativeCredentials())
+ lock (myLock)
{
- return handle.AddListeningPort(addr, nativeCredentials);
+ Preconditions.CheckState(!startRequested);
+ return handle.AddListeningPort(addr);
}
}
- public void Start()
- {
- handle.Start();
-
- // TODO: this basically means the server is single threaded....
- StartHandlingRpcs();
- }
-
/// <summary>
- /// Requests and handles single RPC call.
+ /// Add a secure port on which server should listen.
+ /// Only call this before Start().
/// </summary>
- internal void RunRpc()
+ public int AddListeningPort(string addr, ServerCredentials credentials)
{
- AllowOneRpc();
-
- try
+ lock (myLock)
{
- var rpcInfo = newRpcQueue.Take();
-
- // Console.WriteLine("Server received RPC " + rpcInfo.Method);
-
- IServerCallHandler callHandler;
- if (!callHandlers.TryGetValue(rpcInfo.Method, out callHandler))
+ Preconditions.CheckState(!startRequested);
+ using (var nativeCredentials = credentials.ToNativeCredentials())
{
- callHandler = new NoSuchMethodCallHandler();
+ return handle.AddListeningPort(addr, nativeCredentials);
}
- callHandler.StartCall(rpcInfo.Method, rpcInfo.Call, GetCompletionQueue());
}
- catch (Exception e)
+ }
+
+ /// <summary>
+ /// Starts the server.
+ /// </summary>
+ public void Start()
+ {
+ lock (myLock)
{
- Console.WriteLine("Exception while handling RPC: " + e);
+ Preconditions.CheckState(!startRequested);
+ startRequested = true;
+
+ handle.Start();
+ AllowOneRpc();
}
}
/// <summary>
/// Requests server shutdown and when there are no more calls being serviced,
- /// cleans up used resources.
+ /// cleans up used resources. The returned task finishes when shutdown procedure
+ /// is complete.
/// </summary>
- /// <returns>The async.</returns>
public async Task ShutdownAsync()
{
+ lock (myLock)
+ {
+ Preconditions.CheckState(startRequested);
+ Preconditions.CheckState(!shutdownRequested);
+ shutdownRequested = true;
+ }
+
handle.ShutdownAndNotify(serverShutdownHandler);
await shutdownTcs.Task;
handle.Dispose();
@@ -152,19 +164,43 @@ namespace Grpc.Core
handle.Dispose();
}
- private async Task StartHandlingRpcs()
+ /// <summary>
+ /// Allows one new RPC call to be received by server.
+ /// </summary>
+ private void AllowOneRpc()
{
- while (true)
+ lock (myLock)
{
- await Task.Factory.StartNew(RunRpc);
+ if (!shutdownRequested)
+ {
+ handle.RequestCall(GetCompletionQueue(), newServerRpcHandler);
+ }
}
}
- private void AllowOneRpc()
+ /// <summary>
+ /// Selects corresponding handler for given call and handles the call.
+ /// </summary>
+ private void InvokeCallHandler(CallSafeHandle call, string method)
{
- AssertCallOk(handle.RequestCall(GetCompletionQueue(), newServerRpcHandler));
+ try
+ {
+ IServerCallHandler callHandler;
+ if (!callHandlers.TryGetValue(method, out callHandler))
+ {
+ callHandler = new NoSuchMethodCallHandler();
+ }
+ callHandler.StartCall(method, call, GetCompletionQueue());
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Exception while handling RPC: " + e);
+ }
}
+ /// <summary>
+ /// Handles the native callback.
+ /// </summary>
private void HandleNewServerRpc(GRPCOpError error, IntPtr batchContextPtr)
{
try
@@ -176,13 +212,16 @@ namespace Grpc.Core
// TODO: handle error
}
- var rpcInfo = new NewRpcInfo(ctx.GetServerRpcNewCall(), ctx.GetServerRpcNewMethod());
+ CallSafeHandle call = ctx.GetServerRpcNewCall();
+ string method = ctx.GetServerRpcNewMethod();
// after server shutdown, the callback returns with null call
- if (!rpcInfo.Call.IsInvalid)
+ if (!call.IsInvalid)
{
- newRpcQueue.Add(rpcInfo);
+ Task.Run(() => InvokeCallHandler(call, method));
}
+
+ AllowOneRpc();
}
catch (Exception e)
{
@@ -190,6 +229,10 @@ namespace Grpc.Core
}
}
+ /// <summary>
+ /// Handles native callback.
+ /// </summary>
+ /// <param name="eventPtr"></param>
private void HandleServerShutdown(IntPtr eventPtr)
{
try
@@ -202,42 +245,9 @@ namespace Grpc.Core
}
}
- private static void AssertCallOk(GRPCCallError callError)
- {
- Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
- }
-
private static CompletionQueueSafeHandle GetCompletionQueue()
{
return GrpcEnvironment.ThreadPool.CompletionQueue;
}
-
- private struct NewRpcInfo
- {
- private CallSafeHandle call;
- private string method;
-
- public NewRpcInfo(CallSafeHandle call, string method)
- {
- this.call = call;
- this.method = method;
- }
-
- public CallSafeHandle Call
- {
- get
- {
- return this.call;
- }
- }
-
- public string Method
- {
- get
- {
- return this.method;
- }
- }
- }
}
}
diff --git a/src/csharp/Grpc.Core/Status.cs b/src/csharp/Grpc.Core/Status.cs
index 080bbdc2f5..7d76aec4d1 100644
--- a/src/csharp/Grpc.Core/Status.cs
+++ b/src/csharp/Grpc.Core/Status.cs
@@ -69,5 +69,10 @@ namespace Grpc.Core
return detail;
}
}
+
+ public override string ToString()
+ {
+ return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail);
+ }
}
}
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
index cf711ac362..71967de56e 100644
--- a/src/csharp/Grpc.Core/packages.config
+++ b/src/csharp/Grpc.Core/packages.config
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="System.Collections.Immutable" version="1.1.34-rc" targetFramework="net45" />
+ <package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" />
+ <package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index f5956bd33e..ca7683d399 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -46,11 +46,15 @@ namespace math
MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
MathExamples.DivExample(stub);
- MathExamples.FibExample(stub);
+ MathExamples.DivAsyncExample(stub).Wait();
- MathExamples.SumExample(stub);
+ MathExamples.FibExample(stub).Wait();
- MathExamples.DivManyExample(stub);
+ MathExamples.SumExample(stub).Wait();
+
+ MathExamples.DivManyExample(stub).Wait();
+
+ MathExamples.DependendRequestsExample(stub).Wait();
}
GrpcEnvironment.Shutdown();
diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
index 11fc099a95..1989ca8430 100644
--- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Examples.MathServer/.gitignore b/src/csharp/Grpc.Examples.MathServer/.gitignore
new file mode 100644
index 0000000000..1746e3269e
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
new file mode 100644
index 0000000000..3f7e6c0768
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>10.0.0</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Grpc.Examples.MathServer</RootNamespace>
+ <AssemblyName>Grpc.Examples.MathServer</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Externalconsole>true</Externalconsole>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <Externalconsole>true</Externalconsole>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="MathServer.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+ <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
+ <Name>Grpc.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Grpc.Examples\Grpc.Examples.csproj">
+ <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
+ <Name>Grpc.Examples</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
new file mode 100644
index 0000000000..abc7ef05e4
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -0,0 +1,61 @@
+#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.Runtime.InteropServices;
+using System.Threading;
+using Grpc.Core;
+
+namespace math
+{
+ class MainClass
+ {
+ public static void Main(string[] args)
+ {
+ string host = "0.0.0.0";
+
+ GrpcEnvironment.Initialize();
+
+ Server server = new Server();
+ server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
+ int port = server.AddListeningPort(host + ":23456");
+ server.Start();
+
+ Console.WriteLine("MathServer listening on port " + port);
+
+ Console.WriteLine("Press any key to stop the server...");
+ Console.ReadKey();
+
+ server.ShutdownAsync().Wait();
+ GrpcEnvironment.Shutdown();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..6b3d0516b9
--- /dev/null
+++ b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.Examples.MathServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: AssemblyVersion("0.1.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index cf5a640079..f9c1caf700 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -37,6 +37,18 @@
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
</Reference>
+ <Reference Include="System.Reactive.Interfaces">
+ <HintPath>..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Core">
+ <HintPath>..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.Linq">
+ <HintPath>..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Reactive.PlatformServices">
+ <HintPath>..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index 85f213cb39..fa5d6688a6 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
@@ -120,14 +121,12 @@ namespace math.Tests
[Test]
public void Sum()
{
- var res = client.Sum();
- foreach (var num in new long[] { 10, 20, 30 })
- {
- res.Inputs.OnNext(Num.CreateBuilder().SetNum_(num).Build());
- }
- res.Inputs.OnCompleted();
+ var clientStreamingResult = client.Sum();
+ var numList = new List<long> { 10, 20, 30 }.ConvertAll(
+ n => Num.CreateBuilder().SetNum_(n).Build());
+ numList.Subscribe(clientStreamingResult.Inputs);
- Assert.AreEqual(60, res.Task.Result.Num_);
+ Assert.AreEqual(60, clientStreamingResult.Task.Result.Num_);
}
[Test]
@@ -142,13 +141,7 @@ namespace math.Tests
var recorder = new RecordingObserver<DivReply>();
var requestObserver = client.DivMany(recorder);
-
- foreach (var arg in divArgsList)
- {
- requestObserver.OnNext(arg);
- }
- requestObserver.OnCompleted();
-
+ divArgsList.Subscribe(requestObserver);
var result = recorder.ToList().Result;
CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient));
diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
index 43c7616ac3..d78e9210c0 100644
--- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
index 51c17bcd5e..06c5e6a4eb 100644
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ b/src/csharp/Grpc.Examples.Tests/packages.config
@@ -1,5 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
- <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
- <package id="NUnit" version="2.6.4" targetFramework="net45" />
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
+ <package id="NUnit" version="2.6.4" targetFramework="net45" />
+ <package id="Rx-Core" version="2.2.5" targetFramework="net45" />
+ <package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
+ <package id="Rx-Linq" version="2.2.5" targetFramework="net45" />
+ <package id="Rx-Main" version="2.2.5" targetFramework="net45" />
+ <package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs
index b8bb7eacbd..032372b2a1 100644
--- a/src/csharp/Grpc.Examples/MathExamples.cs
+++ b/src/csharp/Grpc.Examples/MathExamples.cs
@@ -45,51 +45,45 @@ namespace math
Console.WriteLine("Div Result: " + result);
}
- public static void DivAsyncExample(MathGrpc.IMathServiceClient stub)
+ public static async Task DivAsyncExample(MathGrpc.IMathServiceClient stub)
{
- Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
- DivReply result = call.Result;
- Console.WriteLine(result);
+ Task<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+ DivReply result = await resultTask;
+ Console.WriteLine("DivAsync Result: " + result);
}
- public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
+ public static async Task DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
{
- Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
- DivReply result = call.Result;
+ Task<DivReply> resultTask = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
+ DivReply result = await resultTask;
Console.WriteLine(result);
}
- public static void FibExample(MathGrpc.IMathServiceClient stub)
+ public static async Task FibExample(MathGrpc.IMathServiceClient stub)
{
var recorder = new RecordingObserver<Num>();
stub.Fib(new FibArgs.Builder { Limit = 5 }.Build(), recorder);
-
- List<Num> numbers = recorder.ToList().Result;
- Console.WriteLine("Fib Result: " + string.Join("|", recorder.ToList().Result));
+ List<Num> result = await recorder.ToList();
+ Console.WriteLine("Fib Result: " + string.Join("|", result));
}
- public static void SumExample(MathGrpc.IMathServiceClient stub)
+ public static async Task SumExample(MathGrpc.IMathServiceClient stub)
{
- List<Num> numbers = new List<Num>
+ var numbers = new List<Num>
{
new Num.Builder { Num_ = 1 }.Build(),
new Num.Builder { Num_ = 2 }.Build(),
new Num.Builder { Num_ = 3 }.Build()
};
- var res = stub.Sum();
- foreach (var num in numbers)
- {
- res.Inputs.OnNext(num);
- }
- res.Inputs.OnCompleted();
-
- Console.WriteLine("Sum Result: " + res.Task.Result);
+ var clientStreamingResult = stub.Sum();
+ numbers.Subscribe(clientStreamingResult.Inputs);
+ Console.WriteLine("Sum Result: " + await clientStreamingResult.Task);
}
- public static void DivManyExample(MathGrpc.IMathServiceClient stub)
+ public static async Task DivManyExample(MathGrpc.IMathServiceClient stub)
{
- List<DivArgs> divArgsList = new List<DivArgs>
+ var divArgsList = new List<DivArgs>
{
new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
@@ -97,26 +91,27 @@ namespace math
};
var recorder = new RecordingObserver<DivReply>();
-
var inputs = stub.DivMany(recorder);
- foreach (var input in divArgsList)
- {
- inputs.OnNext(input);
- }
- inputs.OnCompleted();
-
- Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result));
+ divArgsList.Subscribe(inputs);
+ var result = await recorder.ToList();
+ Console.WriteLine("DivMany Result: " + string.Join("|", result));
}
- public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
+ public static async Task DependendRequestsExample(MathGrpc.IMathServiceClient stub)
{
- var numberList = new List<Num>
+ 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.Builder { Num_ = 1 }.Build(),
+ new Num.Builder { Num_ = 2 }.Build(),
+ new Num.Builder { Num_ = 3 }.Build()
};
- numberList.ToObservable();
+ var clientStreamingResult = stub.Sum();
+ numbers.Subscribe(clientStreamingResult.Inputs);
+ Num sum = await clientStreamingResult.Task;
+
+ DivReply result = await stub.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build());
+ Console.WriteLine("Avg Result: " + result);
}
}
}
diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
index b55d24166c..fd1cdbbc1c 100644
--- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index b1a4a81916..df05c535e2 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -46,4 +46,7 @@
<Name>Grpc.IntegrationTesting</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
index c93dd1eb2f..d9d36f03e4 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
new file mode 100644
index 0000000000..966b777192
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 73c9f2d207..235897c888 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -46,4 +46,7 @@
<Name>Grpc.IntegrationTesting</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ </ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
index f3def1aea4..b0b163b883 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
new file mode 100644
index 0000000000..966b777192
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index c3e5f03074..13bbb5363f 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -32,6 +32,21 @@
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="Google.Apis.Auth.PlatformServices">
+ <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core">
+ <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
@@ -39,8 +54,20 @@
<Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
</Reference>
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
+ <Reference Include="Newtonsoft.Json">
+ <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="System.Collections.Immutable">
- <HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+ <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -60,8 +87,13 @@
<Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
<Name>Grpc.Core</Name>
</ProjectReference>
+ <ProjectReference Include="..\Grpc.Auth\Grpc.Auth.csproj">
+ <Project>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</Project>
+ <Name>Grpc.Auth</Name>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
+ <None Include="app.config" />
<None Include="packages.config" />
<None Include="proto\test.proto" />
<None Include="proto\empty.proto" />
@@ -79,5 +111,12 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
- <ItemGroup />
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
+ <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 6b92d3c660..1fbae374b1 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -33,12 +33,11 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
+
using Google.ProtocolBuffers;
using grpc.testing;
+using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
using NUnit.Framework;
@@ -47,6 +46,11 @@ 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;
@@ -115,7 +119,18 @@ namespace Grpc.IntegrationTesting
using (Channel channel = new Channel(addr, credentials, channelArgs))
{
- TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel);
+ var stubConfig = StubConfiguration.Default;
+ if (options.testCase == "service_account_creds" || options.testCase == "compute_engine_creds")
+ {
+ var credential = GoogleCredential.GetApplicationDefault();
+ if (credential.IsCreateScopedRequired)
+ {
+ credential = credential.CreateScoped(new[] { AuthScope });
+ }
+ stubConfig = new StubConfiguration(OAuth2InterceptorFactory.Create(credential));
+ }
+
+ TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel, stubConfig);
RunTestCase(options.testCase, client);
}
@@ -144,6 +159,12 @@ namespace Grpc.IntegrationTesting
case "empty_stream":
RunEmptyStream(client);
break;
+ case "service_account_creds":
+ RunServiceAccountCreds(client);
+ break;
+ case "compute_engine_creds":
+ RunComputeEngineCreds(client);
+ break;
case "benchmark_empty_unary":
RunBenchmarkEmptyUnary(client);
break;
@@ -287,6 +308,46 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
+ public static void RunServiceAccountCreds(TestServiceGrpc.ITestServiceClient client)
+ {
+ Console.WriteLine("running service_account_creds");
+ 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 void RunComputeEngineCreds(TestServiceGrpc.ITestServiceClient client)
+ {
+ Console.WriteLine("running compute_engine_creds");
+ 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(ComputeEngineUser, response.Username);
+ Console.WriteLine("Passed!");
+ }
+
// This is not an official interop test, but it's useful.
public static void RunBenchmarkEmptyUnary(TestServiceGrpc.ITestServiceClient client)
{
diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
index f09a448e9e..fe6c8a8aed 100644
--- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
@@ -9,4 +9,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyCopyright("Google Inc. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.1.*")]
+[assembly: AssemblyVersion("0.2.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
new file mode 100644
index 0000000000..966b777192
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+ </dependentAssembly>
+ <dependentAssembly>
+ <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+ <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+ </dependentAssembly>
+ </assemblyBinding>
+ </runtime>
+</configuration> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 157c264eac..e33b6e3e46 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
+ <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
<package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" />
- <package id="System.Collections.Immutable" version="1.1.34-rc" targetFramework="net45" />
</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.nuspec b/src/csharp/Grpc.nuspec
index 96a6aaf6b7..4c106a2ca2 100644
--- a/src/csharp/Grpc.nuspec
+++ b/src/csharp/Grpc.nuspec
@@ -7,7 +7,7 @@
<description>C# implementation of gRPC - an RPC library and framework. See project site for more info.
This is an experimental release, not ready to use.
</description>
- <version>0.1.0</version>
+ <version>0.2.0</version>
<authors>Google Inc.</authors>
<owners>jtattermusch</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
@@ -17,7 +17,7 @@
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
- <dependency id="Grpc.Core" version="0.1.0" />
+ <dependency id="Grpc.Core" version="0.2.0" />
</dependencies>
</metadata>
</package>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 2e6d288699..e2a374e362 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Cli
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{A654F3B8-E859-4E6A-B30D-227527DBEF0D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -47,6 +51,14 @@ Global
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
+ {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86
{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 9a1c908d11..e182468d9b 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -731,7 +731,7 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs,
}
}
-GPR_EXPORT void grpcsharp_credentials_release(grpc_credentials *creds) {
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) {
grpc_credentials_release(creds);
}
@@ -765,7 +765,7 @@ grpcsharp_ssl_server_credentials_create(
return creds;
}
-GPR_EXPORT void grpcsharp_server_credentials_release(
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_server_credentials_release(
grpc_server_credentials *creds) {
grpc_server_credentials_release(creds);
}
diff --git a/src/node/README.md b/src/node/README.md
index b1d2310ede..6e4934151e 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -14,6 +14,12 @@ This requires `node` to be installed. If you instead have the `nodejs` executabl
2. Follow the instructions in the `INSTALL` file in the root of that repository to install the C core library that this package depends on.
3. Run `npm install`.
+If you install the gRPC C core library in a custom location, then you need to set some environment variables to install this library. The command will look like this:
+
+```sh
+CXXFLAGS=-I<custom location>/include LDFLAGS=-L<custom location>/lib npm install [grpc]
+```
+
## Tests
To run the test suite, simply run `npm test` in the install location.
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
index 7ef3bdf4bd..83f72fabca 100644
--- a/src/node/binding.gyp
+++ b/src/node/binding.gyp
@@ -18,12 +18,29 @@
],
'link_settings': {
'libraries': [
- '-lrt',
'-lpthread',
'-lgrpc',
'-lgpr'
- ],
+ ]
},
+ "conditions": [
+ ['OS == "mac"', {
+ 'xcode_settings': {
+ 'MACOSX_DEPLOYMENT_TARGET': '10.9',
+ 'OTHER_CFLAGS': [
+ '-std=c++11',
+ '-stdlib=libc++'
+ ]
+ }
+ }],
+ ['OS != "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lrt'
+ ]
+ }
+ }]
+ ],
"target_name": "grpc",
"sources": [
"ext/byte_buffer.cc",
diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js
index ae548c89e4..3fac193d64 100644
--- a/src/node/examples/math_server.js
+++ b/src/node/examples/math_server.js
@@ -33,10 +33,6 @@
'use strict';
-var util = require('util');
-
-var Transform = require('stream').Transform;
-
var grpc = require('..');
var math = grpc.load(__dirname + '/math.proto').math;
@@ -54,11 +50,12 @@ function mathDiv(call, cb) {
// Unary + is explicit coersion to integer
if (+req.divisor === 0) {
cb(new Error('cannot divide by zero'));
+ } else {
+ cb(null, {
+ quotient: req.dividend / req.divisor,
+ remainder: req.dividend % req.divisor
+ });
}
- cb(null, {
- quotient: req.dividend / req.divisor,
- remainder: req.dividend % req.divisor
- });
}
/**
@@ -97,24 +94,19 @@ function mathSum(call, cb) {
}
function mathDivMany(stream) {
- // Here, call is a standard duplex Node object Stream
- util.inherits(DivTransform, Transform);
- function DivTransform() {
- var options = {objectMode: true};
- Transform.call(this, options);
- }
- DivTransform.prototype._transform = function(div_args, encoding, callback) {
+ stream.on('data', function(div_args) {
if (+div_args.divisor === 0) {
- callback(new Error('cannot divide by zero'));
+ stream.emit('error', new Error('cannot divide by zero'));
+ } else {
+ stream.write({
+ quotient: div_args.dividend / div_args.divisor,
+ remainder: div_args.dividend % div_args.divisor
+ });
}
- callback(null, {
- quotient: div_args.dividend / div_args.divisor,
- remainder: div_args.dividend % div_args.divisor
- });
- };
- var transform = new DivTransform();
- stream.pipe(transform);
- transform.pipe(stream);
+ });
+ stream.on('end', function() {
+ stream.end();
+ });
}
var server = new Server({
diff --git a/src/node/examples/pubsub/label.proto b/src/node/examples/pubsub/label.proto
deleted file mode 100644
index 0af15a25a6..0000000000
--- a/src/node/examples/pubsub/label.proto
+++ /dev/null
@@ -1,79 +0,0 @@
-// This file will be moved to a new location.
-
-// 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.
-
-// Labels provide a way to associate user-defined metadata with various
-// objects. Labels may be used to organize objects into non-hierarchical
-// groups; think metadata tags attached to mp3s.
-
-syntax = "proto2";
-
-package tech.label;
-
-// A key-value pair applied to a given object.
-message Label {
- // The key of a label is a syntactically valid URL (as per RFC 1738) with
- // the "scheme" and initial slashes omitted and with the additional
- // restrictions noted below. Each key should be globally unique. The
- // "host" portion is called the "namespace" and is not necessarily
- // resolvable to a network endpoint. Instead, the namespace indicates what
- // system or entity defines the semantics of the label. Namespaces do not
- // restrict the set of objects to which a label may be associated.
- //
- // Keys are defined by the following grammar:
- //
- // key = hostname "/" kpath
- // kpath = ksegment *[ "/" ksegment ]
- // ksegment = alphadigit | *[ alphadigit | "-" | "_" | "." ]
- //
- // where "hostname" and "alphadigit" are defined as in RFC 1738.
- //
- // Example key:
- // spanner.google.com/universe
- required string key = 1;
-
- // The value of the label.
- oneof value {
- // A string value.
- string str_value = 2;
- // An integer value.
- int64 num_value = 3;
- }
-}
-
-// A collection of labels, such as the set of all labels attached to an
-// object. Each label in the set must have a different key.
-//
-// Users should prefer to embed "repeated Label" directly when possible.
-// This message should only be used in cases where that isn't possible (e.g.
-// with oneof).
-message Labels {
- repeated Label label = 1;
-}
diff --git a/src/node/examples/pubsub/pubsub.proto b/src/node/examples/pubsub/pubsub.proto
deleted file mode 100644
index 41a354773f..0000000000
--- a/src/node/examples/pubsub/pubsub.proto
+++ /dev/null
@@ -1,734 +0,0 @@
-// This file will be moved to a new location.
-
-// 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.
-
-
-// Specification of the Pubsub API.
-
-syntax = "proto2";
-
-import "empty.proto";
-import "label.proto";
-
-package tech.pubsub;
-
-// -----------------------------------------------------------------------------
-// Overview of the Pubsub API
-// -----------------------------------------------------------------------------
-
-// This file describes an API for a Pubsub system. This system provides a
-// reliable many-to-many communication mechanism between independently written
-// publishers and subscribers where the publisher publishes messages to "topics"
-// and each subscriber creates a "subscription" and consumes messages from it.
-//
-// (a) The pubsub system maintains bindings between topics and subscriptions.
-// (b) A publisher publishes messages into a topic.
-// (c) The pubsub system delivers messages from topics into relevant
-// subscriptions.
-// (d) A subscriber receives pending messages from its subscription and
-// acknowledges or nacks each one to the pubsub system.
-// (e) The pubsub system removes acknowledged messages from that subscription.
-
-// -----------------------------------------------------------------------------
-// Data Model
-// -----------------------------------------------------------------------------
-
-// The data model consists of the following:
-//
-// * Topic: A topic is a resource to which messages are published by publishers.
-// Topics are named, and the name of the topic is unique within the pubsub
-// system.
-//
-// * Subscription: A subscription records the subscriber's interest in a topic.
-// It can optionally include a query to select a subset of interesting
-// messages. The pubsub system maintains a logical cursor tracking the
-// matching messages which still need to be delivered and acked so that
-// they can retried as needed. The set of messages that have not been
-// acknowledged is called the subscription backlog.
-//
-// * Message: A message is a unit of data that flows in the system. It contains
-// opaque data from the publisher along with its labels.
-//
-// * Message Labels (optional): A set of opaque key, value pairs assigned
-// by the publisher which the subscriber can use for filtering out messages
-// in the topic. For example, a label with key "foo.com/device_type" and
-// value "mobile" may be added for messages that are only relevant for a
-// mobile subscriber; a subscriber on a phone may decide to create a
-// subscription only for messages that have this label.
-
-// -----------------------------------------------------------------------------
-// Publisher Flow
-// -----------------------------------------------------------------------------
-
-// A publisher publishes messages to the topic using the Publish request:
-//
-// PubsubMessage message;
-// message.set_data("....");
-// Label label;
-// label.set_key("foo.com/key1");
-// label.set_str_value("value1");
-// message.add_label(label);
-// PublishRequest request;
-// request.set_topic("topicName");
-// request.set_message(message);
-// PublisherService.Publish(request);
-
-// -----------------------------------------------------------------------------
-// Subscriber Flow
-// -----------------------------------------------------------------------------
-
-// The subscriber part of the API is richer than the publisher part and has a
-// number of concepts w.r.t. subscription creation and monitoring:
-//
-// (1) A subscriber creates a subscription using the CreateSubscription call.
-// It may specify an optional "query" to indicate that it wants to receive
-// only messages with a certain set of labels using the label query syntax.
-// It may also specify an optional truncation policy to indicate when old
-// messages from the subcription can be removed.
-//
-// (2) A subscriber receives messages in one of two ways: via push or pull.
-//
-// (a) To receive messages via push, the PushConfig field must be specified in
-// the Subscription parameter when creating a subscription. The PushConfig
-// specifies an endpoint at which the subscriber must expose the
-// PushEndpointService. Messages are received via the HandlePubsubEvent
-// method. The push subscriber responds to the HandlePubsubEvent method
-// with a result code that indicates one of three things: Ack (the message
-// has been successfully processed and the Pubsub system may delete it),
-// Nack (the message has been rejected, the Pubsub system should resend it
-// at a later time), or Push-Back (this is a Nack with the additional
-// semantics that the subscriber is overloaded and the pubsub system should
-// back off on the rate at which it is invoking HandlePubsubEvent). The
-// endpoint may be a load balancer for better scalability.
-//
-// (b) To receive messages via pull a subscriber calls the Pull method on the
-// SubscriberService to get messages from the subscription. For each
-// individual message, the subscriber may use the ack_id received in the
-// PullResponse to Ack the message, Nack the message, or modify the ack
-// deadline with ModifyAckDeadline. See the
-// Subscription.ack_deadline_seconds field documentation for details on the
-// ack deadline behavior.
-//
-// Note: Messages may be consumed in parallel by multiple subscribers making
-// Pull calls to the same subscription; this will result in the set of
-// messages from the subscription being shared and each subscriber
-// receiving a subset of the messages.
-//
-// (4) The subscriber can explicitly truncate the current subscription.
-//
-// (5) "Truncated" events are delivered when a subscription is
-// truncated, whether due to the subscription's truncation policy
-// or an explicit request from the subscriber.
-//
-// Subscription creation:
-//
-// Subscription subscription;
-// subscription.set_topic("topicName");
-// subscription.set_name("subscriptionName");
-// subscription.push_config().set_push_endpoint("machinename:8888");
-// SubscriberService.CreateSubscription(subscription);
-//
-// Consuming messages via push:
-//
-// TODO(eschapira): Add HTTP push example.
-//
-// The port 'machinename:8888' must be bound to a stubby server that implements
-// the PushEndpointService with the following method:
-//
-// int HandlePubsubEvent(PubsubEvent event) {
-// if (event.subscription().equals("subscriptionName")) {
-// if (event.has_message()) {
-// Process(event.message().data());
-// } else if (event.truncated()) {
-// ProcessTruncatedEvent();
-// }
-// }
-// return OK; // This return code implies an acknowledgment
-// }
-//
-// Consuming messages via pull:
-//
-// The subscription must be created without setting the push_config field.
-//
-// PullRequest pull_request;
-// pull_request.set_subscription("subscriptionName");
-// pull_request.set_return_immediately(false);
-// while (true) {
-// PullResponse pull_response;
-// if (SubscriberService.Pull(pull_request, pull_response) == OK) {
-// PubsubEvent event = pull_response.pubsub_event();
-// if (event.has_message()) {
-// Process(event.message().data());
-// } else if (event.truncated()) {
-// ProcessTruncatedEvent();
-// }
-// AcknowledgeRequest ack_request;
-// ackRequest.set_subscription("subscriptionName");
-// ackRequest.set_ack_id(pull_response.ack_id());
-// SubscriberService.Acknowledge(ack_request);
-// }
-// }
-
-// -----------------------------------------------------------------------------
-// Reliability Semantics
-// -----------------------------------------------------------------------------
-
-// When a subscriber successfully creates a subscription using
-// Subscriber.CreateSubscription, it establishes a "subscription point" with
-// respect to that subscription - the subscriber is guaranteed to receive any
-// message published after this subscription point that matches the
-// subscription's query. Note that messages published before the Subscription
-// point may or may not be delivered.
-//
-// If the system truncates the subscription according to the specified
-// truncation policy, the system delivers a subscription status event with the
-// "truncated" field set to true. We refer to such events as "truncation
-// events". A truncation event:
-//
-// * Informs the subscriber that part of the subscription messages have been
-// discarded. The subscriber may want to recover from the message loss, e.g.,
-// by resyncing its state with its backend.
-// * Establishes a new subscription point, i.e., the subscriber is guaranteed to
-// receive all changes published after the trunction event is received (or
-// until another truncation event is received).
-//
-// Note that messages are not delivered in any particular order by the pubsub
-// system. Furthermore, the system guarantees at-least-once delivery
-// of each message or truncation events until acked.
-
-// -----------------------------------------------------------------------------
-// Deletion
-// -----------------------------------------------------------------------------
-
-// Both topics and subscriptions may be deleted. Deletion of a topic implies
-// deletion of all attached subscriptions.
-//
-// When a subscription is deleted directly by calling DeleteSubscription, all
-// messages are immediately dropped. If it is a pull subscriber, future pull
-// requests will return NOT_FOUND.
-//
-// When a topic is deleted all corresponding subscriptions are immediately
-// deleted, and subscribers experience the same behavior as directly deleting
-// the subscription.
-
-// -----------------------------------------------------------------------------
-// The Publisher service and its protos.
-// -----------------------------------------------------------------------------
-
-// The service that an application uses to manipulate topics, and to send
-// messages to a topic.
-service PublisherService {
-
- // Creates the given topic with the given name.
- rpc CreateTopic(Topic) returns (Topic) {
- }
-
- // Adds a message to the topic. Returns NOT_FOUND if the topic does not
- // exist.
- // (-- For different error code values returned via Stubby, see
- // util/task/codes.proto. --)
- rpc Publish(PublishRequest) returns (proto2.Empty) {
- }
-
- // Adds one or more messages to the topic. Returns NOT_FOUND if the topic does
- // not exist.
- rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse) {
- }
-
- // Gets the configuration of a topic. Since the topic only has the name
- // attribute, this method is only useful to check the existence of a topic.
- // If other attributes are added in the future, they will be returned here.
- rpc GetTopic(GetTopicRequest) returns (Topic) {
- }
-
- // Lists matching topics.
- rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) {
- }
-
- // Deletes the topic with the given name. All subscriptions to this topic
- // are also deleted. Returns NOT_FOUND if the topic does not exist.
- // After a topic is deleted, a new topic may be created with the same name.
- rpc DeleteTopic(DeleteTopicRequest) returns (proto2.Empty) {
- }
-}
-
-// A topic resource.
-message Topic {
- // Name of the topic.
- optional string name = 1;
-}
-
-// A message data and its labels.
-message PubsubMessage {
- // The message payload.
- optional bytes data = 1;
-
- // Optional list of labels for this message. Keys in this collection must
- // be unique.
- //(-- TODO(eschapira): Define how key namespace may be scoped to the topic.--)
- repeated tech.label.Label label = 2;
-
- // ID of this message assigned by the server at publication time. Guaranteed
- // to be unique within the topic. This value may be read by a subscriber
- // that receives a PubsubMessage via a Pull call or a push delivery. It must
- // not be populated by a publisher in a Publish call.
- optional string message_id = 3;
-}
-
-// Request for the GetTopic method.
-message GetTopicRequest {
- // The name of the topic to get.
- optional string topic = 1;
-}
-
-// Request for the Publish method.
-message PublishRequest {
- // The message in the request will be published on this topic.
- optional string topic = 1;
-
- // The message to publish.
- optional PubsubMessage message = 2;
-}
-
-// Request for the PublishBatch method.
-message PublishBatchRequest {
- // The messages in the request will be published on this topic.
- optional string topic = 1;
-
- // The messages to publish.
- repeated PubsubMessage messages = 2;
-}
-
-// Response for the PublishBatch method.
-message PublishBatchResponse {
- // The server-assigned ID of each published message, in the same order as
- // the messages in the request. IDs are guaranteed to be unique within
- // the topic.
- repeated string message_ids = 1;
-}
-
-// Request for the ListTopics method.
-message ListTopicsRequest {
- // A valid label query expression.
- //
- optional string query = 1;
-
- // Maximum number of topics to return.
- // (-- If not specified or <= 0, the implementation will select a reasonable
- // value. --)
- optional int32 max_results = 2;
-
- // The value obtained in the last <code>ListTopicsResponse</code>
- // for continuation.
- optional string page_token = 3;
-
-}
-
-// Response for the ListTopics method.
-message ListTopicsResponse {
- // The resulting topics.
- repeated Topic topic = 1;
-
- // If not empty, indicates that there are more topics that match the request,
- // and this value should be passed to the next <code>ListTopicsRequest</code>
- // to continue.
- optional string next_page_token = 2;
-}
-
-// Request for the Delete method.
-message DeleteTopicRequest {
- // Name of the topic to delete.
- optional string topic = 1;
-}
-
-// -----------------------------------------------------------------------------
-// The Subscriber service and its protos.
-// -----------------------------------------------------------------------------
-
-// The service that an application uses to manipulate subscriptions and to
-// consume messages from a subscription via the pull method.
-service SubscriberService {
-
- // Creates a subscription on a given topic for a given subscriber.
- // If the subscription already exists, returns ALREADY_EXISTS.
- // If the corresponding topic doesn't exist, returns NOT_FOUND.
- //
- // If the name is not provided in the request, the server will assign a random
- // name for this subscription on the same project as the topic.
- rpc CreateSubscription(Subscription) returns (Subscription) {
- }
-
- // Gets the configuration details of a subscription.
- rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) {
- }
-
- // Lists matching subscriptions.
- rpc ListSubscriptions(ListSubscriptionsRequest)
- returns (ListSubscriptionsResponse) {
- }
-
- // Deletes an existing subscription. All pending messages in the subscription
- // are immediately dropped. Calls to Pull after deletion will return
- // NOT_FOUND.
- rpc DeleteSubscription(DeleteSubscriptionRequest) returns (proto2.Empty) {
- }
-
- // Removes all the pending messages in the subscription and releases the
- // storage associated with them. Results in a truncation event to be sent to
- // the subscriber. Messages added after this call returns are stored in the
- // subscription as before.
- rpc TruncateSubscription(TruncateSubscriptionRequest) returns (proto2.Empty) {
- }
-
- //
- // Push subscriber calls.
- //
-
- // Modifies the <code>PushConfig</code> for a specified subscription.
- // This method can be used to suspend the flow of messages to an endpoint
- // by clearing the <code>PushConfig</code> field in the request. Messages
- // will be accumulated for delivery even if no push configuration is
- // defined or while the configuration is modified.
- rpc ModifyPushConfig(ModifyPushConfigRequest) returns (proto2.Empty) {
- }
-
- //
- // Pull Subscriber calls
- //
-
- // Pulls a single message from the server.
- // If return_immediately is true, and no messages are available in the
- // subscription, this method returns FAILED_PRECONDITION. The system is free
- // to return an UNAVAILABLE error if no messages are available in a
- // reasonable amount of time (to reduce system load).
- rpc Pull(PullRequest) returns (PullResponse) {
- }
-
- // Pulls messages from the server. Returns an empty list if there are no
- // messages available in the backlog. The system is free to return UNAVAILABLE
- // if there are too many pull requests outstanding for the given subscription.
- rpc PullBatch(PullBatchRequest) returns (PullBatchResponse) {
- }
-
- // Modifies the Ack deadline for a message received from a pull request.
- rpc ModifyAckDeadline(ModifyAckDeadlineRequest) returns (proto2.Empty) {
- }
-
- // Acknowledges a particular received message: the Pub/Sub system can remove
- // the given message from the subscription. Acknowledging a message whose
- // Ack deadline has expired may succeed, but the message could have been
- // already redelivered. Acknowledging a message more than once will not
- // result in an error. This is only used for messages received via pull.
- rpc Acknowledge(AcknowledgeRequest) returns (proto2.Empty) {
- }
-
- // Refuses processing a particular received message. The system will
- // redeliver this message to some consumer of the subscription at some
- // future time. This is only used for messages received via pull.
- rpc Nack(NackRequest) returns (proto2.Empty) {
- }
-}
-
-// A subscription resource.
-message Subscription {
- // Name of the subscription.
- optional string name = 1;
-
- // The name of the topic from which this subscription is receiving messages.
- optional string topic = 2;
-
- // If <code>query</code> is non-empty, only messages on the subscriber's
- // topic whose labels match the query will be returned. Otherwise all
- // messages on the topic will be returned.
- //
- optional string query = 3;
-
- // The subscriber may specify requirements for truncating unacknowledged
- // subscription entries. The system will honor the
- // <code>CreateSubscription</code> request only if it can meet these
- // requirements. If this field is not specified, messages are never truncated
- // by the system.
- optional TruncationPolicy truncation_policy = 4;
-
- // Specifies which messages can be truncated by the system.
- message TruncationPolicy {
- oneof policy {
- // If <code>max_bytes</code> is specified, the system is allowed to drop
- // old messages to keep the combined size of stored messages under
- // <code>max_bytes</code>. This is a hint; the system may keep more than
- // this many bytes, but will make a best effort to keep the size from
- // growing much beyond this parameter.
- int64 max_bytes = 1;
-
- // If <code>max_age_seconds</code> is specified, the system is allowed to
- // drop messages that have been stored for at least this many seconds.
- // This is a hint; the system may keep these messages, but will make a
- // best effort to remove them when their maximum age is reached.
- int64 max_age_seconds = 2;
- }
- }
-
- // If push delivery is used with this subscription, this field is
- // used to configure it.
- optional PushConfig push_config = 5;
-
- // For either push or pull delivery, the value is the maximum time after a
- // subscriber receives a message before the subscriber should acknowledge or
- // Nack the message. If the Ack deadline for a message passes without an
- // Ack or a Nack, the Pub/Sub system will eventually redeliver the message.
- // If a subscriber acknowledges after the deadline, the Pub/Sub system may
- // accept the Ack, but it is possible that the message has been already
- // delivered again. Multiple Acks to the message are allowed and will
- // succeed.
- //
- // For push delivery, this value is used to set the request timeout for
- // the call to the push endpoint.
- //
- // For pull delivery, this value is used as the initial value for the Ack
- // deadline. It may be overridden for a specific pull request (message) with
- // <code>ModifyAckDeadline</code>.
- // While a message is outstanding (i.e. it has been delivered to a pull
- // subscriber and the subscriber has not yet Acked or Nacked), the Pub/Sub
- // system will not deliver that message to another pull subscriber
- // (on a best-effort basis).
- optional int32 ack_deadline_seconds = 6;
-
- // If this parameter is set to n, the system is allowed to (but not required
- // to) delete the subscription when at least n seconds have elapsed since the
- // client presence was detected. (Presence is detected through any
- // interaction using the subscription ID, including Pull(), Get(), or
- // acknowledging a message.)
- //
- // If this parameter is not set, the subscription will stay live until
- // explicitly deleted.
- //
- // Clients can detect such garbage collection when a Get call or a Pull call
- // (for pull subscribers only) returns NOT_FOUND.
- optional int64 garbage_collect_seconds = 7;
-}
-
-// Configuration for a push delivery endpoint.
-message PushConfig {
- // A URL locating the endpoint to which messages should be pushed.
- // For example, a Webhook endpoint might use "https://example.com/push".
- // (-- An Android application might use "gcm:<REGID>", where <REGID> is a
- // GCM registration id allocated for pushing messages to the application. --)
- optional string push_endpoint = 1;
-}
-
-// An event indicating a received message or truncation event.
-message PubsubEvent {
- // The subscription that received the event.
- optional string subscription = 1;
-
- oneof type {
- // A received message.
- PubsubMessage message = 2;
-
- // Indicates that this subscription has been truncated.
- bool truncated = 3;
-
- // Indicates that this subscription has been deleted. (Note that pull
- // subscribers will always receive NOT_FOUND in response in their pull
- // request on the subscription, rather than seeing this boolean.)
- bool deleted = 4;
- }
-}
-
-// Request for the GetSubscription method.
-message GetSubscriptionRequest {
- // The name of the subscription to get.
- optional string subscription = 1;
-}
-
-// Request for the ListSubscriptions method.
-message ListSubscriptionsRequest {
- // A valid label query expression.
- // (-- Which labels are required or supported is implementation-specific.
- // TODO(eschapira): This method must support to query by topic. We must
- // define the key URI for the "topic" label. --)
- optional string query = 1;
-
- // Maximum number of subscriptions to return.
- // (-- If not specified or <= 0, the implementation will select a reasonable
- // value. --)
- optional int32 max_results = 3;
-
- // The value obtained in the last <code>ListSubscriptionsResponse</code>
- // for continuation.
- optional string page_token = 4;
-}
-
-// Response for the ListSubscriptions method.
-message ListSubscriptionsResponse {
- // The subscriptions that match the request.
- repeated Subscription subscription = 1;
-
- // If not empty, indicates that there are more subscriptions that match the
- // request and this value should be passed to the next
- // <code>ListSubscriptionsRequest</code> to continue.
- optional string next_page_token = 2;
-}
-
-// Request for the TruncateSubscription method.
-message TruncateSubscriptionRequest {
- // The subscription that is being truncated.
- optional string subscription = 1;
-}
-
-// Request for the DeleteSubscription method.
-message DeleteSubscriptionRequest {
- // The subscription to delete.
- optional string subscription = 1;
-}
-
-// Request for the ModifyPushConfig method.
-message ModifyPushConfigRequest {
- // The name of the subscription.
- optional string subscription = 1;
-
- // An empty <code>push_config</code> indicates that the Pub/Sub system should
- // pause pushing messages from the given subscription.
- optional PushConfig push_config = 2;
-}
-
-// -----------------------------------------------------------------------------
-// The protos used by a pull subscriber.
-// -----------------------------------------------------------------------------
-
-// Request for the Pull method.
-message PullRequest {
- // The subscription from which a message should be pulled.
- optional string subscription = 1;
-
- // If this is specified as true the system will respond immediately even if
- // it is not able to return a message in the Pull response. Otherwise the
- // system is allowed to wait until at least one message is available rather
- // than returning FAILED_PRECONDITION. The client may cancel the request if
- // it does not wish to wait any longer for the response.
- optional bool return_immediately = 2;
-}
-
-// Either a <code>PubsubMessage</code> or a truncation event. One of these two
-// must be populated.
-message PullResponse {
- // This ID must be used to acknowledge the received event or message.
- optional string ack_id = 1;
-
- // A pubsub message or truncation event.
- optional PubsubEvent pubsub_event = 2;
-}
-
-// Request for the PullBatch method.
-message PullBatchRequest {
- // The subscription from which messages should be pulled.
- optional string subscription = 1;
-
- // If this is specified as true the system will respond immediately even if
- // it is not able to return a message in the Pull response. Otherwise the
- // system is allowed to wait until at least one message is available rather
- // than returning no messages. The client may cancel the request if it does
- // not wish to wait any longer for the response.
- optional bool return_immediately = 2;
-
- // The maximum number of PubsubEvents returned for this request. The Pub/Sub
- // system may return fewer than the number of events specified.
- optional int32 max_events = 3;
-}
-
-// Response for the PullBatch method.
-message PullBatchResponse {
-
- // Received Pub/Sub messages or status events. The Pub/Sub system will return
- // zero messages if there are no more messages available in the backlog. The
- // Pub/Sub system may return fewer than the max_events requested even if
- // there are more messages available in the backlog.
- repeated PullResponse pull_responses = 2;
-}
-
-// Request for the ModifyAckDeadline method.
-message ModifyAckDeadlineRequest {
- // The name of the subscription from which messages are being pulled.
- optional string subscription = 1;
-
- // The acknowledgment ID.
- optional string ack_id = 2;
-
- // The new Ack deadline. Must be >= 0.
- optional int32 ack_deadline_seconds = 3;
-}
-
-// Request for the Acknowledge method.
-message AcknowledgeRequest {
- // The subscription whose message is being acknowledged.
- optional string subscription = 1;
-
- // The acknowledgment ID for the message being acknowledged. This was
- // returned by the Pub/Sub system in the Pull response.
- repeated string ack_id = 2;
-}
-
-// Request for the Nack method.
-message NackRequest {
- // The subscription whose message is being Nacked.
- optional string subscription = 1;
-
- // The acknowledgment ID for the message being refused. This was returned by
- // the Pub/Sub system in the Pull response.
- repeated string ack_id = 2;
-}
-
-// -----------------------------------------------------------------------------
-// The service and protos used by a push subscriber.
-// -----------------------------------------------------------------------------
-
-// The service that a subscriber uses to handle messages sent via push
-// delivery.
-// This service is not currently exported for HTTP clients.
-// TODO(eschapira): Explain HTTP subscribers.
-service PushEndpointService {
- // Sends a <code>PubsubMessage</code> or a subscription status event to a
- // push endpoint.
- // The push endpoint responds with an empty message and a code from
- // util/task/codes.proto. The following codes have a particular meaning to the
- // Pub/Sub system:
- // OK - This is interpreted by Pub/Sub as Ack.
- // ABORTED - This is intepreted by Pub/Sub as a Nack, without implying
- // pushback for congestion control. The Pub/Sub system will
- // retry this message at a later time.
- // UNAVAILABLE - This is intepreted by Pub/Sub as a Nack, with the additional
- // semantics of push-back. The Pub/Sub system will use an AIMD
- // congestion control algorithm to backoff the rate of sending
- // messages from this subscription.
- // Any other code, or a failure to respond, will be interpreted in the same
- // way as ABORTED; i.e. the system will retry the message at a later time to
- // ensure reliable delivery.
- rpc HandlePubsubEvent(PubsubEvent) returns (proto2.Empty);
-}
diff --git a/src/node/examples/pubsub/pubsub_demo.js b/src/node/examples/pubsub/pubsub_demo.js
deleted file mode 100644
index 26301515f0..0000000000
--- a/src/node/examples/pubsub/pubsub_demo.js
+++ /dev/null
@@ -1,285 +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 GoogleAuth = require('google-auth-library');
-var parseArgs = require('minimist');
-var strftime = require('strftime');
-var _ = require('underscore');
-var grpc = require('../..');
-var PROTO_PATH = __dirname + '/pubsub.proto';
-var pubsub = grpc.load(PROTO_PATH).tech.pubsub;
-
-function PubsubRunner(pub, sub, args) {
- this.pub = pub;
- this.sub = sub;
- this.args = args;
-}
-
-PubsubRunner.prototype.getTestTopicName = function() {
- var base_name = '/topics/' + this.args.project_id + '/';
- if (this.args.topic_name) {
- return base_name + this.args.topic_name;
- }
- var now_text = strftime('%Y%m%d%H%M%S%L');
- return base_name + process.env.USER + '-' + now_text;
-};
-
-PubsubRunner.prototype.getTestSubName = function() {
- var base_name = '/subscriptions/' + this.args.project_id + '/';
- if (this.args.sub_name) {
- return base_name + this.args.sub_name;
- }
- var now_text = strftime('%Y%m%d%H%M%S%L');
- return base_name + process.env.USER + '-' + now_text;
-};
-
-PubsubRunner.prototype.listProjectTopics = function(callback) {
- var q = ('cloud.googleapis.com/project in (/projects/' +
- this.args.project_id + ')');
- this.pub.listTopics({query: q}, callback);
-};
-
-PubsubRunner.prototype.topicExists = function(name, callback) {
- this.listProjectTopics(function(err, response) {
- if (err) {
- callback(err);
- } else {
- callback(null, _.some(response.topic, function(t) {
- return t.name === name;
- }));
- }
- });
-};
-
-PubsubRunner.prototype.createTopicIfNeeded = function(name, callback) {
- var self = this;
- this.topicExists(name, function(err, exists) {
- if (err) {
- callback(err);
- } else{
- if (exists) {
- callback(null);
- } else {
- self.pub.createTopic({name: name}, callback);
- }
- }
- });
-};
-
-PubsubRunner.prototype.removeTopic = function(callback) {
- var name = this.getTestTopicName();
- console.log('... removing Topic', name);
- this.pub.deleteTopic({topic: name}, function(err, value) {
- if (err) {
- console.log('Could not delete a topic: rpc failed with', err);
- callback(err);
- } else {
- console.log('removed Topic', name, 'OK');
- callback(null);
- }
- });
-};
-
-PubsubRunner.prototype.createTopic = function(callback) {
- var name = this.getTestTopicName();
- console.log('... creating Topic', name);
- this.pub.createTopic({name: name}, function(err, value) {
- if (err) {
- console.log('Could not create a topic: rpc failed with', err);
- callback(err);
- } else {
- console.log('created Topic', name, 'OK');
- callback(null);
- }
- });
-};
-
-PubsubRunner.prototype.listSomeTopics = function(callback) {
- console.log('Listing topics');
- console.log('-------------_');
- this.listProjectTopics(function(err, response) {
- if (err) {
- console.log('Could not list topic: rpc failed with', err);
- callback(err);
- } else {
- _.each(response.topic, function(t) {
- console.log(t.name);
- });
- callback(null);
- }
- });
-};
-
-PubsubRunner.prototype.checkExists = function(callback) {
- var name = this.getTestTopicName();
- console.log('... checking for topic', name);
- this.topicExists(name, function(err, exists) {
- if (err) {
- console.log('Could not check for a topics: rpc failed with', err);
- callback(err);
- } else {
- if (exists) {
- console.log(name, 'is a topic');
- } else {
- console.log(name, 'is not a topic');
- }
- callback(null);
- }
- });
-};
-
-PubsubRunner.prototype.randomPubSub = function(callback) {
- var self = this;
- var topic_name = this.getTestTopicName();
- var sub_name = this.getTestSubName();
- var subscription = {name: sub_name, topic: topic_name};
- async.waterfall([
- _.bind(this.createTopicIfNeeded, this, topic_name),
- _.bind(this.sub.createSubscription, this.sub, subscription),
- function(resp, cb) {
- var msg_count = _.random(10, 30);
- // Set up msg_count messages to publish
- var message_senders = _.times(msg_count, function(n) {
- return _.bind(self.pub.publish, self.pub, {
- topic: topic_name,
- message: {data: new Buffer('message ' + n)}
- });
- });
- async.parallel(message_senders, function(err, result) {
- cb(err, result, msg_count);
- });
- },
- function(result, msg_count, cb) {
- console.log('Sent', msg_count, 'messages to', topic_name + ',',
- 'checking for them now.');
- var batch_request = {
- subscription: sub_name,
- max_events: msg_count
- };
- self.sub.pullBatch(batch_request, cb);
- },
- function(batch, cb) {
- var ack_id = _.pluck(batch.pull_responses, 'ack_id');
- console.log('Got', ack_id.length, 'messages, acknowledging them...');
- var ack_request = {
- subscription: sub_name,
- ack_id: ack_id
- };
- self.sub.acknowledge(ack_request, cb);
- },
- function(result, cb) {
- console.log(
- 'Test messages were acknowledged OK, deleting the subscription');
- self.sub.deleteSubscription({subscription: sub_name}, cb);
- }
- ], function (err, result) {
- if (err) {
- console.log('Could not do random pub sub: rpc failed with', err);
- }
- callback(err, result);
- });
-};
-
-function main(callback) {
- var argv = parseArgs(process.argv, {
- string: [
- 'host',
- 'oauth_scope',
- 'port',
- 'action',
- 'project_id',
- 'topic_name',
- 'sub_name'
- ],
- default: {
- host: 'pubsub-staging.googleapis.com',
- oauth_scope: 'https://www.googleapis.com/auth/pubsub',
- port: 443,
- action: 'listSomeTopics',
- project_id: 'stoked-keyword-656'
- }
- });
- var valid_actions = [
- 'createTopic',
- 'removeTopic',
- 'listSomeTopics',
- 'checkExists',
- 'randomPubSub'
- ];
- if (_.some(valid_actions, function(action) {
- return action === argv.action;
- })) {
- callback(new Error('Action was not valid'));
- }
- var address = argv.host + ':' + argv.port;
- (new GoogleAuth()).getApplicationDefault(function(err, credential) {
- if (err) {
- callback(err);
- return;
- }
- if (credential.createScopedRequired()) {
- credential = credential.createScoped(argv.oauth_scope);
- }
- var updateMetadata = grpc.getGoogleAuthDelegate(credential);
- var ca_path = process.env.SSL_CERT_FILE;
- fs.readFile(ca_path, function(err, ca_data) {
- if (err) {
- callback(err);
- return;
- }
- var ssl_creds = grpc.Credentials.createSsl(ca_data);
- var options = {
- credentials: ssl_creds,
- 'grpc.ssl_target_name_override': argv.host
- };
- var pub = new pubsub.PublisherService(address, options, updateMetadata);
- var sub = new pubsub.SubscriberService(address, options, updateMetadata);
- var runner = new PubsubRunner(pub, sub, argv);
- runner[argv.action](callback);
- });
- });
-}
-
-if (require.main === module) {
- main(function(err) {
- if (err) {
- throw err;
- }
- });
-}
-
-module.exports = PubsubRunner;
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index 82b54b518c..01bd92ea52 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -32,7 +32,6 @@
*/
#include <string.h>
-#include <malloc.h>
#include <node.h>
#include <nan.h>
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 787e274973..d37bf763dd 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -31,8 +31,6 @@
*
*/
-#include <malloc.h>
-
#include <vector>
#include <node.h>
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_async_worker.cc
index cd7acd1d1b..4e57121a85 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_async_worker.cc
@@ -43,6 +43,8 @@
namespace grpc {
namespace node {
+const int max_queue_threads = 2;
+
using v8::Function;
using v8::Handle;
using v8::Object;
@@ -51,6 +53,9 @@ using v8::Value;
grpc_completion_queue *CompletionQueueAsyncWorker::queue;
+int CompletionQueueAsyncWorker::current_threads;
+int CompletionQueueAsyncWorker::waiting_next_calls;
+
CompletionQueueAsyncWorker::CompletionQueueAsyncWorker()
: NanAsyncWorker(NULL) {}
@@ -67,17 +72,30 @@ grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
void CompletionQueueAsyncWorker::Next() {
NanScope();
- CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
- NanAsyncQueueWorker(worker);
+ if (current_threads < max_queue_threads) {
+ CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
+ NanAsyncQueueWorker(worker);
+ } else {
+ waiting_next_calls += 1;
+ }
}
void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
NanScope();
+ current_threads = 0;
+ waiting_next_calls = 0;
queue = grpc_completion_queue_create();
}
void CompletionQueueAsyncWorker::HandleOKCallback() {
NanScope();
+ if (waiting_next_calls > 0) {
+ waiting_next_calls -= 1;
+ CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
+ NanAsyncQueueWorker(worker);
+ } else {
+ current_threads -= 1;
+ }
NanCallback *callback = GetTagCallback(result->tag);
Handle<Value> argv[] = {NanNull(), GetTagNodeValue(result->tag)};
callback->Call(2, argv);
diff --git a/src/node/ext/completion_queue_async_worker.h b/src/node/ext/completion_queue_async_worker.h
index 0ddb5b4cfd..5d52bbb1fb 100644
--- a/src/node/ext/completion_queue_async_worker.h
+++ b/src/node/ext/completion_queue_async_worker.h
@@ -73,6 +73,11 @@ class CompletionQueueAsyncWorker : public NanAsyncWorker {
grpc_event *result;
static grpc_completion_queue *queue;
+
+ // Number of grpc_completion_queue_next calls in the thread pool
+ static int current_threads;
+ // Number of grpc_completion_queue_next calls waiting to enter the thread pool
+ static int waiting_next_calls;
};
} // namespace node
diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc
index e47bac833b..3c2396b810 100644
--- a/src/node/ext/server.cc
+++ b/src/node/ext/server.cc
@@ -38,8 +38,6 @@
#include <node.h>
#include <nan.h>
-#include <malloc.h>
-
#include <vector>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
diff --git a/src/node/index.js b/src/node/index.js
index 0b768edc6b..875756328d 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -67,10 +67,25 @@ function loadObject(value) {
/**
* Load a gRPC object from a .proto file.
* @param {string} filename The file to load
+ * @param {string=} format The file format to expect. Must be either 'proto' or
+ * 'json'. Defaults to 'proto'
* @return {Object<string, *>} The resulting gRPC object
*/
-function load(filename) {
- var builder = ProtoBuf.loadProtoFile(filename);
+function load(filename, format) {
+ if (!format) {
+ format = 'proto';
+ }
+ var builder;
+ switch(format) {
+ case 'proto':
+ builder = ProtoBuf.loadProtoFile(filename);
+ break;
+ case 'json':
+ builder = ProtoBuf.loadJsonFile(filename);
+ break;
+ default:
+ throw new Error('Unrecognized format "' + format + '"');
+ }
return loadObject(builder.ns);
}
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 77804cf595..3341486b9e 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -318,8 +318,8 @@ var test_cases = {
empty_stream: emptyStream,
cancel_after_begin: cancelAfterBegin,
cancel_after_first_response: cancelAfterFirstResponse,
- compute_engine_creds: _.partial(authTest, AUTH_USER),
- service_account_creds: _.partial(authTest, COMPUTE_ENGINE_USER)
+ compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER),
+ service_account_creds: _.partial(authTest, AUTH_USER)
};
/**
diff --git a/src/node/package.json b/src/node/package.json
index 9f52f8c988..6c0953a83f 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
{
"name": "grpc",
- "version": "0.6.0",
+ "version": "0.6.2",
"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 c46f7d0526..fad369c2f8 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -241,13 +241,13 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
callback(err);
return;
}
+ emitter.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
error.code = response.status.code;
callback(error);
return;
}
- emitter.emit('status', response.status);
emitter.emit('metadata', response.metadata);
callback(null, deserialize(response.read));
});
@@ -312,13 +312,13 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
callback(err);
return;
}
+ stream.emit('status', response.status);
if (response.status.code !== grpc.status.OK) {
var error = new Error(response.status.details);
error.code = response.status.code;
callback(error);
return;
}
- stream.emit('status', response.status);
callback(null, deserialize(response.read));
});
});
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 8a26a43606..eef705c44c 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -70,6 +70,9 @@ function handleError(call, error) {
status.details = error.details;
}
}
+ if (error.hasOwnProperty('metadata')) {
+ status.metadata = error.metadata;
+ }
var error_batch = {};
error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
call.startBatch(error_batch, function(){});
@@ -102,15 +105,20 @@ 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
*/
-function sendUnaryResponse(call, value, serialize) {
+function sendUnaryResponse(call, value, serialize, metadata) {
var end_batch = {};
- end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
- end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ var status = {
code: grpc.status.OK,
details: 'OK',
metadata: {}
};
+ if (metadata) {
+ status.metadata = metadata;
+ }
+ end_batch[grpc.opType.SEND_MESSAGE] = serialize(value);
+ end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
call.startBatch(end_batch, function (){});
}
@@ -143,6 +151,7 @@ function setUpWritable(stream, serialize) {
function setStatus(err) {
var code = grpc.status.INTERNAL;
var details = 'Unknown Error';
+ var metadata = {};
if (err.hasOwnProperty('message')) {
details = err.message;
}
@@ -152,7 +161,10 @@ function setUpWritable(stream, serialize) {
details = err.details;
}
}
- stream.status = {code: code, details: details, metadata: {}};
+ if (err.hasOwnProperty('metadata')) {
+ metadata = err.metadata;
+ }
+ stream.status = {code: code, details: details, metadata: metadata};
}
/**
* Terminate the call. This includes indicating that reads are done, draining
@@ -166,6 +178,17 @@ function setUpWritable(stream, serialize) {
stream.end();
}
stream.on('error', terminateCall);
+ /**
+ * Override of Writable#end method that allows for sending metadata with a
+ * success status.
+ * @param {Object=} metadata Metadata to send with the status
+ */
+ stream.end = function(metadata) {
+ if (metadata) {
+ stream.status.metadata = metadata;
+ }
+ Writable.prototype.end.call(this);
+ };
}
/**
@@ -335,11 +358,15 @@ function handleUnary(call, handler, metadata) {
if (emitter.cancelled) {
return;
}
- handler.func(emitter, function sendUnaryData(err, value) {
+ handler.func(emitter, function sendUnaryData(err, value, trailer) {
if (err) {
+ if (trailer) {
+ err.metadata = trailer;
+ }
handleError(call, err);
+ } else {
+ sendUnaryResponse(call, value, handler.serialize, trailer);
}
- sendUnaryResponse(call, value, handler.serialize);
});
});
}
@@ -378,12 +405,16 @@ function handleClientStreaming(call, handler, metadata) {
var metadata_batch = {};
metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
call.startBatch(metadata_batch, function() {});
- handler.func(stream, function(err, value) {
+ handler.func(stream, function(err, value, trailer) {
stream.terminate();
if (err) {
+ if (trailer) {
+ err.metadata = trailer;
+ }
handleError(call, err);
+ } else {
+ sendUnaryResponse(call, value, handler.serialize, trailer);
}
- sendUnaryResponse(call, value, handler.serialize);
});
}
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index d83f64116f..79df97871b 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -68,6 +68,13 @@ describe('Math client', function() {
done();
});
});
+ it('should handle an error from a unary request', function(done) {
+ var arg = {dividend: 7, divisor: 0};
+ math_client.div(arg, function handleDivResult(err, value) {
+ assert(err);
+ done();
+ });
+ });
it('should handle a server streaming request', function(done) {
var call = math_client.fib({limit: 7});
var expected_results = [1, 1, 2, 3, 5, 8, 13];
@@ -115,4 +122,17 @@ describe('Math client', function() {
done();
});
});
+ it('should handle an error from a bidi request', function(done) {
+ var call = math_client.divMany();
+ call.on('data', function(value) {
+ assert.fail(value, undefined, 'Unexpected data response on failing call',
+ '!=');
+ });
+ call.write({dividend: 7, divisor: 0});
+ call.end();
+ call.on('status', function checkStatus(status) {
+ assert.notEqual(status.code, grpc.status.OK);
+ done();
+ });
+ });
});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 96b47815e1..6f63f1044f 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -47,6 +47,28 @@ var mathService = math_proto.lookup('math.Math');
var capitalize = require('underscore.string/capitalize');
+describe('File loader', function() {
+ it('Should load a proto file by default', function() {
+ assert.doesNotThrow(function() {
+ grpc.load(__dirname + '/test_service.proto');
+ });
+ });
+ it('Should load a proto file with the proto format', function() {
+ assert.doesNotThrow(function() {
+ grpc.load(__dirname + '/test_service.proto', 'proto');
+ });
+ });
+ it('Should load a json file with the json format', function() {
+ assert.doesNotThrow(function() {
+ grpc.load(__dirname + '/test_service.json', 'json');
+ });
+ });
+ it('Should fail to load a file with an unknown format', function() {
+ assert.throws(function() {
+ grpc.load(__dirname + '/test_service.proto', 'fake_format');
+ });
+ });
+});
describe('Surface server constructor', function() {
it('Should fail with conflicting method names', function() {
assert.throws(function() {
@@ -126,6 +148,167 @@ describe('Generic client and server', function() {
});
});
});
+describe('Trailing metadata', function() {
+ var client;
+ var server;
+ before(function() {
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+ var test_service = test_proto.lookup('TestService');
+ var Server = grpc.buildServer([test_service]);
+ server = new Server({
+ TestService: {
+ unary: function(call, cb) {
+ var req = call.request;
+ if (req.error) {
+ cb(new Error('Requested error'), null, {metadata: ['yes']});
+ } else {
+ cb(null, {count: 1}, {metadata: ['yes']});
+ }
+ },
+ clientStream: function(stream, cb){
+ var count = 0;
+ var errored;
+ stream.on('data', function(data) {
+ if (data.error) {
+ errored = true;
+ cb(new Error('Requested error'), null, {metadata: ['yes']});
+ } else {
+ count += 1;
+ }
+ });
+ stream.on('end', function() {
+ if (!errored) {
+ cb(null, {count: count}, {metadata: ['yes']});
+ }
+ });
+ },
+ serverStream: function(stream) {
+ var req = stream.request;
+ if (req.error) {
+ var err = new Error('Requested error');
+ err.metadata = {metadata: ['yes']};
+ stream.emit('error', err);
+ } else {
+ for (var i = 0; i < 5; i++) {
+ stream.write({count: i});
+ }
+ stream.end({metadata: ['yes']});
+ }
+ },
+ bidiStream: function(stream) {
+ var count = 0;
+ stream.on('data', function(data) {
+ if (data.error) {
+ var err = new Error('Requested error');
+ err.metadata = {
+ metadata: ['yes'],
+ count: ['' + count]
+ };
+ stream.emit('error', err);
+ } else {
+ stream.write({count: count});
+ count += 1;
+ }
+ });
+ stream.on('end', function() {
+ stream.end({metadata: ['yes']});
+ });
+ }
+ }
+ });
+ var port = server.bind('localhost:0');
+ var Client = surface_client.makeProtobufClientConstructor(test_service);
+ client = new Client('localhost:' + port);
+ server.listen();
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('should be present when a unary call succeeds', function(done) {
+ var call = client.unary({error: false}, function(err, data) {
+ assert.ifError(err);
+ });
+ call.on('status', function(status) {
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a unary call fails', function(done) {
+ var call = client.unary({error: true}, function(err, data) {
+ assert(err);
+ });
+ call.on('status', function(status) {
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a client stream call succeeds', function(done) {
+ var call = client.clientStream(function(err, data) {
+ assert.ifError(err);
+ });
+ call.write({error: false});
+ call.write({error: false});
+ call.end();
+ call.on('status', function(status) {
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a client stream call fails', function(done) {
+ var call = client.clientStream(function(err, data) {
+ assert(err);
+ });
+ call.write({error: false});
+ call.write({error: true});
+ call.end();
+ call.on('status', function(status) {
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a server stream call succeeds', function(done) {
+ var call = client.serverStream({error: false});
+ call.on('data', function(){});
+ call.on('status', function(status) {
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a server stream call fails', function(done) {
+ var call = client.serverStream({error: true});
+ call.on('data', function(){});
+ call.on('status', function(status) {
+ assert.notStrictEqual(status.code, grpc.status.OK);
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a bidi stream succeeds', function(done) {
+ var call = client.bidiStream();
+ call.write({error: false});
+ call.write({error: false});
+ call.end();
+ call.on('data', function(){});
+ call.on('status', function(status) {
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+ it('should be present when a bidi stream fails', function(done) {
+ var call = client.bidiStream();
+ call.write({error: false});
+ call.write({error: true});
+ call.end();
+ call.on('data', function(){});
+ call.on('status', function(status) {
+ assert.notStrictEqual(status.code, grpc.status.OK);
+ assert.deepEqual(status.metadata.metadata, ['yes']);
+ done();
+ });
+ });
+});
describe('Cancelling surface client', function() {
var client;
var server;
diff --git a/src/node/test/test_service.json b/src/node/test/test_service.json
new file mode 100644
index 0000000000..6f952c6ad2
--- /dev/null
+++ b/src/node/test/test_service.json
@@ -0,0 +1,55 @@
+{
+ "package": null,
+ "messages": [
+ {
+ "name": "Request",
+ "fields": [
+ {
+ "rule": "optional",
+ "type": "bool",
+ "name": "error",
+ "id": 1
+ }
+ ]
+ },
+ {
+ "name": "Response",
+ "fields": [
+ {
+ "rule": "optional",
+ "type": "int32",
+ "name": "count",
+ "id": 1
+ }
+ ]
+ }
+ ],
+ "services": [
+ {
+ "name": "TestService",
+ "options": {},
+ "rpc": {
+ "Unary": {
+ "request": "Request",
+ "response": "Response",
+ "options": {}
+ },
+ "ClientStream": {
+ "request": "Request",
+ "response": "Response",
+ "options": {}
+ },
+ "ServerStream": {
+ "request": "Request",
+ "response": "Response",
+ "options": {}
+ },
+ "BidiStream": {
+ "request": "Request",
+ "response": "Response",
+ "options": {}
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/src/node/test/test_service.proto b/src/node/test/test_service.proto
new file mode 100644
index 0000000000..5d3d891841
--- /dev/null
+++ b/src/node/test/test_service.proto
@@ -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.
+
+syntax = "proto2";
+
+message Request {
+ optional bool error = 1;
+}
+
+message Response {
+ optional int32 count = 1;
+}
+
+service TestService {
+ rpc Unary (Request) returns (Response) {
+ }
+
+ rpc ClientStream (stream Request) returns (Response) {
+ }
+
+ rpc ServerStream (Request) returns (stream Response) {
+ }
+
+ rpc BidiStream (stream Request) returns (stream Response) {
+ }
+} \ No newline at end of file
diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h
index 3a18db6137..81b409b9ff 100644
--- a/src/objective-c/GRPCClient/GRPCCall.h
+++ b/src/objective-c/GRPCClient/GRPCCall.h
@@ -32,7 +32,7 @@
*/
#import <Foundation/Foundation.h>
-#import <RxLibrary/GRXWriter.h>
+#import <gRPC/GRXWriter.h>
@class GRPCMethodName;
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index f246b81e63..989ce390e2 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -33,8 +33,8 @@
#import "GRPCCall.h"
-#include <grpc.h>
-#include <support/time.h>
+#include <grpc/grpc.h>
+#include <grpc/support/grpc_time.h>
#import "GRPCMethodName.h"
#import "private/GRPCChannel.h"
diff --git a/src/objective-c/GRPCClient/GRPCClient.podspec b/src/objective-c/GRPCClient/GRPCClient.podspec
deleted file mode 100644
index a34c50b54e..0000000000
--- a/src/objective-c/GRPCClient/GRPCClient.podspec
+++ /dev/null
@@ -1,14 +0,0 @@
-Pod::Spec.new do |s|
- s.name = 'GRPCClient'
- s.version = '0.0.1'
- s.summary = 'Generic gRPC client library for iOS'
- s.author = {
- 'Jorge Canizales' => 'jcanizales@google.com'
- }
- s.source_files = '*.{h,m}', 'private/*.{h,m}'
- s.private_header_files = 'private/*.h'
- s.platform = :ios
- s.ios.deployment_target = '6.0'
- s.requires_arc = true
- s.dependency 'RxLibrary', '~> 0.0'
-end
diff --git a/src/objective-c/GRPCClient/GRPCMethodName.h b/src/objective-c/GRPCClient/GRPCMethodName.h
index dcad8a3347..fe153dd478 100644
--- a/src/objective-c/GRPCClient/GRPCMethodName.h
+++ b/src/objective-c/GRPCClient/GRPCMethodName.h
@@ -37,7 +37,8 @@
// A fully-qualified gRPC method name. Full qualification is needed because a gRPC endpoint can
// implement multiple interfaces.
-// TODO(jcanizales): Is this proto-specific, or actual part of gRPC? If the former, move one layer up.
+// TODO(jcanizales): Move to ProtoRPC package.
+// TODO(jcanizales): Rename interface -> service.
@interface GRPCMethodName : NSObject
@property(nonatomic, readonly) NSString *package;
@property(nonatomic, readonly) NSString *interface;
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 2e07dcc3c7..bc6a47d469 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -45,6 +45,7 @@ struct grpc_channel;
// Convenience constructor to allow for reuse of connections.
+ (instancetype)channelToHost:(NSString *)host;
-// Designated initializer
-- (instancetype)initWithHost:(NSString *)host;
+- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index c8fa69ef91..8b7055815d 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -33,7 +33,10 @@
#import "GRPCChannel.h"
-#import <grpc.h>
+#include <grpc/grpc.h>
+
+#import "GRPCSecureChannel.h"
+#import "GRPCUnsecuredChannel.h"
@implementation GRPCChannel
@@ -46,20 +49,42 @@
return [self initWithHost:nil];
}
-// Designated initializer
- (instancetype)initWithHost:(NSString *)host {
- if (!host) {
- [NSException raise:NSInvalidArgumentException format:@"Host can't be nil."];
+ if (![host containsString:@"://"]) {
+ // No scheme provided; assume https.
+ host = [@"https://" stringByAppendingString:host];
+ }
+ NSURL *hostURL = [NSURL URLWithString:host];
+ if (!hostURL) {
+ [NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", host];
+ }
+ if ([hostURL.scheme isEqualToString:@"https"]) {
+ host = [@[hostURL.host, hostURL.port ?: @443] componentsJoinedByString:@":"];
+ return [[GRPCSecureChannel alloc] initWithHost:host];
+ }
+ if ([hostURL.scheme isEqualToString:@"http"]) {
+ host = [@[hostURL.host, hostURL.port ?: @80] componentsJoinedByString:@":"];
+ return [[GRPCUnsecuredChannel alloc] initWithHost:host];
}
+ [NSException raise:NSInvalidArgumentException
+ format:@"URL scheme %@ isn't supported.", hostURL.scheme];
+ return nil; // silence warning.
+}
+
+- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel {
if ((self = [super init])) {
- _unmanagedChannel = grpc_channel_create(host.UTF8String, NULL);
+ _unmanagedChannel = unmanagedChannel;
}
return self;
}
- (void)dealloc {
- // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
- // as in the past that made this call to crash.
- grpc_channel_destroy(_unmanagedChannel);
+ // _unmanagedChannel is NULL when deallocating an object of the base class (because the
+ // initializer returns a different object).
+ if (_unmanagedChannel) {
+ // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
+ // as in the past that made this call to crash.
+ grpc_channel_destroy(_unmanagedChannel);
+ }
}
@end
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index bc2a824a6b..b98e8ea439 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -33,7 +33,7 @@
#import "GRPCCompletionQueue.h"
-#import <grpc.h>
+#import <grpc/grpc.h>
@implementation GRPCCompletionQueue
diff --git a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m b/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
index 2a3a50f763..ac444ef406 100644
--- a/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
+++ b/src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
@@ -33,7 +33,7 @@
#import "GRPCDelegateWrapper.h"
-#import <RxLibrary/GRXWriteable.h>
+#import <gRPC/GRXWriteable.h>
@interface GRPCDelegateWrapper ()
// These are atomic so that cancellation can nillify them from any thread.
diff --git a/src/php/lib/autoload.php b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
index 42eb33d65b..d34ceaea0c 100755..100644
--- a/src/php/lib/autoload.php
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
@@ -1,4 +1,3 @@
-<?php
/*
*
* Copyright 2015, Google Inc.
@@ -31,23 +30,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-function grpcAutoloader($class) {
- $prefix = 'Grpc\\';
- $base_dir = __DIR__ . '/Grpc/';
+#import "GRPCChannel.h"
- $len = strlen($prefix);
- if (strncmp($prefix, $class, $len) !== 0) {
- return;
- }
+@interface GRPCSecureChannel : GRPCChannel
- $relative_class = substr($class, $len);
-
- $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
-
- if (file_exists($file)) {
- include $file;
- }
-}
-
-spl_autoload_register('grpcAutoloader');
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
new file mode 100644
index 0000000000..47bdfe3f28
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
@@ -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 "GRPCSecureChannel.h"
+
+#import <grpc/grpc_security.h>
+
+@implementation GRPCSecureChannel
+
+- (instancetype)initWithHost:(NSString *)host {
+ // TODO(jcanizales): Load certs only once.
+ NSURL *certsURL = [[NSBundle mainBundle] URLForResource:@"gRPC.bundle/roots" withExtension:@"pem"];
+ NSData *certsData = [NSData dataWithContentsOfURL:certsURL];
+ NSString *certsString = [[NSString alloc] initWithData:certsData encoding:NSUTF8StringEncoding];
+
+ grpc_credentials *credentials = grpc_ssl_credentials_create(certsString.UTF8String, NULL);
+ return (self = [super initWithChannel:grpc_secure_channel_create(credentials,
+ host.UTF8String,
+ NULL)]);
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
new file mode 100644
index 0000000000..9d89cfb541
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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 "GRPCChannel.h"
+
+@interface GRPCUnsecuredChannel : GRPCChannel
+
+@end
diff --git a/src/core/channel/http_filter.h b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
index 1b116ad61f..d27f7ca565 100644
--- a/src/core/channel/http_filter.h
+++ b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
@@ -31,13 +31,14 @@
*
*/
-#ifndef GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H
-#define GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H
+#import "GRPCUnsecuredChannel.h"
-#include "src/core/channel/channel_stack.h"
+#include <grpc/grpc.h>
-/* Processes metadata that is common to both client and server for HTTP2
- transports. */
-extern const grpc_channel_filter grpc_http_filter;
+@implementation GRPCUnsecuredChannel
-#endif /* GRPC_INTERNAL_CORE_CHANNEL_HTTP_FILTER_H */
+- (instancetype)initWithHost:(NSString *)host {
+ return (self = [super initWithChannel:grpc_channel_create(host.UTF8String, NULL)]);
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/NSData+GRPC.m b/src/objective-c/GRPCClient/private/NSData+GRPC.m
index f885e9db9c..5ab16d9d34 100644
--- a/src/objective-c/GRPCClient/private/NSData+GRPC.m
+++ b/src/objective-c/GRPCClient/private/NSData+GRPC.m
@@ -33,7 +33,7 @@
#import "NSData+GRPC.h"
-#include <byte_buffer.h>
+#include <grpc/byte_buffer.h>
#include <string.h>
// TODO(jcanizales): Move these two incantations to the C library.
diff --git a/src/cpp/util/time.h b/src/objective-c/ProtoRPC/ProtoRPC.h
index 8b7fcf55f7..b6375f52d6 100644
--- a/src/cpp/util/time.h
+++ b/src/objective-c/ProtoRPC/ProtoRPC.h
@@ -31,21 +31,16 @@
*
*/
-#ifndef GRPC_INTERNAL_CPP_UTIL_TIME_H
-#define GRPC_INTERNAL_CPP_UTIL_TIME_H
+#import <Foundation/Foundation.h>
+#import <gRPC/GRPCCall.h>
-#include <chrono>
+@interface ProtoRPC : GRPCCall
-#include <grpc/support/time.h>
+- (instancetype)initWithHost:(NSString *)host
+ method:(GRPCMethodName *)method
+ requestsWriter:(id<GRXWriter>)requestsWriter
+ responseClass:(Class)responseClass
+ responsesWriteable:(id<GRXWriteable>)responsesWriteable NS_DESIGNATED_INITIALIZER;
-namespace grpc {
-
-// from and to should be absolute time.
-void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
- gpr_timespec* to);
-
-std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
-
-} // namespace grpc
-
-#endif // GRPC_INTERNAL_CPP_UTIL_TIME_H
+- (void)start;
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoRPC.m b/src/objective-c/ProtoRPC/ProtoRPC.m
new file mode 100644
index 0000000000..6520b3af59
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoRPC.m
@@ -0,0 +1,91 @@
+/*
+ *
+ * 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 "ProtoRPC.h"
+
+#import <gRPC/GRXWriteable.h>
+#import <gRPC/GRXWriter.h>
+#import <gRPC/GRXWriter+Transformations.h>
+#import <ProtocolBuffers/ProtocolBuffers.h>
+
+@implementation ProtoRPC {
+ id<GRXWriteable> _responseWriteable;
+}
+
+- (instancetype)initWithHost:(NSString *)host
+ method:(GRPCMethodName *)method
+ requestsWriter:(id<GRXWriter>)requestsWriter {
+ return [self initWithHost:host
+ method:method
+ requestsWriter:requestsWriter
+ responseClass:nil
+ responsesWriteable:nil];
+}
+
+// Designated initializer
+- (instancetype)initWithHost:(NSString *)host
+ method:(GRPCMethodName *)method
+ requestsWriter:(id<GRXWriter>)requestsWriter
+ responseClass:(Class)responseClass
+ responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+ // Because we can't tell the type system to constrain the class, we need to check at runtime:
+ if (![responseClass respondsToSelector:@selector(parseFromData:)]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"A protobuf class to parse the responses must be provided."];
+ }
+ // A writer that serializes the proto messages to send.
+ id<GRXWriter> bytesWriter =
+ [[[GRXWriter alloc] initWithWriter:requestsWriter] map:^id(PBGeneratedMessage *proto) {
+ return [proto data];
+ }];
+ if ((self = [super initWithHost:host method:method requestsWriter:bytesWriter])) {
+ // A writeable that parses the proto messages received.
+ _responseWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ [responsesWriteable didReceiveValue:[responseClass parseFromData:value]];
+ } completionHandler:^(NSError *errorOrNil) {
+ [responsesWriteable didFinishWithError:errorOrNil];
+ }];
+ }
+ return self;
+}
+
+- (void)start {
+ [self startWithWriteable:_responseWriteable];
+}
+
+- (void)startWithWriteable:(id<GRXWriteable>)writeable {
+ [super startWithWriteable:writeable];
+ // Break retain cycles.
+ _responseWriteable = nil;
+}
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.h b/src/objective-c/ProtoRPC/ProtoService.h
new file mode 100644
index 0000000000..c5ef820f48
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoService.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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>
+
+@class ProtoRPC;
+@protocol GRXWriteable;
+@protocol GRXWriter;
+
+@interface ProtoService : NSObject
+- (instancetype)initWithHost:(NSString *)host
+ packageName:(NSString *)packageName
+ serviceName:(NSString *)serviceName NS_DESIGNATED_INITIALIZER;
+
+- (ProtoRPC *)RPCToMethod:(NSString *)method
+ requestsWriter:(id<GRXWriter>)requestsWriter
+ responseClass:(Class)responseClass
+ responsesWriteable:(id<GRXWriteable>)responsesWriteable;
+@end
diff --git a/src/objective-c/ProtoRPC/ProtoService.m b/src/objective-c/ProtoRPC/ProtoService.m
new file mode 100644
index 0000000000..453d7b3f1a
--- /dev/null
+++ b/src/objective-c/ProtoRPC/ProtoService.m
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "ProtoService.h"
+
+#import <gRPC/GRPCMethodName.h>
+#import <gRPC/GRXWriteable.h>
+#import <gRPC/GRXWriter.h>
+
+#import "ProtoRPC.h"
+
+@implementation ProtoService {
+ NSString *_host;
+ NSString *_packageName;
+ NSString *_serviceName;
+}
+
+- (instancetype)init {
+ return [self initWithHost:nil packageName:nil serviceName:nil];
+}
+
+// Designated initializer
+- (instancetype)initWithHost:(NSString *)host
+ packageName:(NSString *)packageName
+ serviceName:(NSString *)serviceName {
+ if (!host || !serviceName) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Neither host nor serviceName can be nil."];
+ }
+ if ((self = [super init])) {
+ _host = [host copy];
+ _packageName = [packageName copy];
+ _serviceName = [serviceName copy];
+ }
+ return self;
+}
+
+- (ProtoRPC *)RPCToMethod:(NSString *)method
+ requestsWriter:(id<GRXWriter>)requestsWriter
+ responseClass:(Class)responseClass
+ responsesWriteable:(id<GRXWriteable>)responsesWriteable {
+ GRPCMethodName *methodName = [[GRPCMethodName alloc] initWithPackage:_packageName
+ interface:_serviceName
+ method:method];
+ return [[ProtoRPC alloc] initWithHost:_host
+ method:methodName
+ requestsWriter:requestsWriter
+ responseClass:responseClass
+ responsesWriteable:responsesWriteable];
+}
+@end
diff --git a/src/objective-c/RxLibrary/GRXWriteable.h b/src/objective-c/RxLibrary/GRXWriteable.h
index cdcb99f459..6f6ea142e0 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.h
+++ b/src/objective-c/RxLibrary/GRXWriteable.h
@@ -50,10 +50,16 @@
typedef void (^GRXValueHandler)(id value);
typedef void (^GRXCompletionHandler)(NSError *errorOrNil);
+typedef void (^GRXSingleValueHandler)(id value, NSError *errorOrNil);
+typedef void (^GRXStreamHandler)(BOOL done, id value, NSError *error);
// Utility to create objects that conform to the GRXWriteable protocol, from
// blocks that handle each of the two methods of the protocol.
@interface GRXWriteable : NSObject<GRXWriteable>
+
++ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler;
++ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler;
+
- (instancetype)initWithValueHandler:(GRXValueHandler)valueHandler
completionHandler:(GRXCompletionHandler)completionHandler
NS_DESIGNATED_INITIALIZER;
diff --git a/src/objective-c/RxLibrary/GRXWriteable.m b/src/objective-c/RxLibrary/GRXWriteable.m
index 7231f06462..7000a078d1 100644
--- a/src/objective-c/RxLibrary/GRXWriteable.m
+++ b/src/objective-c/RxLibrary/GRXWriteable.m
@@ -38,6 +38,30 @@
GRXCompletionHandler _completionHandler;
}
++ (instancetype)writeableWithSingleValueHandler:(GRXSingleValueHandler)handler {
+ if (!handler) {
+ return [[self alloc] init];
+ }
+ return [[self alloc] initWithValueHandler:^(id value) {
+ handler(value, nil);
+ } completionHandler:^(NSError *errorOrNil) {
+ if (errorOrNil) {
+ handler(nil, errorOrNil);
+ }
+ }];
+}
+
++ (instancetype)writeableWithStreamHandler:(GRXStreamHandler)handler {
+ if (!handler) {
+ return [[self alloc] init];
+ }
+ return [[self alloc] initWithValueHandler:^(id value) {
+ handler(NO, value, nil);
+ } completionHandler:^(NSError *errorOrNil) {
+ handler(YES, nil, errorOrNil);
+ }];
+}
+
- (instancetype)init {
return [self initWithValueHandler:nil completionHandler:nil];
}
diff --git a/src/objective-c/RxLibrary/RxLibrary.podspec b/src/objective-c/RxLibrary/RxLibrary.podspec
deleted file mode 100644
index 605aedaf10..0000000000
--- a/src/objective-c/RxLibrary/RxLibrary.podspec
+++ /dev/null
@@ -1,13 +0,0 @@
-Pod::Spec.new do |s|
- s.name = 'RxLibrary'
- s.version = '0.0.1'
- s.summary = 'Reactive Extensions library for iOS'
- s.author = {
- 'Jorge Canizales' => 'jcanizales@google.com'
- }
- s.source_files = '*.{h,m}', 'transformations/*.{h,m}', 'private/*.{h,m}'
- s.private_header_files = 'private/*.h'
- s.platform = :ios
- s.ios.deployment_target = '6.0'
- s.requires_arc = true
-end
diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile
index 2b142a67d0..8b1a90e39b 100644
--- a/src/objective-c/examples/Sample/Podfile
+++ b/src/objective-c/examples/Sample/Podfile
@@ -1,13 +1,14 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
-pod 'RxLibrary', :path => "../../RxLibrary"
-pod 'GRPCClient', :path => "../../GRPCClient"
+pod 'gRPC', :path => "../../../.."
+pod 'Route_guide', :path => "RouteGuideClient"
+pod 'RemoteTest', :path => "RemoteTestClient"
-target 'Sample' do
+link_with 'Sample', 'SampleTests'
+target 'Sample' do
end
target 'SampleTests' do
-
end
diff --git a/src/objective-c/examples/Sample/Podfile.lock b/src/objective-c/examples/Sample/Podfile.lock
deleted file mode 100644
index 7fa4f5d547..0000000000
--- a/src/objective-c/examples/Sample/Podfile.lock
+++ /dev/null
@@ -1,20 +0,0 @@
-PODS:
- - GRPCClient (0.0.1):
- - RxLibrary (~> 0.0)
- - RxLibrary (0.0.1)
-
-DEPENDENCIES:
- - GRPCClient (from `../../GRPCClient`)
- - RxLibrary (from `../../RxLibrary`)
-
-EXTERNAL SOURCES:
- GRPCClient:
- :path: ../../GRPCClient
- RxLibrary:
- :path: ../../RxLibrary
-
-SPEC CHECKSUMS:
- GRPCClient: 05c58faab99661384178bb7c5f93b60c2bfc89f8
- RxLibrary: 70cfcf1573ec16a375b4fe61d976a3188aab9303
-
-COCOAPODS: 0.35.0
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCCall.h b/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCCall.h
deleted file mode 120000
index cacb26174f..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCCall.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../GRPCClient/GRPCCall.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCMethodName.h b/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCMethodName.h
deleted file mode 120000
index 4dddbd8955..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/GRPCClient/GRPCMethodName.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../GRPCClient/GRPCMethodName.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXImmediateWriter.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXImmediateWriter.h
deleted file mode 120000
index 915b0e4f90..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXImmediateWriter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/GRXImmediateWriter.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXMappingWriter.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXMappingWriter.h
deleted file mode 120000
index 4d1073f451..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXMappingWriter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/transformations/GRXMappingWriter.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriteable.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriteable.h
deleted file mode 120000
index cb275199fc..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriteable.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/GRXWriteable.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Immediate.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Immediate.h
deleted file mode 120000
index fe5e740afb..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Immediate.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/GRXWriter+Immediate.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Transformations.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Transformations.h
deleted file mode 120000
index c57168c9ef..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter+Transformations.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/GRXWriter+Transformations.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter.h
deleted file mode 120000
index c4f657e567..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/GRXWriter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/GRXWriter.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/NSEnumerator+GRXUtil.h b/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/NSEnumerator+GRXUtil.h
deleted file mode 120000
index 97c6aaeeec..0000000000
--- a/src/objective-c/examples/Sample/Pods/Headers/Public/RxLibrary/NSEnumerator+GRXUtil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../RxLibrary/NSEnumerator+GRXUtil.h \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Local Podspecs/GRPCClient.podspec b/src/objective-c/examples/Sample/Pods/Local Podspecs/GRPCClient.podspec
deleted file mode 100644
index a34c50b54e..0000000000
--- a/src/objective-c/examples/Sample/Pods/Local Podspecs/GRPCClient.podspec
+++ /dev/null
@@ -1,14 +0,0 @@
-Pod::Spec.new do |s|
- s.name = 'GRPCClient'
- s.version = '0.0.1'
- s.summary = 'Generic gRPC client library for iOS'
- s.author = {
- 'Jorge Canizales' => 'jcanizales@google.com'
- }
- s.source_files = '*.{h,m}', 'private/*.{h,m}'
- s.private_header_files = 'private/*.h'
- s.platform = :ios
- s.ios.deployment_target = '6.0'
- s.requires_arc = true
- s.dependency 'RxLibrary', '~> 0.0'
-end
diff --git a/src/objective-c/examples/Sample/Pods/Local Podspecs/RxLibrary.podspec b/src/objective-c/examples/Sample/Pods/Local Podspecs/RxLibrary.podspec
deleted file mode 100644
index 605aedaf10..0000000000
--- a/src/objective-c/examples/Sample/Pods/Local Podspecs/RxLibrary.podspec
+++ /dev/null
@@ -1,13 +0,0 @@
-Pod::Spec.new do |s|
- s.name = 'RxLibrary'
- s.version = '0.0.1'
- s.summary = 'Reactive Extensions library for iOS'
- s.author = {
- 'Jorge Canizales' => 'jcanizales@google.com'
- }
- s.source_files = '*.{h,m}', 'transformations/*.{h,m}', 'private/*.{h,m}'
- s.private_header_files = 'private/*.h'
- s.platform = :ios
- s.ios.deployment_target = '6.0'
- s.requires_arc = true
-end
diff --git a/src/objective-c/examples/Sample/Pods/Manifest.lock b/src/objective-c/examples/Sample/Pods/Manifest.lock
deleted file mode 100644
index 7fa4f5d547..0000000000
--- a/src/objective-c/examples/Sample/Pods/Manifest.lock
+++ /dev/null
@@ -1,20 +0,0 @@
-PODS:
- - GRPCClient (0.0.1):
- - RxLibrary (~> 0.0)
- - RxLibrary (0.0.1)
-
-DEPENDENCIES:
- - GRPCClient (from `../../GRPCClient`)
- - RxLibrary (from `../../RxLibrary`)
-
-EXTERNAL SOURCES:
- GRPCClient:
- :path: ../../GRPCClient
- RxLibrary:
- :path: ../../RxLibrary
-
-SPEC CHECKSUMS:
- GRPCClient: 05c58faab99661384178bb7c5f93b60c2bfc89f8
- RxLibrary: 70cfcf1573ec16a375b4fe61d976a3188aab9303
-
-COCOAPODS: 0.35.0
diff --git a/src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj
deleted file mode 100644
index b6f4c37b93..0000000000
--- a/src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,4582 +0,0 @@
-<?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>archiveVersion</key>
- <string>1</string>
- <key>classes</key>
- <dict/>
- <key>objectVersion</key>
- <string>46</string>
- <key>objects</key>
- <dict>
- <key>00303CC3049D1C9E8709A044</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-RxLibrary.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>003D718984A073D9C6C71422</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRPCDelegateWrapper.h</string>
- <key>path</key>
- <string>private/GRPCDelegateWrapper.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>0041F7F38D0B99E977EC7A9B</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>02396B6B22E0450EA29193E9</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>00669D4383CB42C429D06591</key>
- <dict>
- <key>fileRef</key>
- <string>D0641C22EEADF13905743122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>0104C23B56A2F6D406AD513A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient-prefix.pch</string>
- <key>path</key>
- <string>../Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>01E37BE5C7114E128C4664FB</key>
- <dict>
- <key>fileRef</key>
- <string>9470FB5E010191C87542871D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>02396B6B22E0450EA29193E9</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-RxLibrary-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>03289193476D7E6EE456FAA8</key>
- <dict>
- <key>fileRef</key>
- <string>16D5B426090D302B58B8FF40</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>041582131ADE9EA5C2A319BB</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary</string>
- <key>target</key>
- <string>474A50F85C06F74769FAD474</string>
- <key>targetProxy</key>
- <string>FBC9D2D66DA1B0B501961B55</string>
- </dict>
- <key>048EFCCABBC3F25828644716</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-SampleTests.debug.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>077EB8C42818FBCCF960B6A2</key>
- <dict>
- <key>fileRef</key>
- <string>0B083D6614A831642ECCDB95</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>078103DC988BEF03083FEB98</key>
- <dict>
- <key>fileRef</key>
- <string>D0641C22EEADF13905743122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>07DA0CCF4F2346740326BD7D</key>
- <dict>
- <key>fileRef</key>
- <string>9470FB5E010191C87542871D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>0843899658450810B81AC1DD</key>
- <dict>
- <key>fileRef</key>
- <string>66A375345A9F319AE182BDBD</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>09759845E529CE5CD00BECA5</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary-prefix.pch</string>
- <key>path</key>
- <string>../Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>098BE814C7B5F9F21878CDE6</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>3369A2EF668725CAF3F75D1F</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>0A5311098107B761AEF843FF</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>3DE1AA4AD4B460F4312B1359</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>0B083D6614A831642ECCDB95</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRXNSBlockEnumerator.h</string>
- <key>path</key>
- <string>private/GRXNSBlockEnumerator.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>0C52B5B243390BA62033C734</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRXWriteable.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>0CA3C7D4D3EF8429533AB7D5</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>D1C458EAFDCA48A4C90131E9</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>0CB824BF5CED7188A205D06F</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>CLANG_CXX_LANGUAGE_STANDARD</key>
- <string>gnu++0x</string>
- <key>CLANG_CXX_LIBRARY</key>
- <string>libc++</string>
- <key>CLANG_ENABLE_MODULES</key>
- <string>YES</string>
- <key>CLANG_ENABLE_OBJC_ARC</key>
- <string>YES</string>
- <key>CLANG_WARN_BOOL_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_CONSTANT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
- <string>YES</string>
- <key>CLANG_WARN_EMPTY_BODY</key>
- <string>YES</string>
- <key>CLANG_WARN_ENUM_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_INT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_OBJC_ROOT_CLASS</key>
- <string>YES</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>ENABLE_NS_ASSERTIONS</key>
- <string>NO</string>
- <key>GCC_C_LANGUAGE_STANDARD</key>
- <string>gnu99</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>RELEASE=1</string>
- </array>
- <key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
- <string>YES</string>
- <key>GCC_WARN_ABOUT_RETURN_TYPE</key>
- <string>YES</string>
- <key>GCC_WARN_UNDECLARED_SELECTOR</key>
- <string>YES</string>
- <key>GCC_WARN_UNINITIALIZED_AUTOS</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_FUNCTION</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_VARIABLE</key>
- <string>YES</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>STRIP_INSTALLED_PRODUCT</key>
- <string>NO</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>0E66C9AA7C5988807A667377</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>A0416D4A1F0C863C1856405A</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>0F24DA6964D128ACB940F0A6</key>
- <dict>
- <key>fileRef</key>
- <string>B5E4A18F0B2376BE20D1C8A5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>0F5AF35D0B405F8C010B9E02</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>A0B86020532CA90CD846B0C8</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>1284152D2F99A63F97EE1E41</key>
- <dict>
- <key>fileRef</key>
- <string>439AF2B977736E012C79B2FE</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>14C9839270FF7F89876551CF</key>
- <dict>
- <key>fileRef</key>
- <string>6394EA7A57663B87FD034792</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>152BFB6270DCF24A85D66444</key>
- <dict>
- <key>fileRef</key>
- <string>D0641C22EEADF13905743122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>16054FFCB52E34B7784B3D2C</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-RxLibrary.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>164DD73ED2C34BC6B3156AE5</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>16D5B426090D302B58B8FF40</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>Pods-Sample-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>1769B37B91BE6D2B4C498D2C</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary</string>
- <key>target</key>
- <string>4E2021A981DA9A189922E0C6</string>
- <key>targetProxy</key>
- <string>17CC3137FB05C14750ECA482</string>
- </dict>
- <key>17CC3137FB05C14750ECA482</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>4E2021A981DA9A189922E0C6</string>
- <key>remoteInfo</key>
- <string>Pods-Sample-RxLibrary</string>
- </dict>
- <key>18738628EC8A28187A30D51F</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>A10CFA4D4ED9B20894905742</string>
- <key>remoteInfo</key>
- <string>Pods-SampleTests-GRPCClient</string>
- </dict>
- <key>1939E5289BFF2A898AB652F4</key>
- <dict>
- <key>fileRef</key>
- <string>0B083D6614A831642ECCDB95</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>19A733EC94B0F847F901D308</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRXNSFastEnumerator.m</string>
- <key>path</key>
- <string>private/GRXNSFastEnumerator.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>1A2D9424BA1BE0E3B2598D06</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRXNSFastEnumerator.h</string>
- <key>path</key>
- <string>private/GRXNSFastEnumerator.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>1C191978ED182A611393A626</key>
- <dict>
- <key>fileRef</key>
- <string>0B083D6614A831642ECCDB95</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>1D1E67A62BDD0A04136468E9</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>CDA9A715DCFCE07755974888</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>1D35328CE231F0F9CD0AD192</key>
- <dict>
- <key>fileRef</key>
- <string>BC51F603F893AA6A748EB8EC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>1D7BCFDFE2B63B8DF9A95779</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>667F52E3CC55312354C2DA1C</string>
- <string>741B3AB48094A74BA06E4B41</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>1EFB19037775E7D8E9F6FC6B</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>CAB17FE3D2357BFAF9B8598F</string>
- <string>F156B1B8573809A342E0AE1F</string>
- <string>DFF269EBCC2A9D30DC7E264F</string>
- <string>6C5ACDD3AAB1F431A03610FF</string>
- <string>276C69BC7FCAF06166AC8561</string>
- <string>688A44CE404A30F009CEAD70</string>
- <string>39148152D8AC33FCD691ABF9</string>
- <string>1284152D2F99A63F97EE1E41</string>
- <string>CD18BC77ECA79D031662CC51</string>
- <string>B367BCF63161EE64CC1B1DE0</string>
- <string>2E60F7CE1E262CF0A0579F77</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>1F1DE3733C2AC2A97CA8885A</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>AC12B8262555F9F61255BBC0</string>
- <key>buildPhases</key>
- <array>
- <string>F058968A71750BBCF4F4FB1C</string>
- <string>E066A01F3A992087F10B31CF</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>69D3EA284F3612F9F534DEBB</string>
- <string>1769B37B91BE6D2B4C498D2C</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-Sample</string>
- <key>productName</key>
- <string>Pods-Sample</string>
- <key>productReference</key>
- <string>E4F23FE4AEB216E7D1E2B7EE</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>1F8BB7EDC9650BA44338F8C8</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>21E0A8B187DFAE6BD32D1302</key>
- <dict>
- <key>fileRef</key>
- <string>35A079DEB6141A6FDFF69D63</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>23C7B3ADDC7C78F4EEEB5FCE</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>363608E39D7F7AA17945644A</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>24F79AE5DB5FB86FCB2E2C39</key>
- <dict>
- <key>fileRef</key>
- <string>423B94F0660BA470EAD9DA5E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2504847B854AC340A0712235</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient</string>
- <key>target</key>
- <string>A10CFA4D4ED9B20894905742</string>
- <key>targetProxy</key>
- <string>18738628EC8A28187A30D51F</string>
- </dict>
- <key>255EE0013C9A672760CB1F29</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.script.sh</string>
- <key>path</key>
- <string>Pods-SampleTests-resources.sh</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2598A10FC8B9442686B70419</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>A2F53747970EB33A4D75EAB4</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>25992CA77847232BA741CA19</key>
- <dict>
- <key>fileRef</key>
- <string>D444D13D4D0829CF4142949A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>26A838790310501CB08753A6</key>
- <dict>
- <key>fileRef</key>
- <string>FB880554D85130C733402058</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2705BF8D166EFF8A2D44B2BA</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>NSEnumerator+GRXUtil.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2747C9BA8D7E0E6EFDFE5D3E</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>D153B061942AF56AA4E13412</string>
- <string>14C9839270FF7F89876551CF</string>
- <string>D250768ADF5442C9C8880A18</string>
- <string>40E563CF0E6B25CBB6DB08E8</string>
- <string>40F62119098548A9D94FC1CD</string>
- <string>69179090F5D6919F11110907</string>
- <string>8D8D6FB22E4E5302E899F3C7</string>
- <string>8944DC99856C99235675D65C</string>
- <string>B7FD4EDD742EE7C18D733B84</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>276C69BC7FCAF06166AC8561</key>
- <dict>
- <key>fileRef</key>
- <string>2DA7CCAA52B82F817FA61F5A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>28C6D48989DA211E0BACAFC2</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-Sample.debug.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2C4B95CD783F7C0739F77B66</key>
- <dict>
- <key>fileRef</key>
- <string>0C52B5B243390BA62033C734</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2C949CFC10D3564D45005639</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>Pods-Sample-environment.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2CF8BB8D6A668D6213E18915</key>
- <dict>
- <key>fileRef</key>
- <string>3E850442224A3D7C7540C6C5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2D505FE685E88A2746CB2C30</key>
- <dict>
- <key>fileRef</key>
- <string>D45F5D73E3D255043B7E349A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2D97FDE1D611758F0CC8EAC3</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary-dummy.m</string>
- <key>path</key>
- <string>../Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2DA7CCAA52B82F817FA61F5A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRXNSScalarEnumerator.m</string>
- <key>path</key>
- <string>private/GRXNSScalarEnumerator.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>2E60F7CE1E262CF0A0579F77</key>
- <dict>
- <key>fileRef</key>
- <string>93CEF17866E8E476701B3AEB</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>2EBE2A8DBCF9EED6B632AE6F</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>23C7B3ADDC7C78F4EEEB5FCE</string>
- <string>B32DC879307F72182ED4B8EF</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>306408CC38FAB0410E0D90E7</key>
- <dict>
- <key>fileRef</key>
- <string>003D718984A073D9C6C71422</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>31B56E69FEFEC33075859CFE</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary-prefix.pch</string>
- <key>path</key>
- <string>../Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>327414DEAB5056533318E26E</key>
- <dict>
- <key>children</key>
- <array>
- <string>AD88FBBAFBF1F13467342BD1</string>
- <string>EB86FC57EE5F50944BA86EE3</string>
- <string>7E3BE2E23E465D87ECF0E962</string>
- <string>EE156F6201B39BDD5F905822</string>
- <string>AAD40140819824C5EF180664</string>
- <string>A2F53747970EB33A4D75EAB4</string>
- <string>732C03DC74F2738AE9E86ECA</string>
- <string>0104C23B56A2F6D406AD513A</string>
- <string>45F8559BE23F19F91747A28B</string>
- <string>CDA9A715DCFCE07755974888</string>
- <string>D0E4885FFC11D4A532FAB517</string>
- <string>4B2A75095DECE2C0424CBCFC</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Support Files</string>
- <key>path</key>
- <string>../examples/Sample/Pods/Target Support Files/Pods-GRPCClient</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>3369A2EF668725CAF3F75D1F</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary-Private.xcconfig</string>
- <key>path</key>
- <string>../Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>339F0D64DF0A7BD0AA48186E</key>
- <dict>
- <key>fileRef</key>
- <string>0C52B5B243390BA62033C734</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>34373F1941450D17C3F85B57</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRXNSBlockEnumerator.m</string>
- <key>path</key>
- <string>private/GRXNSBlockEnumerator.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>34D39E370FE6AF621D048E13</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>357862381E5517983B1A7AA9</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary-dummy.m</string>
- <key>path</key>
- <string>../Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>35A079DEB6141A6FDFF69D63</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRXMappingWriter.h</string>
- <key>path</key>
- <string>transformations/GRXMappingWriter.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>363608E39D7F7AA17945644A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods.debug.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>36CC8128F585662CE7EF2114</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>NSData+GRPC.m</string>
- <key>path</key>
- <string>private/NSData+GRPC.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>39148152D8AC33FCD691ABF9</key>
- <dict>
- <key>fileRef</key>
- <string>EA915E5B33F07CD0B9F8ACE9</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>39B5F5991112189C12D87D40</key>
- <dict>
- <key>children</key>
- <array>
- <string>EC4BA4B1D02C3BA6DBB450E7</string>
- <string>A0064CCC8EC60B3CD0E4F72F</string>
- <string>7484EC496D674B8D63C9B14A</string>
- <string>4D580403A4A30D76B96E9775</string>
- <string>E2EA100B27BDAB6CA32F3814</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>3B52D357FFBB1F7AA20D702F</key>
- <dict>
- <key>fileRef</key>
- <string>78C38086F90849CD909A9847</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>3C7D98B6D2E351C032BE20A6</key>
- <dict>
- <key>fileRef</key>
- <string>6394EA7A57663B87FD034792</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>3CBFCE5C8506BD28C4AA47EC</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary</string>
- <key>target</key>
- <string>4E2021A981DA9A189922E0C6</string>
- <key>targetProxy</key>
- <string>9F21B0DA9C171E66AC1CB1E2</string>
- </dict>
- <key>3D7B59A31C0CF6B937B6B56F</key>
- <dict>
- <key>fileRef</key>
- <string>439AF2B977736E012C79B2FE</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>3DE1AA4AD4B460F4312B1359</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>3E850442224A3D7C7540C6C5</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>NSError+GRPC.h</string>
- <key>path</key>
- <string>private/NSError+GRPC.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>3FFB0F49732540C0F34BEA5D</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.plist.xml</string>
- <key>path</key>
- <string>Pods-Sample-acknowledgements.plist</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>40E563CF0E6B25CBB6DB08E8</key>
- <dict>
- <key>fileRef</key>
- <string>003D718984A073D9C6C71422</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>40F1A996749176D9DB148901</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>C59D49EFF10934AFF82CA873</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>40F62119098548A9D94FC1CD</key>
- <dict>
- <key>fileRef</key>
- <string>EE695A82B047142EA781152E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>41FD4DEF364AC343F07212C1</key>
- <dict>
- <key>fileRef</key>
- <string>FB880554D85130C733402058</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>423B94F0660BA470EAD9DA5E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRPCMethodName.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>42669F81E3800361030A567A</key>
- <dict>
- <key>fileRef</key>
- <string>517E28171A4524F9C518EAAC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>430E7D130A089632FA407274</key>
- <dict>
- <key>children</key>
- <array>
- <string>BC51F603F893AA6A748EB8EC</string>
- <string>53A5EA857F02C1DEEC269122</string>
- <string>6394EA7A57663B87FD034792</string>
- <string>FB880554D85130C733402058</string>
- <string>6A4F426FF21092B2A4B44022</string>
- <string>D0641C22EEADF13905743122</string>
- <string>003D718984A073D9C6C71422</string>
- <string>F541961867C9493F07D54B8E</string>
- <string>423B94F0660BA470EAD9DA5E</string>
- <string>E0CF2237012441B69E760029</string>
- <string>EE695A82B047142EA781152E</string>
- <string>78C38086F90849CD909A9847</string>
- <string>D45F5D73E3D255043B7E349A</string>
- <string>36CC8128F585662CE7EF2114</string>
- <string>517E28171A4524F9C518EAAC</string>
- <string>66A375345A9F319AE182BDBD</string>
- <string>3E850442224A3D7C7540C6C5</string>
- <string>6BBDA0AD2955451BBF881052</string>
- <string>327414DEAB5056533318E26E</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>GRPCClient</string>
- <key>path</key>
- <string>../../../GRPCClient</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>433B6972ED95680C5FB6FAE3</key>
- <dict>
- <key>fileRef</key>
- <string>1A2D9424BA1BE0E3B2598D06</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>439AF2B977736E012C79B2FE</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRXWriter+Transformations.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>44C27BC8E89A85C90BC42638</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>1D35328CE231F0F9CD0AD192</string>
- <string>9C6B481EF2F6601D5D6F4B6D</string>
- <string>C31B151DCFB1F263B8E344BF</string>
- <string>EC47C9C8660A81111C71C967</string>
- <string>8C3E05D9178D147F7D7EA7D0</string>
- <string>24F79AE5DB5FB86FCB2E2C39</string>
- <string>2D505FE685E88A2746CB2C30</string>
- <string>AB2C87B84886AB4CF107C5A1</string>
- <string>F911880EC1D908050569F8AF</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>45F8559BE23F19F91747A28B</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient.xcconfig</string>
- <key>path</key>
- <string>../Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>474A50F85C06F74769FAD474</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>C75867D6DF922C6894ACCC88</string>
- <key>buildPhases</key>
- <array>
- <string>7C51A49564BFF0A55C886597</string>
- <string>D520F3474212A72655D2F0ED</string>
- <string>5AE8B8582CBA2762187AB9CB</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array/>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary</string>
- <key>productName</key>
- <string>Pods-SampleTests-RxLibrary</string>
- <key>productReference</key>
- <string>C438A6F7EF173F2ED50AF192</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>48E3F41513DAE1D12CBF544D</key>
- <dict>
- <key>fileRef</key>
- <string>7F5DF8C37493F93C2636BAD6</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>49D70C2F1EBB0B8BC452D632</key>
- <dict>
- <key>fileRef</key>
- <string>35A079DEB6141A6FDFF69D63</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>4B0816A85B8DA041883CEDBE</key>
- <dict>
- <key>fileRef</key>
- <string>36CC8128F585662CE7EF2114</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>4B2A75095DECE2C0424CBCFC</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient-prefix.pch</string>
- <key>path</key>
- <string>../Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>4B765AEAB08FDC86E8082F7A</key>
- <dict>
- <key>children</key>
- <array>
- <string>AF8AB55F74FABAD365BDACF0</string>
- <string>FFC668E9994CC6407B338F9D</string>
- <string>7E5BC0233C371682047C39BD</string>
- <string>CC354BAF9312E63AB7D4404A</string>
- <string>8565F9710EFA641EF9EAE78E</string>
- <string>363608E39D7F7AA17945644A</string>
- <string>9B871E85E76E178A206CC642</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Pods</string>
- <key>path</key>
- <string>Target Support Files/Pods</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>4D580403A4A30D76B96E9775</key>
- <dict>
- <key>children</key>
- <array>
- <string>AD11CEF56188F659CB36CB34</string>
- <string>932CFA5D0C5C2C8DA3C328AF</string>
- <string>00303CC3049D1C9E8709A044</string>
- <string>E4F23FE4AEB216E7D1E2B7EE</string>
- <string>CBB34B55930DEFBDE44A62E0</string>
- <string>EA41D57C3938E8D766E0224F</string>
- <string>675E56BADC0C4C93E3B6B263</string>
- <string>8DD3112B6E527E20F688C5A0</string>
- <string>C438A6F7EF173F2ED50AF192</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Products</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>4E2021A981DA9A189922E0C6</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>1D7BCFDFE2B63B8DF9A95779</string>
- <key>buildPhases</key>
- <array>
- <string>5011677F9A4B34B7CC28BC27</string>
- <string>9CFF85471050427EE3796F6F</string>
- <string>C818D7947CCCEA0324CD9E79</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array/>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary</string>
- <key>productName</key>
- <string>Pods-Sample-RxLibrary</string>
- <key>productReference</key>
- <string>EA41D57C3938E8D766E0224F</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>4F529EACF630FA5A638408A4</key>
- <dict>
- <key>fileRef</key>
- <string>78C38086F90849CD909A9847</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>5011677F9A4B34B7CC28BC27</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>25992CA77847232BA741CA19</string>
- <string>7EE012957E76C86620A8B82D</string>
- <string>F636FFBF62AFF197BE3CB427</string>
- <string>8F24508F2BC37AE7B2282E42</string>
- <string>CA8337B362EA0132CA470DB0</string>
- <string>7B72787324EC9346B7243E79</string>
- <string>61D40C951CD9463DBAC928AE</string>
- <string>3D7B59A31C0CF6B937B6B56F</string>
- <string>B37BACFCD1765840986F8AC5</string>
- <string>9CC98083B837EFAE1058E03E</string>
- <string>A0C815D67EA636E8E6A5E655</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>517E28171A4524F9C518EAAC</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>NSDictionary+GRPC.h</string>
- <key>path</key>
- <string>private/NSDictionary+GRPC.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>51DBA8F3C7D4E67BDD768066</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-SampleTests.release.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>53A5EA857F02C1DEEC269122</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRPCCall.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>53E7256294CEEC3844B70A31</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>EB86FC57EE5F50944BA86EE3</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>55A1C5AA37880BD7D2D575C1</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>1F8BB7EDC9650BA44338F8C8</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>5654D46158ECA8C27895A755</key>
- <dict>
- <key>fileRef</key>
- <string>53A5EA857F02C1DEEC269122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>583EF09FCBF65B9A4E5C22A7</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>7D6F600B59E9C29030A96526</string>
- <string>2598A10FC8B9442686B70419</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>5AE8B8582CBA2762187AB9CB</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>07DA0CCF4F2346740326BD7D</string>
- <string>8D0A2E1D25EEA3A096E08B1A</string>
- <string>1939E5289BFF2A898AB652F4</string>
- <string>433B6972ED95680C5FB6FAE3</string>
- <string>C90E8B6A34A6456422C8086E</string>
- <string>7769061BD3B0C3FA2591F01E</string>
- <string>48E3F41513DAE1D12CBF544D</string>
- <string>9F3C74AA5715E325880AE886</string>
- <string>0F24DA6964D128ACB940F0A6</string>
- <string>7C036237AA7E88A084C751E0</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>5BDD559FB35594584D1BE09E</key>
- <dict>
- <key>fileRef</key>
- <string>66A375345A9F319AE182BDBD</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>617AA57F150724B1881EC92E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRXNSScalarEnumerator.h</string>
- <key>path</key>
- <string>private/GRXNSScalarEnumerator.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>61D40C951CD9463DBAC928AE</key>
- <dict>
- <key>fileRef</key>
- <string>EA915E5B33F07CD0B9F8ACE9</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6354A9E233C358103A8D02C2</key>
- <dict>
- <key>fileRef</key>
- <string>D6D8919597D4E28EBF5D166B</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6394EA7A57663B87FD034792</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRPCChannel.h</string>
- <key>path</key>
- <string>private/GRPCChannel.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>644143496CECB668F61BCD16</key>
- <dict>
- <key>children</key>
- <array>
- <string>98695E4E6F8168938F9CC49E</string>
- <string>3FFB0F49732540C0F34BEA5D</string>
- <string>16D5B426090D302B58B8FF40</string>
- <string>2C949CFC10D3564D45005639</string>
- <string>BEEA6A0D27020465FC6CD0AA</string>
- <string>28C6D48989DA211E0BACAFC2</string>
- <string>A0416D4A1F0C863C1856405A</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Pods-Sample</string>
- <key>path</key>
- <string>Target Support Files/Pods-Sample</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>66448F9949C234988DD11E4E</key>
- <dict>
- <key>fileRef</key>
- <string>68A0ACB0AFAA7186EB2ABE09</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>667F52E3CC55312354C2DA1C</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>6C1CC360881CEA3DD2D1FE14</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>66A375345A9F319AE182BDBD</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>NSDictionary+GRPC.m</string>
- <key>path</key>
- <string>private/NSDictionary+GRPC.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>66E177AC7F3B02B51D36A226</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>583EF09FCBF65B9A4E5C22A7</string>
- <key>buildPhases</key>
- <array>
- <string>A5EDB7E25EA71C67EF1B3F82</string>
- <string>55A1C5AA37880BD7D2D575C1</string>
- <string>2747C9BA8D7E0E6EFDFE5D3E</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>3CBFCE5C8506BD28C4AA47EC</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient</string>
- <key>productName</key>
- <string>Pods-Sample-GRPCClient</string>
- <key>productReference</key>
- <string>CBB34B55930DEFBDE44A62E0</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>675E56BADC0C4C93E3B6B263</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-SampleTests.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>688A44CE404A30F009CEAD70</key>
- <dict>
- <key>fileRef</key>
- <string>D6D8919597D4E28EBF5D166B</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>68A0ACB0AFAA7186EB2ABE09</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>NSEnumerator+GRXUtil.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>69179090F5D6919F11110907</key>
- <dict>
- <key>fileRef</key>
- <string>423B94F0660BA470EAD9DA5E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>69D3EA284F3612F9F534DEBB</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient</string>
- <key>target</key>
- <string>66E177AC7F3B02B51D36A226</string>
- <key>targetProxy</key>
- <string>72246839A1947E6558591655</string>
- </dict>
- <key>6A4F426FF21092B2A4B44022</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRPCCompletionQueue.h</string>
- <key>path</key>
- <string>private/GRPCCompletionQueue.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6AA10AF7AE19131F66FB8586</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>3369A2EF668725CAF3F75D1F</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>6B6C68F7F3769BB8EBEB7EE5</key>
- <dict>
- <key>fileRef</key>
- <string>EA915E5B33F07CD0B9F8ACE9</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6BBDA0AD2955451BBF881052</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>NSError+GRPC.m</string>
- <key>path</key>
- <string>private/NSError+GRPC.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6BC5E8D01392B97FF237C655</key>
- <dict>
- <key>children</key>
- <array>
- <string>16054FFCB52E34B7784B3D2C</string>
- <string>02396B6B22E0450EA29193E9</string>
- <string>93CEF17866E8E476701B3AEB</string>
- <string>E256AF33BE1D5C30780D4E96</string>
- <string>F6B6558E339AD89F764A6D88</string>
- <string>6C1CC360881CEA3DD2D1FE14</string>
- <string>2D97FDE1D611758F0CC8EAC3</string>
- <string>31B56E69FEFEC33075859CFE</string>
- <string>DD9A2AC14E9E04D4337DB76E</string>
- <string>3369A2EF668725CAF3F75D1F</string>
- <string>357862381E5517983B1A7AA9</string>
- <string>09759845E529CE5CD00BECA5</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Support Files</string>
- <key>path</key>
- <string>../examples/Sample/Pods/Target Support Files/Pods-RxLibrary</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6C1CC360881CEA3DD2D1FE14</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary-Private.xcconfig</string>
- <key>path</key>
- <string>../Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6C5ACDD3AAB1F431A03610FF</key>
- <dict>
- <key>fileRef</key>
- <string>19A733EC94B0F847F901D308</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6EDAC415AC0B16B221E0397F</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-RxLibrary</string>
- <key>target</key>
- <string>AEECE9DFCC8F060F1E30A421</string>
- <key>targetProxy</key>
- <string>BCB580E2193B3624D1C471DB</string>
- </dict>
- <key>72246839A1947E6558591655</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>66E177AC7F3B02B51D36A226</string>
- <key>remoteInfo</key>
- <string>Pods-Sample-GRPCClient</string>
- </dict>
- <key>73107A4E8F55EFE854586192</key>
- <dict>
- <key>fileRef</key>
- <string>732C03DC74F2738AE9E86ECA</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>732C03DC74F2738AE9E86ECA</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient-dummy.m</string>
- <key>path</key>
- <string>../Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>741B3AB48094A74BA06E4B41</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>6C1CC360881CEA3DD2D1FE14</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>7484EC496D674B8D63C9B14A</key>
- <dict>
- <key>children</key>
- <array>
- <string>808CD0E97EA8B9B2423DFBB4</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Frameworks</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>7769061BD3B0C3FA2591F01E</key>
- <dict>
- <key>fileRef</key>
- <string>0C52B5B243390BA62033C734</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>78C38086F90849CD909A9847</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRPCMethodName+HTTP2Encoding.m</string>
- <key>path</key>
- <string>private/GRPCMethodName+HTTP2Encoding.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>79254B326EAE190FCCF68500</key>
- <dict>
- <key>fileRef</key>
- <string>D444D13D4D0829CF4142949A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>7962371F2502CBAEBF859730</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>2EBE2A8DBCF9EED6B632AE6F</string>
- <key>buildPhases</key>
- <array>
- <string>0F5AF35D0B405F8C010B9E02</string>
- <string>0A5311098107B761AEF843FF</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>9420C1F89C211902C0D87225</string>
- <string>7EAAEBF540915967146B03A6</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods</string>
- <key>productName</key>
- <string>Pods</string>
- <key>productReference</key>
- <string>AD11CEF56188F659CB36CB34</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>7A1AC6EA0DE9920EE46DD7C6</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>D965694635120F86B2E5E101</string>
- <string>49D70C2F1EBB0B8BC452D632</string>
- <string>077EB8C42818FBCCF960B6A2</string>
- <string>8563E3DF7CFBE5A416F679DD</string>
- <string>B42B413709D355A8828EEC76</string>
- <string>339F0D64DF0A7BD0AA48186E</string>
- <string>832D68435FCFF5497A72F1D3</string>
- <string>BD38F7B336495294670A28A4</string>
- <string>D54769D14A73816406636B14</string>
- <string>9D4AD7A95C9F70261CF7E09E</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>7B72787324EC9346B7243E79</key>
- <dict>
- <key>fileRef</key>
- <string>D6D8919597D4E28EBF5D166B</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>7BA366CBC6DBCDC7984BCC50</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>CDA9A715DCFCE07755974888</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>7C036237AA7E88A084C751E0</key>
- <dict>
- <key>fileRef</key>
- <string>2705BF8D166EFF8A2D44B2BA</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>7C51A49564BFF0A55C886597</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>79254B326EAE190FCCF68500</string>
- <string>E23D43F03E7C19D671C93F81</string>
- <string>E328084D7C583851D3BE25CF</string>
- <string>8304D6194CF27F78FD63D3E0</string>
- <string>7E0A094939C76D9C1097CE47</string>
- <string>6354A9E233C358103A8D02C2</string>
- <string>6B6C68F7F3769BB8EBEB7EE5</string>
- <string>9520D95CEA199664DEA83898</string>
- <string>A8C31E8535FB26B38A1831C0</string>
- <string>66448F9949C234988DD11E4E</string>
- <string>95ABB7ADC6AA8ABDA7E32C0B</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>7D6F600B59E9C29030A96526</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>A2F53747970EB33A4D75EAB4</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>7E0A094939C76D9C1097CE47</key>
- <dict>
- <key>fileRef</key>
- <string>2DA7CCAA52B82F817FA61F5A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>7E3BE2E23E465D87ECF0E962</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>Pods-GRPCClient-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>7E5BC0233C371682047C39BD</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>Pods-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>7EAAEBF540915967146B03A6</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-RxLibrary</string>
- <key>target</key>
- <string>AEECE9DFCC8F060F1E30A421</string>
- <key>targetProxy</key>
- <string>DF829332517E7136AED2EC79</string>
- </dict>
- <key>7EE012957E76C86620A8B82D</key>
- <dict>
- <key>fileRef</key>
- <string>CEA794A7056AFAB8256CC44D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>7F5DF8C37493F93C2636BAD6</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRXWriter+Immediate.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>808CD0E97EA8B9B2423DFBB4</key>
- <dict>
- <key>children</key>
- <array>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>iOS</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>80CC1C2E2C60B0F9CADA36AF</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>164DD73ED2C34BC6B3156AE5</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>822AA7CD03CFBA9265225E74</key>
- <dict>
- <key>fileRef</key>
- <string>36CC8128F585662CE7EF2114</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8304D6194CF27F78FD63D3E0</key>
- <dict>
- <key>fileRef</key>
- <string>19A733EC94B0F847F901D308</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>832D68435FCFF5497A72F1D3</key>
- <dict>
- <key>fileRef</key>
- <string>7F5DF8C37493F93C2636BAD6</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8563E3DF7CFBE5A416F679DD</key>
- <dict>
- <key>fileRef</key>
- <string>1A2D9424BA1BE0E3B2598D06</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8565F9710EFA641EF9EAE78E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.script.sh</string>
- <key>path</key>
- <string>Pods-resources.sh</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>87F549870DB778A5F152B608</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8944DC99856C99235675D65C</key>
- <dict>
- <key>fileRef</key>
- <string>517E28171A4524F9C518EAAC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8A203557337361CF44D2D664</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRXWriter.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>8ACE4DE290D8847EA219A1B8</key>
- <dict>
- <key>fileRef</key>
- <string>2705BF8D166EFF8A2D44B2BA</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8C3E05D9178D147F7D7EA7D0</key>
- <dict>
- <key>fileRef</key>
- <string>EE695A82B047142EA781152E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8D0A2E1D25EEA3A096E08B1A</key>
- <dict>
- <key>fileRef</key>
- <string>35A079DEB6141A6FDFF69D63</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8D8D6FB22E4E5302E899F3C7</key>
- <dict>
- <key>fileRef</key>
- <string>D45F5D73E3D255043B7E349A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8DD3112B6E527E20F688C5A0</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-SampleTests-GRPCClient.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>8F24508F2BC37AE7B2282E42</key>
- <dict>
- <key>fileRef</key>
- <string>19A733EC94B0F847F901D308</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>8FC9893C41EDC73475EA96B8</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>CLANG_CXX_LANGUAGE_STANDARD</key>
- <string>gnu++0x</string>
- <key>CLANG_CXX_LIBRARY</key>
- <string>libc++</string>
- <key>CLANG_ENABLE_MODULES</key>
- <string>YES</string>
- <key>CLANG_ENABLE_OBJC_ARC</key>
- <string>YES</string>
- <key>CLANG_WARN_BOOL_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_CONSTANT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
- <string>YES</string>
- <key>CLANG_WARN_EMPTY_BODY</key>
- <string>YES</string>
- <key>CLANG_WARN_ENUM_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_INT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_OBJC_ROOT_CLASS</key>
- <string>YES</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>GCC_C_LANGUAGE_STANDARD</key>
- <string>gnu99</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
- <string>YES</string>
- <key>GCC_WARN_ABOUT_RETURN_TYPE</key>
- <string>YES</string>
- <key>GCC_WARN_UNDECLARED_SELECTOR</key>
- <string>YES</string>
- <key>GCC_WARN_UNINITIALIZED_AUTOS</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_FUNCTION</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_VARIABLE</key>
- <string>YES</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>ONLY_ACTIVE_ARCH</key>
- <string>YES</string>
- <key>STRIP_INSTALLED_PRODUCT</key>
- <string>NO</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>91B3D53E73C867A8F1B3B392</key>
- <dict>
- <key>fileRef</key>
- <string>BC51F603F893AA6A748EB8EC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>91D5786D0585930DEFAB636E</key>
- <dict>
- <key>fileRef</key>
- <string>F541961867C9493F07D54B8E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>932CFA5D0C5C2C8DA3C328AF</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-GRPCClient.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>93CEF17866E8E476701B3AEB</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>Pods-RxLibrary-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>9420C1F89C211902C0D87225</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-GRPCClient</string>
- <key>target</key>
- <string>AB3F9F2CFA29030A599E9231</string>
- <key>targetProxy</key>
- <string>D6715088D2AB1CBAA49F8651</string>
- </dict>
- <key>9470FB5E010191C87542871D</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRXImmediateWriter.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>94DDD64BC43C045541FB9BEC</key>
- <dict>
- <key>fileRef</key>
- <string>EE695A82B047142EA781152E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>9520D95CEA199664DEA83898</key>
- <dict>
- <key>fileRef</key>
- <string>439AF2B977736E012C79B2FE</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>95ABB7ADC6AA8ABDA7E32C0B</key>
- <dict>
- <key>fileRef</key>
- <string>357862381E5517983B1A7AA9</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>96CD01ACF90F6977972AA5C7</key>
- <dict>
- <key>fileRef</key>
- <string>53A5EA857F02C1DEEC269122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>98695E4E6F8168938F9CC49E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text</string>
- <key>path</key>
- <string>Pods-Sample-acknowledgements.markdown</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>9A637A6516AB11F29615FC18</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>7BA366CBC6DBCDC7984BCC50</string>
- <string>1D1E67A62BDD0A04136468E9</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>9B871E85E76E178A206CC642</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods.release.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>9C6B481EF2F6601D5D6F4B6D</key>
- <dict>
- <key>fileRef</key>
- <string>6394EA7A57663B87FD034792</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>9CC98083B837EFAE1058E03E</key>
- <dict>
- <key>fileRef</key>
- <string>68A0ACB0AFAA7186EB2ABE09</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>9CFF85471050427EE3796F6F</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>D548663391776A14DCAC50B8</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>9D4AD7A95C9F70261CF7E09E</key>
- <dict>
- <key>fileRef</key>
- <string>2705BF8D166EFF8A2D44B2BA</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>9F21B0DA9C171E66AC1CB1E2</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>4E2021A981DA9A189922E0C6</string>
- <key>remoteInfo</key>
- <string>Pods-Sample-RxLibrary</string>
- </dict>
- <key>9F3C74AA5715E325880AE886</key>
- <dict>
- <key>fileRef</key>
- <string>F776B445ABD393C908B02302</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A0064CCC8EC60B3CD0E4F72F</key>
- <dict>
- <key>children</key>
- <array>
- <string>430E7D130A089632FA407274</string>
- <string>D7BA8B8D4FFF3674A537221D</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Development Pods</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>A0416D4A1F0C863C1856405A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-Sample.release.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>A0B86020532CA90CD846B0C8</key>
- <dict>
- <key>fileRef</key>
- <string>7E5BC0233C371682047C39BD</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A0C815D67EA636E8E6A5E655</key>
- <dict>
- <key>fileRef</key>
- <string>2D97FDE1D611758F0CC8EAC3</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A0C9AE64F2D6C0E3A4F26302</key>
- <dict>
- <key>fileRef</key>
- <string>6BBDA0AD2955451BBF881052</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A10CFA4D4ED9B20894905742</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>9A637A6516AB11F29615FC18</string>
- <key>buildPhases</key>
- <array>
- <string>B31604CF386150298F4572B7</string>
- <string>80CC1C2E2C60B0F9CADA36AF</string>
- <string>A7DF070735AAA7A85C474BBD</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>EF97D57CA44A79151103F06B</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient</string>
- <key>productName</key>
- <string>Pods-SampleTests-GRPCClient</string>
- <key>productReference</key>
- <string>8DD3112B6E527E20F688C5A0</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>A152A54E946159BB41FF6E04</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>F4586BA420EA562FECC43A3A</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>A2F53747970EB33A4D75EAB4</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient-Private.xcconfig</string>
- <key>path</key>
- <string>../Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>A32A838D0E36519FB68C73DF</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.plist.xml</string>
- <key>path</key>
- <string>Pods-SampleTests-acknowledgements.plist</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>A5A038CAD7AF2C628752EF63</key>
- <dict>
- <key>fileRef</key>
- <string>D0E4885FFC11D4A532FAB517</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A5EDB7E25EA71C67EF1B3F82</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>96CD01ACF90F6977972AA5C7</string>
- <string>41FD4DEF364AC343F07212C1</string>
- <string>152BFB6270DCF24A85D66444</string>
- <string>FD9953A9B079B03396B2FEA3</string>
- <string>4F529EACF630FA5A638408A4</string>
- <string>CDB4449E284965A752BD1786</string>
- <string>A8CBA848BF8F6538176F3424</string>
- <string>5BDD559FB35594584D1BE09E</string>
- <string>A0C9AE64F2D6C0E3A4F26302</string>
- <string>73107A4E8F55EFE854586192</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>A7CE4BCE7B6959BCDC54B854</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>wrapper.framework</string>
- <key>name</key>
- <string>Foundation.framework</string>
- <key>path</key>
- <string>Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/System/Library/Frameworks/Foundation.framework</string>
- <key>sourceTree</key>
- <string>DEVELOPER_DIR</string>
- </dict>
- <key>A7DF070735AAA7A85C474BBD</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>91B3D53E73C867A8F1B3B392</string>
- <string>3C7D98B6D2E351C032BE20A6</string>
- <string>AC6CF5430FB75930354FD7B3</string>
- <string>306408CC38FAB0410E0D90E7</string>
- <string>94DDD64BC43C045541FB9BEC</string>
- <string>D0B7F6736070533C215E7DE3</string>
- <string>E05C4D27465DD5F292E2A8EE</string>
- <string>42669F81E3800361030A567A</string>
- <string>2CF8BB8D6A668D6213E18915</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>A8C31E8535FB26B38A1831C0</key>
- <dict>
- <key>fileRef</key>
- <string>8A203557337361CF44D2D664</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>A8CBA848BF8F6538176F3424</key>
- <dict>
- <key>fileRef</key>
- <string>36CC8128F585662CE7EF2114</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>AAAEE7AE6F373AA2C0D1969F</key>
- <dict>
- <key>fileRef</key>
- <string>78C38086F90849CD909A9847</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>AAD40140819824C5EF180664</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-Sample-GRPCClient.xcconfig</string>
- <key>path</key>
- <string>../Pods-Sample-GRPCClient/Pods-Sample-GRPCClient.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>AB2C87B84886AB4CF107C5A1</key>
- <dict>
- <key>fileRef</key>
- <string>517E28171A4524F9C518EAAC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>AB3F9F2CFA29030A599E9231</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>ADEFC2A6E68AD0102A5683BB</string>
- <key>buildPhases</key>
- <array>
- <string>D5B158492CFF90F975B03B8D</string>
- <string>0CA3C7D4D3EF8429533AB7D5</string>
- <string>44C27BC8E89A85C90BC42638</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>6EDAC415AC0B16B221E0397F</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-GRPCClient</string>
- <key>productName</key>
- <string>Pods-GRPCClient</string>
- <key>productReference</key>
- <string>932CFA5D0C5C2C8DA3C328AF</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>AC12B8262555F9F61255BBC0</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>BE19113B79057D8A53A04303</string>
- <string>0E66C9AA7C5988807A667377</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>AC6CF5430FB75930354FD7B3</key>
- <dict>
- <key>fileRef</key>
- <string>6A4F426FF21092B2A4B44022</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>AD11CEF56188F659CB36CB34</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>AD88FBBAFBF1F13467342BD1</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-GRPCClient.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>ADEFC2A6E68AD0102A5683BB</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>CA294BA3C4F9A1948B2AE213</string>
- <string>53E7256294CEEC3844B70A31</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>AEECE9DFCC8F060F1E30A421</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>FF34F6701990B0955422EC9C</string>
- <key>buildPhases</key>
- <array>
- <string>1EFB19037775E7D8E9F6FC6B</string>
- <string>D0C130BBB6DBFE22F6B649E8</string>
- <string>7A1AC6EA0DE9920EE46DD7C6</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array/>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-RxLibrary</string>
- <key>productName</key>
- <string>Pods-RxLibrary</string>
- <key>productReference</key>
- <string>00303CC3049D1C9E8709A044</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>AF8AB55F74FABAD365BDACF0</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text</string>
- <key>path</key>
- <string>Pods-acknowledgements.markdown</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>B22A719DB3DFD2337E996D6A</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>8FC9893C41EDC73475EA96B8</string>
- <string>0CB824BF5CED7188A205D06F</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>B31604CF386150298F4572B7</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>5654D46158ECA8C27895A755</string>
- <string>FA5E9BC13067F1E32D6311E6</string>
- <string>078103DC988BEF03083FEB98</string>
- <string>D80E545131A1D2922F88C5D7</string>
- <string>3B52D357FFBB1F7AA20D702F</string>
- <string>F2B5B896D8C7E13B5E8ADA28</string>
- <string>4B0816A85B8DA041883CEDBE</string>
- <string>B6D29DCA02F3DFEEB77A8567</string>
- <string>C55E900FEB92A7F9134BA484</string>
- <string>A5A038CAD7AF2C628752EF63</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>B32DC879307F72182ED4B8EF</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>9B871E85E76E178A206CC642</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>B367BCF63161EE64CC1B1DE0</key>
- <dict>
- <key>fileRef</key>
- <string>68A0ACB0AFAA7186EB2ABE09</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>B37278C2CEC4C1C433BEF120</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>F6A0AD6C190915DD52886BE2</string>
- <key>buildPhases</key>
- <array>
- <string>40F1A996749176D9DB148901</string>
- <string>A152A54E946159BB41FF6E04</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>2504847B854AC340A0712235</string>
- <string>041582131ADE9EA5C2A319BB</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Pods-SampleTests</string>
- <key>productName</key>
- <string>Pods-SampleTests</string>
- <key>productReference</key>
- <string>675E56BADC0C4C93E3B6B263</string>
- <key>productType</key>
- <string>com.apple.product-type.library.static</string>
- </dict>
- <key>B37BACFCD1765840986F8AC5</key>
- <dict>
- <key>fileRef</key>
- <string>8A203557337361CF44D2D664</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>B42B413709D355A8828EEC76</key>
- <dict>
- <key>fileRef</key>
- <string>617AA57F150724B1881EC92E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>B5E4A18F0B2376BE20D1C8A5</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRXWriter.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>B6D29DCA02F3DFEEB77A8567</key>
- <dict>
- <key>fileRef</key>
- <string>66A375345A9F319AE182BDBD</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>B7FD4EDD742EE7C18D733B84</key>
- <dict>
- <key>fileRef</key>
- <string>3E850442224A3D7C7540C6C5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>BC51F603F893AA6A748EB8EC</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRPCCall.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>BCB580E2193B3624D1C471DB</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>AEECE9DFCC8F060F1E30A421</string>
- <key>remoteInfo</key>
- <string>Pods-RxLibrary</string>
- </dict>
- <key>BD38F7B336495294670A28A4</key>
- <dict>
- <key>fileRef</key>
- <string>F776B445ABD393C908B02302</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>BE19113B79057D8A53A04303</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>28C6D48989DA211E0BACAFC2</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>BEEA6A0D27020465FC6CD0AA</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.script.sh</string>
- <key>path</key>
- <string>Pods-Sample-resources.sh</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>C31B151DCFB1F263B8E344BF</key>
- <dict>
- <key>fileRef</key>
- <string>6A4F426FF21092B2A4B44022</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>C3E4DEFB7877BA48A9458947</key>
- <dict>
- <key>fileRef</key>
- <string>1A2D9424BA1BE0E3B2598D06</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>C438A6F7EF173F2ED50AF192</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-SampleTests-RxLibrary.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>C55E900FEB92A7F9134BA484</key>
- <dict>
- <key>fileRef</key>
- <string>6BBDA0AD2955451BBF881052</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>C59D49EFF10934AFF82CA873</key>
- <dict>
- <key>fileRef</key>
- <string>C5A09DD572522E9567EC6CD1</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>C5A09DD572522E9567EC6CD1</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>Pods-SampleTests-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>C75867D6DF922C6894ACCC88</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>098BE814C7B5F9F21878CDE6</string>
- <string>6AA10AF7AE19131F66FB8586</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>C818D7947CCCEA0324CD9E79</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>01E37BE5C7114E128C4664FB</string>
- <string>21E0A8B187DFAE6BD32D1302</string>
- <string>1C191978ED182A611393A626</string>
- <string>C3E4DEFB7877BA48A9458947</string>
- <string>FF378D56A81AE6EFC739CDE6</string>
- <string>2C4B95CD783F7C0739F77B66</string>
- <string>CC00C5E75E69BE36B9D2816E</string>
- <string>EA8F6101AB32D6B0A3FC0163</string>
- <string>D2BE15266514D3FE8B3E8820</string>
- <string>8ACE4DE290D8847EA219A1B8</string>
- </array>
- <key>isa</key>
- <string>PBXHeadersBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>C90E8B6A34A6456422C8086E</key>
- <dict>
- <key>fileRef</key>
- <string>617AA57F150724B1881EC92E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CA294BA3C4F9A1948B2AE213</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>EB86FC57EE5F50944BA86EE3</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>CA8337B362EA0132CA470DB0</key>
- <dict>
- <key>fileRef</key>
- <string>2DA7CCAA52B82F817FA61F5A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CAB17FE3D2357BFAF9B8598F</key>
- <dict>
- <key>fileRef</key>
- <string>D444D13D4D0829CF4142949A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CB5B0489448E9051E9F9E423</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CBB34B55930DEFBDE44A62E0</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-Sample-GRPCClient.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>CC00C5E75E69BE36B9D2816E</key>
- <dict>
- <key>fileRef</key>
- <string>7F5DF8C37493F93C2636BAD6</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CC354BAF9312E63AB7D4404A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>Pods-environment.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>CD18BC77ECA79D031662CC51</key>
- <dict>
- <key>fileRef</key>
- <string>8A203557337361CF44D2D664</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CDA9A715DCFCE07755974888</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient-Private.xcconfig</string>
- <key>path</key>
- <string>../Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>CDB4449E284965A752BD1786</key>
- <dict>
- <key>fileRef</key>
- <string>E0CF2237012441B69E760029</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>CEA794A7056AFAB8256CC44D</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRXMappingWriter.m</string>
- <key>path</key>
- <string>transformations/GRXMappingWriter.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D0641C22EEADF13905743122</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRPCCompletionQueue.m</string>
- <key>path</key>
- <string>private/GRPCCompletionQueue.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D0B7F6736070533C215E7DE3</key>
- <dict>
- <key>fileRef</key>
- <string>423B94F0660BA470EAD9DA5E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D0C130BBB6DBFE22F6B649E8</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>34D39E370FE6AF621D048E13</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>D0E4885FFC11D4A532FAB517</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>Pods-SampleTests-GRPCClient-dummy.m</string>
- <key>path</key>
- <string>../Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-dummy.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D153B061942AF56AA4E13412</key>
- <dict>
- <key>fileRef</key>
- <string>BC51F603F893AA6A748EB8EC</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D1C458EAFDCA48A4C90131E9</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D250768ADF5442C9C8880A18</key>
- <dict>
- <key>fileRef</key>
- <string>6A4F426FF21092B2A4B44022</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D2BE15266514D3FE8B3E8820</key>
- <dict>
- <key>fileRef</key>
- <string>B5E4A18F0B2376BE20D1C8A5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D444D13D4D0829CF4142949A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRXImmediateWriter.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D45F5D73E3D255043B7E349A</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>NSData+GRPC.h</string>
- <key>path</key>
- <string>private/NSData+GRPC.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D520F3474212A72655D2F0ED</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>CB5B0489448E9051E9F9E423</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>D54769D14A73816406636B14</key>
- <dict>
- <key>fileRef</key>
- <string>B5E4A18F0B2376BE20D1C8A5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D548663391776A14DCAC50B8</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D5B158492CFF90F975B03B8D</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>E0CA82F272732A2A5F024AD6</string>
- <string>26A838790310501CB08753A6</string>
- <string>00669D4383CB42C429D06591</string>
- <string>91D5786D0585930DEFAB636E</string>
- <string>AAAEE7AE6F373AA2C0D1969F</string>
- <string>F84427B4C72738E045D44E6C</string>
- <string>822AA7CD03CFBA9265225E74</string>
- <string>0843899658450810B81AC1DD</string>
- <string>F37E3DFDFA20082CBC4E2257</string>
- <string>DDC9480509EAE89DED87393D</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>D6715088D2AB1CBAA49F8651</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>AB3F9F2CFA29030A599E9231</string>
- <key>remoteInfo</key>
- <string>Pods-GRPCClient</string>
- </dict>
- <key>D6D8919597D4E28EBF5D166B</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRXWriteable.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D756E08287486CC7A7034803</key>
- <dict>
- <key>children</key>
- <array>
- <string>EB0497400F84ADD968F6AB42</string>
- <string>A32A838D0E36519FB68C73DF</string>
- <string>C5A09DD572522E9567EC6CD1</string>
- <string>D985414BAA4686F0ED38ACF8</string>
- <string>255EE0013C9A672760CB1F29</string>
- <string>048EFCCABBC3F25828644716</string>
- <string>51DBA8F3C7D4E67BDD768066</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Pods-SampleTests</string>
- <key>path</key>
- <string>Target Support Files/Pods-SampleTests</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D7BA8B8D4FFF3674A537221D</key>
- <dict>
- <key>children</key>
- <array>
- <string>9470FB5E010191C87542871D</string>
- <string>D444D13D4D0829CF4142949A</string>
- <string>35A079DEB6141A6FDFF69D63</string>
- <string>CEA794A7056AFAB8256CC44D</string>
- <string>0B083D6614A831642ECCDB95</string>
- <string>34373F1941450D17C3F85B57</string>
- <string>1A2D9424BA1BE0E3B2598D06</string>
- <string>19A733EC94B0F847F901D308</string>
- <string>617AA57F150724B1881EC92E</string>
- <string>2DA7CCAA52B82F817FA61F5A</string>
- <string>0C52B5B243390BA62033C734</string>
- <string>D6D8919597D4E28EBF5D166B</string>
- <string>B5E4A18F0B2376BE20D1C8A5</string>
- <string>8A203557337361CF44D2D664</string>
- <string>7F5DF8C37493F93C2636BAD6</string>
- <string>EA915E5B33F07CD0B9F8ACE9</string>
- <string>F776B445ABD393C908B02302</string>
- <string>439AF2B977736E012C79B2FE</string>
- <string>2705BF8D166EFF8A2D44B2BA</string>
- <string>68A0ACB0AFAA7186EB2ABE09</string>
- <string>6BC5E8D01392B97FF237C655</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>RxLibrary</string>
- <key>path</key>
- <string>../../../RxLibrary</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>D80E545131A1D2922F88C5D7</key>
- <dict>
- <key>fileRef</key>
- <string>F541961867C9493F07D54B8E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D965694635120F86B2E5E101</key>
- <dict>
- <key>fileRef</key>
- <string>9470FB5E010191C87542871D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>D985414BAA4686F0ED38ACF8</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>Pods-SampleTests-environment.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>DD9A2AC14E9E04D4337DB76E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary.xcconfig</string>
- <key>path</key>
- <string>../Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>DDC9480509EAE89DED87393D</key>
- <dict>
- <key>fileRef</key>
- <string>7E3BE2E23E465D87ECF0E962</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>DF829332517E7136AED2EC79</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>AEECE9DFCC8F060F1E30A421</string>
- <key>remoteInfo</key>
- <string>Pods-RxLibrary</string>
- </dict>
- <key>DFF269EBCC2A9D30DC7E264F</key>
- <dict>
- <key>fileRef</key>
- <string>34373F1941450D17C3F85B57</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>E05C4D27465DD5F292E2A8EE</key>
- <dict>
- <key>fileRef</key>
- <string>D45F5D73E3D255043B7E349A</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>E066A01F3A992087F10B31CF</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>87F549870DB778A5F152B608</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>E0CA82F272732A2A5F024AD6</key>
- <dict>
- <key>fileRef</key>
- <string>53A5EA857F02C1DEEC269122</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>E0CF2237012441B69E760029</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRPCMethodName.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>E23D43F03E7C19D671C93F81</key>
- <dict>
- <key>fileRef</key>
- <string>CEA794A7056AFAB8256CC44D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>E256AF33BE1D5C30780D4E96</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>Pods-RxLibrary-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>E2EA100B27BDAB6CA32F3814</key>
- <dict>
- <key>children</key>
- <array>
- <string>4B765AEAB08FDC86E8082F7A</string>
- <string>644143496CECB668F61BCD16</string>
- <string>D756E08287486CC7A7034803</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Targets Support Files</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>E328084D7C583851D3BE25CF</key>
- <dict>
- <key>fileRef</key>
- <string>34373F1941450D17C3F85B57</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>E4F23FE4AEB216E7D1E2B7EE</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-Sample.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>E61F9CBEB0CA9A172C4AA56B</key>
- <dict>
- <key>attributes</key>
- <dict>
- <key>LastUpgradeCheck</key>
- <string>0510</string>
- </dict>
- <key>buildConfigurationList</key>
- <string>B22A719DB3DFD2337E996D6A</string>
- <key>compatibilityVersion</key>
- <string>Xcode 3.2</string>
- <key>developmentRegion</key>
- <string>English</string>
- <key>hasScannedForEncodings</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXProject</string>
- <key>knownRegions</key>
- <array>
- <string>en</string>
- </array>
- <key>mainGroup</key>
- <string>39B5F5991112189C12D87D40</string>
- <key>productRefGroup</key>
- <string>4D580403A4A30D76B96E9775</string>
- <key>projectDirPath</key>
- <string></string>
- <key>projectReferences</key>
- <array/>
- <key>projectRoot</key>
- <string></string>
- <key>targets</key>
- <array>
- <string>7962371F2502CBAEBF859730</string>
- <string>AB3F9F2CFA29030A599E9231</string>
- <string>AEECE9DFCC8F060F1E30A421</string>
- <string>1F1DE3733C2AC2A97CA8885A</string>
- <string>66E177AC7F3B02B51D36A226</string>
- <string>4E2021A981DA9A189922E0C6</string>
- <string>B37278C2CEC4C1C433BEF120</string>
- <string>A10CFA4D4ED9B20894905742</string>
- <string>474A50F85C06F74769FAD474</string>
- </array>
- </dict>
- <key>EA41D57C3938E8D766E0224F</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods-Sample-RxLibrary.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>EA8F6101AB32D6B0A3FC0163</key>
- <dict>
- <key>fileRef</key>
- <string>F776B445ABD393C908B02302</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>EA915E5B33F07CD0B9F8ACE9</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>GRXWriter+Immediate.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>EB0497400F84ADD968F6AB42</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text</string>
- <key>path</key>
- <string>Pods-SampleTests-acknowledgements.markdown</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>EB86FC57EE5F50944BA86EE3</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>path</key>
- <string>Pods-GRPCClient-Private.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>EBB8787CD50E6221A0ABA3AE</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>02396B6B22E0450EA29193E9</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREFIX_HEADER</key>
- <string>Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>EC47C9C8660A81111C71C967</key>
- <dict>
- <key>fileRef</key>
- <string>003D718984A073D9C6C71422</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>EC4BA4B1D02C3BA6DBB450E7</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text</string>
- <key>name</key>
- <string>Podfile</string>
- <key>path</key>
- <string>../Podfile</string>
- <key>sourceTree</key>
- <string>SOURCE_ROOT</string>
- <key>xcLanguageSpecificationIdentifier</key>
- <string>xcode.lang.ruby</string>
- </dict>
- <key>ED9460BEAAB47A2752887CE9</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>51DBA8F3C7D4E67BDD768066</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_CFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_CPLUSPLUSFLAGS</key>
- <array>
- <string>-DNS_BLOCK_ASSERTIONS=1</string>
- <string>$(inherited)</string>
- </array>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>EE156F6201B39BDD5F905822</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>Pods-GRPCClient-prefix.pch</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>EE695A82B047142EA781152E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>name</key>
- <string>GRPCMethodName+HTTP2Encoding.h</string>
- <key>path</key>
- <string>private/GRPCMethodName+HTTP2Encoding.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>EE85C49640E6202C2A33CDF6</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>048EFCCABBC3F25828644716</string>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>DSTROOT</key>
- <string>/tmp/xcodeproj.dst</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PRECOMPILE_PREFIX_HEADER</key>
- <string>YES</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>INSTALL_PATH</key>
- <string>$(BUILT_PRODUCTS_DIR)</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.0</string>
- <key>OTHER_LDFLAGS</key>
- <string></string>
- <key>OTHER_LIBTOOLFLAGS</key>
- <string></string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>PUBLIC_HEADERS_FOLDER_PATH</key>
- <string>$(TARGET_NAME)</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>SKIP_INSTALL</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>EF97D57CA44A79151103F06B</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>name</key>
- <string>Pods-SampleTests-RxLibrary</string>
- <key>target</key>
- <string>474A50F85C06F74769FAD474</string>
- <key>targetProxy</key>
- <string>FE333C59E3BD0F9986105E29</string>
- </dict>
- <key>F058968A71750BBCF4F4FB1C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>03289193476D7E6EE456FAA8</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>F156B1B8573809A342E0AE1F</key>
- <dict>
- <key>fileRef</key>
- <string>CEA794A7056AFAB8256CC44D</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F2B5B896D8C7E13B5E8ADA28</key>
- <dict>
- <key>fileRef</key>
- <string>E0CF2237012441B69E760029</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F37E3DFDFA20082CBC4E2257</key>
- <dict>
- <key>fileRef</key>
- <string>6BBDA0AD2955451BBF881052</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F4586BA420EA562FECC43A3A</key>
- <dict>
- <key>fileRef</key>
- <string>A7CE4BCE7B6959BCDC54B854</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F541961867C9493F07D54B8E</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRPCDelegateWrapper.m</string>
- <key>path</key>
- <string>private/GRPCDelegateWrapper.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>F636FFBF62AFF197BE3CB427</key>
- <dict>
- <key>fileRef</key>
- <string>34373F1941450D17C3F85B57</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F6A0AD6C190915DD52886BE2</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>EE85C49640E6202C2A33CDF6</string>
- <string>ED9460BEAAB47A2752887CE9</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>F6B6558E339AD89F764A6D88</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods-Sample-RxLibrary.xcconfig</string>
- <key>path</key>
- <string>../Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>F776B445ABD393C908B02302</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>GRXWriter+Transformations.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>F84427B4C72738E045D44E6C</key>
- <dict>
- <key>fileRef</key>
- <string>E0CF2237012441B69E760029</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>F911880EC1D908050569F8AF</key>
- <dict>
- <key>fileRef</key>
- <string>3E850442224A3D7C7540C6C5</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>FA5E9BC13067F1E32D6311E6</key>
- <dict>
- <key>fileRef</key>
- <string>FB880554D85130C733402058</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>FB880554D85130C733402058</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>name</key>
- <string>GRPCChannel.m</string>
- <key>path</key>
- <string>private/GRPCChannel.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>FBC9D2D66DA1B0B501961B55</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>474A50F85C06F74769FAD474</string>
- <key>remoteInfo</key>
- <string>Pods-SampleTests-RxLibrary</string>
- </dict>
- <key>FD9953A9B079B03396B2FEA3</key>
- <dict>
- <key>fileRef</key>
- <string>F541961867C9493F07D54B8E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>FE333C59E3BD0F9986105E29</key>
- <dict>
- <key>containerPortal</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>474A50F85C06F74769FAD474</string>
- <key>remoteInfo</key>
- <string>Pods-SampleTests-RxLibrary</string>
- </dict>
- <key>FF34F6701990B0955422EC9C</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>EBB8787CD50E6221A0ABA3AE</string>
- <string>0041F7F38D0B99E977EC7A9B</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>FF378D56A81AE6EFC739CDE6</key>
- <dict>
- <key>fileRef</key>
- <string>617AA57F150724B1881EC92E</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>FFC668E9994CC6407B338F9D</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.plist.xml</string>
- <key>path</key>
- <string>Pods-acknowledgements.plist</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- </dict>
- <key>rootObject</key>
- <string>E61F9CBEB0CA9A172C4AA56B</string>
-</dict>
-</plist>
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-Private.xcconfig
deleted file mode 100644
index 27df354315..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-GRPCClient.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/GRPCClient" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-dummy.m
deleted file mode 100644
index 8cac89bb84..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_GRPCClient : NSObject
-@end
-@implementation PodsDummy_Pods_GRPCClient
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch
deleted file mode 100644
index 95cf11d9fb..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-GRPCClient/Pods-GRPCClient.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-Private.xcconfig
deleted file mode 100644
index a1c3897b81..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-RxLibrary.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-dummy.m
deleted file mode 100644
index 79e1460257..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_RxLibrary : NSObject
-@end
-@implementation PodsDummy_Pods_RxLibrary
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch
deleted file mode 100644
index 95cf11d9fb..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-RxLibrary/Pods-RxLibrary.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-Private.xcconfig
deleted file mode 100644
index e23f7be66f..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-Sample-GRPCClient.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/GRPCClient" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-dummy.m
deleted file mode 100644
index 2bf2682a72..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_Sample_GRPCClient : NSObject
-@end
-@implementation PodsDummy_Pods_Sample_GRPCClient
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch
deleted file mode 100644
index 0e807f67a3..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-Sample-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-GRPCClient/Pods-Sample-GRPCClient.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig
deleted file mode 100644
index 023a22eb14..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-Sample-RxLibrary.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m
deleted file mode 100644
index c81b57bbe8..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_Sample_RxLibrary : NSObject
-@end
-@implementation PodsDummy_Pods_Sample_RxLibrary
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch
deleted file mode 100644
index 0e807f67a3..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-Sample-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample-RxLibrary/Pods-Sample-RxLibrary.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.markdown b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.markdown
deleted file mode 100644
index 255149a828..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.markdown
+++ /dev/null
@@ -1,3 +0,0 @@
-# Acknowledgements
-This application makes use of the following third party libraries:
-Generated by CocoaPods - http://cocoapods.org
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.plist b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.plist
deleted file mode 100644
index e4edebe92d..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-acknowledgements.plist
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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>PreferenceSpecifiers</key>
- <array>
- <dict>
- <key>FooterText</key>
- <string>This application makes use of the following third party libraries:</string>
- <key>Title</key>
- <string>Acknowledgements</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>Generated by CocoaPods - http://cocoapods.org</string>
- <key>Title</key>
- <string></string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- </array>
- <key>StringsTable</key>
- <string>Acknowledgements</string>
- <key>Title</key>
- <string>Acknowledgements</string>
-</dict>
-</plist>
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-dummy.m
deleted file mode 100644
index b5ca68a1c5..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_Sample : NSObject
-@end
-@implementation PodsDummy_Pods_Sample
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-environment.h b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-environment.h
deleted file mode 100644
index d0acfc70ec..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-environment.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-// To check if a library is compiled with CocoaPods you
-// can use the `COCOAPODS` macro definition which is
-// defined in the xcconfigs so it is available in
-// headers also when they are imported in the client
-// project.
-
-
-// GRPCClient
-#define COCOAPODS_POD_AVAILABLE_GRPCClient
-#define COCOAPODS_VERSION_MAJOR_GRPCClient 0
-#define COCOAPODS_VERSION_MINOR_GRPCClient 0
-#define COCOAPODS_VERSION_PATCH_GRPCClient 1
-
-// RxLibrary
-#define COCOAPODS_POD_AVAILABLE_RxLibrary
-#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
-#define COCOAPODS_VERSION_MINOR_RxLibrary 0
-#define COCOAPODS_VERSION_PATCH_RxLibrary 1
-
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh
deleted file mode 100755
index e149064a09..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-set -e
-
-mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-
-RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
-> "$RESOURCES_TO_COPY"
-
-install_resource()
-{
- case $1 in
- *.storyboard)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.xib)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.framework)
- echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- ;;
- *.xcdatamodel)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
- ;;
- *.xcdatamodeld)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
- ;;
- *.xcmappingmodel)
- echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
- xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
- ;;
- *.xcassets)
- ;;
- /*)
- echo "$1"
- echo "$1" >> "$RESOURCES_TO_COPY"
- ;;
- *)
- echo "${PODS_ROOT}/$1"
- echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
- ;;
- esac
-}
-
-rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-if [[ "${ACTION}" == "install" ]]; then
- rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
-rm -f "$RESOURCES_TO_COPY"
-
-if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
-then
- case "${TARGETED_DEVICE_FAMILY}" in
- 1,2)
- TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
- ;;
- 1)
- TARGET_DEVICE_ARGS="--target-device iphone"
- ;;
- 2)
- TARGET_DEVICE_ARGS="--target-device ipad"
- ;;
- *)
- TARGET_DEVICE_ARGS="--target-device mac"
- ;;
- esac
- find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig
deleted file mode 100644
index 06aa64cfac..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-Sample-GRPCClient" -l"Pods-Sample-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig
deleted file mode 100644
index 06aa64cfac..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-Sample-GRPCClient" -l"Pods-Sample-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-Private.xcconfig
deleted file mode 100644
index 01e25c4a88..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-SampleTests-GRPCClient.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/GRPCClient" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-dummy.m
deleted file mode 100644
index 7ecd57a34b..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_SampleTests_GRPCClient : NSObject
-@end
-@implementation PodsDummy_Pods_SampleTests_GRPCClient
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch
deleted file mode 100644
index abd5651587..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-SampleTests-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-GRPCClient/Pods-SampleTests-GRPCClient.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig
deleted file mode 100644
index 67069bae5d..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-Private.xcconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "Pods-SampleTests-RxLibrary.xcconfig"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Build" "${PODS_ROOT}/Headers/Build/RxLibrary" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC
-PODS_ROOT = ${SRCROOT} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m
deleted file mode 100644
index d57aef11d6..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_SampleTests_RxLibrary : NSObject
-@end
-@implementation PodsDummy_Pods_SampleTests_RxLibrary
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch
deleted file mode 100644
index abd5651587..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary-prefix.pch
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#endif
-
-#import "Pods-SampleTests-environment.h"
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests-RxLibrary/Pods-SampleTests-RxLibrary.xcconfig
+++ /dev/null
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.markdown b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.markdown
deleted file mode 100644
index 255149a828..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.markdown
+++ /dev/null
@@ -1,3 +0,0 @@
-# Acknowledgements
-This application makes use of the following third party libraries:
-Generated by CocoaPods - http://cocoapods.org
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.plist b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.plist
deleted file mode 100644
index e4edebe92d..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-acknowledgements.plist
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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>PreferenceSpecifiers</key>
- <array>
- <dict>
- <key>FooterText</key>
- <string>This application makes use of the following third party libraries:</string>
- <key>Title</key>
- <string>Acknowledgements</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>Generated by CocoaPods - http://cocoapods.org</string>
- <key>Title</key>
- <string></string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- </array>
- <key>StringsTable</key>
- <string>Acknowledgements</string>
- <key>Title</key>
- <string>Acknowledgements</string>
-</dict>
-</plist>
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-dummy.m
deleted file mode 100644
index 01b4ad73ba..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_SampleTests : NSObject
-@end
-@implementation PodsDummy_Pods_SampleTests
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-environment.h b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-environment.h
deleted file mode 100644
index d0acfc70ec..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-environment.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-// To check if a library is compiled with CocoaPods you
-// can use the `COCOAPODS` macro definition which is
-// defined in the xcconfigs so it is available in
-// headers also when they are imported in the client
-// project.
-
-
-// GRPCClient
-#define COCOAPODS_POD_AVAILABLE_GRPCClient
-#define COCOAPODS_VERSION_MAJOR_GRPCClient 0
-#define COCOAPODS_VERSION_MINOR_GRPCClient 0
-#define COCOAPODS_VERSION_PATCH_GRPCClient 1
-
-// RxLibrary
-#define COCOAPODS_POD_AVAILABLE_RxLibrary
-#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
-#define COCOAPODS_VERSION_MINOR_RxLibrary 0
-#define COCOAPODS_VERSION_PATCH_RxLibrary 1
-
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh
deleted file mode 100755
index e149064a09..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-set -e
-
-mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-
-RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
-> "$RESOURCES_TO_COPY"
-
-install_resource()
-{
- case $1 in
- *.storyboard)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.xib)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.framework)
- echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- ;;
- *.xcdatamodel)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
- ;;
- *.xcdatamodeld)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
- ;;
- *.xcmappingmodel)
- echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
- xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
- ;;
- *.xcassets)
- ;;
- /*)
- echo "$1"
- echo "$1" >> "$RESOURCES_TO_COPY"
- ;;
- *)
- echo "${PODS_ROOT}/$1"
- echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
- ;;
- esac
-}
-
-rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-if [[ "${ACTION}" == "install" ]]; then
- rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
-rm -f "$RESOURCES_TO_COPY"
-
-if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
-then
- case "${TARGETED_DEVICE_FAMILY}" in
- 1,2)
- TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
- ;;
- 1)
- TARGET_DEVICE_ARGS="--target-device iphone"
- ;;
- 2)
- TARGET_DEVICE_ARGS="--target-device ipad"
- ;;
- *)
- TARGET_DEVICE_ARGS="--target-device mac"
- ;;
- esac
- find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig
deleted file mode 100644
index 892541c53e..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-SampleTests-GRPCClient" -l"Pods-SampleTests-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig
deleted file mode 100644
index 892541c53e..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-SampleTests-GRPCClient" -l"Pods-SampleTests-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
deleted file mode 100644
index 255149a828..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown
+++ /dev/null
@@ -1,3 +0,0 @@
-# Acknowledgements
-This application makes use of the following third party libraries:
-Generated by CocoaPods - http://cocoapods.org
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
deleted file mode 100644
index e4edebe92d..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-acknowledgements.plist
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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>PreferenceSpecifiers</key>
- <array>
- <dict>
- <key>FooterText</key>
- <string>This application makes use of the following third party libraries:</string>
- <key>Title</key>
- <string>Acknowledgements</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>Generated by CocoaPods - http://cocoapods.org</string>
- <key>Title</key>
- <string></string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- </array>
- <key>StringsTable</key>
- <string>Acknowledgements</string>
- <key>Title</key>
- <string>Acknowledgements</string>
-</dict>
-</plist>
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-dummy.m b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-dummy.m
deleted file mode 100644
index ade64bd1a9..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-dummy.m
+++ /dev/null
@@ -1,5 +0,0 @@
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods : NSObject
-@end
-@implementation PodsDummy_Pods
-@end
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-environment.h b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-environment.h
deleted file mode 100644
index d0acfc70ec..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-environment.h
+++ /dev/null
@@ -1,20 +0,0 @@
-
-// To check if a library is compiled with CocoaPods you
-// can use the `COCOAPODS` macro definition which is
-// defined in the xcconfigs so it is available in
-// headers also when they are imported in the client
-// project.
-
-
-// GRPCClient
-#define COCOAPODS_POD_AVAILABLE_GRPCClient
-#define COCOAPODS_VERSION_MAJOR_GRPCClient 0
-#define COCOAPODS_VERSION_MINOR_GRPCClient 0
-#define COCOAPODS_VERSION_PATCH_GRPCClient 1
-
-// RxLibrary
-#define COCOAPODS_POD_AVAILABLE_RxLibrary
-#define COCOAPODS_VERSION_MAJOR_RxLibrary 0
-#define COCOAPODS_VERSION_MINOR_RxLibrary 0
-#define COCOAPODS_VERSION_PATCH_RxLibrary 1
-
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-resources.sh b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-resources.sh
deleted file mode 100755
index e149064a09..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods-resources.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-set -e
-
-mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-
-RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
-> "$RESOURCES_TO_COPY"
-
-install_resource()
-{
- case $1 in
- *.storyboard)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.xib)
- echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
- ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
- ;;
- *.framework)
- echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
- ;;
- *.xcdatamodel)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
- ;;
- *.xcdatamodeld)
- echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
- xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
- ;;
- *.xcmappingmodel)
- echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\""
- xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
- ;;
- *.xcassets)
- ;;
- /*)
- echo "$1"
- echo "$1" >> "$RESOURCES_TO_COPY"
- ;;
- *)
- echo "${PODS_ROOT}/$1"
- echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
- ;;
- esac
-}
-
-rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-if [[ "${ACTION}" == "install" ]]; then
- rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
-rm -f "$RESOURCES_TO_COPY"
-
-if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
-then
- case "${TARGETED_DEVICE_FAMILY}" in
- 1,2)
- TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
- ;;
- 1)
- TARGET_DEVICE_ARGS="--target-device iphone"
- ;;
- 2)
- TARGET_DEVICE_ARGS="--target-device ipad"
- ;;
- *)
- TARGET_DEVICE_ARGS="--target-device mac"
- ;;
- esac
- find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
-fi
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.debug.xcconfig
deleted file mode 100644
index e9fafccb07..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.debug.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-GRPCClient" -l"Pods-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.release.xcconfig b/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.release.xcconfig
deleted file mode 100644
index e9fafccb07..0000000000
--- a/src/objective-c/examples/Sample/Pods/Target Support Files/Pods/Pods.release.xcconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GRPCClient" "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/GRPCClient" -isystem "${PODS_ROOT}/Headers/Public/RxLibrary"
-OTHER_LDFLAGS = -ObjC -l"Pods-GRPCClient" -l"Pods-RxLibrary"
-OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
-PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/README.md b/src/objective-c/examples/Sample/README.md
index 45ba544a34..716241bb75 100644
--- a/src/objective-c/examples/Sample/README.md
+++ b/src/objective-c/examples/Sample/README.md
@@ -1,2 +1 @@
-When contributing changes to this sample, use Cocoapods to manage the workspace
-file and everything under the Pods directory. \ No newline at end of file
+This sample app requires the use of Cocoapods. After installing Cocoapods, run `pod install` in this directory to recreate its dependencies. (This will compile OpenSSL, which takes some time).
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.h b/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.h
new file mode 100644
index 0000000000..bf9fa3e36f
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.h
@@ -0,0 +1,103 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import <ProtocolBuffers/ProtocolBuffers.h>
+
+// @@protoc_insertion_point(imports)
+
+@class ObjectiveCFileOptions;
+@class ObjectiveCFileOptionsBuilder;
+@class PBDescriptorProto;
+@class PBDescriptorProtoBuilder;
+@class PBDescriptorProtoExtensionRange;
+@class PBDescriptorProtoExtensionRangeBuilder;
+@class PBEnumDescriptorProto;
+@class PBEnumDescriptorProtoBuilder;
+@class PBEnumOptions;
+@class PBEnumOptionsBuilder;
+@class PBEnumValueDescriptorProto;
+@class PBEnumValueDescriptorProtoBuilder;
+@class PBEnumValueOptions;
+@class PBEnumValueOptionsBuilder;
+@class PBFieldDescriptorProto;
+@class PBFieldDescriptorProtoBuilder;
+@class PBFieldOptions;
+@class PBFieldOptionsBuilder;
+@class PBFileDescriptorProto;
+@class PBFileDescriptorProtoBuilder;
+@class PBFileDescriptorSet;
+@class PBFileDescriptorSetBuilder;
+@class PBFileOptions;
+@class PBFileOptionsBuilder;
+@class PBMessageOptions;
+@class PBMessageOptionsBuilder;
+@class PBMethodDescriptorProto;
+@class PBMethodDescriptorProtoBuilder;
+@class PBMethodOptions;
+@class PBMethodOptionsBuilder;
+@class PBOneofDescriptorProto;
+@class PBOneofDescriptorProtoBuilder;
+@class PBServiceDescriptorProto;
+@class PBServiceDescriptorProtoBuilder;
+@class PBServiceOptions;
+@class PBServiceOptionsBuilder;
+@class PBSourceCodeInfo;
+@class PBSourceCodeInfoBuilder;
+@class PBSourceCodeInfoLocation;
+@class PBSourceCodeInfoLocationBuilder;
+@class PBUninterpretedOption;
+@class PBUninterpretedOptionBuilder;
+@class PBUninterpretedOptionNamePart;
+@class PBUninterpretedOptionNamePartBuilder;
+@class RMTEmpty;
+@class RMTEmptyBuilder;
+
+
+
+@interface RMTEmptyRoot : NSObject {
+}
++ (PBExtensionRegistry*) extensionRegistry;
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry;
+@end
+
+@interface RMTEmpty : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+}
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTEmptyBuilder*) builder;
++ (RMTEmptyBuilder*) builder;
++ (RMTEmptyBuilder*) builderWithPrototype:(RMTEmpty*) prototype;
+- (RMTEmptyBuilder*) toBuilder;
+
++ (RMTEmpty*) parseFromData:(NSData*) data;
++ (RMTEmpty*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTEmpty*) parseFromInputStream:(NSInputStream*) input;
++ (RMTEmpty*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTEmpty*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTEmpty*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTEmptyBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTEmpty* resultEmpty;
+}
+
+- (RMTEmpty*) defaultInstance;
+
+- (RMTEmptyBuilder*) clear;
+- (RMTEmptyBuilder*) clone;
+
+- (RMTEmpty*) build;
+- (RMTEmpty*) buildPartial;
+
+- (RMTEmptyBuilder*) mergeFrom:(RMTEmpty*) other;
+- (RMTEmptyBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTEmptyBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.m b/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.m
new file mode 100644
index 0000000000..8e39cb70d1
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.m
@@ -0,0 +1,179 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import "Empty.pb.h"
+// @@protoc_insertion_point(imports)
+
+@implementation RMTEmptyRoot
+static PBExtensionRegistry* extensionRegistry = nil;
++ (PBExtensionRegistry*) extensionRegistry {
+ return extensionRegistry;
+}
+
++ (void) initialize {
+ if (self == [RMTEmptyRoot class]) {
+ PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry];
+ [self registerAllExtensions:registry];
+ [ObjectivecDescriptorRoot registerAllExtensions:registry];
+ extensionRegistry = registry;
+ }
+}
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry {
+}
+@end
+
+@interface RMTEmpty ()
+@end
+
+@implementation RMTEmpty
+
+- (instancetype) init {
+ if ((self = [super init])) {
+ }
+ return self;
+}
+static RMTEmpty* defaultRMTEmptyInstance = nil;
++ (void) initialize {
+ if (self == [RMTEmpty class]) {
+ defaultRMTEmptyInstance = [[RMTEmpty alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTEmptyInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTEmptyInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTEmpty*) parseFromData:(NSData*) data {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromData:data] build];
+}
++ (RMTEmpty*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTEmpty*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromInputStream:input] build];
+}
++ (RMTEmpty*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTEmpty*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTEmpty*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTEmpty*)[[[RMTEmpty builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTEmptyBuilder*) builder {
+ return [[RMTEmptyBuilder alloc] init];
+}
++ (RMTEmptyBuilder*) builderWithPrototype:(RMTEmpty*) prototype {
+ return [[RMTEmpty builder] mergeFrom:prototype];
+}
+- (RMTEmptyBuilder*) builder {
+ return [RMTEmpty builder];
+}
+- (RMTEmptyBuilder*) toBuilder {
+ return [RMTEmpty builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTEmpty class]]) {
+ return NO;
+ }
+ RMTEmpty *otherMessage = other;
+ return
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTEmptyBuilder()
+@property (strong) RMTEmpty* resultEmpty;
+@end
+
+@implementation RMTEmptyBuilder
+@synthesize resultEmpty;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultEmpty = [[RMTEmpty alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultEmpty;
+}
+- (RMTEmptyBuilder*) clear {
+ self.resultEmpty = [[RMTEmpty alloc] init];
+ return self;
+}
+- (RMTEmptyBuilder*) clone {
+ return [RMTEmpty builderWithPrototype:resultEmpty];
+}
+- (RMTEmpty*) defaultInstance {
+ return [RMTEmpty defaultInstance];
+}
+- (RMTEmpty*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTEmpty*) buildPartial {
+ RMTEmpty* returnMe = resultEmpty;
+ self.resultEmpty = nil;
+ return returnMe;
+}
+- (RMTEmptyBuilder*) mergeFrom:(RMTEmpty*) other {
+ if (other == [RMTEmpty defaultInstance]) {
+ return self;
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTEmptyBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTEmptyBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ }
+ }
+}
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.h b/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.h
new file mode 100644
index 0000000000..0a08e67702
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.h
@@ -0,0 +1,578 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import <ProtocolBuffers/ProtocolBuffers.h>
+
+// @@protoc_insertion_point(imports)
+
+@class ObjectiveCFileOptions;
+@class ObjectiveCFileOptionsBuilder;
+@class PBDescriptorProto;
+@class PBDescriptorProtoBuilder;
+@class PBDescriptorProtoExtensionRange;
+@class PBDescriptorProtoExtensionRangeBuilder;
+@class PBEnumDescriptorProto;
+@class PBEnumDescriptorProtoBuilder;
+@class PBEnumOptions;
+@class PBEnumOptionsBuilder;
+@class PBEnumValueDescriptorProto;
+@class PBEnumValueDescriptorProtoBuilder;
+@class PBEnumValueOptions;
+@class PBEnumValueOptionsBuilder;
+@class PBFieldDescriptorProto;
+@class PBFieldDescriptorProtoBuilder;
+@class PBFieldOptions;
+@class PBFieldOptionsBuilder;
+@class PBFileDescriptorProto;
+@class PBFileDescriptorProtoBuilder;
+@class PBFileDescriptorSet;
+@class PBFileDescriptorSetBuilder;
+@class PBFileOptions;
+@class PBFileOptionsBuilder;
+@class PBMessageOptions;
+@class PBMessageOptionsBuilder;
+@class PBMethodDescriptorProto;
+@class PBMethodDescriptorProtoBuilder;
+@class PBMethodOptions;
+@class PBMethodOptionsBuilder;
+@class PBOneofDescriptorProto;
+@class PBOneofDescriptorProtoBuilder;
+@class PBServiceDescriptorProto;
+@class PBServiceDescriptorProtoBuilder;
+@class PBServiceOptions;
+@class PBServiceOptionsBuilder;
+@class PBSourceCodeInfo;
+@class PBSourceCodeInfoBuilder;
+@class PBSourceCodeInfoLocation;
+@class PBSourceCodeInfoLocationBuilder;
+@class PBUninterpretedOption;
+@class PBUninterpretedOptionBuilder;
+@class PBUninterpretedOptionNamePart;
+@class PBUninterpretedOptionNamePartBuilder;
+@class RMTPayload;
+@class RMTPayloadBuilder;
+@class RMTResponseParameters;
+@class RMTResponseParametersBuilder;
+@class RMTSimpleRequest;
+@class RMTSimpleRequestBuilder;
+@class RMTSimpleResponse;
+@class RMTSimpleResponseBuilder;
+@class RMTStreamingInputCallRequest;
+@class RMTStreamingInputCallRequestBuilder;
+@class RMTStreamingInputCallResponse;
+@class RMTStreamingInputCallResponseBuilder;
+@class RMTStreamingOutputCallRequest;
+@class RMTStreamingOutputCallRequestBuilder;
+@class RMTStreamingOutputCallResponse;
+@class RMTStreamingOutputCallResponseBuilder;
+
+
+typedef NS_ENUM(SInt32, RMTPayloadType) {
+ RMTPayloadTypeCompressable = 0,
+ RMTPayloadTypeUncompressable = 1,
+ RMTPayloadTypeRandom = 2,
+};
+
+BOOL RMTPayloadTypeIsValidValue(RMTPayloadType value);
+NSString *NSStringFromRMTPayloadType(RMTPayloadType value);
+
+
+@interface RMTMessagesRoot : NSObject {
+}
++ (PBExtensionRegistry*) extensionRegistry;
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry;
+@end
+
+@interface RMTPayload : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasBody_:1;
+ BOOL hasType_:1;
+ NSData* body;
+ RMTPayloadType type;
+}
+- (BOOL) hasType;
+- (BOOL) hasBody;
+@property (readonly) RMTPayloadType type;
+@property (readonly, strong) NSData* body;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTPayloadBuilder*) builder;
++ (RMTPayloadBuilder*) builder;
++ (RMTPayloadBuilder*) builderWithPrototype:(RMTPayload*) prototype;
+- (RMTPayloadBuilder*) toBuilder;
+
++ (RMTPayload*) parseFromData:(NSData*) data;
++ (RMTPayload*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTPayload*) parseFromInputStream:(NSInputStream*) input;
++ (RMTPayload*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTPayload*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTPayload*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTPayloadBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTPayload* resultPayload;
+}
+
+- (RMTPayload*) defaultInstance;
+
+- (RMTPayloadBuilder*) clear;
+- (RMTPayloadBuilder*) clone;
+
+- (RMTPayload*) build;
+- (RMTPayload*) buildPartial;
+
+- (RMTPayloadBuilder*) mergeFrom:(RMTPayload*) other;
+- (RMTPayloadBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTPayloadBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasType;
+- (RMTPayloadType) type;
+- (RMTPayloadBuilder*) setType:(RMTPayloadType) value;
+- (RMTPayloadBuilder*) clearType;
+
+- (BOOL) hasBody;
+- (NSData*) body;
+- (RMTPayloadBuilder*) setBody:(NSData*) value;
+- (RMTPayloadBuilder*) clearBody;
+@end
+
+@interface RMTSimpleRequest : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasFillUsername_:1;
+ BOOL hasFillOauthScope_:1;
+ BOOL hasResponseSize_:1;
+ BOOL hasPayload_:1;
+ BOOL hasResponseType_:1;
+ BOOL fillUsername_:1;
+ BOOL fillOauthScope_:1;
+ SInt32 responseSize;
+ RMTPayload* payload;
+ RMTPayloadType responseType;
+}
+- (BOOL) hasResponseType;
+- (BOOL) hasResponseSize;
+- (BOOL) hasPayload;
+- (BOOL) hasFillUsername;
+- (BOOL) hasFillOauthScope;
+@property (readonly) RMTPayloadType responseType;
+@property (readonly) SInt32 responseSize;
+@property (readonly, strong) RMTPayload* payload;
+- (BOOL) fillUsername;
+- (BOOL) fillOauthScope;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTSimpleRequestBuilder*) builder;
++ (RMTSimpleRequestBuilder*) builder;
++ (RMTSimpleRequestBuilder*) builderWithPrototype:(RMTSimpleRequest*) prototype;
+- (RMTSimpleRequestBuilder*) toBuilder;
+
++ (RMTSimpleRequest*) parseFromData:(NSData*) data;
++ (RMTSimpleRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTSimpleRequest*) parseFromInputStream:(NSInputStream*) input;
++ (RMTSimpleRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTSimpleRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTSimpleRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTSimpleRequestBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTSimpleRequest* resultSimpleRequest;
+}
+
+- (RMTSimpleRequest*) defaultInstance;
+
+- (RMTSimpleRequestBuilder*) clear;
+- (RMTSimpleRequestBuilder*) clone;
+
+- (RMTSimpleRequest*) build;
+- (RMTSimpleRequest*) buildPartial;
+
+- (RMTSimpleRequestBuilder*) mergeFrom:(RMTSimpleRequest*) other;
+- (RMTSimpleRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTSimpleRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasResponseType;
+- (RMTPayloadType) responseType;
+- (RMTSimpleRequestBuilder*) setResponseType:(RMTPayloadType) value;
+- (RMTSimpleRequestBuilder*) clearResponseType;
+
+- (BOOL) hasResponseSize;
+- (SInt32) responseSize;
+- (RMTSimpleRequestBuilder*) setResponseSize:(SInt32) value;
+- (RMTSimpleRequestBuilder*) clearResponseSize;
+
+- (BOOL) hasPayload;
+- (RMTPayload*) payload;
+- (RMTSimpleRequestBuilder*) setPayload:(RMTPayload*) value;
+- (RMTSimpleRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue;
+- (RMTSimpleRequestBuilder*) mergePayload:(RMTPayload*) value;
+- (RMTSimpleRequestBuilder*) clearPayload;
+
+- (BOOL) hasFillUsername;
+- (BOOL) fillUsername;
+- (RMTSimpleRequestBuilder*) setFillUsername:(BOOL) value;
+- (RMTSimpleRequestBuilder*) clearFillUsername;
+
+- (BOOL) hasFillOauthScope;
+- (BOOL) fillOauthScope;
+- (RMTSimpleRequestBuilder*) setFillOauthScope:(BOOL) value;
+- (RMTSimpleRequestBuilder*) clearFillOauthScope;
+@end
+
+@interface RMTSimpleResponse : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasUsername_:1;
+ BOOL hasOauthScope_:1;
+ BOOL hasPayload_:1;
+ NSString* username;
+ NSString* oauthScope;
+ RMTPayload* payload;
+}
+- (BOOL) hasPayload;
+- (BOOL) hasUsername;
+- (BOOL) hasOauthScope;
+@property (readonly, strong) RMTPayload* payload;
+@property (readonly, strong) NSString* username;
+@property (readonly, strong) NSString* oauthScope;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTSimpleResponseBuilder*) builder;
++ (RMTSimpleResponseBuilder*) builder;
++ (RMTSimpleResponseBuilder*) builderWithPrototype:(RMTSimpleResponse*) prototype;
+- (RMTSimpleResponseBuilder*) toBuilder;
+
++ (RMTSimpleResponse*) parseFromData:(NSData*) data;
++ (RMTSimpleResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTSimpleResponse*) parseFromInputStream:(NSInputStream*) input;
++ (RMTSimpleResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTSimpleResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTSimpleResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTSimpleResponseBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTSimpleResponse* resultSimpleResponse;
+}
+
+- (RMTSimpleResponse*) defaultInstance;
+
+- (RMTSimpleResponseBuilder*) clear;
+- (RMTSimpleResponseBuilder*) clone;
+
+- (RMTSimpleResponse*) build;
+- (RMTSimpleResponse*) buildPartial;
+
+- (RMTSimpleResponseBuilder*) mergeFrom:(RMTSimpleResponse*) other;
+- (RMTSimpleResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTSimpleResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasPayload;
+- (RMTPayload*) payload;
+- (RMTSimpleResponseBuilder*) setPayload:(RMTPayload*) value;
+- (RMTSimpleResponseBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue;
+- (RMTSimpleResponseBuilder*) mergePayload:(RMTPayload*) value;
+- (RMTSimpleResponseBuilder*) clearPayload;
+
+- (BOOL) hasUsername;
+- (NSString*) username;
+- (RMTSimpleResponseBuilder*) setUsername:(NSString*) value;
+- (RMTSimpleResponseBuilder*) clearUsername;
+
+- (BOOL) hasOauthScope;
+- (NSString*) oauthScope;
+- (RMTSimpleResponseBuilder*) setOauthScope:(NSString*) value;
+- (RMTSimpleResponseBuilder*) clearOauthScope;
+@end
+
+@interface RMTStreamingInputCallRequest : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasPayload_:1;
+ RMTPayload* payload;
+}
+- (BOOL) hasPayload;
+@property (readonly, strong) RMTPayload* payload;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTStreamingInputCallRequestBuilder*) builder;
++ (RMTStreamingInputCallRequestBuilder*) builder;
++ (RMTStreamingInputCallRequestBuilder*) builderWithPrototype:(RMTStreamingInputCallRequest*) prototype;
+- (RMTStreamingInputCallRequestBuilder*) toBuilder;
+
++ (RMTStreamingInputCallRequest*) parseFromData:(NSData*) data;
++ (RMTStreamingInputCallRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingInputCallRequest*) parseFromInputStream:(NSInputStream*) input;
++ (RMTStreamingInputCallRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingInputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTStreamingInputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTStreamingInputCallRequestBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTStreamingInputCallRequest* resultStreamingInputCallRequest;
+}
+
+- (RMTStreamingInputCallRequest*) defaultInstance;
+
+- (RMTStreamingInputCallRequestBuilder*) clear;
+- (RMTStreamingInputCallRequestBuilder*) clone;
+
+- (RMTStreamingInputCallRequest*) build;
+- (RMTStreamingInputCallRequest*) buildPartial;
+
+- (RMTStreamingInputCallRequestBuilder*) mergeFrom:(RMTStreamingInputCallRequest*) other;
+- (RMTStreamingInputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTStreamingInputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasPayload;
+- (RMTPayload*) payload;
+- (RMTStreamingInputCallRequestBuilder*) setPayload:(RMTPayload*) value;
+- (RMTStreamingInputCallRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue;
+- (RMTStreamingInputCallRequestBuilder*) mergePayload:(RMTPayload*) value;
+- (RMTStreamingInputCallRequestBuilder*) clearPayload;
+@end
+
+@interface RMTStreamingInputCallResponse : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasAggregatedPayloadSize_:1;
+ SInt32 aggregatedPayloadSize;
+}
+- (BOOL) hasAggregatedPayloadSize;
+@property (readonly) SInt32 aggregatedPayloadSize;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTStreamingInputCallResponseBuilder*) builder;
++ (RMTStreamingInputCallResponseBuilder*) builder;
++ (RMTStreamingInputCallResponseBuilder*) builderWithPrototype:(RMTStreamingInputCallResponse*) prototype;
+- (RMTStreamingInputCallResponseBuilder*) toBuilder;
+
++ (RMTStreamingInputCallResponse*) parseFromData:(NSData*) data;
++ (RMTStreamingInputCallResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingInputCallResponse*) parseFromInputStream:(NSInputStream*) input;
++ (RMTStreamingInputCallResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingInputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTStreamingInputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTStreamingInputCallResponseBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTStreamingInputCallResponse* resultStreamingInputCallResponse;
+}
+
+- (RMTStreamingInputCallResponse*) defaultInstance;
+
+- (RMTStreamingInputCallResponseBuilder*) clear;
+- (RMTStreamingInputCallResponseBuilder*) clone;
+
+- (RMTStreamingInputCallResponse*) build;
+- (RMTStreamingInputCallResponse*) buildPartial;
+
+- (RMTStreamingInputCallResponseBuilder*) mergeFrom:(RMTStreamingInputCallResponse*) other;
+- (RMTStreamingInputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTStreamingInputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasAggregatedPayloadSize;
+- (SInt32) aggregatedPayloadSize;
+- (RMTStreamingInputCallResponseBuilder*) setAggregatedPayloadSize:(SInt32) value;
+- (RMTStreamingInputCallResponseBuilder*) clearAggregatedPayloadSize;
+@end
+
+@interface RMTResponseParameters : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasSize_:1;
+ BOOL hasIntervalUs_:1;
+ SInt32 size;
+ SInt32 intervalUs;
+}
+- (BOOL) hasSize;
+- (BOOL) hasIntervalUs;
+@property (readonly) SInt32 size;
+@property (readonly) SInt32 intervalUs;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTResponseParametersBuilder*) builder;
++ (RMTResponseParametersBuilder*) builder;
++ (RMTResponseParametersBuilder*) builderWithPrototype:(RMTResponseParameters*) prototype;
+- (RMTResponseParametersBuilder*) toBuilder;
+
++ (RMTResponseParameters*) parseFromData:(NSData*) data;
++ (RMTResponseParameters*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTResponseParameters*) parseFromInputStream:(NSInputStream*) input;
++ (RMTResponseParameters*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTResponseParameters*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTResponseParameters*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTResponseParametersBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTResponseParameters* resultResponseParameters;
+}
+
+- (RMTResponseParameters*) defaultInstance;
+
+- (RMTResponseParametersBuilder*) clear;
+- (RMTResponseParametersBuilder*) clone;
+
+- (RMTResponseParameters*) build;
+- (RMTResponseParameters*) buildPartial;
+
+- (RMTResponseParametersBuilder*) mergeFrom:(RMTResponseParameters*) other;
+- (RMTResponseParametersBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTResponseParametersBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasSize;
+- (SInt32) size;
+- (RMTResponseParametersBuilder*) setSize:(SInt32) value;
+- (RMTResponseParametersBuilder*) clearSize;
+
+- (BOOL) hasIntervalUs;
+- (SInt32) intervalUs;
+- (RMTResponseParametersBuilder*) setIntervalUs:(SInt32) value;
+- (RMTResponseParametersBuilder*) clearIntervalUs;
+@end
+
+@interface RMTStreamingOutputCallRequest : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasPayload_:1;
+ BOOL hasResponseType_:1;
+ RMTPayload* payload;
+ RMTPayloadType responseType;
+ NSMutableArray * responseParametersArray;
+}
+- (BOOL) hasResponseType;
+- (BOOL) hasPayload;
+@property (readonly) RMTPayloadType responseType;
+@property (readonly, strong) NSArray * responseParameters;
+@property (readonly, strong) RMTPayload* payload;
+- (RMTResponseParameters*)responseParametersAtIndex:(NSUInteger)index;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTStreamingOutputCallRequestBuilder*) builder;
++ (RMTStreamingOutputCallRequestBuilder*) builder;
++ (RMTStreamingOutputCallRequestBuilder*) builderWithPrototype:(RMTStreamingOutputCallRequest*) prototype;
+- (RMTStreamingOutputCallRequestBuilder*) toBuilder;
+
++ (RMTStreamingOutputCallRequest*) parseFromData:(NSData*) data;
++ (RMTStreamingOutputCallRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingOutputCallRequest*) parseFromInputStream:(NSInputStream*) input;
++ (RMTStreamingOutputCallRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingOutputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTStreamingOutputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTStreamingOutputCallRequestBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTStreamingOutputCallRequest* resultStreamingOutputCallRequest;
+}
+
+- (RMTStreamingOutputCallRequest*) defaultInstance;
+
+- (RMTStreamingOutputCallRequestBuilder*) clear;
+- (RMTStreamingOutputCallRequestBuilder*) clone;
+
+- (RMTStreamingOutputCallRequest*) build;
+- (RMTStreamingOutputCallRequest*) buildPartial;
+
+- (RMTStreamingOutputCallRequestBuilder*) mergeFrom:(RMTStreamingOutputCallRequest*) other;
+- (RMTStreamingOutputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTStreamingOutputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasResponseType;
+- (RMTPayloadType) responseType;
+- (RMTStreamingOutputCallRequestBuilder*) setResponseType:(RMTPayloadType) value;
+- (RMTStreamingOutputCallRequestBuilder*) clearResponseType;
+
+- (NSMutableArray *)responseParameters;
+- (RMTResponseParameters*)responseParametersAtIndex:(NSUInteger)index;
+- (RMTStreamingOutputCallRequestBuilder *)addResponseParameters:(RMTResponseParameters*)value;
+- (RMTStreamingOutputCallRequestBuilder *)setResponseParametersArray:(NSArray *)array;
+- (RMTStreamingOutputCallRequestBuilder *)clearResponseParameters;
+
+- (BOOL) hasPayload;
+- (RMTPayload*) payload;
+- (RMTStreamingOutputCallRequestBuilder*) setPayload:(RMTPayload*) value;
+- (RMTStreamingOutputCallRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue;
+- (RMTStreamingOutputCallRequestBuilder*) mergePayload:(RMTPayload*) value;
+- (RMTStreamingOutputCallRequestBuilder*) clearPayload;
+@end
+
+@interface RMTStreamingOutputCallResponse : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasPayload_:1;
+ RMTPayload* payload;
+}
+- (BOOL) hasPayload;
+@property (readonly, strong) RMTPayload* payload;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RMTStreamingOutputCallResponseBuilder*) builder;
++ (RMTStreamingOutputCallResponseBuilder*) builder;
++ (RMTStreamingOutputCallResponseBuilder*) builderWithPrototype:(RMTStreamingOutputCallResponse*) prototype;
+- (RMTStreamingOutputCallResponseBuilder*) toBuilder;
+
++ (RMTStreamingOutputCallResponse*) parseFromData:(NSData*) data;
++ (RMTStreamingOutputCallResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingOutputCallResponse*) parseFromInputStream:(NSInputStream*) input;
++ (RMTStreamingOutputCallResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RMTStreamingOutputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RMTStreamingOutputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RMTStreamingOutputCallResponseBuilder : PBGeneratedMessageBuilder {
+@private
+ RMTStreamingOutputCallResponse* resultStreamingOutputCallResponse;
+}
+
+- (RMTStreamingOutputCallResponse*) defaultInstance;
+
+- (RMTStreamingOutputCallResponseBuilder*) clear;
+- (RMTStreamingOutputCallResponseBuilder*) clone;
+
+- (RMTStreamingOutputCallResponse*) build;
+- (RMTStreamingOutputCallResponse*) buildPartial;
+
+- (RMTStreamingOutputCallResponseBuilder*) mergeFrom:(RMTStreamingOutputCallResponse*) other;
+- (RMTStreamingOutputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RMTStreamingOutputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasPayload;
+- (RMTPayload*) payload;
+- (RMTStreamingOutputCallResponseBuilder*) setPayload:(RMTPayload*) value;
+- (RMTStreamingOutputCallResponseBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue;
+- (RMTStreamingOutputCallResponseBuilder*) mergePayload:(RMTPayload*) value;
+- (RMTStreamingOutputCallResponseBuilder*) clearPayload;
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.m b/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.m
new file mode 100644
index 0000000000..fbad1a9c09
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.m
@@ -0,0 +1,2256 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import "Messages.pb.h"
+// @@protoc_insertion_point(imports)
+
+@implementation RMTMessagesRoot
+static PBExtensionRegistry* extensionRegistry = nil;
++ (PBExtensionRegistry*) extensionRegistry {
+ return extensionRegistry;
+}
+
++ (void) initialize {
+ if (self == [RMTMessagesRoot class]) {
+ PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry];
+ [self registerAllExtensions:registry];
+ [ObjectivecDescriptorRoot registerAllExtensions:registry];
+ extensionRegistry = registry;
+ }
+}
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry {
+}
+@end
+
+BOOL RMTPayloadTypeIsValidValue(RMTPayloadType value) {
+ switch (value) {
+ case RMTPayloadTypeCompressable:
+ case RMTPayloadTypeUncompressable:
+ case RMTPayloadTypeRandom:
+ return YES;
+ default:
+ return NO;
+ }
+}
+NSString *NSStringFromRMTPayloadType(RMTPayloadType value) {
+ switch (value) {
+ case RMTPayloadTypeCompressable:
+ return @"RMTPayloadTypeCompressable";
+ case RMTPayloadTypeUncompressable:
+ return @"RMTPayloadTypeUncompressable";
+ case RMTPayloadTypeRandom:
+ return @"RMTPayloadTypeRandom";
+ default:
+ return nil;
+ }
+}
+
+@interface RMTPayload ()
+@property RMTPayloadType type;
+@property (strong) NSData* body;
+@end
+
+@implementation RMTPayload
+
+- (BOOL) hasType {
+ return !!hasType_;
+}
+- (void) setHasType:(BOOL) _value_ {
+ hasType_ = !!_value_;
+}
+@synthesize type;
+- (BOOL) hasBody {
+ return !!hasBody_;
+}
+- (void) setHasBody:(BOOL) _value_ {
+ hasBody_ = !!_value_;
+}
+@synthesize body;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.type = RMTPayloadTypeCompressable;
+ self.body = [NSData data];
+ }
+ return self;
+}
+static RMTPayload* defaultRMTPayloadInstance = nil;
++ (void) initialize {
+ if (self == [RMTPayload class]) {
+ defaultRMTPayloadInstance = [[RMTPayload alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTPayloadInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTPayloadInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasType) {
+ [output writeEnum:1 value:self.type];
+ }
+ if (self.hasBody) {
+ [output writeData:2 value:self.body];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasType) {
+ size_ += computeEnumSize(1, self.type);
+ }
+ if (self.hasBody) {
+ size_ += computeDataSize(2, self.body);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTPayload*) parseFromData:(NSData*) data {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromData:data] build];
+}
++ (RMTPayload*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTPayload*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromInputStream:input] build];
+}
++ (RMTPayload*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTPayload*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTPayload*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTPayload*)[[[RMTPayload builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTPayloadBuilder*) builder {
+ return [[RMTPayloadBuilder alloc] init];
+}
++ (RMTPayloadBuilder*) builderWithPrototype:(RMTPayload*) prototype {
+ return [[RMTPayload builder] mergeFrom:prototype];
+}
+- (RMTPayloadBuilder*) builder {
+ return [RMTPayload builder];
+}
+- (RMTPayloadBuilder*) toBuilder {
+ return [RMTPayload builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasType) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"type", NSStringFromRMTPayloadType(self.type)];
+ }
+ if (self.hasBody) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"body", self.body];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTPayload class]]) {
+ return NO;
+ }
+ RMTPayload *otherMessage = other;
+ return
+ self.hasType == otherMessage.hasType &&
+ (!self.hasType || self.type == otherMessage.type) &&
+ self.hasBody == otherMessage.hasBody &&
+ (!self.hasBody || [self.body isEqual:otherMessage.body]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasType) {
+ hashCode = hashCode * 31 + self.type;
+ }
+ if (self.hasBody) {
+ hashCode = hashCode * 31 + [self.body hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTPayloadBuilder()
+@property (strong) RMTPayload* resultPayload;
+@end
+
+@implementation RMTPayloadBuilder
+@synthesize resultPayload;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultPayload = [[RMTPayload alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultPayload;
+}
+- (RMTPayloadBuilder*) clear {
+ self.resultPayload = [[RMTPayload alloc] init];
+ return self;
+}
+- (RMTPayloadBuilder*) clone {
+ return [RMTPayload builderWithPrototype:resultPayload];
+}
+- (RMTPayload*) defaultInstance {
+ return [RMTPayload defaultInstance];
+}
+- (RMTPayload*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTPayload*) buildPartial {
+ RMTPayload* returnMe = resultPayload;
+ self.resultPayload = nil;
+ return returnMe;
+}
+- (RMTPayloadBuilder*) mergeFrom:(RMTPayload*) other {
+ if (other == [RMTPayload defaultInstance]) {
+ return self;
+ }
+ if (other.hasType) {
+ [self setType:other.type];
+ }
+ if (other.hasBody) {
+ [self setBody:other.body];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTPayloadBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTPayloadBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ RMTPayloadType value = (RMTPayloadType)[input readEnum];
+ if (RMTPayloadTypeIsValidValue(value)) {
+ [self setType:value];
+ } else {
+ [unknownFields mergeVarintField:1 value:value];
+ }
+ break;
+ }
+ case 18: {
+ [self setBody:[input readData]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasType {
+ return resultPayload.hasType;
+}
+- (RMTPayloadType) type {
+ return resultPayload.type;
+}
+- (RMTPayloadBuilder*) setType:(RMTPayloadType) value {
+ resultPayload.hasType = YES;
+ resultPayload.type = value;
+ return self;
+}
+- (RMTPayloadBuilder*) clearType {
+ resultPayload.hasType = NO;
+ resultPayload.type = RMTPayloadTypeCompressable;
+ return self;
+}
+- (BOOL) hasBody {
+ return resultPayload.hasBody;
+}
+- (NSData*) body {
+ return resultPayload.body;
+}
+- (RMTPayloadBuilder*) setBody:(NSData*) value {
+ resultPayload.hasBody = YES;
+ resultPayload.body = value;
+ return self;
+}
+- (RMTPayloadBuilder*) clearBody {
+ resultPayload.hasBody = NO;
+ resultPayload.body = [NSData data];
+ return self;
+}
+@end
+
+@interface RMTSimpleRequest ()
+@property RMTPayloadType responseType;
+@property SInt32 responseSize;
+@property (strong) RMTPayload* payload;
+@property BOOL fillUsername;
+@property BOOL fillOauthScope;
+@end
+
+@implementation RMTSimpleRequest
+
+- (BOOL) hasResponseType {
+ return !!hasResponseType_;
+}
+- (void) setHasResponseType:(BOOL) _value_ {
+ hasResponseType_ = !!_value_;
+}
+@synthesize responseType;
+- (BOOL) hasResponseSize {
+ return !!hasResponseSize_;
+}
+- (void) setHasResponseSize:(BOOL) _value_ {
+ hasResponseSize_ = !!_value_;
+}
+@synthesize responseSize;
+- (BOOL) hasPayload {
+ return !!hasPayload_;
+}
+- (void) setHasPayload:(BOOL) _value_ {
+ hasPayload_ = !!_value_;
+}
+@synthesize payload;
+- (BOOL) hasFillUsername {
+ return !!hasFillUsername_;
+}
+- (void) setHasFillUsername:(BOOL) _value_ {
+ hasFillUsername_ = !!_value_;
+}
+- (BOOL) fillUsername {
+ return !!fillUsername_;
+}
+- (void) setFillUsername:(BOOL) _value_ {
+ fillUsername_ = !!_value_;
+}
+- (BOOL) hasFillOauthScope {
+ return !!hasFillOauthScope_;
+}
+- (void) setHasFillOauthScope:(BOOL) _value_ {
+ hasFillOauthScope_ = !!_value_;
+}
+- (BOOL) fillOauthScope {
+ return !!fillOauthScope_;
+}
+- (void) setFillOauthScope:(BOOL) _value_ {
+ fillOauthScope_ = !!_value_;
+}
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.responseType = RMTPayloadTypeCompressable;
+ self.responseSize = 0;
+ self.payload = [RMTPayload defaultInstance];
+ self.fillUsername = NO;
+ self.fillOauthScope = NO;
+ }
+ return self;
+}
+static RMTSimpleRequest* defaultRMTSimpleRequestInstance = nil;
++ (void) initialize {
+ if (self == [RMTSimpleRequest class]) {
+ defaultRMTSimpleRequestInstance = [[RMTSimpleRequest alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTSimpleRequestInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTSimpleRequestInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasResponseType) {
+ [output writeEnum:1 value:self.responseType];
+ }
+ if (self.hasResponseSize) {
+ [output writeInt32:2 value:self.responseSize];
+ }
+ if (self.hasPayload) {
+ [output writeMessage:3 value:self.payload];
+ }
+ if (self.hasFillUsername) {
+ [output writeBool:4 value:self.fillUsername];
+ }
+ if (self.hasFillOauthScope) {
+ [output writeBool:5 value:self.fillOauthScope];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasResponseType) {
+ size_ += computeEnumSize(1, self.responseType);
+ }
+ if (self.hasResponseSize) {
+ size_ += computeInt32Size(2, self.responseSize);
+ }
+ if (self.hasPayload) {
+ size_ += computeMessageSize(3, self.payload);
+ }
+ if (self.hasFillUsername) {
+ size_ += computeBoolSize(4, self.fillUsername);
+ }
+ if (self.hasFillOauthScope) {
+ size_ += computeBoolSize(5, self.fillOauthScope);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTSimpleRequest*) parseFromData:(NSData*) data {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromData:data] build];
+}
++ (RMTSimpleRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleRequest*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromInputStream:input] build];
+}
++ (RMTSimpleRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTSimpleRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleRequest*)[[[RMTSimpleRequest builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleRequestBuilder*) builder {
+ return [[RMTSimpleRequestBuilder alloc] init];
+}
++ (RMTSimpleRequestBuilder*) builderWithPrototype:(RMTSimpleRequest*) prototype {
+ return [[RMTSimpleRequest builder] mergeFrom:prototype];
+}
+- (RMTSimpleRequestBuilder*) builder {
+ return [RMTSimpleRequest builder];
+}
+- (RMTSimpleRequestBuilder*) toBuilder {
+ return [RMTSimpleRequest builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasResponseType) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"responseType", NSStringFromRMTPayloadType(self.responseType)];
+ }
+ if (self.hasResponseSize) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"responseSize", [NSNumber numberWithInteger:self.responseSize]];
+ }
+ if (self.hasPayload) {
+ [output appendFormat:@"%@%@ {\n", indent, @"payload"];
+ [self.payload writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ if (self.hasFillUsername) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"fillUsername", [NSNumber numberWithBool:self.fillUsername]];
+ }
+ if (self.hasFillOauthScope) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"fillOauthScope", [NSNumber numberWithBool:self.fillOauthScope]];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTSimpleRequest class]]) {
+ return NO;
+ }
+ RMTSimpleRequest *otherMessage = other;
+ return
+ self.hasResponseType == otherMessage.hasResponseType &&
+ (!self.hasResponseType || self.responseType == otherMessage.responseType) &&
+ self.hasResponseSize == otherMessage.hasResponseSize &&
+ (!self.hasResponseSize || self.responseSize == otherMessage.responseSize) &&
+ self.hasPayload == otherMessage.hasPayload &&
+ (!self.hasPayload || [self.payload isEqual:otherMessage.payload]) &&
+ self.hasFillUsername == otherMessage.hasFillUsername &&
+ (!self.hasFillUsername || self.fillUsername == otherMessage.fillUsername) &&
+ self.hasFillOauthScope == otherMessage.hasFillOauthScope &&
+ (!self.hasFillOauthScope || self.fillOauthScope == otherMessage.fillOauthScope) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasResponseType) {
+ hashCode = hashCode * 31 + self.responseType;
+ }
+ if (self.hasResponseSize) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.responseSize] hash];
+ }
+ if (self.hasPayload) {
+ hashCode = hashCode * 31 + [self.payload hash];
+ }
+ if (self.hasFillUsername) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.fillUsername] hash];
+ }
+ if (self.hasFillOauthScope) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithBool:self.fillOauthScope] hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTSimpleRequestBuilder()
+@property (strong) RMTSimpleRequest* resultSimpleRequest;
+@end
+
+@implementation RMTSimpleRequestBuilder
+@synthesize resultSimpleRequest;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultSimpleRequest = [[RMTSimpleRequest alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultSimpleRequest;
+}
+- (RMTSimpleRequestBuilder*) clear {
+ self.resultSimpleRequest = [[RMTSimpleRequest alloc] init];
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clone {
+ return [RMTSimpleRequest builderWithPrototype:resultSimpleRequest];
+}
+- (RMTSimpleRequest*) defaultInstance {
+ return [RMTSimpleRequest defaultInstance];
+}
+- (RMTSimpleRequest*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTSimpleRequest*) buildPartial {
+ RMTSimpleRequest* returnMe = resultSimpleRequest;
+ self.resultSimpleRequest = nil;
+ return returnMe;
+}
+- (RMTSimpleRequestBuilder*) mergeFrom:(RMTSimpleRequest*) other {
+ if (other == [RMTSimpleRequest defaultInstance]) {
+ return self;
+ }
+ if (other.hasResponseType) {
+ [self setResponseType:other.responseType];
+ }
+ if (other.hasResponseSize) {
+ [self setResponseSize:other.responseSize];
+ }
+ if (other.hasPayload) {
+ [self mergePayload:other.payload];
+ }
+ if (other.hasFillUsername) {
+ [self setFillUsername:other.fillUsername];
+ }
+ if (other.hasFillOauthScope) {
+ [self setFillOauthScope:other.fillOauthScope];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTSimpleRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTSimpleRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ RMTPayloadType value = (RMTPayloadType)[input readEnum];
+ if (RMTPayloadTypeIsValidValue(value)) {
+ [self setResponseType:value];
+ } else {
+ [unknownFields mergeVarintField:1 value:value];
+ }
+ break;
+ }
+ case 16: {
+ [self setResponseSize:[input readInt32]];
+ break;
+ }
+ case 26: {
+ RMTPayloadBuilder* subBuilder = [RMTPayload builder];
+ if (self.hasPayload) {
+ [subBuilder mergeFrom:self.payload];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setPayload:[subBuilder buildPartial]];
+ break;
+ }
+ case 32: {
+ [self setFillUsername:[input readBool]];
+ break;
+ }
+ case 40: {
+ [self setFillOauthScope:[input readBool]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasResponseType {
+ return resultSimpleRequest.hasResponseType;
+}
+- (RMTPayloadType) responseType {
+ return resultSimpleRequest.responseType;
+}
+- (RMTSimpleRequestBuilder*) setResponseType:(RMTPayloadType) value {
+ resultSimpleRequest.hasResponseType = YES;
+ resultSimpleRequest.responseType = value;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clearResponseType {
+ resultSimpleRequest.hasResponseType = NO;
+ resultSimpleRequest.responseType = RMTPayloadTypeCompressable;
+ return self;
+}
+- (BOOL) hasResponseSize {
+ return resultSimpleRequest.hasResponseSize;
+}
+- (SInt32) responseSize {
+ return resultSimpleRequest.responseSize;
+}
+- (RMTSimpleRequestBuilder*) setResponseSize:(SInt32) value {
+ resultSimpleRequest.hasResponseSize = YES;
+ resultSimpleRequest.responseSize = value;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clearResponseSize {
+ resultSimpleRequest.hasResponseSize = NO;
+ resultSimpleRequest.responseSize = 0;
+ return self;
+}
+- (BOOL) hasPayload {
+ return resultSimpleRequest.hasPayload;
+}
+- (RMTPayload*) payload {
+ return resultSimpleRequest.payload;
+}
+- (RMTSimpleRequestBuilder*) setPayload:(RMTPayload*) value {
+ resultSimpleRequest.hasPayload = YES;
+ resultSimpleRequest.payload = value;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue {
+ return [self setPayload:[builderForValue build]];
+}
+- (RMTSimpleRequestBuilder*) mergePayload:(RMTPayload*) value {
+ if (resultSimpleRequest.hasPayload &&
+ resultSimpleRequest.payload != [RMTPayload defaultInstance]) {
+ resultSimpleRequest.payload =
+ [[[RMTPayload builderWithPrototype:resultSimpleRequest.payload] mergeFrom:value] buildPartial];
+ } else {
+ resultSimpleRequest.payload = value;
+ }
+ resultSimpleRequest.hasPayload = YES;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clearPayload {
+ resultSimpleRequest.hasPayload = NO;
+ resultSimpleRequest.payload = [RMTPayload defaultInstance];
+ return self;
+}
+- (BOOL) hasFillUsername {
+ return resultSimpleRequest.hasFillUsername;
+}
+- (BOOL) fillUsername {
+ return resultSimpleRequest.fillUsername;
+}
+- (RMTSimpleRequestBuilder*) setFillUsername:(BOOL) value {
+ resultSimpleRequest.hasFillUsername = YES;
+ resultSimpleRequest.fillUsername = value;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clearFillUsername {
+ resultSimpleRequest.hasFillUsername = NO;
+ resultSimpleRequest.fillUsername = NO;
+ return self;
+}
+- (BOOL) hasFillOauthScope {
+ return resultSimpleRequest.hasFillOauthScope;
+}
+- (BOOL) fillOauthScope {
+ return resultSimpleRequest.fillOauthScope;
+}
+- (RMTSimpleRequestBuilder*) setFillOauthScope:(BOOL) value {
+ resultSimpleRequest.hasFillOauthScope = YES;
+ resultSimpleRequest.fillOauthScope = value;
+ return self;
+}
+- (RMTSimpleRequestBuilder*) clearFillOauthScope {
+ resultSimpleRequest.hasFillOauthScope = NO;
+ resultSimpleRequest.fillOauthScope = NO;
+ return self;
+}
+@end
+
+@interface RMTSimpleResponse ()
+@property (strong) RMTPayload* payload;
+@property (strong) NSString* username;
+@property (strong) NSString* oauthScope;
+@end
+
+@implementation RMTSimpleResponse
+
+- (BOOL) hasPayload {
+ return !!hasPayload_;
+}
+- (void) setHasPayload:(BOOL) _value_ {
+ hasPayload_ = !!_value_;
+}
+@synthesize payload;
+- (BOOL) hasUsername {
+ return !!hasUsername_;
+}
+- (void) setHasUsername:(BOOL) _value_ {
+ hasUsername_ = !!_value_;
+}
+@synthesize username;
+- (BOOL) hasOauthScope {
+ return !!hasOauthScope_;
+}
+- (void) setHasOauthScope:(BOOL) _value_ {
+ hasOauthScope_ = !!_value_;
+}
+@synthesize oauthScope;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.payload = [RMTPayload defaultInstance];
+ self.username = @"";
+ self.oauthScope = @"";
+ }
+ return self;
+}
+static RMTSimpleResponse* defaultRMTSimpleResponseInstance = nil;
++ (void) initialize {
+ if (self == [RMTSimpleResponse class]) {
+ defaultRMTSimpleResponseInstance = [[RMTSimpleResponse alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTSimpleResponseInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTSimpleResponseInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasPayload) {
+ [output writeMessage:1 value:self.payload];
+ }
+ if (self.hasUsername) {
+ [output writeString:2 value:self.username];
+ }
+ if (self.hasOauthScope) {
+ [output writeString:3 value:self.oauthScope];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasPayload) {
+ size_ += computeMessageSize(1, self.payload);
+ }
+ if (self.hasUsername) {
+ size_ += computeStringSize(2, self.username);
+ }
+ if (self.hasOauthScope) {
+ size_ += computeStringSize(3, self.oauthScope);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTSimpleResponse*) parseFromData:(NSData*) data {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromData:data] build];
+}
++ (RMTSimpleResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleResponse*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromInputStream:input] build];
+}
++ (RMTSimpleResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTSimpleResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTSimpleResponse*)[[[RMTSimpleResponse builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTSimpleResponseBuilder*) builder {
+ return [[RMTSimpleResponseBuilder alloc] init];
+}
++ (RMTSimpleResponseBuilder*) builderWithPrototype:(RMTSimpleResponse*) prototype {
+ return [[RMTSimpleResponse builder] mergeFrom:prototype];
+}
+- (RMTSimpleResponseBuilder*) builder {
+ return [RMTSimpleResponse builder];
+}
+- (RMTSimpleResponseBuilder*) toBuilder {
+ return [RMTSimpleResponse builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasPayload) {
+ [output appendFormat:@"%@%@ {\n", indent, @"payload"];
+ [self.payload writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ if (self.hasUsername) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"username", self.username];
+ }
+ if (self.hasOauthScope) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"oauthScope", self.oauthScope];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTSimpleResponse class]]) {
+ return NO;
+ }
+ RMTSimpleResponse *otherMessage = other;
+ return
+ self.hasPayload == otherMessage.hasPayload &&
+ (!self.hasPayload || [self.payload isEqual:otherMessage.payload]) &&
+ self.hasUsername == otherMessage.hasUsername &&
+ (!self.hasUsername || [self.username isEqual:otherMessage.username]) &&
+ self.hasOauthScope == otherMessage.hasOauthScope &&
+ (!self.hasOauthScope || [self.oauthScope isEqual:otherMessage.oauthScope]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasPayload) {
+ hashCode = hashCode * 31 + [self.payload hash];
+ }
+ if (self.hasUsername) {
+ hashCode = hashCode * 31 + [self.username hash];
+ }
+ if (self.hasOauthScope) {
+ hashCode = hashCode * 31 + [self.oauthScope hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTSimpleResponseBuilder()
+@property (strong) RMTSimpleResponse* resultSimpleResponse;
+@end
+
+@implementation RMTSimpleResponseBuilder
+@synthesize resultSimpleResponse;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultSimpleResponse = [[RMTSimpleResponse alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultSimpleResponse;
+}
+- (RMTSimpleResponseBuilder*) clear {
+ self.resultSimpleResponse = [[RMTSimpleResponse alloc] init];
+ return self;
+}
+- (RMTSimpleResponseBuilder*) clone {
+ return [RMTSimpleResponse builderWithPrototype:resultSimpleResponse];
+}
+- (RMTSimpleResponse*) defaultInstance {
+ return [RMTSimpleResponse defaultInstance];
+}
+- (RMTSimpleResponse*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTSimpleResponse*) buildPartial {
+ RMTSimpleResponse* returnMe = resultSimpleResponse;
+ self.resultSimpleResponse = nil;
+ return returnMe;
+}
+- (RMTSimpleResponseBuilder*) mergeFrom:(RMTSimpleResponse*) other {
+ if (other == [RMTSimpleResponse defaultInstance]) {
+ return self;
+ }
+ if (other.hasPayload) {
+ [self mergePayload:other.payload];
+ }
+ if (other.hasUsername) {
+ [self setUsername:other.username];
+ }
+ if (other.hasOauthScope) {
+ [self setOauthScope:other.oauthScope];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTSimpleResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTSimpleResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ RMTPayloadBuilder* subBuilder = [RMTPayload builder];
+ if (self.hasPayload) {
+ [subBuilder mergeFrom:self.payload];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setPayload:[subBuilder buildPartial]];
+ break;
+ }
+ case 18: {
+ [self setUsername:[input readString]];
+ break;
+ }
+ case 26: {
+ [self setOauthScope:[input readString]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasPayload {
+ return resultSimpleResponse.hasPayload;
+}
+- (RMTPayload*) payload {
+ return resultSimpleResponse.payload;
+}
+- (RMTSimpleResponseBuilder*) setPayload:(RMTPayload*) value {
+ resultSimpleResponse.hasPayload = YES;
+ resultSimpleResponse.payload = value;
+ return self;
+}
+- (RMTSimpleResponseBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue {
+ return [self setPayload:[builderForValue build]];
+}
+- (RMTSimpleResponseBuilder*) mergePayload:(RMTPayload*) value {
+ if (resultSimpleResponse.hasPayload &&
+ resultSimpleResponse.payload != [RMTPayload defaultInstance]) {
+ resultSimpleResponse.payload =
+ [[[RMTPayload builderWithPrototype:resultSimpleResponse.payload] mergeFrom:value] buildPartial];
+ } else {
+ resultSimpleResponse.payload = value;
+ }
+ resultSimpleResponse.hasPayload = YES;
+ return self;
+}
+- (RMTSimpleResponseBuilder*) clearPayload {
+ resultSimpleResponse.hasPayload = NO;
+ resultSimpleResponse.payload = [RMTPayload defaultInstance];
+ return self;
+}
+- (BOOL) hasUsername {
+ return resultSimpleResponse.hasUsername;
+}
+- (NSString*) username {
+ return resultSimpleResponse.username;
+}
+- (RMTSimpleResponseBuilder*) setUsername:(NSString*) value {
+ resultSimpleResponse.hasUsername = YES;
+ resultSimpleResponse.username = value;
+ return self;
+}
+- (RMTSimpleResponseBuilder*) clearUsername {
+ resultSimpleResponse.hasUsername = NO;
+ resultSimpleResponse.username = @"";
+ return self;
+}
+- (BOOL) hasOauthScope {
+ return resultSimpleResponse.hasOauthScope;
+}
+- (NSString*) oauthScope {
+ return resultSimpleResponse.oauthScope;
+}
+- (RMTSimpleResponseBuilder*) setOauthScope:(NSString*) value {
+ resultSimpleResponse.hasOauthScope = YES;
+ resultSimpleResponse.oauthScope = value;
+ return self;
+}
+- (RMTSimpleResponseBuilder*) clearOauthScope {
+ resultSimpleResponse.hasOauthScope = NO;
+ resultSimpleResponse.oauthScope = @"";
+ return self;
+}
+@end
+
+@interface RMTStreamingInputCallRequest ()
+@property (strong) RMTPayload* payload;
+@end
+
+@implementation RMTStreamingInputCallRequest
+
+- (BOOL) hasPayload {
+ return !!hasPayload_;
+}
+- (void) setHasPayload:(BOOL) _value_ {
+ hasPayload_ = !!_value_;
+}
+@synthesize payload;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.payload = [RMTPayload defaultInstance];
+ }
+ return self;
+}
+static RMTStreamingInputCallRequest* defaultRMTStreamingInputCallRequestInstance = nil;
++ (void) initialize {
+ if (self == [RMTStreamingInputCallRequest class]) {
+ defaultRMTStreamingInputCallRequestInstance = [[RMTStreamingInputCallRequest alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTStreamingInputCallRequestInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTStreamingInputCallRequestInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasPayload) {
+ [output writeMessage:1 value:self.payload];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasPayload) {
+ size_ += computeMessageSize(1, self.payload);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTStreamingInputCallRequest*) parseFromData:(NSData*) data {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromData:data] build];
+}
++ (RMTStreamingInputCallRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallRequest*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromInputStream:input] build];
+}
++ (RMTStreamingInputCallRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTStreamingInputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallRequest*)[[[RMTStreamingInputCallRequest builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallRequestBuilder*) builder {
+ return [[RMTStreamingInputCallRequestBuilder alloc] init];
+}
++ (RMTStreamingInputCallRequestBuilder*) builderWithPrototype:(RMTStreamingInputCallRequest*) prototype {
+ return [[RMTStreamingInputCallRequest builder] mergeFrom:prototype];
+}
+- (RMTStreamingInputCallRequestBuilder*) builder {
+ return [RMTStreamingInputCallRequest builder];
+}
+- (RMTStreamingInputCallRequestBuilder*) toBuilder {
+ return [RMTStreamingInputCallRequest builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasPayload) {
+ [output appendFormat:@"%@%@ {\n", indent, @"payload"];
+ [self.payload writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTStreamingInputCallRequest class]]) {
+ return NO;
+ }
+ RMTStreamingInputCallRequest *otherMessage = other;
+ return
+ self.hasPayload == otherMessage.hasPayload &&
+ (!self.hasPayload || [self.payload isEqual:otherMessage.payload]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasPayload) {
+ hashCode = hashCode * 31 + [self.payload hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTStreamingInputCallRequestBuilder()
+@property (strong) RMTStreamingInputCallRequest* resultStreamingInputCallRequest;
+@end
+
+@implementation RMTStreamingInputCallRequestBuilder
+@synthesize resultStreamingInputCallRequest;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultStreamingInputCallRequest = [[RMTStreamingInputCallRequest alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultStreamingInputCallRequest;
+}
+- (RMTStreamingInputCallRequestBuilder*) clear {
+ self.resultStreamingInputCallRequest = [[RMTStreamingInputCallRequest alloc] init];
+ return self;
+}
+- (RMTStreamingInputCallRequestBuilder*) clone {
+ return [RMTStreamingInputCallRequest builderWithPrototype:resultStreamingInputCallRequest];
+}
+- (RMTStreamingInputCallRequest*) defaultInstance {
+ return [RMTStreamingInputCallRequest defaultInstance];
+}
+- (RMTStreamingInputCallRequest*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTStreamingInputCallRequest*) buildPartial {
+ RMTStreamingInputCallRequest* returnMe = resultStreamingInputCallRequest;
+ self.resultStreamingInputCallRequest = nil;
+ return returnMe;
+}
+- (RMTStreamingInputCallRequestBuilder*) mergeFrom:(RMTStreamingInputCallRequest*) other {
+ if (other == [RMTStreamingInputCallRequest defaultInstance]) {
+ return self;
+ }
+ if (other.hasPayload) {
+ [self mergePayload:other.payload];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTStreamingInputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTStreamingInputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ RMTPayloadBuilder* subBuilder = [RMTPayload builder];
+ if (self.hasPayload) {
+ [subBuilder mergeFrom:self.payload];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setPayload:[subBuilder buildPartial]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasPayload {
+ return resultStreamingInputCallRequest.hasPayload;
+}
+- (RMTPayload*) payload {
+ return resultStreamingInputCallRequest.payload;
+}
+- (RMTStreamingInputCallRequestBuilder*) setPayload:(RMTPayload*) value {
+ resultStreamingInputCallRequest.hasPayload = YES;
+ resultStreamingInputCallRequest.payload = value;
+ return self;
+}
+- (RMTStreamingInputCallRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue {
+ return [self setPayload:[builderForValue build]];
+}
+- (RMTStreamingInputCallRequestBuilder*) mergePayload:(RMTPayload*) value {
+ if (resultStreamingInputCallRequest.hasPayload &&
+ resultStreamingInputCallRequest.payload != [RMTPayload defaultInstance]) {
+ resultStreamingInputCallRequest.payload =
+ [[[RMTPayload builderWithPrototype:resultStreamingInputCallRequest.payload] mergeFrom:value] buildPartial];
+ } else {
+ resultStreamingInputCallRequest.payload = value;
+ }
+ resultStreamingInputCallRequest.hasPayload = YES;
+ return self;
+}
+- (RMTStreamingInputCallRequestBuilder*) clearPayload {
+ resultStreamingInputCallRequest.hasPayload = NO;
+ resultStreamingInputCallRequest.payload = [RMTPayload defaultInstance];
+ return self;
+}
+@end
+
+@interface RMTStreamingInputCallResponse ()
+@property SInt32 aggregatedPayloadSize;
+@end
+
+@implementation RMTStreamingInputCallResponse
+
+- (BOOL) hasAggregatedPayloadSize {
+ return !!hasAggregatedPayloadSize_;
+}
+- (void) setHasAggregatedPayloadSize:(BOOL) _value_ {
+ hasAggregatedPayloadSize_ = !!_value_;
+}
+@synthesize aggregatedPayloadSize;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.aggregatedPayloadSize = 0;
+ }
+ return self;
+}
+static RMTStreamingInputCallResponse* defaultRMTStreamingInputCallResponseInstance = nil;
++ (void) initialize {
+ if (self == [RMTStreamingInputCallResponse class]) {
+ defaultRMTStreamingInputCallResponseInstance = [[RMTStreamingInputCallResponse alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTStreamingInputCallResponseInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTStreamingInputCallResponseInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasAggregatedPayloadSize) {
+ [output writeInt32:1 value:self.aggregatedPayloadSize];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasAggregatedPayloadSize) {
+ size_ += computeInt32Size(1, self.aggregatedPayloadSize);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTStreamingInputCallResponse*) parseFromData:(NSData*) data {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromData:data] build];
+}
++ (RMTStreamingInputCallResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallResponse*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromInputStream:input] build];
+}
++ (RMTStreamingInputCallResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTStreamingInputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingInputCallResponse*)[[[RMTStreamingInputCallResponse builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingInputCallResponseBuilder*) builder {
+ return [[RMTStreamingInputCallResponseBuilder alloc] init];
+}
++ (RMTStreamingInputCallResponseBuilder*) builderWithPrototype:(RMTStreamingInputCallResponse*) prototype {
+ return [[RMTStreamingInputCallResponse builder] mergeFrom:prototype];
+}
+- (RMTStreamingInputCallResponseBuilder*) builder {
+ return [RMTStreamingInputCallResponse builder];
+}
+- (RMTStreamingInputCallResponseBuilder*) toBuilder {
+ return [RMTStreamingInputCallResponse builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasAggregatedPayloadSize) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"aggregatedPayloadSize", [NSNumber numberWithInteger:self.aggregatedPayloadSize]];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTStreamingInputCallResponse class]]) {
+ return NO;
+ }
+ RMTStreamingInputCallResponse *otherMessage = other;
+ return
+ self.hasAggregatedPayloadSize == otherMessage.hasAggregatedPayloadSize &&
+ (!self.hasAggregatedPayloadSize || self.aggregatedPayloadSize == otherMessage.aggregatedPayloadSize) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasAggregatedPayloadSize) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.aggregatedPayloadSize] hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTStreamingInputCallResponseBuilder()
+@property (strong) RMTStreamingInputCallResponse* resultStreamingInputCallResponse;
+@end
+
+@implementation RMTStreamingInputCallResponseBuilder
+@synthesize resultStreamingInputCallResponse;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultStreamingInputCallResponse = [[RMTStreamingInputCallResponse alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultStreamingInputCallResponse;
+}
+- (RMTStreamingInputCallResponseBuilder*) clear {
+ self.resultStreamingInputCallResponse = [[RMTStreamingInputCallResponse alloc] init];
+ return self;
+}
+- (RMTStreamingInputCallResponseBuilder*) clone {
+ return [RMTStreamingInputCallResponse builderWithPrototype:resultStreamingInputCallResponse];
+}
+- (RMTStreamingInputCallResponse*) defaultInstance {
+ return [RMTStreamingInputCallResponse defaultInstance];
+}
+- (RMTStreamingInputCallResponse*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTStreamingInputCallResponse*) buildPartial {
+ RMTStreamingInputCallResponse* returnMe = resultStreamingInputCallResponse;
+ self.resultStreamingInputCallResponse = nil;
+ return returnMe;
+}
+- (RMTStreamingInputCallResponseBuilder*) mergeFrom:(RMTStreamingInputCallResponse*) other {
+ if (other == [RMTStreamingInputCallResponse defaultInstance]) {
+ return self;
+ }
+ if (other.hasAggregatedPayloadSize) {
+ [self setAggregatedPayloadSize:other.aggregatedPayloadSize];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTStreamingInputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTStreamingInputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ [self setAggregatedPayloadSize:[input readInt32]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasAggregatedPayloadSize {
+ return resultStreamingInputCallResponse.hasAggregatedPayloadSize;
+}
+- (SInt32) aggregatedPayloadSize {
+ return resultStreamingInputCallResponse.aggregatedPayloadSize;
+}
+- (RMTStreamingInputCallResponseBuilder*) setAggregatedPayloadSize:(SInt32) value {
+ resultStreamingInputCallResponse.hasAggregatedPayloadSize = YES;
+ resultStreamingInputCallResponse.aggregatedPayloadSize = value;
+ return self;
+}
+- (RMTStreamingInputCallResponseBuilder*) clearAggregatedPayloadSize {
+ resultStreamingInputCallResponse.hasAggregatedPayloadSize = NO;
+ resultStreamingInputCallResponse.aggregatedPayloadSize = 0;
+ return self;
+}
+@end
+
+@interface RMTResponseParameters ()
+@property SInt32 size;
+@property SInt32 intervalUs;
+@end
+
+@implementation RMTResponseParameters
+
+- (BOOL) hasSize {
+ return !!hasSize_;
+}
+- (void) setHasSize:(BOOL) _value_ {
+ hasSize_ = !!_value_;
+}
+@synthesize size;
+- (BOOL) hasIntervalUs {
+ return !!hasIntervalUs_;
+}
+- (void) setHasIntervalUs:(BOOL) _value_ {
+ hasIntervalUs_ = !!_value_;
+}
+@synthesize intervalUs;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.size = 0;
+ self.intervalUs = 0;
+ }
+ return self;
+}
+static RMTResponseParameters* defaultRMTResponseParametersInstance = nil;
++ (void) initialize {
+ if (self == [RMTResponseParameters class]) {
+ defaultRMTResponseParametersInstance = [[RMTResponseParameters alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTResponseParametersInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTResponseParametersInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasSize) {
+ [output writeInt32:1 value:self.size];
+ }
+ if (self.hasIntervalUs) {
+ [output writeInt32:2 value:self.intervalUs];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasSize) {
+ size_ += computeInt32Size(1, self.size);
+ }
+ if (self.hasIntervalUs) {
+ size_ += computeInt32Size(2, self.intervalUs);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTResponseParameters*) parseFromData:(NSData*) data {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromData:data] build];
+}
++ (RMTResponseParameters*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTResponseParameters*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromInputStream:input] build];
+}
++ (RMTResponseParameters*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTResponseParameters*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTResponseParameters*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTResponseParameters*)[[[RMTResponseParameters builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTResponseParametersBuilder*) builder {
+ return [[RMTResponseParametersBuilder alloc] init];
+}
++ (RMTResponseParametersBuilder*) builderWithPrototype:(RMTResponseParameters*) prototype {
+ return [[RMTResponseParameters builder] mergeFrom:prototype];
+}
+- (RMTResponseParametersBuilder*) builder {
+ return [RMTResponseParameters builder];
+}
+- (RMTResponseParametersBuilder*) toBuilder {
+ return [RMTResponseParameters builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasSize) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"size", [NSNumber numberWithInteger:self.size]];
+ }
+ if (self.hasIntervalUs) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"intervalUs", [NSNumber numberWithInteger:self.intervalUs]];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTResponseParameters class]]) {
+ return NO;
+ }
+ RMTResponseParameters *otherMessage = other;
+ return
+ self.hasSize == otherMessage.hasSize &&
+ (!self.hasSize || self.size == otherMessage.size) &&
+ self.hasIntervalUs == otherMessage.hasIntervalUs &&
+ (!self.hasIntervalUs || self.intervalUs == otherMessage.intervalUs) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasSize) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.size] hash];
+ }
+ if (self.hasIntervalUs) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.intervalUs] hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTResponseParametersBuilder()
+@property (strong) RMTResponseParameters* resultResponseParameters;
+@end
+
+@implementation RMTResponseParametersBuilder
+@synthesize resultResponseParameters;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultResponseParameters = [[RMTResponseParameters alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultResponseParameters;
+}
+- (RMTResponseParametersBuilder*) clear {
+ self.resultResponseParameters = [[RMTResponseParameters alloc] init];
+ return self;
+}
+- (RMTResponseParametersBuilder*) clone {
+ return [RMTResponseParameters builderWithPrototype:resultResponseParameters];
+}
+- (RMTResponseParameters*) defaultInstance {
+ return [RMTResponseParameters defaultInstance];
+}
+- (RMTResponseParameters*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTResponseParameters*) buildPartial {
+ RMTResponseParameters* returnMe = resultResponseParameters;
+ self.resultResponseParameters = nil;
+ return returnMe;
+}
+- (RMTResponseParametersBuilder*) mergeFrom:(RMTResponseParameters*) other {
+ if (other == [RMTResponseParameters defaultInstance]) {
+ return self;
+ }
+ if (other.hasSize) {
+ [self setSize:other.size];
+ }
+ if (other.hasIntervalUs) {
+ [self setIntervalUs:other.intervalUs];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTResponseParametersBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTResponseParametersBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ [self setSize:[input readInt32]];
+ break;
+ }
+ case 16: {
+ [self setIntervalUs:[input readInt32]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasSize {
+ return resultResponseParameters.hasSize;
+}
+- (SInt32) size {
+ return resultResponseParameters.size;
+}
+- (RMTResponseParametersBuilder*) setSize:(SInt32) value {
+ resultResponseParameters.hasSize = YES;
+ resultResponseParameters.size = value;
+ return self;
+}
+- (RMTResponseParametersBuilder*) clearSize {
+ resultResponseParameters.hasSize = NO;
+ resultResponseParameters.size = 0;
+ return self;
+}
+- (BOOL) hasIntervalUs {
+ return resultResponseParameters.hasIntervalUs;
+}
+- (SInt32) intervalUs {
+ return resultResponseParameters.intervalUs;
+}
+- (RMTResponseParametersBuilder*) setIntervalUs:(SInt32) value {
+ resultResponseParameters.hasIntervalUs = YES;
+ resultResponseParameters.intervalUs = value;
+ return self;
+}
+- (RMTResponseParametersBuilder*) clearIntervalUs {
+ resultResponseParameters.hasIntervalUs = NO;
+ resultResponseParameters.intervalUs = 0;
+ return self;
+}
+@end
+
+@interface RMTStreamingOutputCallRequest ()
+@property RMTPayloadType responseType;
+@property (strong) NSMutableArray * responseParametersArray;
+@property (strong) RMTPayload* payload;
+@end
+
+@implementation RMTStreamingOutputCallRequest
+
+- (BOOL) hasResponseType {
+ return !!hasResponseType_;
+}
+- (void) setHasResponseType:(BOOL) _value_ {
+ hasResponseType_ = !!_value_;
+}
+@synthesize responseType;
+@synthesize responseParametersArray;
+@dynamic responseParameters;
+- (BOOL) hasPayload {
+ return !!hasPayload_;
+}
+- (void) setHasPayload:(BOOL) _value_ {
+ hasPayload_ = !!_value_;
+}
+@synthesize payload;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.responseType = RMTPayloadTypeCompressable;
+ self.payload = [RMTPayload defaultInstance];
+ }
+ return self;
+}
+static RMTStreamingOutputCallRequest* defaultRMTStreamingOutputCallRequestInstance = nil;
++ (void) initialize {
+ if (self == [RMTStreamingOutputCallRequest class]) {
+ defaultRMTStreamingOutputCallRequestInstance = [[RMTStreamingOutputCallRequest alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTStreamingOutputCallRequestInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTStreamingOutputCallRequestInstance;
+}
+- (NSArray *)responseParameters {
+ return responseParametersArray;
+}
+- (RMTResponseParameters*)responseParametersAtIndex:(NSUInteger)index {
+ return [responseParametersArray objectAtIndex:index];
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasResponseType) {
+ [output writeEnum:1 value:self.responseType];
+ }
+ [self.responseParametersArray enumerateObjectsUsingBlock:^(RMTResponseParameters *element, NSUInteger idx, BOOL *stop) {
+ [output writeMessage:2 value:element];
+ }];
+ if (self.hasPayload) {
+ [output writeMessage:3 value:self.payload];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasResponseType) {
+ size_ += computeEnumSize(1, self.responseType);
+ }
+ [self.responseParametersArray enumerateObjectsUsingBlock:^(RMTResponseParameters *element, NSUInteger idx, BOOL *stop) {
+ size_ += computeMessageSize(2, element);
+ }];
+ if (self.hasPayload) {
+ size_ += computeMessageSize(3, self.payload);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTStreamingOutputCallRequest*) parseFromData:(NSData*) data {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromData:data] build];
+}
++ (RMTStreamingOutputCallRequest*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallRequest*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromInputStream:input] build];
+}
++ (RMTStreamingOutputCallRequest*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTStreamingOutputCallRequest*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallRequest*)[[[RMTStreamingOutputCallRequest builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallRequestBuilder*) builder {
+ return [[RMTStreamingOutputCallRequestBuilder alloc] init];
+}
++ (RMTStreamingOutputCallRequestBuilder*) builderWithPrototype:(RMTStreamingOutputCallRequest*) prototype {
+ return [[RMTStreamingOutputCallRequest builder] mergeFrom:prototype];
+}
+- (RMTStreamingOutputCallRequestBuilder*) builder {
+ return [RMTStreamingOutputCallRequest builder];
+}
+- (RMTStreamingOutputCallRequestBuilder*) toBuilder {
+ return [RMTStreamingOutputCallRequest builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasResponseType) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"responseType", NSStringFromRMTPayloadType(self.responseType)];
+ }
+ [self.responseParametersArray enumerateObjectsUsingBlock:^(RMTResponseParameters *element, NSUInteger idx, BOOL *stop) {
+ [output appendFormat:@"%@%@ {\n", indent, @"responseParameters"];
+ [element writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }];
+ if (self.hasPayload) {
+ [output appendFormat:@"%@%@ {\n", indent, @"payload"];
+ [self.payload writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTStreamingOutputCallRequest class]]) {
+ return NO;
+ }
+ RMTStreamingOutputCallRequest *otherMessage = other;
+ return
+ self.hasResponseType == otherMessage.hasResponseType &&
+ (!self.hasResponseType || self.responseType == otherMessage.responseType) &&
+ [self.responseParametersArray isEqualToArray:otherMessage.responseParametersArray] &&
+ self.hasPayload == otherMessage.hasPayload &&
+ (!self.hasPayload || [self.payload isEqual:otherMessage.payload]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasResponseType) {
+ hashCode = hashCode * 31 + self.responseType;
+ }
+ [self.responseParametersArray enumerateObjectsUsingBlock:^(RMTResponseParameters *element, NSUInteger idx, BOOL *stop) {
+ hashCode = hashCode * 31 + [element hash];
+ }];
+ if (self.hasPayload) {
+ hashCode = hashCode * 31 + [self.payload hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTStreamingOutputCallRequestBuilder()
+@property (strong) RMTStreamingOutputCallRequest* resultStreamingOutputCallRequest;
+@end
+
+@implementation RMTStreamingOutputCallRequestBuilder
+@synthesize resultStreamingOutputCallRequest;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultStreamingOutputCallRequest = [[RMTStreamingOutputCallRequest alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultStreamingOutputCallRequest;
+}
+- (RMTStreamingOutputCallRequestBuilder*) clear {
+ self.resultStreamingOutputCallRequest = [[RMTStreamingOutputCallRequest alloc] init];
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder*) clone {
+ return [RMTStreamingOutputCallRequest builderWithPrototype:resultStreamingOutputCallRequest];
+}
+- (RMTStreamingOutputCallRequest*) defaultInstance {
+ return [RMTStreamingOutputCallRequest defaultInstance];
+}
+- (RMTStreamingOutputCallRequest*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTStreamingOutputCallRequest*) buildPartial {
+ RMTStreamingOutputCallRequest* returnMe = resultStreamingOutputCallRequest;
+ self.resultStreamingOutputCallRequest = nil;
+ return returnMe;
+}
+- (RMTStreamingOutputCallRequestBuilder*) mergeFrom:(RMTStreamingOutputCallRequest*) other {
+ if (other == [RMTStreamingOutputCallRequest defaultInstance]) {
+ return self;
+ }
+ if (other.hasResponseType) {
+ [self setResponseType:other.responseType];
+ }
+ if (other.responseParametersArray.count > 0) {
+ if (resultStreamingOutputCallRequest.responseParametersArray == nil) {
+ resultStreamingOutputCallRequest.responseParametersArray = [[NSMutableArray alloc] initWithArray:other.responseParametersArray];
+ } else {
+ [resultStreamingOutputCallRequest.responseParametersArray addObjectsFromArray:other.responseParametersArray];
+ }
+ }
+ if (other.hasPayload) {
+ [self mergePayload:other.payload];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTStreamingOutputCallRequestBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ RMTPayloadType value = (RMTPayloadType)[input readEnum];
+ if (RMTPayloadTypeIsValidValue(value)) {
+ [self setResponseType:value];
+ } else {
+ [unknownFields mergeVarintField:1 value:value];
+ }
+ break;
+ }
+ case 18: {
+ RMTResponseParametersBuilder* subBuilder = [RMTResponseParameters builder];
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self addResponseParameters:[subBuilder buildPartial]];
+ break;
+ }
+ case 26: {
+ RMTPayloadBuilder* subBuilder = [RMTPayload builder];
+ if (self.hasPayload) {
+ [subBuilder mergeFrom:self.payload];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setPayload:[subBuilder buildPartial]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasResponseType {
+ return resultStreamingOutputCallRequest.hasResponseType;
+}
+- (RMTPayloadType) responseType {
+ return resultStreamingOutputCallRequest.responseType;
+}
+- (RMTStreamingOutputCallRequestBuilder*) setResponseType:(RMTPayloadType) value {
+ resultStreamingOutputCallRequest.hasResponseType = YES;
+ resultStreamingOutputCallRequest.responseType = value;
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder*) clearResponseType {
+ resultStreamingOutputCallRequest.hasResponseType = NO;
+ resultStreamingOutputCallRequest.responseType = RMTPayloadTypeCompressable;
+ return self;
+}
+- (NSMutableArray *)responseParameters {
+ return resultStreamingOutputCallRequest.responseParametersArray;
+}
+- (RMTResponseParameters*)responseParametersAtIndex:(NSUInteger)index {
+ return [resultStreamingOutputCallRequest responseParametersAtIndex:index];
+}
+- (RMTStreamingOutputCallRequestBuilder *)addResponseParameters:(RMTResponseParameters*)value {
+ if (resultStreamingOutputCallRequest.responseParametersArray == nil) {
+ resultStreamingOutputCallRequest.responseParametersArray = [[NSMutableArray alloc]init];
+ }
+ [resultStreamingOutputCallRequest.responseParametersArray addObject:value];
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder *)setResponseParametersArray:(NSArray *)array {
+ resultStreamingOutputCallRequest.responseParametersArray = [[NSMutableArray alloc]initWithArray:array];
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder *)clearResponseParameters {
+ resultStreamingOutputCallRequest.responseParametersArray = nil;
+ return self;
+}
+- (BOOL) hasPayload {
+ return resultStreamingOutputCallRequest.hasPayload;
+}
+- (RMTPayload*) payload {
+ return resultStreamingOutputCallRequest.payload;
+}
+- (RMTStreamingOutputCallRequestBuilder*) setPayload:(RMTPayload*) value {
+ resultStreamingOutputCallRequest.hasPayload = YES;
+ resultStreamingOutputCallRequest.payload = value;
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue {
+ return [self setPayload:[builderForValue build]];
+}
+- (RMTStreamingOutputCallRequestBuilder*) mergePayload:(RMTPayload*) value {
+ if (resultStreamingOutputCallRequest.hasPayload &&
+ resultStreamingOutputCallRequest.payload != [RMTPayload defaultInstance]) {
+ resultStreamingOutputCallRequest.payload =
+ [[[RMTPayload builderWithPrototype:resultStreamingOutputCallRequest.payload] mergeFrom:value] buildPartial];
+ } else {
+ resultStreamingOutputCallRequest.payload = value;
+ }
+ resultStreamingOutputCallRequest.hasPayload = YES;
+ return self;
+}
+- (RMTStreamingOutputCallRequestBuilder*) clearPayload {
+ resultStreamingOutputCallRequest.hasPayload = NO;
+ resultStreamingOutputCallRequest.payload = [RMTPayload defaultInstance];
+ return self;
+}
+@end
+
+@interface RMTStreamingOutputCallResponse ()
+@property (strong) RMTPayload* payload;
+@end
+
+@implementation RMTStreamingOutputCallResponse
+
+- (BOOL) hasPayload {
+ return !!hasPayload_;
+}
+- (void) setHasPayload:(BOOL) _value_ {
+ hasPayload_ = !!_value_;
+}
+@synthesize payload;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.payload = [RMTPayload defaultInstance];
+ }
+ return self;
+}
+static RMTStreamingOutputCallResponse* defaultRMTStreamingOutputCallResponseInstance = nil;
++ (void) initialize {
+ if (self == [RMTStreamingOutputCallResponse class]) {
+ defaultRMTStreamingOutputCallResponseInstance = [[RMTStreamingOutputCallResponse alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRMTStreamingOutputCallResponseInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRMTStreamingOutputCallResponseInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasPayload) {
+ [output writeMessage:1 value:self.payload];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasPayload) {
+ size_ += computeMessageSize(1, self.payload);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RMTStreamingOutputCallResponse*) parseFromData:(NSData*) data {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromData:data] build];
+}
++ (RMTStreamingOutputCallResponse*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallResponse*) parseFromInputStream:(NSInputStream*) input {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromInputStream:input] build];
+}
++ (RMTStreamingOutputCallResponse*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromCodedInputStream:input] build];
+}
++ (RMTStreamingOutputCallResponse*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RMTStreamingOutputCallResponse*)[[[RMTStreamingOutputCallResponse builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RMTStreamingOutputCallResponseBuilder*) builder {
+ return [[RMTStreamingOutputCallResponseBuilder alloc] init];
+}
++ (RMTStreamingOutputCallResponseBuilder*) builderWithPrototype:(RMTStreamingOutputCallResponse*) prototype {
+ return [[RMTStreamingOutputCallResponse builder] mergeFrom:prototype];
+}
+- (RMTStreamingOutputCallResponseBuilder*) builder {
+ return [RMTStreamingOutputCallResponse builder];
+}
+- (RMTStreamingOutputCallResponseBuilder*) toBuilder {
+ return [RMTStreamingOutputCallResponse builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasPayload) {
+ [output appendFormat:@"%@%@ {\n", indent, @"payload"];
+ [self.payload writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RMTStreamingOutputCallResponse class]]) {
+ return NO;
+ }
+ RMTStreamingOutputCallResponse *otherMessage = other;
+ return
+ self.hasPayload == otherMessage.hasPayload &&
+ (!self.hasPayload || [self.payload isEqual:otherMessage.payload]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasPayload) {
+ hashCode = hashCode * 31 + [self.payload hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RMTStreamingOutputCallResponseBuilder()
+@property (strong) RMTStreamingOutputCallResponse* resultStreamingOutputCallResponse;
+@end
+
+@implementation RMTStreamingOutputCallResponseBuilder
+@synthesize resultStreamingOutputCallResponse;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultStreamingOutputCallResponse = [[RMTStreamingOutputCallResponse alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultStreamingOutputCallResponse;
+}
+- (RMTStreamingOutputCallResponseBuilder*) clear {
+ self.resultStreamingOutputCallResponse = [[RMTStreamingOutputCallResponse alloc] init];
+ return self;
+}
+- (RMTStreamingOutputCallResponseBuilder*) clone {
+ return [RMTStreamingOutputCallResponse builderWithPrototype:resultStreamingOutputCallResponse];
+}
+- (RMTStreamingOutputCallResponse*) defaultInstance {
+ return [RMTStreamingOutputCallResponse defaultInstance];
+}
+- (RMTStreamingOutputCallResponse*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RMTStreamingOutputCallResponse*) buildPartial {
+ RMTStreamingOutputCallResponse* returnMe = resultStreamingOutputCallResponse;
+ self.resultStreamingOutputCallResponse = nil;
+ return returnMe;
+}
+- (RMTStreamingOutputCallResponseBuilder*) mergeFrom:(RMTStreamingOutputCallResponse*) other {
+ if (other == [RMTStreamingOutputCallResponse defaultInstance]) {
+ return self;
+ }
+ if (other.hasPayload) {
+ [self mergePayload:other.payload];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RMTStreamingOutputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RMTStreamingOutputCallResponseBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ RMTPayloadBuilder* subBuilder = [RMTPayload builder];
+ if (self.hasPayload) {
+ [subBuilder mergeFrom:self.payload];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setPayload:[subBuilder buildPartial]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasPayload {
+ return resultStreamingOutputCallResponse.hasPayload;
+}
+- (RMTPayload*) payload {
+ return resultStreamingOutputCallResponse.payload;
+}
+- (RMTStreamingOutputCallResponseBuilder*) setPayload:(RMTPayload*) value {
+ resultStreamingOutputCallResponse.hasPayload = YES;
+ resultStreamingOutputCallResponse.payload = value;
+ return self;
+}
+- (RMTStreamingOutputCallResponseBuilder*) setPayloadBuilder:(RMTPayloadBuilder*) builderForValue {
+ return [self setPayload:[builderForValue build]];
+}
+- (RMTStreamingOutputCallResponseBuilder*) mergePayload:(RMTPayload*) value {
+ if (resultStreamingOutputCallResponse.hasPayload &&
+ resultStreamingOutputCallResponse.payload != [RMTPayload defaultInstance]) {
+ resultStreamingOutputCallResponse.payload =
+ [[[RMTPayload builderWithPrototype:resultStreamingOutputCallResponse.payload] mergeFrom:value] buildPartial];
+ } else {
+ resultStreamingOutputCallResponse.payload = value;
+ }
+ resultStreamingOutputCallResponse.hasPayload = YES;
+ return self;
+}
+- (RMTStreamingOutputCallResponseBuilder*) clearPayload {
+ resultStreamingOutputCallResponse.hasPayload = NO;
+ resultStreamingOutputCallResponse.payload = [RMTPayload defaultInstance];
+ return self;
+}
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
new file mode 100644
index 0000000000..7b025ce252
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
@@ -0,0 +1,18 @@
+Pod::Spec.new do |s|
+ s.name = 'RemoteTest'
+ s.version = '0.0.1'
+ s.summary = 'Protobuf library generated from test.proto, messages.proto, and empty.proto'
+ s.homepage = 'https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample/RemoteTestClient'
+ s.license = 'New BSD'
+ s.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
+
+ s.source_files = '*.pb.{h,m}'
+ s.public_header_files = '*.pb.h'
+
+ s.platform = :ios
+ s.ios.deployment_target = '6.0'
+ s.requires_arc = true
+
+ s.dependency 'ProtocolBuffers', '~> 1.9'
+ s.dependency 'gRPC', '~> 0.0'
+end
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
new file mode 100644
index 0000000000..b6111b15b8
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
@@ -0,0 +1,167 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import <ProtocolBuffers/ProtocolBuffers.h>
+
+#import "Empty.pb.h"
+#import "Messages.pb.h"
+#import <gRPC/ProtoService.h>
+// @@protoc_insertion_point(imports)
+
+@class ObjectiveCFileOptions;
+@class ObjectiveCFileOptionsBuilder;
+@class PBDescriptorProto;
+@class PBDescriptorProtoBuilder;
+@class PBDescriptorProtoExtensionRange;
+@class PBDescriptorProtoExtensionRangeBuilder;
+@class PBEnumDescriptorProto;
+@class PBEnumDescriptorProtoBuilder;
+@class PBEnumOptions;
+@class PBEnumOptionsBuilder;
+@class PBEnumValueDescriptorProto;
+@class PBEnumValueDescriptorProtoBuilder;
+@class PBEnumValueOptions;
+@class PBEnumValueOptionsBuilder;
+@class PBFieldDescriptorProto;
+@class PBFieldDescriptorProtoBuilder;
+@class PBFieldOptions;
+@class PBFieldOptionsBuilder;
+@class PBFileDescriptorProto;
+@class PBFileDescriptorProtoBuilder;
+@class PBFileDescriptorSet;
+@class PBFileDescriptorSetBuilder;
+@class PBFileOptions;
+@class PBFileOptionsBuilder;
+@class PBMessageOptions;
+@class PBMessageOptionsBuilder;
+@class PBMethodDescriptorProto;
+@class PBMethodDescriptorProtoBuilder;
+@class PBMethodOptions;
+@class PBMethodOptionsBuilder;
+@class PBOneofDescriptorProto;
+@class PBOneofDescriptorProtoBuilder;
+@class PBServiceDescriptorProto;
+@class PBServiceDescriptorProtoBuilder;
+@class PBServiceOptions;
+@class PBServiceOptionsBuilder;
+@class PBSourceCodeInfo;
+@class PBSourceCodeInfoBuilder;
+@class PBSourceCodeInfoLocation;
+@class PBSourceCodeInfoLocationBuilder;
+@class PBUninterpretedOption;
+@class PBUninterpretedOptionBuilder;
+@class PBUninterpretedOptionNamePart;
+@class PBUninterpretedOptionNamePartBuilder;
+@class RMTEmpty;
+@class RMTEmptyBuilder;
+@class RMTPayload;
+@class RMTPayloadBuilder;
+@class RMTResponseParameters;
+@class RMTResponseParametersBuilder;
+@class RMTSimpleRequest;
+@class RMTSimpleRequestBuilder;
+@class RMTSimpleResponse;
+@class RMTSimpleResponseBuilder;
+@class RMTStreamingInputCallRequest;
+@class RMTStreamingInputCallRequestBuilder;
+@class RMTStreamingInputCallResponse;
+@class RMTStreamingInputCallResponseBuilder;
+@class RMTStreamingOutputCallRequest;
+@class RMTStreamingOutputCallRequestBuilder;
+@class RMTStreamingOutputCallResponse;
+@class RMTStreamingOutputCallResponseBuilder;
+
+
+
+@interface RMTTestRoot : NSObject {
+}
++ (PBExtensionRegistry*) extensionRegistry;
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry;
+@end
+
+
+
+@protocol GRXWriteable;
+@protocol GRXWriter;
+
+@protocol RMTTestService <NSObject>
+
+#pragma mark EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty)
+
+// One empty request followed by one empty response.
+- (void)emptyCallWithRequest:(RMTEmpty *)request
+ handler:(void(^)(RMTEmpty *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToEmptyCallWithRequest:(RMTEmpty *)request
+ handler:(void(^)(RMTEmpty *response, NSError *error))handler;
+
+
+#pragma mark UnaryCall(SimpleRequest) returns (SimpleResponse)
+
+// One request followed by one response.
+- (void)unaryCallWithRequest:(RMTSimpleRequest *)request
+ handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToUnaryCallWithRequest:(RMTSimpleRequest *)request
+ handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler;
+
+
+#pragma mark StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// One request followed by a sequence of responses (streamed download).
+// The server returns the payload with client desired type and sizes.
+- (void)streamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse)
+
+// A sequence of requests followed by one response (streamed upload).
+// The server returns the aggregated size of client payload as the result.
+- (void)streamingInputCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingInputCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// 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.
+- (void)fullDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToFullDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+
+#pragma mark HalfDuplexCall(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.
+- (void)halfDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToHalfDuplexCallWithRequestsWriter:(id<GRXWriter>)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler;
+
+@end
+
+// Basic service implementation, over gRPC, that only does marshalling and parsing.
+@interface RMTTestService : ProtoService<RMTTestService>
+- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+@end
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
new file mode 100644
index 0000000000..31a3ba3a61
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
@@ -0,0 +1,163 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import "Test.pb.h"
+
+#import <gRPC/GRXWriteable.h>
+#import <gRPC/GRXWriter+Immediate.h>
+#import <gRPC/ProtoRPC.h>
+// @@protoc_insertion_point(imports)
+
+@implementation RMTTestRoot
+static PBExtensionRegistry* extensionRegistry = nil;
++ (PBExtensionRegistry*) extensionRegistry {
+ return extensionRegistry;
+}
+
++ (void) initialize {
+ if (self == [RMTTestRoot class]) {
+ PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry];
+ [self registerAllExtensions:registry];
+ [RMTEmptyRoot registerAllExtensions:registry];
+ [RMTMessagesRoot registerAllExtensions:registry];
+ [ObjectivecDescriptorRoot registerAllExtensions:registry];
+ extensionRegistry = registry;
+ }
+}
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry {
+}
+@end
+
+
+static NSString *const kPackageName = @"grpc.testing";
+static NSString *const kServiceName = @"TestService";
+
+@implementation RMTTestService
+
+// Designated initializer
+- (instancetype)initWithHost:(NSString *)host {
+ return (self = [super initWithHost:host packageName:kPackageName serviceName:kServiceName]);
+}
+
+- (instancetype)initWithHost:(NSString *)host
+ packageName:(NSString *)packageName
+ serviceName:(NSString *)serviceName {
+ return [self initWithHost:host];
+}
+
+#pragma mark EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty)
+
+// One empty request followed by one empty response.
+- (void)emptyCallWithRequest:(RMTEmpty *)request
+ handler:(void(^)(RMTEmpty *response, NSError *error))handler {
+ [[self RPCToEmptyCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToEmptyCallWithRequest:(RMTEmpty *)request
+ handler:(void(^)(RMTEmpty *response, NSError *error))handler {
+ return [self RPCToMethod:@"EmptyCall"
+ requestsWriter:[GRXWriter writerWithValue:request]
+ responseClass:[RMTEmpty class]
+ responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark UnaryCall(SimpleRequest) returns (SimpleResponse)
+
+// One request followed by one response.
+- (void)unaryCallWithRequest:(RMTSimpleRequest *)request
+ handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler {
+ [[self RPCToUnaryCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToUnaryCallWithRequest:(RMTSimpleRequest *)request
+ handler:(void(^)(RMTSimpleResponse *response, NSError *error))handler {
+ return [self RPCToMethod:@"UnaryCall"
+ requestsWriter:[GRXWriter writerWithValue:request]
+ responseClass:[RMTSimpleResponse class]
+ responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark StreamingOutputCall(StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// One request followed by a sequence of responses (streamed download).
+// The server returns the payload with client desired type and sizes.
+- (void)streamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ [[self RPCToStreamingOutputCallWithRequest:request handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingOutputCallWithRequest:(RMTStreamingOutputCallRequest *)request
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ return [self RPCToMethod:@"StreamingOutputCall"
+ requestsWriter:[GRXWriter writerWithValue:request]
+ responseClass:[RMTStreamingOutputCallResponse class]
+ responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+
+#pragma mark StreamingInputCall(stream StreamingInputCallRequest) returns (StreamingInputCallResponse)
+
+// A sequence of requests followed by one response (streamed upload).
+// The server returns the aggregated size of client payload as the result.
+- (void)streamingInputCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler {
+ [[self RPCToStreamingInputCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToStreamingInputCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(RMTStreamingInputCallResponse *response, NSError *error))handler {
+ return [self RPCToMethod:@"StreamingInputCall"
+ requestsWriter:requestsWriter
+ responseClass:[RMTStreamingInputCallResponse class]
+ responsesWriteable:[GRXWriteable writeableWithSingleValueHandler:handler]];
+}
+
+
+#pragma mark FullDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse)
+
+// 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.
+- (void)fullDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ [[self RPCToFullDuplexCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToFullDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ return [self RPCToMethod:@"FullDuplexCall"
+ requestsWriter:requestsWriter
+ responseClass:[RMTStreamingOutputCallResponse class]
+ responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+
+#pragma mark HalfDuplexCall(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.
+- (void)halfDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ [[self RPCToHalfDuplexCallWithRequestsWriter:requestsWriter handler:handler] start];
+}
+
+// Returns a not-yet-started RPC object.
+- (ProtoRPC *)RPCToHalfDuplexCallWithRequestsWriter:(id<GRXWriter>)requestsWriter
+ handler:(void(^)(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error))handler {
+ return [self RPCToMethod:@"HalfDuplexCall"
+ requestsWriter:requestsWriter
+ responseClass:[RMTStreamingOutputCallResponse class]
+ responsesWriteable:[GRXWriteable writeableWithStreamHandler:handler]];
+}
+
+@end
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/empty.proto b/src/objective-c/examples/Sample/RemoteTestClient/empty.proto
new file mode 100644
index 0000000000..3b626ab131
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/empty.proto
@@ -0,0 +1,46 @@
+// 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 = "proto2";
+
+import "google/protobuf/objectivec-descriptor.proto";
+
+package grpc.testing;
+
+option (google.protobuf.objectivec_file_options).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/Sample/RemoteTestClient/messages.proto b/src/objective-c/examples/Sample/RemoteTestClient/messages.proto
new file mode 100644
index 0000000000..ab8577401f
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/messages.proto
@@ -0,0 +1,135 @@
+// 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 = "proto2";
+
+import "google/protobuf/objectivec-descriptor.proto";
+
+package grpc.testing;
+
+option (google.protobuf.objectivec_file_options).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.
+ optional PayloadType type = 1;
+ // Primary contents of payload.
+ optional 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;
+
+ // 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;
+
+ // Optional input payload sent along with the request.
+ optional Payload payload = 3;
+
+ // Whether SimpleResponse should include username.
+ optional bool fill_username = 4;
+
+ // Whether SimpleResponse should include OAuth scope.
+ optional bool fill_oauth_scope = 5;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+ // Payload to increase message size.
+ optional Payload payload = 1;
+ // The user the request came from, for verifying authentication was
+ // successful when the client expected it.
+ optional string username = 2;
+ // OAuth scope.
+ optional string oauth_scope = 3;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+ // Optional input payload sent along with the request.
+ optional Payload payload = 1;
+
+ // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+ // Aggregated size of payloads received from the client.
+ optional 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;
+
+ // Desired interval between consecutive responses in the response stream in
+ // microseconds.
+ optional 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.
+ optional 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;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+ // Payload to increase response size.
+ optional Payload payload = 1;
+}
diff --git a/src/objective-c/examples/Sample/RemoteTestClient/test.proto b/src/objective-c/examples/Sample/RemoteTestClient/test.proto
new file mode 100644
index 0000000000..4b08220599
--- /dev/null
+++ b/src/objective-c/examples/Sample/RemoteTestClient/test.proto
@@ -0,0 +1,74 @@
+// 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 = "proto2";
+
+import "empty.proto";
+import "messages.proto";
+import "google/protobuf/objectivec-descriptor.proto";
+
+package grpc.testing;
+
+option (google.protobuf.objectivec_file_options).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/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.h b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.h
new file mode 100644
index 0000000000..194bfc5f2a
--- /dev/null
+++ b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.h
@@ -0,0 +1,387 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import <ProtocolBuffers/ProtocolBuffers.h>
+
+// @@protoc_insertion_point(imports)
+
+@class ObjectiveCFileOptions;
+@class ObjectiveCFileOptionsBuilder;
+@class PBDescriptorProto;
+@class PBDescriptorProtoBuilder;
+@class PBDescriptorProtoExtensionRange;
+@class PBDescriptorProtoExtensionRangeBuilder;
+@class PBEnumDescriptorProto;
+@class PBEnumDescriptorProtoBuilder;
+@class PBEnumOptions;
+@class PBEnumOptionsBuilder;
+@class PBEnumValueDescriptorProto;
+@class PBEnumValueDescriptorProtoBuilder;
+@class PBEnumValueOptions;
+@class PBEnumValueOptionsBuilder;
+@class PBFieldDescriptorProto;
+@class PBFieldDescriptorProtoBuilder;
+@class PBFieldOptions;
+@class PBFieldOptionsBuilder;
+@class PBFileDescriptorProto;
+@class PBFileDescriptorProtoBuilder;
+@class PBFileDescriptorSet;
+@class PBFileDescriptorSetBuilder;
+@class PBFileOptions;
+@class PBFileOptionsBuilder;
+@class PBMessageOptions;
+@class PBMessageOptionsBuilder;
+@class PBMethodDescriptorProto;
+@class PBMethodDescriptorProtoBuilder;
+@class PBMethodOptions;
+@class PBMethodOptionsBuilder;
+@class PBOneofDescriptorProto;
+@class PBOneofDescriptorProtoBuilder;
+@class PBServiceDescriptorProto;
+@class PBServiceDescriptorProtoBuilder;
+@class PBServiceOptions;
+@class PBServiceOptionsBuilder;
+@class PBSourceCodeInfo;
+@class PBSourceCodeInfoBuilder;
+@class PBSourceCodeInfoLocation;
+@class PBSourceCodeInfoLocationBuilder;
+@class PBUninterpretedOption;
+@class PBUninterpretedOptionBuilder;
+@class PBUninterpretedOptionNamePart;
+@class PBUninterpretedOptionNamePartBuilder;
+@class RGDFeature;
+@class RGDFeatureBuilder;
+@class RGDPoint;
+@class RGDPointBuilder;
+@class RGDRectangle;
+@class RGDRectangleBuilder;
+@class RGDRouteNote;
+@class RGDRouteNoteBuilder;
+@class RGDRouteSummary;
+@class RGDRouteSummaryBuilder;
+
+
+
+@interface RGDRouteGuideRoot : NSObject {
+}
++ (PBExtensionRegistry*) extensionRegistry;
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry;
+@end
+
+@interface RGDPoint : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasLatitude_:1;
+ BOOL hasLongitude_:1;
+ SInt32 latitude;
+ SInt32 longitude;
+}
+- (BOOL) hasLatitude;
+- (BOOL) hasLongitude;
+@property (readonly) SInt32 latitude;
+@property (readonly) SInt32 longitude;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RGDPointBuilder*) builder;
++ (RGDPointBuilder*) builder;
++ (RGDPointBuilder*) builderWithPrototype:(RGDPoint*) prototype;
+- (RGDPointBuilder*) toBuilder;
+
++ (RGDPoint*) parseFromData:(NSData*) data;
++ (RGDPoint*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDPoint*) parseFromInputStream:(NSInputStream*) input;
++ (RGDPoint*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDPoint*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RGDPoint*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RGDPointBuilder : PBGeneratedMessageBuilder {
+@private
+ RGDPoint* resultPoint;
+}
+
+- (RGDPoint*) defaultInstance;
+
+- (RGDPointBuilder*) clear;
+- (RGDPointBuilder*) clone;
+
+- (RGDPoint*) build;
+- (RGDPoint*) buildPartial;
+
+- (RGDPointBuilder*) mergeFrom:(RGDPoint*) other;
+- (RGDPointBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RGDPointBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasLatitude;
+- (SInt32) latitude;
+- (RGDPointBuilder*) setLatitude:(SInt32) value;
+- (RGDPointBuilder*) clearLatitude;
+
+- (BOOL) hasLongitude;
+- (SInt32) longitude;
+- (RGDPointBuilder*) setLongitude:(SInt32) value;
+- (RGDPointBuilder*) clearLongitude;
+@end
+
+@interface RGDRectangle : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasLo_:1;
+ BOOL hasHi_:1;
+ RGDPoint* lo;
+ RGDPoint* hi;
+}
+- (BOOL) hasLo;
+- (BOOL) hasHi;
+@property (readonly, strong) RGDPoint* lo;
+@property (readonly, strong) RGDPoint* hi;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RGDRectangleBuilder*) builder;
++ (RGDRectangleBuilder*) builder;
++ (RGDRectangleBuilder*) builderWithPrototype:(RGDRectangle*) prototype;
+- (RGDRectangleBuilder*) toBuilder;
+
++ (RGDRectangle*) parseFromData:(NSData*) data;
++ (RGDRectangle*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRectangle*) parseFromInputStream:(NSInputStream*) input;
++ (RGDRectangle*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRectangle*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RGDRectangle*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RGDRectangleBuilder : PBGeneratedMessageBuilder {
+@private
+ RGDRectangle* resultRectangle;
+}
+
+- (RGDRectangle*) defaultInstance;
+
+- (RGDRectangleBuilder*) clear;
+- (RGDRectangleBuilder*) clone;
+
+- (RGDRectangle*) build;
+- (RGDRectangle*) buildPartial;
+
+- (RGDRectangleBuilder*) mergeFrom:(RGDRectangle*) other;
+- (RGDRectangleBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RGDRectangleBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasLo;
+- (RGDPoint*) lo;
+- (RGDRectangleBuilder*) setLo:(RGDPoint*) value;
+- (RGDRectangleBuilder*) setLoBuilder:(RGDPointBuilder*) builderForValue;
+- (RGDRectangleBuilder*) mergeLo:(RGDPoint*) value;
+- (RGDRectangleBuilder*) clearLo;
+
+- (BOOL) hasHi;
+- (RGDPoint*) hi;
+- (RGDRectangleBuilder*) setHi:(RGDPoint*) value;
+- (RGDRectangleBuilder*) setHiBuilder:(RGDPointBuilder*) builderForValue;
+- (RGDRectangleBuilder*) mergeHi:(RGDPoint*) value;
+- (RGDRectangleBuilder*) clearHi;
+@end
+
+@interface RGDFeature : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasName_:1;
+ BOOL hasLocation_:1;
+ NSString* name;
+ RGDPoint* location;
+}
+- (BOOL) hasName;
+- (BOOL) hasLocation;
+@property (readonly, strong) NSString* name;
+@property (readonly, strong) RGDPoint* location;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RGDFeatureBuilder*) builder;
++ (RGDFeatureBuilder*) builder;
++ (RGDFeatureBuilder*) builderWithPrototype:(RGDFeature*) prototype;
+- (RGDFeatureBuilder*) toBuilder;
+
++ (RGDFeature*) parseFromData:(NSData*) data;
++ (RGDFeature*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDFeature*) parseFromInputStream:(NSInputStream*) input;
++ (RGDFeature*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDFeature*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RGDFeature*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RGDFeatureBuilder : PBGeneratedMessageBuilder {
+@private
+ RGDFeature* resultFeature;
+}
+
+- (RGDFeature*) defaultInstance;
+
+- (RGDFeatureBuilder*) clear;
+- (RGDFeatureBuilder*) clone;
+
+- (RGDFeature*) build;
+- (RGDFeature*) buildPartial;
+
+- (RGDFeatureBuilder*) mergeFrom:(RGDFeature*) other;
+- (RGDFeatureBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RGDFeatureBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasName;
+- (NSString*) name;
+- (RGDFeatureBuilder*) setName:(NSString*) value;
+- (RGDFeatureBuilder*) clearName;
+
+- (BOOL) hasLocation;
+- (RGDPoint*) location;
+- (RGDFeatureBuilder*) setLocation:(RGDPoint*) value;
+- (RGDFeatureBuilder*) setLocationBuilder:(RGDPointBuilder*) builderForValue;
+- (RGDFeatureBuilder*) mergeLocation:(RGDPoint*) value;
+- (RGDFeatureBuilder*) clearLocation;
+@end
+
+@interface RGDRouteNote : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasMessage_:1;
+ BOOL hasLocation_:1;
+ NSString* message;
+ RGDPoint* location;
+}
+- (BOOL) hasLocation;
+- (BOOL) hasMessage;
+@property (readonly, strong) RGDPoint* location;
+@property (readonly, strong) NSString* message;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RGDRouteNoteBuilder*) builder;
++ (RGDRouteNoteBuilder*) builder;
++ (RGDRouteNoteBuilder*) builderWithPrototype:(RGDRouteNote*) prototype;
+- (RGDRouteNoteBuilder*) toBuilder;
+
++ (RGDRouteNote*) parseFromData:(NSData*) data;
++ (RGDRouteNote*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRouteNote*) parseFromInputStream:(NSInputStream*) input;
++ (RGDRouteNote*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRouteNote*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RGDRouteNote*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RGDRouteNoteBuilder : PBGeneratedMessageBuilder {
+@private
+ RGDRouteNote* resultRouteNote;
+}
+
+- (RGDRouteNote*) defaultInstance;
+
+- (RGDRouteNoteBuilder*) clear;
+- (RGDRouteNoteBuilder*) clone;
+
+- (RGDRouteNote*) build;
+- (RGDRouteNote*) buildPartial;
+
+- (RGDRouteNoteBuilder*) mergeFrom:(RGDRouteNote*) other;
+- (RGDRouteNoteBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RGDRouteNoteBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasLocation;
+- (RGDPoint*) location;
+- (RGDRouteNoteBuilder*) setLocation:(RGDPoint*) value;
+- (RGDRouteNoteBuilder*) setLocationBuilder:(RGDPointBuilder*) builderForValue;
+- (RGDRouteNoteBuilder*) mergeLocation:(RGDPoint*) value;
+- (RGDRouteNoteBuilder*) clearLocation;
+
+- (BOOL) hasMessage;
+- (NSString*) message;
+- (RGDRouteNoteBuilder*) setMessage:(NSString*) value;
+- (RGDRouteNoteBuilder*) clearMessage;
+@end
+
+@interface RGDRouteSummary : PBGeneratedMessage<GeneratedMessageProtocol> {
+@private
+ BOOL hasPointCount_:1;
+ BOOL hasFeatureCount_:1;
+ BOOL hasDistance_:1;
+ BOOL hasElapsedTime_:1;
+ SInt32 pointCount;
+ SInt32 featureCount;
+ SInt32 distance;
+ SInt32 elapsedTime;
+}
+- (BOOL) hasPointCount;
+- (BOOL) hasFeatureCount;
+- (BOOL) hasDistance;
+- (BOOL) hasElapsedTime;
+@property (readonly) SInt32 pointCount;
+@property (readonly) SInt32 featureCount;
+@property (readonly) SInt32 distance;
+@property (readonly) SInt32 elapsedTime;
+
++ (instancetype) defaultInstance;
+- (instancetype) defaultInstance;
+
+- (BOOL) isInitialized;
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output;
+- (RGDRouteSummaryBuilder*) builder;
++ (RGDRouteSummaryBuilder*) builder;
++ (RGDRouteSummaryBuilder*) builderWithPrototype:(RGDRouteSummary*) prototype;
+- (RGDRouteSummaryBuilder*) toBuilder;
+
++ (RGDRouteSummary*) parseFromData:(NSData*) data;
++ (RGDRouteSummary*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRouteSummary*) parseFromInputStream:(NSInputStream*) input;
++ (RGDRouteSummary*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
++ (RGDRouteSummary*) parseFromCodedInputStream:(PBCodedInputStream*) input;
++ (RGDRouteSummary*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+@end
+
+@interface RGDRouteSummaryBuilder : PBGeneratedMessageBuilder {
+@private
+ RGDRouteSummary* resultRouteSummary;
+}
+
+- (RGDRouteSummary*) defaultInstance;
+
+- (RGDRouteSummaryBuilder*) clear;
+- (RGDRouteSummaryBuilder*) clone;
+
+- (RGDRouteSummary*) build;
+- (RGDRouteSummary*) buildPartial;
+
+- (RGDRouteSummaryBuilder*) mergeFrom:(RGDRouteSummary*) other;
+- (RGDRouteSummaryBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input;
+- (RGDRouteSummaryBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry;
+
+- (BOOL) hasPointCount;
+- (SInt32) pointCount;
+- (RGDRouteSummaryBuilder*) setPointCount:(SInt32) value;
+- (RGDRouteSummaryBuilder*) clearPointCount;
+
+- (BOOL) hasFeatureCount;
+- (SInt32) featureCount;
+- (RGDRouteSummaryBuilder*) setFeatureCount:(SInt32) value;
+- (RGDRouteSummaryBuilder*) clearFeatureCount;
+
+- (BOOL) hasDistance;
+- (SInt32) distance;
+- (RGDRouteSummaryBuilder*) setDistance:(SInt32) value;
+- (RGDRouteSummaryBuilder*) clearDistance;
+
+- (BOOL) hasElapsedTime;
+- (SInt32) elapsedTime;
+- (RGDRouteSummaryBuilder*) setElapsedTime:(SInt32) value;
+- (RGDRouteSummaryBuilder*) clearElapsedTime;
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.m b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.m
new file mode 100644
index 0000000000..63cdd00206
--- /dev/null
+++ b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.m
@@ -0,0 +1,1435 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+
+#import "Route_guide.pb.h"
+// @@protoc_insertion_point(imports)
+
+@implementation RGDRouteGuideRoot
+static PBExtensionRegistry* extensionRegistry = nil;
++ (PBExtensionRegistry*) extensionRegistry {
+ return extensionRegistry;
+}
+
++ (void) initialize {
+ if (self == [RGDRouteGuideRoot class]) {
+ PBMutableExtensionRegistry* registry = [PBMutableExtensionRegistry registry];
+ [self registerAllExtensions:registry];
+ [ObjectivecDescriptorRoot registerAllExtensions:registry];
+ extensionRegistry = registry;
+ }
+}
++ (void) registerAllExtensions:(PBMutableExtensionRegistry*) registry {
+}
+@end
+
+@interface RGDPoint ()
+@property SInt32 latitude;
+@property SInt32 longitude;
+@end
+
+@implementation RGDPoint
+
+- (BOOL) hasLatitude {
+ return !!hasLatitude_;
+}
+- (void) setHasLatitude:(BOOL) _value_ {
+ hasLatitude_ = !!_value_;
+}
+@synthesize latitude;
+- (BOOL) hasLongitude {
+ return !!hasLongitude_;
+}
+- (void) setHasLongitude:(BOOL) _value_ {
+ hasLongitude_ = !!_value_;
+}
+@synthesize longitude;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.latitude = 0;
+ self.longitude = 0;
+ }
+ return self;
+}
+static RGDPoint* defaultRGDPointInstance = nil;
++ (void) initialize {
+ if (self == [RGDPoint class]) {
+ defaultRGDPointInstance = [[RGDPoint alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRGDPointInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRGDPointInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasLatitude) {
+ [output writeInt32:1 value:self.latitude];
+ }
+ if (self.hasLongitude) {
+ [output writeInt32:2 value:self.longitude];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasLatitude) {
+ size_ += computeInt32Size(1, self.latitude);
+ }
+ if (self.hasLongitude) {
+ size_ += computeInt32Size(2, self.longitude);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RGDPoint*) parseFromData:(NSData*) data {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromData:data] build];
+}
++ (RGDPoint*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RGDPoint*) parseFromInputStream:(NSInputStream*) input {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromInputStream:input] build];
+}
++ (RGDPoint*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDPoint*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromCodedInputStream:input] build];
+}
++ (RGDPoint*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDPoint*)[[[RGDPoint builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDPointBuilder*) builder {
+ return [[RGDPointBuilder alloc] init];
+}
++ (RGDPointBuilder*) builderWithPrototype:(RGDPoint*) prototype {
+ return [[RGDPoint builder] mergeFrom:prototype];
+}
+- (RGDPointBuilder*) builder {
+ return [RGDPoint builder];
+}
+- (RGDPointBuilder*) toBuilder {
+ return [RGDPoint builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasLatitude) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"latitude", [NSNumber numberWithInteger:self.latitude]];
+ }
+ if (self.hasLongitude) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"longitude", [NSNumber numberWithInteger:self.longitude]];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RGDPoint class]]) {
+ return NO;
+ }
+ RGDPoint *otherMessage = other;
+ return
+ self.hasLatitude == otherMessage.hasLatitude &&
+ (!self.hasLatitude || self.latitude == otherMessage.latitude) &&
+ self.hasLongitude == otherMessage.hasLongitude &&
+ (!self.hasLongitude || self.longitude == otherMessage.longitude) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasLatitude) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.latitude] hash];
+ }
+ if (self.hasLongitude) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.longitude] hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RGDPointBuilder()
+@property (strong) RGDPoint* resultPoint;
+@end
+
+@implementation RGDPointBuilder
+@synthesize resultPoint;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultPoint = [[RGDPoint alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultPoint;
+}
+- (RGDPointBuilder*) clear {
+ self.resultPoint = [[RGDPoint alloc] init];
+ return self;
+}
+- (RGDPointBuilder*) clone {
+ return [RGDPoint builderWithPrototype:resultPoint];
+}
+- (RGDPoint*) defaultInstance {
+ return [RGDPoint defaultInstance];
+}
+- (RGDPoint*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RGDPoint*) buildPartial {
+ RGDPoint* returnMe = resultPoint;
+ self.resultPoint = nil;
+ return returnMe;
+}
+- (RGDPointBuilder*) mergeFrom:(RGDPoint*) other {
+ if (other == [RGDPoint defaultInstance]) {
+ return self;
+ }
+ if (other.hasLatitude) {
+ [self setLatitude:other.latitude];
+ }
+ if (other.hasLongitude) {
+ [self setLongitude:other.longitude];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RGDPointBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RGDPointBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ [self setLatitude:[input readInt32]];
+ break;
+ }
+ case 16: {
+ [self setLongitude:[input readInt32]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasLatitude {
+ return resultPoint.hasLatitude;
+}
+- (SInt32) latitude {
+ return resultPoint.latitude;
+}
+- (RGDPointBuilder*) setLatitude:(SInt32) value {
+ resultPoint.hasLatitude = YES;
+ resultPoint.latitude = value;
+ return self;
+}
+- (RGDPointBuilder*) clearLatitude {
+ resultPoint.hasLatitude = NO;
+ resultPoint.latitude = 0;
+ return self;
+}
+- (BOOL) hasLongitude {
+ return resultPoint.hasLongitude;
+}
+- (SInt32) longitude {
+ return resultPoint.longitude;
+}
+- (RGDPointBuilder*) setLongitude:(SInt32) value {
+ resultPoint.hasLongitude = YES;
+ resultPoint.longitude = value;
+ return self;
+}
+- (RGDPointBuilder*) clearLongitude {
+ resultPoint.hasLongitude = NO;
+ resultPoint.longitude = 0;
+ return self;
+}
+@end
+
+@interface RGDRectangle ()
+@property (strong) RGDPoint* lo;
+@property (strong) RGDPoint* hi;
+@end
+
+@implementation RGDRectangle
+
+- (BOOL) hasLo {
+ return !!hasLo_;
+}
+- (void) setHasLo:(BOOL) _value_ {
+ hasLo_ = !!_value_;
+}
+@synthesize lo;
+- (BOOL) hasHi {
+ return !!hasHi_;
+}
+- (void) setHasHi:(BOOL) _value_ {
+ hasHi_ = !!_value_;
+}
+@synthesize hi;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.lo = [RGDPoint defaultInstance];
+ self.hi = [RGDPoint defaultInstance];
+ }
+ return self;
+}
+static RGDRectangle* defaultRGDRectangleInstance = nil;
++ (void) initialize {
+ if (self == [RGDRectangle class]) {
+ defaultRGDRectangleInstance = [[RGDRectangle alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRGDRectangleInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRGDRectangleInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasLo) {
+ [output writeMessage:1 value:self.lo];
+ }
+ if (self.hasHi) {
+ [output writeMessage:2 value:self.hi];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasLo) {
+ size_ += computeMessageSize(1, self.lo);
+ }
+ if (self.hasHi) {
+ size_ += computeMessageSize(2, self.hi);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RGDRectangle*) parseFromData:(NSData*) data {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromData:data] build];
+}
++ (RGDRectangle*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RGDRectangle*) parseFromInputStream:(NSInputStream*) input {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromInputStream:input] build];
+}
++ (RGDRectangle*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRectangle*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromCodedInputStream:input] build];
+}
++ (RGDRectangle*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRectangle*)[[[RGDRectangle builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRectangleBuilder*) builder {
+ return [[RGDRectangleBuilder alloc] init];
+}
++ (RGDRectangleBuilder*) builderWithPrototype:(RGDRectangle*) prototype {
+ return [[RGDRectangle builder] mergeFrom:prototype];
+}
+- (RGDRectangleBuilder*) builder {
+ return [RGDRectangle builder];
+}
+- (RGDRectangleBuilder*) toBuilder {
+ return [RGDRectangle builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasLo) {
+ [output appendFormat:@"%@%@ {\n", indent, @"lo"];
+ [self.lo writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ if (self.hasHi) {
+ [output appendFormat:@"%@%@ {\n", indent, @"hi"];
+ [self.hi writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RGDRectangle class]]) {
+ return NO;
+ }
+ RGDRectangle *otherMessage = other;
+ return
+ self.hasLo == otherMessage.hasLo &&
+ (!self.hasLo || [self.lo isEqual:otherMessage.lo]) &&
+ self.hasHi == otherMessage.hasHi &&
+ (!self.hasHi || [self.hi isEqual:otherMessage.hi]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasLo) {
+ hashCode = hashCode * 31 + [self.lo hash];
+ }
+ if (self.hasHi) {
+ hashCode = hashCode * 31 + [self.hi hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RGDRectangleBuilder()
+@property (strong) RGDRectangle* resultRectangle;
+@end
+
+@implementation RGDRectangleBuilder
+@synthesize resultRectangle;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultRectangle = [[RGDRectangle alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultRectangle;
+}
+- (RGDRectangleBuilder*) clear {
+ self.resultRectangle = [[RGDRectangle alloc] init];
+ return self;
+}
+- (RGDRectangleBuilder*) clone {
+ return [RGDRectangle builderWithPrototype:resultRectangle];
+}
+- (RGDRectangle*) defaultInstance {
+ return [RGDRectangle defaultInstance];
+}
+- (RGDRectangle*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RGDRectangle*) buildPartial {
+ RGDRectangle* returnMe = resultRectangle;
+ self.resultRectangle = nil;
+ return returnMe;
+}
+- (RGDRectangleBuilder*) mergeFrom:(RGDRectangle*) other {
+ if (other == [RGDRectangle defaultInstance]) {
+ return self;
+ }
+ if (other.hasLo) {
+ [self mergeLo:other.lo];
+ }
+ if (other.hasHi) {
+ [self mergeHi:other.hi];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RGDRectangleBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RGDRectangleBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ RGDPointBuilder* subBuilder = [RGDPoint builder];
+ if (self.hasLo) {
+ [subBuilder mergeFrom:self.lo];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setLo:[subBuilder buildPartial]];
+ break;
+ }
+ case 18: {
+ RGDPointBuilder* subBuilder = [RGDPoint builder];
+ if (self.hasHi) {
+ [subBuilder mergeFrom:self.hi];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setHi:[subBuilder buildPartial]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasLo {
+ return resultRectangle.hasLo;
+}
+- (RGDPoint*) lo {
+ return resultRectangle.lo;
+}
+- (RGDRectangleBuilder*) setLo:(RGDPoint*) value {
+ resultRectangle.hasLo = YES;
+ resultRectangle.lo = value;
+ return self;
+}
+- (RGDRectangleBuilder*) setLoBuilder:(RGDPointBuilder*) builderForValue {
+ return [self setLo:[builderForValue build]];
+}
+- (RGDRectangleBuilder*) mergeLo:(RGDPoint*) value {
+ if (resultRectangle.hasLo &&
+ resultRectangle.lo != [RGDPoint defaultInstance]) {
+ resultRectangle.lo =
+ [[[RGDPoint builderWithPrototype:resultRectangle.lo] mergeFrom:value] buildPartial];
+ } else {
+ resultRectangle.lo = value;
+ }
+ resultRectangle.hasLo = YES;
+ return self;
+}
+- (RGDRectangleBuilder*) clearLo {
+ resultRectangle.hasLo = NO;
+ resultRectangle.lo = [RGDPoint defaultInstance];
+ return self;
+}
+- (BOOL) hasHi {
+ return resultRectangle.hasHi;
+}
+- (RGDPoint*) hi {
+ return resultRectangle.hi;
+}
+- (RGDRectangleBuilder*) setHi:(RGDPoint*) value {
+ resultRectangle.hasHi = YES;
+ resultRectangle.hi = value;
+ return self;
+}
+- (RGDRectangleBuilder*) setHiBuilder:(RGDPointBuilder*) builderForValue {
+ return [self setHi:[builderForValue build]];
+}
+- (RGDRectangleBuilder*) mergeHi:(RGDPoint*) value {
+ if (resultRectangle.hasHi &&
+ resultRectangle.hi != [RGDPoint defaultInstance]) {
+ resultRectangle.hi =
+ [[[RGDPoint builderWithPrototype:resultRectangle.hi] mergeFrom:value] buildPartial];
+ } else {
+ resultRectangle.hi = value;
+ }
+ resultRectangle.hasHi = YES;
+ return self;
+}
+- (RGDRectangleBuilder*) clearHi {
+ resultRectangle.hasHi = NO;
+ resultRectangle.hi = [RGDPoint defaultInstance];
+ return self;
+}
+@end
+
+@interface RGDFeature ()
+@property (strong) NSString* name;
+@property (strong) RGDPoint* location;
+@end
+
+@implementation RGDFeature
+
+- (BOOL) hasName {
+ return !!hasName_;
+}
+- (void) setHasName:(BOOL) _value_ {
+ hasName_ = !!_value_;
+}
+@synthesize name;
+- (BOOL) hasLocation {
+ return !!hasLocation_;
+}
+- (void) setHasLocation:(BOOL) _value_ {
+ hasLocation_ = !!_value_;
+}
+@synthesize location;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.name = @"";
+ self.location = [RGDPoint defaultInstance];
+ }
+ return self;
+}
+static RGDFeature* defaultRGDFeatureInstance = nil;
++ (void) initialize {
+ if (self == [RGDFeature class]) {
+ defaultRGDFeatureInstance = [[RGDFeature alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRGDFeatureInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRGDFeatureInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasName) {
+ [output writeString:1 value:self.name];
+ }
+ if (self.hasLocation) {
+ [output writeMessage:2 value:self.location];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasName) {
+ size_ += computeStringSize(1, self.name);
+ }
+ if (self.hasLocation) {
+ size_ += computeMessageSize(2, self.location);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RGDFeature*) parseFromData:(NSData*) data {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromData:data] build];
+}
++ (RGDFeature*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RGDFeature*) parseFromInputStream:(NSInputStream*) input {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromInputStream:input] build];
+}
++ (RGDFeature*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDFeature*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromCodedInputStream:input] build];
+}
++ (RGDFeature*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDFeature*)[[[RGDFeature builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDFeatureBuilder*) builder {
+ return [[RGDFeatureBuilder alloc] init];
+}
++ (RGDFeatureBuilder*) builderWithPrototype:(RGDFeature*) prototype {
+ return [[RGDFeature builder] mergeFrom:prototype];
+}
+- (RGDFeatureBuilder*) builder {
+ return [RGDFeature builder];
+}
+- (RGDFeatureBuilder*) toBuilder {
+ return [RGDFeature builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasName) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"name", self.name];
+ }
+ if (self.hasLocation) {
+ [output appendFormat:@"%@%@ {\n", indent, @"location"];
+ [self.location writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RGDFeature class]]) {
+ return NO;
+ }
+ RGDFeature *otherMessage = other;
+ return
+ self.hasName == otherMessage.hasName &&
+ (!self.hasName || [self.name isEqual:otherMessage.name]) &&
+ self.hasLocation == otherMessage.hasLocation &&
+ (!self.hasLocation || [self.location isEqual:otherMessage.location]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasName) {
+ hashCode = hashCode * 31 + [self.name hash];
+ }
+ if (self.hasLocation) {
+ hashCode = hashCode * 31 + [self.location hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RGDFeatureBuilder()
+@property (strong) RGDFeature* resultFeature;
+@end
+
+@implementation RGDFeatureBuilder
+@synthesize resultFeature;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultFeature = [[RGDFeature alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultFeature;
+}
+- (RGDFeatureBuilder*) clear {
+ self.resultFeature = [[RGDFeature alloc] init];
+ return self;
+}
+- (RGDFeatureBuilder*) clone {
+ return [RGDFeature builderWithPrototype:resultFeature];
+}
+- (RGDFeature*) defaultInstance {
+ return [RGDFeature defaultInstance];
+}
+- (RGDFeature*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RGDFeature*) buildPartial {
+ RGDFeature* returnMe = resultFeature;
+ self.resultFeature = nil;
+ return returnMe;
+}
+- (RGDFeatureBuilder*) mergeFrom:(RGDFeature*) other {
+ if (other == [RGDFeature defaultInstance]) {
+ return self;
+ }
+ if (other.hasName) {
+ [self setName:other.name];
+ }
+ if (other.hasLocation) {
+ [self mergeLocation:other.location];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RGDFeatureBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RGDFeatureBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ [self setName:[input readString]];
+ break;
+ }
+ case 18: {
+ RGDPointBuilder* subBuilder = [RGDPoint builder];
+ if (self.hasLocation) {
+ [subBuilder mergeFrom:self.location];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setLocation:[subBuilder buildPartial]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasName {
+ return resultFeature.hasName;
+}
+- (NSString*) name {
+ return resultFeature.name;
+}
+- (RGDFeatureBuilder*) setName:(NSString*) value {
+ resultFeature.hasName = YES;
+ resultFeature.name = value;
+ return self;
+}
+- (RGDFeatureBuilder*) clearName {
+ resultFeature.hasName = NO;
+ resultFeature.name = @"";
+ return self;
+}
+- (BOOL) hasLocation {
+ return resultFeature.hasLocation;
+}
+- (RGDPoint*) location {
+ return resultFeature.location;
+}
+- (RGDFeatureBuilder*) setLocation:(RGDPoint*) value {
+ resultFeature.hasLocation = YES;
+ resultFeature.location = value;
+ return self;
+}
+- (RGDFeatureBuilder*) setLocationBuilder:(RGDPointBuilder*) builderForValue {
+ return [self setLocation:[builderForValue build]];
+}
+- (RGDFeatureBuilder*) mergeLocation:(RGDPoint*) value {
+ if (resultFeature.hasLocation &&
+ resultFeature.location != [RGDPoint defaultInstance]) {
+ resultFeature.location =
+ [[[RGDPoint builderWithPrototype:resultFeature.location] mergeFrom:value] buildPartial];
+ } else {
+ resultFeature.location = value;
+ }
+ resultFeature.hasLocation = YES;
+ return self;
+}
+- (RGDFeatureBuilder*) clearLocation {
+ resultFeature.hasLocation = NO;
+ resultFeature.location = [RGDPoint defaultInstance];
+ return self;
+}
+@end
+
+@interface RGDRouteNote ()
+@property (strong) RGDPoint* location;
+@property (strong) NSString* message;
+@end
+
+@implementation RGDRouteNote
+
+- (BOOL) hasLocation {
+ return !!hasLocation_;
+}
+- (void) setHasLocation:(BOOL) _value_ {
+ hasLocation_ = !!_value_;
+}
+@synthesize location;
+- (BOOL) hasMessage {
+ return !!hasMessage_;
+}
+- (void) setHasMessage:(BOOL) _value_ {
+ hasMessage_ = !!_value_;
+}
+@synthesize message;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.location = [RGDPoint defaultInstance];
+ self.message = @"";
+ }
+ return self;
+}
+static RGDRouteNote* defaultRGDRouteNoteInstance = nil;
++ (void) initialize {
+ if (self == [RGDRouteNote class]) {
+ defaultRGDRouteNoteInstance = [[RGDRouteNote alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRGDRouteNoteInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRGDRouteNoteInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasLocation) {
+ [output writeMessage:1 value:self.location];
+ }
+ if (self.hasMessage) {
+ [output writeString:2 value:self.message];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasLocation) {
+ size_ += computeMessageSize(1, self.location);
+ }
+ if (self.hasMessage) {
+ size_ += computeStringSize(2, self.message);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RGDRouteNote*) parseFromData:(NSData*) data {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromData:data] build];
+}
++ (RGDRouteNote*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteNote*) parseFromInputStream:(NSInputStream*) input {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromInputStream:input] build];
+}
++ (RGDRouteNote*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteNote*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromCodedInputStream:input] build];
+}
++ (RGDRouteNote*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteNote*)[[[RGDRouteNote builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteNoteBuilder*) builder {
+ return [[RGDRouteNoteBuilder alloc] init];
+}
++ (RGDRouteNoteBuilder*) builderWithPrototype:(RGDRouteNote*) prototype {
+ return [[RGDRouteNote builder] mergeFrom:prototype];
+}
+- (RGDRouteNoteBuilder*) builder {
+ return [RGDRouteNote builder];
+}
+- (RGDRouteNoteBuilder*) toBuilder {
+ return [RGDRouteNote builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasLocation) {
+ [output appendFormat:@"%@%@ {\n", indent, @"location"];
+ [self.location writeDescriptionTo:output
+ withIndent:[NSString stringWithFormat:@"%@ ", indent]];
+ [output appendFormat:@"%@}\n", indent];
+ }
+ if (self.hasMessage) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"message", self.message];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RGDRouteNote class]]) {
+ return NO;
+ }
+ RGDRouteNote *otherMessage = other;
+ return
+ self.hasLocation == otherMessage.hasLocation &&
+ (!self.hasLocation || [self.location isEqual:otherMessage.location]) &&
+ self.hasMessage == otherMessage.hasMessage &&
+ (!self.hasMessage || [self.message isEqual:otherMessage.message]) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasLocation) {
+ hashCode = hashCode * 31 + [self.location hash];
+ }
+ if (self.hasMessage) {
+ hashCode = hashCode * 31 + [self.message hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RGDRouteNoteBuilder()
+@property (strong) RGDRouteNote* resultRouteNote;
+@end
+
+@implementation RGDRouteNoteBuilder
+@synthesize resultRouteNote;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultRouteNote = [[RGDRouteNote alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultRouteNote;
+}
+- (RGDRouteNoteBuilder*) clear {
+ self.resultRouteNote = [[RGDRouteNote alloc] init];
+ return self;
+}
+- (RGDRouteNoteBuilder*) clone {
+ return [RGDRouteNote builderWithPrototype:resultRouteNote];
+}
+- (RGDRouteNote*) defaultInstance {
+ return [RGDRouteNote defaultInstance];
+}
+- (RGDRouteNote*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RGDRouteNote*) buildPartial {
+ RGDRouteNote* returnMe = resultRouteNote;
+ self.resultRouteNote = nil;
+ return returnMe;
+}
+- (RGDRouteNoteBuilder*) mergeFrom:(RGDRouteNote*) other {
+ if (other == [RGDRouteNote defaultInstance]) {
+ return self;
+ }
+ if (other.hasLocation) {
+ [self mergeLocation:other.location];
+ }
+ if (other.hasMessage) {
+ [self setMessage:other.message];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RGDRouteNoteBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RGDRouteNoteBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 10: {
+ RGDPointBuilder* subBuilder = [RGDPoint builder];
+ if (self.hasLocation) {
+ [subBuilder mergeFrom:self.location];
+ }
+ [input readMessage:subBuilder extensionRegistry:extensionRegistry];
+ [self setLocation:[subBuilder buildPartial]];
+ break;
+ }
+ case 18: {
+ [self setMessage:[input readString]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasLocation {
+ return resultRouteNote.hasLocation;
+}
+- (RGDPoint*) location {
+ return resultRouteNote.location;
+}
+- (RGDRouteNoteBuilder*) setLocation:(RGDPoint*) value {
+ resultRouteNote.hasLocation = YES;
+ resultRouteNote.location = value;
+ return self;
+}
+- (RGDRouteNoteBuilder*) setLocationBuilder:(RGDPointBuilder*) builderForValue {
+ return [self setLocation:[builderForValue build]];
+}
+- (RGDRouteNoteBuilder*) mergeLocation:(RGDPoint*) value {
+ if (resultRouteNote.hasLocation &&
+ resultRouteNote.location != [RGDPoint defaultInstance]) {
+ resultRouteNote.location =
+ [[[RGDPoint builderWithPrototype:resultRouteNote.location] mergeFrom:value] buildPartial];
+ } else {
+ resultRouteNote.location = value;
+ }
+ resultRouteNote.hasLocation = YES;
+ return self;
+}
+- (RGDRouteNoteBuilder*) clearLocation {
+ resultRouteNote.hasLocation = NO;
+ resultRouteNote.location = [RGDPoint defaultInstance];
+ return self;
+}
+- (BOOL) hasMessage {
+ return resultRouteNote.hasMessage;
+}
+- (NSString*) message {
+ return resultRouteNote.message;
+}
+- (RGDRouteNoteBuilder*) setMessage:(NSString*) value {
+ resultRouteNote.hasMessage = YES;
+ resultRouteNote.message = value;
+ return self;
+}
+- (RGDRouteNoteBuilder*) clearMessage {
+ resultRouteNote.hasMessage = NO;
+ resultRouteNote.message = @"";
+ return self;
+}
+@end
+
+@interface RGDRouteSummary ()
+@property SInt32 pointCount;
+@property SInt32 featureCount;
+@property SInt32 distance;
+@property SInt32 elapsedTime;
+@end
+
+@implementation RGDRouteSummary
+
+- (BOOL) hasPointCount {
+ return !!hasPointCount_;
+}
+- (void) setHasPointCount:(BOOL) _value_ {
+ hasPointCount_ = !!_value_;
+}
+@synthesize pointCount;
+- (BOOL) hasFeatureCount {
+ return !!hasFeatureCount_;
+}
+- (void) setHasFeatureCount:(BOOL) _value_ {
+ hasFeatureCount_ = !!_value_;
+}
+@synthesize featureCount;
+- (BOOL) hasDistance {
+ return !!hasDistance_;
+}
+- (void) setHasDistance:(BOOL) _value_ {
+ hasDistance_ = !!_value_;
+}
+@synthesize distance;
+- (BOOL) hasElapsedTime {
+ return !!hasElapsedTime_;
+}
+- (void) setHasElapsedTime:(BOOL) _value_ {
+ hasElapsedTime_ = !!_value_;
+}
+@synthesize elapsedTime;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.pointCount = 0;
+ self.featureCount = 0;
+ self.distance = 0;
+ self.elapsedTime = 0;
+ }
+ return self;
+}
+static RGDRouteSummary* defaultRGDRouteSummaryInstance = nil;
++ (void) initialize {
+ if (self == [RGDRouteSummary class]) {
+ defaultRGDRouteSummaryInstance = [[RGDRouteSummary alloc] init];
+ }
+}
++ (instancetype) defaultInstance {
+ return defaultRGDRouteSummaryInstance;
+}
+- (instancetype) defaultInstance {
+ return defaultRGDRouteSummaryInstance;
+}
+- (BOOL) isInitialized {
+ return YES;
+}
+- (void) writeToCodedOutputStream:(PBCodedOutputStream*) output {
+ if (self.hasPointCount) {
+ [output writeInt32:1 value:self.pointCount];
+ }
+ if (self.hasFeatureCount) {
+ [output writeInt32:2 value:self.featureCount];
+ }
+ if (self.hasDistance) {
+ [output writeInt32:3 value:self.distance];
+ }
+ if (self.hasElapsedTime) {
+ [output writeInt32:4 value:self.elapsedTime];
+ }
+ [self.unknownFields writeToCodedOutputStream:output];
+}
+- (SInt32) serializedSize {
+ __block SInt32 size_ = memoizedSerializedSize;
+ if (size_ != -1) {
+ return size_;
+ }
+
+ size_ = 0;
+ if (self.hasPointCount) {
+ size_ += computeInt32Size(1, self.pointCount);
+ }
+ if (self.hasFeatureCount) {
+ size_ += computeInt32Size(2, self.featureCount);
+ }
+ if (self.hasDistance) {
+ size_ += computeInt32Size(3, self.distance);
+ }
+ if (self.hasElapsedTime) {
+ size_ += computeInt32Size(4, self.elapsedTime);
+ }
+ size_ += self.unknownFields.serializedSize;
+ memoizedSerializedSize = size_;
+ return size_;
+}
++ (RGDRouteSummary*) parseFromData:(NSData*) data {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromData:data] build];
+}
++ (RGDRouteSummary*) parseFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromData:data extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteSummary*) parseFromInputStream:(NSInputStream*) input {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromInputStream:input] build];
+}
++ (RGDRouteSummary*) parseFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteSummary*) parseFromCodedInputStream:(PBCodedInputStream*) input {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromCodedInputStream:input] build];
+}
++ (RGDRouteSummary*) parseFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ return (RGDRouteSummary*)[[[RGDRouteSummary builder] mergeFromCodedInputStream:input extensionRegistry:extensionRegistry] build];
+}
++ (RGDRouteSummaryBuilder*) builder {
+ return [[RGDRouteSummaryBuilder alloc] init];
+}
++ (RGDRouteSummaryBuilder*) builderWithPrototype:(RGDRouteSummary*) prototype {
+ return [[RGDRouteSummary builder] mergeFrom:prototype];
+}
+- (RGDRouteSummaryBuilder*) builder {
+ return [RGDRouteSummary builder];
+}
+- (RGDRouteSummaryBuilder*) toBuilder {
+ return [RGDRouteSummary builderWithPrototype:self];
+}
+- (void) writeDescriptionTo:(NSMutableString*) output withIndent:(NSString*) indent {
+ if (self.hasPointCount) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"pointCount", [NSNumber numberWithInteger:self.pointCount]];
+ }
+ if (self.hasFeatureCount) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"featureCount", [NSNumber numberWithInteger:self.featureCount]];
+ }
+ if (self.hasDistance) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"distance", [NSNumber numberWithInteger:self.distance]];
+ }
+ if (self.hasElapsedTime) {
+ [output appendFormat:@"%@%@: %@\n", indent, @"elapsedTime", [NSNumber numberWithInteger:self.elapsedTime]];
+ }
+ [self.unknownFields writeDescriptionTo:output withIndent:indent];
+}
+- (BOOL) isEqual:(id)other {
+ if (other == self) {
+ return YES;
+ }
+ if (![other isKindOfClass:[RGDRouteSummary class]]) {
+ return NO;
+ }
+ RGDRouteSummary *otherMessage = other;
+ return
+ self.hasPointCount == otherMessage.hasPointCount &&
+ (!self.hasPointCount || self.pointCount == otherMessage.pointCount) &&
+ self.hasFeatureCount == otherMessage.hasFeatureCount &&
+ (!self.hasFeatureCount || self.featureCount == otherMessage.featureCount) &&
+ self.hasDistance == otherMessage.hasDistance &&
+ (!self.hasDistance || self.distance == otherMessage.distance) &&
+ self.hasElapsedTime == otherMessage.hasElapsedTime &&
+ (!self.hasElapsedTime || self.elapsedTime == otherMessage.elapsedTime) &&
+ (self.unknownFields == otherMessage.unknownFields || (self.unknownFields != nil && [self.unknownFields isEqual:otherMessage.unknownFields]));
+}
+- (NSUInteger) hash {
+ __block NSUInteger hashCode = 7;
+ if (self.hasPointCount) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.pointCount] hash];
+ }
+ if (self.hasFeatureCount) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.featureCount] hash];
+ }
+ if (self.hasDistance) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.distance] hash];
+ }
+ if (self.hasElapsedTime) {
+ hashCode = hashCode * 31 + [[NSNumber numberWithInteger:self.elapsedTime] hash];
+ }
+ hashCode = hashCode * 31 + [self.unknownFields hash];
+ return hashCode;
+}
+@end
+
+@interface RGDRouteSummaryBuilder()
+@property (strong) RGDRouteSummary* resultRouteSummary;
+@end
+
+@implementation RGDRouteSummaryBuilder
+@synthesize resultRouteSummary;
+- (instancetype) init {
+ if ((self = [super init])) {
+ self.resultRouteSummary = [[RGDRouteSummary alloc] init];
+ }
+ return self;
+}
+- (PBGeneratedMessage*) internalGetResult {
+ return resultRouteSummary;
+}
+- (RGDRouteSummaryBuilder*) clear {
+ self.resultRouteSummary = [[RGDRouteSummary alloc] init];
+ return self;
+}
+- (RGDRouteSummaryBuilder*) clone {
+ return [RGDRouteSummary builderWithPrototype:resultRouteSummary];
+}
+- (RGDRouteSummary*) defaultInstance {
+ return [RGDRouteSummary defaultInstance];
+}
+- (RGDRouteSummary*) build {
+ [self checkInitialized];
+ return [self buildPartial];
+}
+- (RGDRouteSummary*) buildPartial {
+ RGDRouteSummary* returnMe = resultRouteSummary;
+ self.resultRouteSummary = nil;
+ return returnMe;
+}
+- (RGDRouteSummaryBuilder*) mergeFrom:(RGDRouteSummary*) other {
+ if (other == [RGDRouteSummary defaultInstance]) {
+ return self;
+ }
+ if (other.hasPointCount) {
+ [self setPointCount:other.pointCount];
+ }
+ if (other.hasFeatureCount) {
+ [self setFeatureCount:other.featureCount];
+ }
+ if (other.hasDistance) {
+ [self setDistance:other.distance];
+ }
+ if (other.hasElapsedTime) {
+ [self setElapsedTime:other.elapsedTime];
+ }
+ [self mergeUnknownFields:other.unknownFields];
+ return self;
+}
+- (RGDRouteSummaryBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input {
+ return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]];
+}
+- (RGDRouteSummaryBuilder*) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
+ PBUnknownFieldSetBuilder* unknownFields = [PBUnknownFieldSet builderWithUnknownFields:self.unknownFields];
+ while (YES) {
+ SInt32 tag = [input readTag];
+ switch (tag) {
+ case 0:
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ default: {
+ if (![self parseUnknownField:input unknownFields:unknownFields extensionRegistry:extensionRegistry tag:tag]) {
+ [self setUnknownFields:[unknownFields build]];
+ return self;
+ }
+ break;
+ }
+ case 8: {
+ [self setPointCount:[input readInt32]];
+ break;
+ }
+ case 16: {
+ [self setFeatureCount:[input readInt32]];
+ break;
+ }
+ case 24: {
+ [self setDistance:[input readInt32]];
+ break;
+ }
+ case 32: {
+ [self setElapsedTime:[input readInt32]];
+ break;
+ }
+ }
+ }
+}
+- (BOOL) hasPointCount {
+ return resultRouteSummary.hasPointCount;
+}
+- (SInt32) pointCount {
+ return resultRouteSummary.pointCount;
+}
+- (RGDRouteSummaryBuilder*) setPointCount:(SInt32) value {
+ resultRouteSummary.hasPointCount = YES;
+ resultRouteSummary.pointCount = value;
+ return self;
+}
+- (RGDRouteSummaryBuilder*) clearPointCount {
+ resultRouteSummary.hasPointCount = NO;
+ resultRouteSummary.pointCount = 0;
+ return self;
+}
+- (BOOL) hasFeatureCount {
+ return resultRouteSummary.hasFeatureCount;
+}
+- (SInt32) featureCount {
+ return resultRouteSummary.featureCount;
+}
+- (RGDRouteSummaryBuilder*) setFeatureCount:(SInt32) value {
+ resultRouteSummary.hasFeatureCount = YES;
+ resultRouteSummary.featureCount = value;
+ return self;
+}
+- (RGDRouteSummaryBuilder*) clearFeatureCount {
+ resultRouteSummary.hasFeatureCount = NO;
+ resultRouteSummary.featureCount = 0;
+ return self;
+}
+- (BOOL) hasDistance {
+ return resultRouteSummary.hasDistance;
+}
+- (SInt32) distance {
+ return resultRouteSummary.distance;
+}
+- (RGDRouteSummaryBuilder*) setDistance:(SInt32) value {
+ resultRouteSummary.hasDistance = YES;
+ resultRouteSummary.distance = value;
+ return self;
+}
+- (RGDRouteSummaryBuilder*) clearDistance {
+ resultRouteSummary.hasDistance = NO;
+ resultRouteSummary.distance = 0;
+ return self;
+}
+- (BOOL) hasElapsedTime {
+ return resultRouteSummary.hasElapsedTime;
+}
+- (SInt32) elapsedTime {
+ return resultRouteSummary.elapsedTime;
+}
+- (RGDRouteSummaryBuilder*) setElapsedTime:(SInt32) value {
+ resultRouteSummary.hasElapsedTime = YES;
+ resultRouteSummary.elapsedTime = value;
+ return self;
+}
+- (RGDRouteSummaryBuilder*) clearElapsedTime {
+ resultRouteSummary.hasElapsedTime = NO;
+ resultRouteSummary.elapsedTime = 0;
+ return self;
+}
+@end
+
+
+// @@protoc_insertion_point(global_scope)
diff --git a/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.podspec b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.podspec
new file mode 100644
index 0000000000..04d847bf8f
--- /dev/null
+++ b/src/objective-c/examples/Sample/RouteGuideClient/Route_guide.podspec
@@ -0,0 +1,17 @@
+Pod::Spec.new do |s|
+ s.name = 'Route_guide'
+ s.version = '0.0.1'
+ s.summary = 'Protobuf library generated from route_guide.proto'
+ s.homepage = 'https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample/RouteGuideClient'
+ s.license = 'New BSD'
+ s.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
+
+ s.source_files = '*.pb.{h,m}'
+ s.public_header_files = '*.pb.h'
+
+ s.platform = :ios
+ s.ios.deployment_target = '6.0'
+ s.requires_arc = true
+
+ s.dependency 'ProtocolBuffers', '~> 1.9'
+end
diff --git a/src/objective-c/examples/Sample/RouteGuideClient/route_guide.proto b/src/objective-c/examples/Sample/RouteGuideClient/route_guide.proto
new file mode 100644
index 0000000000..91b0372a07
--- /dev/null
+++ b/src/objective-c/examples/Sample/RouteGuideClient/route_guide.proto
@@ -0,0 +1,121 @@
+// 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 = "proto2";
+
+package grpc.example.routeguide;
+
+import "google/protobuf/objectivec-descriptor.proto";
+option (google.protobuf.objectivec_file_options).class_prefix = "RGD";
+
+// 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 {
+ optional int32 latitude = 1;
+ optional int32 longitude = 2;
+}
+
+// A latitude-longitude rectangle, represented as two diagonally opposite
+// points "lo" and "hi".
+message Rectangle {
+ // One corner of the rectangle.
+ optional Point lo = 1;
+
+ // The other corner of the rectangle.
+ optional 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.
+ optional string name = 1;
+
+ // The point where the feature is detected.
+ optional Point location = 2;
+}
+
+// A RouteNote is a message sent while at a given point.
+message RouteNote {
+ // The location from which the message is sent.
+ optional Point location = 1;
+
+ // The message to be sent.
+ optional 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.
+ optional int32 point_count = 1;
+
+ // The number of known features passed while traversing the route.
+ optional int32 feature_count = 2;
+
+ // The distance covered in metres.
+ optional int32 distance = 3;
+
+ // The duration of the traversal in seconds.
+ optional int32 elapsed_time = 4;
+} \ No newline at end of file
diff --git a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
index 142e60e2b2..17c2255b5a 100644
--- a/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
+++ b/src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
@@ -1,955 +1,536 @@
-<?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>archiveVersion</key>
- <string>1</string>
- <key>classes</key>
- <dict/>
- <key>objectVersion</key>
- <string>46</string>
- <key>objects</key>
- <dict>
- <key>04554623324BE4A838846086</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array/>
- <key>inputPaths</key>
- <array/>
- <key>isa</key>
- <string>PBXShellScriptBuildPhase</string>
- <key>name</key>
- <string>Copy Pods Resources</string>
- <key>outputPaths</key>
- <array/>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- <key>shellPath</key>
- <string>/bin/sh</string>
- <key>shellScript</key>
- <string>"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh"
-</string>
- <key>showEnvVarsInLog</key>
- <string>0</string>
- </dict>
- <key>2DC7B7C4C0410F43B9621631</key>
- <dict>
- <key>explicitFileType</key>
- <string>archive.ar</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>libPods.a</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>41F7486D8F66994B0BFB84AF</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array/>
- <key>inputPaths</key>
- <array/>
- <key>isa</key>
- <string>PBXShellScriptBuildPhase</string>
- <key>name</key>
- <string>Check Pods Manifest.lock</string>
- <key>outputPaths</key>
- <array/>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- <key>shellPath</key>
- <string>/bin/sh</string>
- <key>shellScript</key>
- <string>diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" &gt; /dev/null
-if [[ $? != 0 ]] ; then
- cat &lt;&lt; EOM
-error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
-EOM
- exit 1
-fi
-</string>
- <key>showEnvVarsInLog</key>
- <string>0</string>
- </dict>
- <key>6369A2611A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A26C1A9322E20015FC5C</string>
- <string>6369A2861A9322E20015FC5C</string>
- <string>6369A26B1A9322E20015FC5C</string>
- <string>AB3331C9AE6488E61B2B094E</string>
- <string>C4C2C5219053E079C9EFB930</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2621A9322E20015FC5C</key>
- <dict>
- <key>attributes</key>
- <dict>
- <key>LastUpgradeCheck</key>
- <string>0610</string>
- <key>ORGANIZATIONNAME</key>
- <string>gRPC</string>
- <key>TargetAttributes</key>
- <dict>
- <key>6369A2691A9322E20015FC5C</key>
- <dict>
- <key>CreatedOnToolsVersion</key>
- <string>6.1.1</string>
- </dict>
- <key>6369A2821A9322E20015FC5C</key>
- <dict>
- <key>CreatedOnToolsVersion</key>
- <string>6.1.1</string>
- <key>TestTargetID</key>
- <string>6369A2691A9322E20015FC5C</string>
- </dict>
- </dict>
- </dict>
- <key>buildConfigurationList</key>
- <string>6369A2651A9322E20015FC5C</string>
- <key>compatibilityVersion</key>
- <string>Xcode 3.2</string>
- <key>developmentRegion</key>
- <string>English</string>
- <key>hasScannedForEncodings</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXProject</string>
- <key>knownRegions</key>
- <array>
- <string>en</string>
- <string>Base</string>
- </array>
- <key>mainGroup</key>
- <string>6369A2611A9322E20015FC5C</string>
- <key>productRefGroup</key>
- <string>6369A26B1A9322E20015FC5C</string>
- <key>projectDirPath</key>
- <string></string>
- <key>projectReferences</key>
- <array/>
- <key>projectRoot</key>
- <string></string>
- <key>targets</key>
- <array>
- <string>6369A2691A9322E20015FC5C</string>
- <string>6369A2821A9322E20015FC5C</string>
- </array>
- </dict>
- <key>6369A2651A9322E20015FC5C</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>6369A28B1A9322E20015FC5C</string>
- <string>6369A28C1A9322E20015FC5C</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>defaultConfigurationName</key>
- <string>Release</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>6369A2661A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>6369A2761A9322E20015FC5C</string>
- <string>6369A2731A9322E20015FC5C</string>
- <string>6369A2701A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2671A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>FC81FE63CA655031F3524EC0</string>
- </array>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2681A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>6369A2791A9322E20015FC5C</string>
- <string>6369A27E1A9322E20015FC5C</string>
- <string>6369A27B1A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXResourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2691A9322E20015FC5C</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>6369A28D1A9322E20015FC5C</string>
- <key>buildPhases</key>
- <array>
- <string>41F7486D8F66994B0BFB84AF</string>
- <string>6369A2661A9322E20015FC5C</string>
- <string>6369A2671A9322E20015FC5C</string>
- <string>6369A2681A9322E20015FC5C</string>
- <string>04554623324BE4A838846086</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array/>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>Sample</string>
- <key>productName</key>
- <string>Sample</string>
- <key>productReference</key>
- <string>6369A26A1A9322E20015FC5C</string>
- <key>productType</key>
- <string>com.apple.product-type.application</string>
- </dict>
- <key>6369A26A1A9322E20015FC5C</key>
- <dict>
- <key>explicitFileType</key>
- <string>wrapper.application</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>Sample.app</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>6369A26B1A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A26A1A9322E20015FC5C</string>
- <string>6369A2831A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Products</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A26C1A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A2711A9322E20015FC5C</string>
- <string>6369A2721A9322E20015FC5C</string>
- <string>6369A2741A9322E20015FC5C</string>
- <string>6369A2751A9322E20015FC5C</string>
- <string>6369A2771A9322E20015FC5C</string>
- <string>6369A27A1A9322E20015FC5C</string>
- <string>6369A27C1A9322E20015FC5C</string>
- <string>6369A26D1A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>path</key>
- <string>Sample</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A26D1A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A26E1A9322E20015FC5C</string>
- <string>6369A26F1A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Supporting Files</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A26E1A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.plist.xml</string>
- <key>path</key>
- <string>Info.plist</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A26F1A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>main.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2701A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A26F1A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A2711A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>AppDelegate.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2721A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>AppDelegate.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2731A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A2721A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A2741A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.h</string>
- <key>path</key>
- <string>ViewController.h</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2751A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>ViewController.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2761A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A2751A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A2771A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A2781A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXVariantGroup</string>
- <key>name</key>
- <string>Main.storyboard</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2781A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>file.storyboard</string>
- <key>name</key>
- <string>Base</string>
- <key>path</key>
- <string>Base.lproj/Main.storyboard</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2791A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A2771A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A27A1A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>folder.assetcatalog</string>
- <key>path</key>
- <string>Images.xcassets</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A27B1A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A27A1A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A27C1A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A27D1A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXVariantGroup</string>
- <key>name</key>
- <string>LaunchScreen.xib</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A27D1A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>file.xib</string>
- <key>name</key>
- <string>Base</string>
- <key>path</key>
- <string>Base.lproj/LaunchScreen.xib</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A27E1A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A27C1A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A27F1A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array>
- <string>6369A28A1A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXSourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2801A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array/>
- <key>isa</key>
- <string>PBXFrameworksBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2811A9322E20015FC5C</key>
- <dict>
- <key>buildActionMask</key>
- <string>2147483647</string>
- <key>files</key>
- <array/>
- <key>isa</key>
- <string>PBXResourcesBuildPhase</string>
- <key>runOnlyForDeploymentPostprocessing</key>
- <string>0</string>
- </dict>
- <key>6369A2821A9322E20015FC5C</key>
- <dict>
- <key>buildConfigurationList</key>
- <string>6369A2901A9322E20015FC5C</string>
- <key>buildPhases</key>
- <array>
- <string>6369A27F1A9322E20015FC5C</string>
- <string>6369A2801A9322E20015FC5C</string>
- <string>6369A2811A9322E20015FC5C</string>
- </array>
- <key>buildRules</key>
- <array/>
- <key>dependencies</key>
- <array>
- <string>6369A2851A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXNativeTarget</string>
- <key>name</key>
- <string>SampleTests</string>
- <key>productName</key>
- <string>SampleTests</string>
- <key>productReference</key>
- <string>6369A2831A9322E20015FC5C</string>
- <key>productType</key>
- <string>com.apple.product-type.bundle.unit-test</string>
- </dict>
- <key>6369A2831A9322E20015FC5C</key>
- <dict>
- <key>explicitFileType</key>
- <string>wrapper.cfbundle</string>
- <key>includeInIndex</key>
- <string>0</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>path</key>
- <string>SampleTests.xctest</string>
- <key>sourceTree</key>
- <string>BUILT_PRODUCTS_DIR</string>
- </dict>
- <key>6369A2841A9322E20015FC5C</key>
- <dict>
- <key>containerPortal</key>
- <string>6369A2621A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXContainerItemProxy</string>
- <key>proxyType</key>
- <string>1</string>
- <key>remoteGlobalIDString</key>
- <string>6369A2691A9322E20015FC5C</string>
- <key>remoteInfo</key>
- <string>Sample</string>
- </dict>
- <key>6369A2851A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXTargetDependency</string>
- <key>target</key>
- <string>6369A2691A9322E20015FC5C</string>
- <key>targetProxy</key>
- <string>6369A2841A9322E20015FC5C</string>
- </dict>
- <key>6369A2861A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A2891A9322E20015FC5C</string>
- <string>6369A2871A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>path</key>
- <string>SampleTests</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2871A9322E20015FC5C</key>
- <dict>
- <key>children</key>
- <array>
- <string>6369A2881A9322E20015FC5C</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Supporting Files</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2881A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.plist.xml</string>
- <key>path</key>
- <string>Info.plist</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A2891A9322E20015FC5C</key>
- <dict>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>sourcecode.c.objc</string>
- <key>path</key>
- <string>SampleTests.m</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>6369A28A1A9322E20015FC5C</key>
- <dict>
- <key>fileRef</key>
- <string>6369A2891A9322E20015FC5C</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- <key>6369A28B1A9322E20015FC5C</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>CLANG_CXX_LANGUAGE_STANDARD</key>
- <string>gnu++0x</string>
- <key>CLANG_CXX_LIBRARY</key>
- <string>libc++</string>
- <key>CLANG_ENABLE_MODULES</key>
- <string>YES</string>
- <key>CLANG_ENABLE_OBJC_ARC</key>
- <string>YES</string>
- <key>CLANG_WARN_BOOL_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_CONSTANT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
- <string>YES_ERROR</string>
- <key>CLANG_WARN_EMPTY_BODY</key>
- <string>YES</string>
- <key>CLANG_WARN_ENUM_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_INT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_OBJC_ROOT_CLASS</key>
- <string>YES_ERROR</string>
- <key>CLANG_WARN_UNREACHABLE_CODE</key>
- <string>YES</string>
- <key>CLANG_WARN__DUPLICATE_METHOD_MATCH</key>
- <string>YES</string>
- <key>CODE_SIGN_IDENTITY[sdk=iphoneos*]</key>
- <string>iPhone Developer</string>
- <key>COPY_PHASE_STRIP</key>
- <string>NO</string>
- <key>ENABLE_STRICT_OBJC_MSGSEND</key>
- <string>YES</string>
- <key>GCC_C_LANGUAGE_STANDARD</key>
- <string>gnu99</string>
- <key>GCC_DYNAMIC_NO_PIC</key>
- <string>NO</string>
- <key>GCC_OPTIMIZATION_LEVEL</key>
- <string>0</string>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_SYMBOLS_PRIVATE_EXTERN</key>
- <string>NO</string>
- <key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
- <string>YES</string>
- <key>GCC_WARN_ABOUT_RETURN_TYPE</key>
- <string>YES_ERROR</string>
- <key>GCC_WARN_UNDECLARED_SELECTOR</key>
- <string>YES</string>
- <key>GCC_WARN_UNINITIALIZED_AUTOS</key>
- <string>YES_AGGRESSIVE</string>
- <key>GCC_WARN_UNUSED_FUNCTION</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_VARIABLE</key>
- <string>YES</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.1</string>
- <key>MTL_ENABLE_DEBUG_INFO</key>
- <string>YES</string>
- <key>ONLY_ACTIVE_ARCH</key>
- <string>YES</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>TARGETED_DEVICE_FAMILY</key>
- <string>1,2</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>6369A28C1A9322E20015FC5C</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>ALWAYS_SEARCH_USER_PATHS</key>
- <string>NO</string>
- <key>CLANG_CXX_LANGUAGE_STANDARD</key>
- <string>gnu++0x</string>
- <key>CLANG_CXX_LIBRARY</key>
- <string>libc++</string>
- <key>CLANG_ENABLE_MODULES</key>
- <string>YES</string>
- <key>CLANG_ENABLE_OBJC_ARC</key>
- <string>YES</string>
- <key>CLANG_WARN_BOOL_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_CONSTANT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_DIRECT_OBJC_ISA_USAGE</key>
- <string>YES_ERROR</string>
- <key>CLANG_WARN_EMPTY_BODY</key>
- <string>YES</string>
- <key>CLANG_WARN_ENUM_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_INT_CONVERSION</key>
- <string>YES</string>
- <key>CLANG_WARN_OBJC_ROOT_CLASS</key>
- <string>YES_ERROR</string>
- <key>CLANG_WARN_UNREACHABLE_CODE</key>
- <string>YES</string>
- <key>CLANG_WARN__DUPLICATE_METHOD_MATCH</key>
- <string>YES</string>
- <key>CODE_SIGN_IDENTITY[sdk=iphoneos*]</key>
- <string>iPhone Developer</string>
- <key>COPY_PHASE_STRIP</key>
- <string>YES</string>
- <key>ENABLE_NS_ASSERTIONS</key>
- <string>NO</string>
- <key>ENABLE_STRICT_OBJC_MSGSEND</key>
- <string>YES</string>
- <key>GCC_C_LANGUAGE_STANDARD</key>
- <string>gnu99</string>
- <key>GCC_WARN_64_TO_32_BIT_CONVERSION</key>
- <string>YES</string>
- <key>GCC_WARN_ABOUT_RETURN_TYPE</key>
- <string>YES_ERROR</string>
- <key>GCC_WARN_UNDECLARED_SELECTOR</key>
- <string>YES</string>
- <key>GCC_WARN_UNINITIALIZED_AUTOS</key>
- <string>YES_AGGRESSIVE</string>
- <key>GCC_WARN_UNUSED_FUNCTION</key>
- <string>YES</string>
- <key>GCC_WARN_UNUSED_VARIABLE</key>
- <string>YES</string>
- <key>IPHONEOS_DEPLOYMENT_TARGET</key>
- <string>8.1</string>
- <key>MTL_ENABLE_DEBUG_INFO</key>
- <string>NO</string>
- <key>SDKROOT</key>
- <string>iphoneos</string>
- <key>TARGETED_DEVICE_FAMILY</key>
- <string>1,2</string>
- <key>VALIDATE_PRODUCT</key>
- <string>YES</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>6369A28D1A9322E20015FC5C</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>6369A28E1A9322E20015FC5C</string>
- <string>6369A28F1A9322E20015FC5C</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>6369A28E1A9322E20015FC5C</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>AC29DD6FCDF962F519FEBB0D</string>
- <key>buildSettings</key>
- <dict>
- <key>ASSETCATALOG_COMPILER_APPICON_NAME</key>
- <string>AppIcon</string>
- <key>INFOPLIST_FILE</key>
- <string>Sample/Info.plist</string>
- <key>LD_RUNPATH_SEARCH_PATHS</key>
- <string>$(inherited) @executable_path/Frameworks</string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>6369A28F1A9322E20015FC5C</key>
- <dict>
- <key>baseConfigurationReference</key>
- <string>C68330F8D451CC6ACEABA09F</string>
- <key>buildSettings</key>
- <dict>
- <key>ASSETCATALOG_COMPILER_APPICON_NAME</key>
- <string>AppIcon</string>
- <key>INFOPLIST_FILE</key>
- <string>Sample/Info.plist</string>
- <key>LD_RUNPATH_SEARCH_PATHS</key>
- <string>$(inherited) @executable_path/Frameworks</string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>6369A2901A9322E20015FC5C</key>
- <dict>
- <key>buildConfigurations</key>
- <array>
- <string>6369A2911A9322E20015FC5C</string>
- <string>6369A2921A9322E20015FC5C</string>
- </array>
- <key>defaultConfigurationIsVisible</key>
- <string>0</string>
- <key>isa</key>
- <string>XCConfigurationList</string>
- </dict>
- <key>6369A2911A9322E20015FC5C</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>BUNDLE_LOADER</key>
- <string>$(TEST_HOST)</string>
- <key>FRAMEWORK_SEARCH_PATHS</key>
- <array>
- <string>$(SDKROOT)/Developer/Library/Frameworks</string>
- <string>$(inherited)</string>
- </array>
- <key>GCC_PREPROCESSOR_DEFINITIONS</key>
- <array>
- <string>DEBUG=1</string>
- <string>$(inherited)</string>
- </array>
- <key>INFOPLIST_FILE</key>
- <string>SampleTests/Info.plist</string>
- <key>LD_RUNPATH_SEARCH_PATHS</key>
- <string>$(inherited) @executable_path/Frameworks @loader_path/Frameworks</string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>TEST_HOST</key>
- <string>$(BUILT_PRODUCTS_DIR)/Sample.app/Sample</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Debug</string>
- </dict>
- <key>6369A2921A9322E20015FC5C</key>
- <dict>
- <key>buildSettings</key>
- <dict>
- <key>BUNDLE_LOADER</key>
- <string>$(TEST_HOST)</string>
- <key>FRAMEWORK_SEARCH_PATHS</key>
- <array>
- <string>$(SDKROOT)/Developer/Library/Frameworks</string>
- <string>$(inherited)</string>
- </array>
- <key>INFOPLIST_FILE</key>
- <string>SampleTests/Info.plist</string>
- <key>LD_RUNPATH_SEARCH_PATHS</key>
- <string>$(inherited) @executable_path/Frameworks @loader_path/Frameworks</string>
- <key>PRODUCT_NAME</key>
- <string>$(TARGET_NAME)</string>
- <key>TEST_HOST</key>
- <string>$(BUILT_PRODUCTS_DIR)/Sample.app/Sample</string>
- </dict>
- <key>isa</key>
- <string>XCBuildConfiguration</string>
- <key>name</key>
- <string>Release</string>
- </dict>
- <key>AB3331C9AE6488E61B2B094E</key>
- <dict>
- <key>children</key>
- <array>
- <string>AC29DD6FCDF962F519FEBB0D</string>
- <string>C68330F8D451CC6ACEABA09F</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Pods</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>AC29DD6FCDF962F519FEBB0D</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods.debug.xcconfig</string>
- <key>path</key>
- <string>Pods/Target Support Files/Pods/Pods.debug.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>C4C2C5219053E079C9EFB930</key>
- <dict>
- <key>children</key>
- <array>
- <string>2DC7B7C4C0410F43B9621631</string>
- </array>
- <key>isa</key>
- <string>PBXGroup</string>
- <key>name</key>
- <string>Frameworks</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>C68330F8D451CC6ACEABA09F</key>
- <dict>
- <key>includeInIndex</key>
- <string>1</string>
- <key>isa</key>
- <string>PBXFileReference</string>
- <key>lastKnownFileType</key>
- <string>text.xcconfig</string>
- <key>name</key>
- <string>Pods.release.xcconfig</string>
- <key>path</key>
- <string>Pods/Target Support Files/Pods/Pods.release.xcconfig</string>
- <key>sourceTree</key>
- <string>&lt;group&gt;</string>
- </dict>
- <key>FC81FE63CA655031F3524EC0</key>
- <dict>
- <key>fileRef</key>
- <string>2DC7B7C4C0410F43B9621631</string>
- <key>isa</key>
- <string>PBXBuildFile</string>
- </dict>
- </dict>
- <key>rootObject</key>
- <string>6369A2621A9322E20015FC5C</string>
-</dict>
-</plist>
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 60BBBBB15823BBF7639D7AA9 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC7B7C4C0410F43B9621631 /* libPods.a */; };
+ 6340F0491AE66E3300FB6A3D /* RemoteProtoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6340F0481AE66E3300FB6A3D /* RemoteProtoTests.m */; };
+ 6356D1DE1AC11FE00075FBBC /* RemoteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6356D1DD1AC11FE00075FBBC /* RemoteTests.m */; };
+ 6369A2701A9322E20015FC5C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A26F1A9322E20015FC5C /* main.m */; };
+ 6369A2731A9322E20015FC5C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2721A9322E20015FC5C /* AppDelegate.m */; };
+ 6369A2761A9322E20015FC5C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2751A9322E20015FC5C /* ViewController.m */; };
+ 6369A2791A9322E20015FC5C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6369A2771A9322E20015FC5C /* Main.storyboard */; };
+ 6369A27B1A9322E20015FC5C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6369A27A1A9322E20015FC5C /* Images.xcassets */; };
+ 6369A27E1A9322E20015FC5C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6369A27C1A9322E20015FC5C /* LaunchScreen.xib */; };
+ 6369A28A1A9322E20015FC5C /* SampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6369A2891A9322E20015FC5C /* SampleTests.m */; };
+ FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DC7B7C4C0410F43B9621631 /* libPods.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 6369A2841A9322E20015FC5C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 6369A2621A9322E20015FC5C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6369A2691A9322E20015FC5C;
+ remoteInfo = Sample;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 2DC7B7C4C0410F43B9621631 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6340F0481AE66E3300FB6A3D /* RemoteProtoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoteProtoTests.m; sourceTree = "<group>"; };
+ 6356D1DD1AC11FE00075FBBC /* RemoteTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoteTests.m; sourceTree = "<group>"; };
+ 6369A26A1A9322E20015FC5C /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6369A26E1A9322E20015FC5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 6369A26F1A9322E20015FC5C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 6369A2711A9322E20015FC5C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 6369A2721A9322E20015FC5C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 6369A2741A9322E20015FC5C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ 6369A2751A9322E20015FC5C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ 6369A2781A9322E20015FC5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ 6369A27A1A9322E20015FC5C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+ 6369A27D1A9322E20015FC5C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
+ 6369A2831A9322E20015FC5C /* SampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 6369A2881A9322E20015FC5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 6369A2891A9322E20015FC5C /* SampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleTests.m; sourceTree = "<group>"; };
+ AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
+ C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 6369A2671A9322E20015FC5C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC81FE63CA655031F3524EC0 /* libPods.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6369A2801A9322E20015FC5C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 60BBBBB15823BBF7639D7AA9 /* libPods.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 6369A2611A9322E20015FC5C = {
+ isa = PBXGroup;
+ children = (
+ 6369A26C1A9322E20015FC5C /* Sample */,
+ 6369A2861A9322E20015FC5C /* SampleTests */,
+ 6369A26B1A9322E20015FC5C /* Products */,
+ AB3331C9AE6488E61B2B094E /* Pods */,
+ C4C2C5219053E079C9EFB930 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 6369A26B1A9322E20015FC5C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 6369A26A1A9322E20015FC5C /* Sample.app */,
+ 6369A2831A9322E20015FC5C /* SampleTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 6369A26C1A9322E20015FC5C /* Sample */ = {
+ isa = PBXGroup;
+ children = (
+ 6369A2711A9322E20015FC5C /* AppDelegate.h */,
+ 6369A2721A9322E20015FC5C /* AppDelegate.m */,
+ 6369A2741A9322E20015FC5C /* ViewController.h */,
+ 6369A2751A9322E20015FC5C /* ViewController.m */,
+ 6369A2771A9322E20015FC5C /* Main.storyboard */,
+ 6369A27A1A9322E20015FC5C /* Images.xcassets */,
+ 6369A27C1A9322E20015FC5C /* LaunchScreen.xib */,
+ 6369A26D1A9322E20015FC5C /* Supporting Files */,
+ );
+ path = Sample;
+ sourceTree = "<group>";
+ };
+ 6369A26D1A9322E20015FC5C /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 6369A26E1A9322E20015FC5C /* Info.plist */,
+ 6369A26F1A9322E20015FC5C /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 6369A2861A9322E20015FC5C /* SampleTests */ = {
+ isa = PBXGroup;
+ children = (
+ 6340F0481AE66E3300FB6A3D /* RemoteProtoTests.m */,
+ 6369A2891A9322E20015FC5C /* SampleTests.m */,
+ 6369A2871A9322E20015FC5C /* Supporting Files */,
+ 6356D1DD1AC11FE00075FBBC /* RemoteTests.m */,
+ );
+ path = SampleTests;
+ sourceTree = "<group>";
+ };
+ 6369A2871A9322E20015FC5C /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 6369A2881A9322E20015FC5C /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ AB3331C9AE6488E61B2B094E /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */,
+ C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
+ C4C2C5219053E079C9EFB930 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 2DC7B7C4C0410F43B9621631 /* libPods.a */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 6369A2691A9322E20015FC5C /* Sample */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 6369A28D1A9322E20015FC5C /* Build configuration list for PBXNativeTarget "Sample" */;
+ buildPhases = (
+ 41F7486D8F66994B0BFB84AF /* Check Pods Manifest.lock */,
+ 6369A2661A9322E20015FC5C /* Sources */,
+ 6369A2671A9322E20015FC5C /* Frameworks */,
+ 6369A2681A9322E20015FC5C /* Resources */,
+ 04554623324BE4A838846086 /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Sample;
+ productName = Sample;
+ productReference = 6369A26A1A9322E20015FC5C /* Sample.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 6369A2821A9322E20015FC5C /* SampleTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 6369A2901A9322E20015FC5C /* Build configuration list for PBXNativeTarget "SampleTests" */;
+ buildPhases = (
+ 75C393B2FDC60A22B2121058 /* Check Pods Manifest.lock */,
+ 6369A27F1A9322E20015FC5C /* Sources */,
+ 6369A2801A9322E20015FC5C /* Frameworks */,
+ 6369A2811A9322E20015FC5C /* Resources */,
+ 7B8CDC152F76D6014A96C798 /* Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 6369A2851A9322E20015FC5C /* PBXTargetDependency */,
+ );
+ name = SampleTests;
+ productName = SampleTests;
+ productReference = 6369A2831A9322E20015FC5C /* SampleTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 6369A2621A9322E20015FC5C /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = gRPC;
+ TargetAttributes = {
+ 6369A2691A9322E20015FC5C = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ 6369A2821A9322E20015FC5C = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = 6369A2691A9322E20015FC5C;
+ };
+ };
+ };
+ buildConfigurationList = 6369A2651A9322E20015FC5C /* Build configuration list for PBXProject "Sample" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 6369A2611A9322E20015FC5C;
+ productRefGroup = 6369A26B1A9322E20015FC5C /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 6369A2691A9322E20015FC5C /* Sample */,
+ 6369A2821A9322E20015FC5C /* SampleTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 6369A2681A9322E20015FC5C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6369A2791A9322E20015FC5C /* Main.storyboard in Resources */,
+ 6369A27E1A9322E20015FC5C /* LaunchScreen.xib in Resources */,
+ 6369A27B1A9322E20015FC5C /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6369A2811A9322E20015FC5C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 04554623324BE4A838846086 /* 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;
+ };
+ 41F7486D8F66994B0BFB84AF /* 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;
+ };
+ 75C393B2FDC60A22B2121058 /* 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;
+ };
+ 7B8CDC152F76D6014A96C798 /* 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 */
+ 6369A2661A9322E20015FC5C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6369A2761A9322E20015FC5C /* ViewController.m in Sources */,
+ 6369A2731A9322E20015FC5C /* AppDelegate.m in Sources */,
+ 6369A2701A9322E20015FC5C /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6369A27F1A9322E20015FC5C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6369A28A1A9322E20015FC5C /* SampleTests.m in Sources */,
+ 6340F0491AE66E3300FB6A3D /* RemoteProtoTests.m in Sources */,
+ 6356D1DE1AC11FE00075FBBC /* RemoteTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 6369A2851A9322E20015FC5C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6369A2691A9322E20015FC5C /* Sample */;
+ targetProxy = 6369A2841A9322E20015FC5C /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 6369A2771A9322E20015FC5C /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 6369A2781A9322E20015FC5C /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+ 6369A27C1A9322E20015FC5C /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 6369A27D1A9322E20015FC5C /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 6369A28B1A9322E20015FC5C /* 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;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 6369A28C1A9322E20015FC5C /* 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 = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 6369A28E1A9322E20015FC5C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Sample/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 6369A28F1A9322E20015FC5C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = Sample/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 6369A2911A9322E20015FC5C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AC29DD6FCDF962F519FEBB0D /* Pods.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SampleTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample";
+ };
+ name = Debug;
+ };
+ 6369A2921A9322E20015FC5C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C68330F8D451CC6ACEABA09F /* Pods.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SampleTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Sample.app/Sample";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 6369A2651A9322E20015FC5C /* Build configuration list for PBXProject "Sample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6369A28B1A9322E20015FC5C /* Debug */,
+ 6369A28C1A9322E20015FC5C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 6369A28D1A9322E20015FC5C /* Build configuration list for PBXNativeTarget "Sample" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6369A28E1A9322E20015FC5C /* Debug */,
+ 6369A28F1A9322E20015FC5C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 6369A2901A9322E20015FC5C /* Build configuration list for PBXNativeTarget "SampleTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 6369A2911A9322E20015FC5C /* Debug */,
+ 6369A2921A9322E20015FC5C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 6369A2621A9322E20015FC5C /* Project object */;
+}
diff --git a/src/objective-c/examples/Sample/Sample.xcworkspace/contents.xcworkspacedata b/src/objective-c/examples/Sample/Sample.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 7b5a2f3050..0000000000
--- a/src/objective-c/examples/Sample/Sample.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "group:Sample.xcodeproj">
- </FileRef>
- <FileRef
- location = "group:Pods/Pods.xcodeproj">
- </FileRef>
-</Workspace>
diff --git a/src/objective-c/examples/Sample/Sample/AppDelegate.h b/src/objective-c/examples/Sample/Sample/AppDelegate.h
index 867e62842a..b1857f28e0 100644
--- a/src/objective-c/examples/Sample/Sample/AppDelegate.h
+++ b/src/objective-c/examples/Sample/Sample/AppDelegate.h
@@ -37,6 +37,5 @@
@property (strong, nonatomic) UIWindow *window;
-
@end
diff --git a/src/objective-c/examples/Sample/Sample/AppDelegate.m b/src/objective-c/examples/Sample/Sample/AppDelegate.m
index 66fceffd85..12e1ad9d67 100644
--- a/src/objective-c/examples/Sample/Sample/AppDelegate.m
+++ b/src/objective-c/examples/Sample/Sample/AppDelegate.m
@@ -34,37 +34,12 @@
#import "AppDelegate.h"
@interface AppDelegate ()
-
@end
@implementation AppDelegate
-
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
- // Override point for customization after application launch.
return YES;
}
-- (void)applicationWillResignActive:(UIApplication *)application {
- // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
- // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application {
- // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
- // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
-}
-
-- (void)applicationWillEnterForeground:(UIApplication *)application {
- // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
-}
-
-- (void)applicationDidBecomeActive:(UIApplication *)application {
- // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
-}
-
-- (void)applicationWillTerminate:(UIApplication *)application {
- // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
-}
-
@end
diff --git a/src/objective-c/examples/Sample/Sample/ViewController.h b/src/objective-c/examples/Sample/Sample/ViewController.h
index 38cd7f92b6..c0b4aca77e 100644
--- a/src/objective-c/examples/Sample/Sample/ViewController.h
+++ b/src/objective-c/examples/Sample/Sample/ViewController.h
@@ -34,7 +34,4 @@
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
-
-
@end
-
diff --git a/src/objective-c/examples/Sample/Sample/ViewController.m b/src/objective-c/examples/Sample/Sample/ViewController.m
index f24d81888b..c7d8e0d145 100644
--- a/src/objective-c/examples/Sample/Sample/ViewController.m
+++ b/src/objective-c/examples/Sample/Sample/ViewController.m
@@ -32,39 +32,44 @@
*/
#import "ViewController.h"
-#import <GRPCClient/GRPCCall.h>
-#import <GRPCClient/GRPCMethodName.h>
-#import <RxLibrary/GRXWriter+Immediate.h>
-#import <RxLibrary/GRXWriteable.h>
-@interface ViewController ()
+#import <gRPC/GRPCCall.h>
+#import <gRPC/GRPCMethodName.h>
+#import <gRPC/GRXWriter+Immediate.h>
+#import <gRPC/GRXWriteable.h>
+#import <RemoteTest/Messages.pb.h>
+@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
interface:@"TestService"
- method:@"EmptyCall"];
+ method:@"UnaryCall"];
- GRPCCall *call = [[GRPCCall alloc] initWithHost:@"localhost"
+ RMTSimpleRequest *request = [[[[[[RMTSimpleRequestBuilder alloc] init]
+ setResponseSize:100]
+ setFillUsername:YES]
+ setFillOauthScope:YES]
+ build];
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"grpc-test.sandbox.google.com"
method:method
- requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
+ requestsWriter:requestsWriter];
- [call startWithWriteable:[[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
- NSLog(@"Received response: %@", value);
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value];
+ NSLog(@"Received response:\n%@", response);
} completionHandler:^(NSError *errorOrNil) {
NSLog(@"Finished with error: %@", errorOrNil);
- }]];
-}
+ }];
-- (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
+ [call startWithWriteable:responsesWriteable];
}
@end
diff --git a/src/objective-c/examples/Sample/SampleTests/RemoteProtoTests.m b/src/objective-c/examples/Sample/SampleTests/RemoteProtoTests.m
new file mode 100644
index 0000000000..2ef6a6e4ab
--- /dev/null
+++ b/src/objective-c/examples/Sample/SampleTests/RemoteProtoTests.m
@@ -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.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+#import <gRPC/GRXWriter+Immediate.h>
+#import <RemoteTest/Messages.pb.h>
+#import <RemoteTest/Test.pb.h>
+
+@interface RemoteProtoTests : XCTestCase
+@end
+
+@implementation RemoteProtoTests {
+ RMTTestService *_service;
+}
+
+- (void)setUp {
+ _service = [[RMTTestService alloc] initWithHost:@"grpc-test.sandbox.google.com"];
+}
+
+// Tests as described here: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
+
+- (void)testEmptyUnaryRPC {
+ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];
+
+ RMTEmpty *request = [RMTEmpty defaultInstance];
+
+ [_service emptyCallWithRequest:request handler:^(RMTEmpty *response, NSError *error) {
+ XCTAssertNil(error, @"Finished with unexpected error: %@", error);
+
+ id expectedResponse = [RMTEmpty defaultInstance];
+ XCTAssertEqualObjects(response, expectedResponse);
+
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:2. handler:nil];
+}
+
+- (void)testLargeUnaryRPC {
+ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];
+
+ RMTSimpleRequest *request = [[[[[[RMTSimpleRequestBuilder alloc] init]
+ setResponseType:RMTPayloadTypeCompressable]
+ setResponseSize:314159]
+ setPayloadBuilder:[[[RMTPayloadBuilder alloc] init]
+ setBody:[NSMutableData dataWithLength:271828]]]
+ build];
+
+ [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) {
+ XCTAssertNil(error, @"Finished with unexpected error: %@", error);
+
+ id expectedResponse = [[[[RMTSimpleResponseBuilder alloc] init]
+ setPayloadBuilder:[[[[RMTPayloadBuilder alloc] init]
+ setType:RMTPayloadTypeCompressable]
+ setBody:[NSMutableData dataWithLength:314159]]]
+ build];
+ XCTAssertEqualObjects(response, expectedResponse);
+
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:4. handler:nil];
+}
+
+- (void)testClientStreamingRPC {
+ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];
+
+ id request1 = [[[[RMTStreamingInputCallRequestBuilder alloc] init]
+ setPayloadBuilder:[[[RMTPayloadBuilder alloc] init]
+ setBody:[NSMutableData dataWithLength:27182]]]
+ build];
+ id request2 = [[[[RMTStreamingInputCallRequestBuilder alloc] init]
+ setPayloadBuilder:[[[RMTPayloadBuilder alloc] init]
+ setBody:[NSMutableData dataWithLength:8]]]
+ build];
+ id request3 = [[[[RMTStreamingInputCallRequestBuilder alloc] init]
+ setPayloadBuilder:[[[RMTPayloadBuilder alloc] init]
+ setBody:[NSMutableData dataWithLength:1828]]]
+ build];
+ id request4 = [[[[RMTStreamingInputCallRequestBuilder alloc] init]
+ setPayloadBuilder:[[[RMTPayloadBuilder alloc] init]
+ setBody:[NSMutableData dataWithLength:45904]]]
+ build];
+ id<GRXWriter> writer = [GRXWriter writerWithContainer:@[request1, request2, request3, request4]];
+
+ [_service streamingInputCallWithRequestsWriter:writer
+ handler:^(RMTStreamingInputCallResponse *response, NSError *error) {
+ XCTAssertNil(error, @"Finished with unexpected error: %@", error);
+
+ id expectedResponse = [[[[RMTStreamingInputCallResponseBuilder alloc] init]
+ setAggregatedPayloadSize:74922]
+ build];
+ XCTAssertEqualObjects(response, expectedResponse);
+
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectationsWithTimeout:4. handler:nil];
+}
+
+@end
diff --git a/src/objective-c/examples/Sample/SampleTests/RemoteTests.m b/src/objective-c/examples/Sample/SampleTests/RemoteTests.m
new file mode 100644
index 0000000000..6091aa9d31
--- /dev/null
+++ b/src/objective-c/examples/Sample/SampleTests/RemoteTests.m
@@ -0,0 +1,144 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <UIKit/UIKit.h>
+#import <XCTest/XCTest.h>
+
+#import <gRPC/GRPCCall.h>
+#import <gRPC/GRPCMethodName.h>
+#import <gRPC/GRXWriter+Immediate.h>
+#import <gRPC/GRXWriteable.h>
+#import <RemoteTest/Messages.pb.h>
+
+@interface RemoteTests : XCTestCase
+@end
+
+@implementation RemoteTests
+
+- (void)testConnectionToRemoteServer {
+ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."];
+
+ // This method isn't implemented by the remote server.
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
+ interface:@"TestService"
+ method:@"Nonexistent"];
+
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[NSData data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"grpc-test.sandbox.google.com"
+ method:method
+ requestsWriter:requestsWriter];
+
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTFail(@"Received unexpected response: %@", value);
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNotNil(errorOrNil, @"Finished without error!");
+ // TODO(jcanizales): The server should return code 12 UNIMPLEMENTED, not 5 NOT FOUND.
+ XCTAssertEqual(errorOrNil.code, 5, @"Finished with unexpected error: %@", errorOrNil);
+ [expectation fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2. handler:nil];
+}
+
+- (void)testEmptyRPC {
+ __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
+ __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
+
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
+ interface:@"TestService"
+ method:@"EmptyCall"];
+
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[NSData data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"grpc-test.sandbox.google.com"
+ method:method
+ requestsWriter:requestsWriter];
+
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTAssertNotNil(value, @"nil value received as response.");
+ XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
+ [response fulfill];
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
+ [completion fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2. handler:nil];
+}
+
+- (void)testSimpleProtoRPC {
+ __weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."];
+ __weak XCTestExpectation *expectedResponse =
+ [self expectationWithDescription:@"Expected response."];
+ __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
+
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
+ interface:@"TestService"
+ method:@"UnaryCall"];
+
+ RMTSimpleRequest *request = [[[[[[RMTSimpleRequestBuilder alloc] init]
+ setResponseSize:100]
+ setFillUsername:YES]
+ setFillOauthScope:YES]
+ build];
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"grpc-test.sandbox.google.com"
+ method:method
+ requestsWriter:requestsWriter];
+
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTAssertNotNil(value, @"nil value received as response.");
+ [response fulfill];
+ XCTAssertGreaterThan(value.length, 0, @"Empty response received.");
+ RMTSimpleResponse *response = [RMTSimpleResponse parseFromData:value];
+ // We expect empty strings, not nil:
+ XCTAssertNotNil(response.username, @"Response's username is nil.");
+ XCTAssertNotNil(response.oauthScope, @"Response's OAuth scope is nil.");
+ [expectedResponse fulfill];
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
+ [completion fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2. handler:nil];
+}
+
+@end
diff --git a/src/objective-c/examples/Sample/SampleTests/SampleTests.m b/src/objective-c/examples/Sample/SampleTests/SampleTests.m
index 9a1d4b14d4..6d6875c233 100644
--- a/src/objective-c/examples/Sample/SampleTests/SampleTests.m
+++ b/src/objective-c/examples/Sample/SampleTests/SampleTests.m
@@ -34,32 +34,106 @@
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
-@interface SampleTests : XCTestCase
+#import <gRPC/GRPCCall.h>
+#import <gRPC/GRPCMethodName.h>
+#import <gRPC/GRXWriter+Immediate.h>
+#import <gRPC/GRXWriteable.h>
+#import <Route_guide/Route_guide.pb.h>
+@interface SampleTests : XCTestCase
@end
+// These tests require the gRPC-Java "RouteGuide" sample server to be running locally. Install the
+// gRPC-Java library following the instructions here: https://github.com/grpc/grpc-java And run the
+// server by following the instructions here: https://github.com/grpc/grpc-java/tree/master/examples
@implementation SampleTests
-- (void)setUp {
- [super setUp];
- // Put setup code here. This method is called before the invocation of each test method in the class.
-}
+- (void)testConnectionToLocalServer {
+ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Server reachable."];
-- (void)tearDown {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- [super tearDown];
-}
+ // This method isn't implemented by the local server.
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
+ interface:@"TestService"
+ method:@"EmptyCall"];
+
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[NSData data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"http://127.0.0.1:8980"
+ method:method
+ requestsWriter:requestsWriter];
-- (void)testExample {
- // This is an example of a functional test case.
- XCTAssert(YES, @"Pass");
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTFail(@"Received unexpected response: %@", value);
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNotNil(errorOrNil, @"Finished without error!");
+ XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil);
+ [expectation fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2.0 handler:nil];
}
-- (void)testPerformanceExample {
- // This is an example of a performance test case.
- [self measureBlock:^{
- // Put the code you want to measure the time of here.
- }];
+- (void)testEmptyRPC {
+ __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
+ __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
+
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.example.routeguide"
+ interface:@"RouteGuide"
+ method:@"RecordRoute"];
+
+ id<GRXWriter> requestsWriter = [GRXWriter emptyWriter];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"http://127.0.0.1:8980"
+ method:method
+ requestsWriter:requestsWriter];
+
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTAssertNotNil(value, @"nil value received as response.");
+ XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
+ [response fulfill];
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
+ [completion fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2.0 handler:nil];
}
+- (void)testSimpleProtoRPC {
+ __weak XCTestExpectation *response = [self expectationWithDescription:@"Response received."];
+ __weak XCTestExpectation *expectedResponse =
+ [self expectationWithDescription:@"Expected response."];
+ __weak XCTestExpectation *completion = [self expectationWithDescription:@"RPC completed."];
+
+ GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.example.routeguide"
+ interface:@"RouteGuide"
+ method:@"GetFeature"];
+
+ RGDPoint *point = [[[[[RGDPointBuilder alloc] init] setLatitude:28E7] setLongitude:-15E7] build];
+ id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[point data]];
+
+ GRPCCall *call = [[GRPCCall alloc] initWithHost:@"http://127.0.0.1:8980"
+ method:method
+ requestsWriter:requestsWriter];
+
+ id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
+ XCTAssertNotNil(value, @"nil value received as response.");
+ [response fulfill];
+ RGDFeature *feature = [RGDFeature parseFromData:value];
+ XCTAssertEqualObjects(point, feature.location);
+ XCTAssertNotNil(feature.name, @"Response's name is nil.");
+ [expectedResponse fulfill];
+ } completionHandler:^(NSError *errorOrNil) {
+ XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
+ [completion fulfill];
+ }];
+
+ [call startWithWriteable:responsesWriteable];
+
+ [self waitForExpectationsWithTimeout:2.0 handler:nil];
+}
@end
diff --git a/src/ruby/lib/grpc/core/event.rb b/src/php/bin/generate_proto_php.sh
index 194aa8ecac..16f93747ab 100644..100755
--- a/src/ruby/lib/grpc/core/event.rb
+++ b/src/php/bin/generate_proto_php.sh
@@ -1,3 +1,4 @@
+#!/bin/sh
# Copyright 2015, Google Inc.
# All rights reserved.
#
@@ -27,18 +28,13 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc'
-# GRPC contains the General RPC module.
-module GRPC
- module Core
- # Event is a class defined in the c extension
- #
- # Here, we add an inspect method.
- class Event
- def inspect
- "<#{self.class}: type:#{type}, tag:#{tag} result:#{result}>"
- end
- end
- end
-end
+set +e
+cd $(dirname $0)
+
+gen_code='../tests/generated_code'
+interop='../tests/interop'
+
+protoc-gen-php -i $gen_code -o $gen_code $gen_code/math.proto
+
+protoc-gen-php -i $interop -o $interop $interop/test.proto
diff --git a/src/php/bin/interop_client.sh b/src/php/bin/interop_client.sh
index 2c61ea8aa0..22e4a493c4 100755
--- a/src/php/bin/interop_client.sh
+++ b/src/php/bin/interop_client.sh
@@ -31,5 +31,8 @@
set +e
cd $(dirname $0)
-php -d extension_dir=../ext/grpc/modules/ -d extension=grpc.so \
+
+module_dir=`php --version | grep -q 'PHP 5.6' && echo '../ext/grpc' || echo '../ext/grpc/modules'`
+
+php -d extension_dir=$module_dir -d extension=grpc.so \
../tests/interop/interop_client.php $@ 1>&2
diff --git a/src/php/bin/run_gen_code_test.sh b/src/php/bin/run_gen_code_test.sh
index 3f176fb5e4..79abbe6cf8 100755
--- a/src/php/bin/run_gen_code_test.sh
+++ b/src/php/bin/run_gen_code_test.sh
@@ -32,3 +32,6 @@ cd $(dirname $0)
GRPC_TEST_HOST=localhost:7070 php -d extension_dir=../ext/grpc/modules/ \
-d extension=grpc.so /usr/local/bin/phpunit -v --debug --strict \
../tests/generated_code/GeneratedCodeTest.php
+GRPC_TEST_HOST=localhost:7070 php -d extension_dir=../ext/grpc/modules/ \
+ -d extension=grpc.so /usr/local/bin/phpunit -v --debug --strict \
+ ../tests/generated_code/GeneratedCodeWithCallbackTest.php
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
index c3358ed899..1335672e9e 100755
--- a/src/php/bin/run_tests.sh
+++ b/src/php/bin/run_tests.sh
@@ -34,13 +34,15 @@ set -e
cd $(dirname $0)
default_extension_dir=`php -i | grep extension_dir | sed 's/.*=> //g'`
+module_dir=`php --version | grep -q 'PHP 5.6' && echo '../ext/grpc' || echo '../ext/grpc/modules'`
+
# sym-link in system supplied extensions
for f in $default_extension_dir/*.so
do
- ln -s $f ../ext/grpc/modules/$(basename $f) &> /dev/null || true
+ ln -s $f $module_dir/$(basename $f) &> /dev/null || true
done
php \
- -d extension_dir=../ext/grpc/modules/ \
+ -d extension_dir=$module_dir \
-d extension=grpc.so \
`which phpunit` -v --debug --strict ../tests/unit_tests
diff --git a/src/php/composer.json b/src/php/composer.json
new file mode 100644
index 0000000000..3c0cb37231
--- /dev/null
+++ b/src/php/composer.json
@@ -0,0 +1,15 @@
+{
+ "name": "grpc/grpc",
+ "description": "gRPC library for PHP",
+ "version": "0.5.0",
+ "homepage": "http://grpc.io",
+ "license": "BSD-3-Clause",
+ "require": {
+ "php": ">=5.5.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Grpc\\": "lib/Grpc/"
+ }
+ }
+}
diff --git a/src/php/composer.lock b/src/php/composer.lock
new file mode 100644
index 0000000000..47fc70fd2d
--- /dev/null
+++ b/src/php/composer.lock
@@ -0,0 +1,19 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "65467a098f5fd8b8fe5f7f6e10226f8a",
+ "packages": [],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.5.0"
+ },
+ "platform-dev": []
+}
diff --git a/src/php/ext/grpc/byte_buffer.c b/src/php/ext/grpc/byte_buffer.c
index 1ced1bf3f0..4f3e6b67af 100644
--- a/src/php/ext/grpc/byte_buffer.c
+++ b/src/php/ext/grpc/byte_buffer.c
@@ -35,18 +35,18 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
#include <string.h>
#include "byte_buffer.h"
-#include "grpc/grpc.h"
-#include "grpc/support/slice.h"
+#include <grpc/grpc.h>
+#include <grpc/support/slice.h>
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
@@ -57,6 +57,11 @@ grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length) {
+ if (buffer == NULL) {
+ *out_string = NULL;
+ *out_length = 0;
+ return;
+ }
size_t length = grpc_byte_buffer_length(buffer);
char *string = ecalloc(length + 1, sizeof(char));
size_t offset = 0;
diff --git a/src/php/ext/grpc/byte_buffer.h b/src/php/ext/grpc/byte_buffer.h
index 7a40638591..0e9d1e7145 100644
--- a/src/php/ext/grpc/byte_buffer.h
+++ b/src/php/ext/grpc/byte_buffer.h
@@ -34,7 +34,7 @@
#ifndef NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_
#define NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length);
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index d0e324e2cc..b1525e9246 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -37,20 +37,20 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
#include <stdbool.h>
-#include "grpc/support/log.h"
-#include "grpc/support/alloc.h"
-#include "grpc/grpc.h"
+#include <grpc/support/log.h>
+#include <grpc/support/alloc.h>
+#include <grpc/grpc.h>
#include "timeval.h"
#include "channel.h"
@@ -263,7 +263,7 @@ PHP_METHOD(Call, __construct) {
* @param array batch Array of actions to take
* @return object Object with results of all actions
*/
-PHP_METHOD(Call, start_batch) {
+PHP_METHOD(Call, startBatch) {
wrapped_grpc_call *call =
(wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_op ops[8];
@@ -443,22 +443,29 @@ PHP_METHOD(Call, start_batch) {
add_property_bool(result, "send_status", true);
break;
case GRPC_OP_RECV_INITIAL_METADATA:
- add_property_zval(result, "metadata",
- grpc_parse_metadata_array(&recv_metadata));
+ array = grpc_parse_metadata_array(&recv_metadata);
+ add_property_zval(result, "metadata", array);
+ Z_DELREF_P(array);
break;
case GRPC_OP_RECV_MESSAGE:
byte_buffer_to_string(message, &message_str, &message_len);
- add_property_stringl(result, "message", message_str, message_len,
- false);
+ if (message_str == NULL) {
+ add_property_null(result, "message");
+ } else {
+ add_property_stringl(result, "message", message_str, message_len,
+ false);
+ }
break;
case GRPC_OP_RECV_STATUS_ON_CLIENT:
MAKE_STD_ZVAL(recv_status);
object_init(recv_status);
- add_property_zval(recv_status, "metadata",
- grpc_parse_metadata_array(&recv_trailing_metadata));
+ array = grpc_parse_metadata_array(&recv_trailing_metadata);
+ add_property_zval(recv_status, "metadata", array);
+ Z_DELREF_P(array);
add_property_long(recv_status, "code", status);
add_property_string(recv_status, "details", status_details, true);
add_property_zval(result, "status", recv_status);
+ Z_DELREF_P(recv_status);
break;
case GRPC_OP_RECV_CLOSE_ON_SERVER:
add_property_bool(result, "cancelled", cancelled);
@@ -478,9 +485,20 @@ cleanup:
RETURN_DESTROY_ZVAL(result);
}
+/**
+ * Cancel the call. This will cause the call to end with STATUS_CANCELLED if it
+ * has not already ended with another status.
+ */
+PHP_METHOD(Call, cancel) {
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ grpc_call_cancel(call->wrapped);
+}
+
static zend_function_entry call_methods[] = {
PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(Call, start_batch, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+ PHP_ME(Call, startBatch, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
void grpc_init_call(TSRMLS_D) {
zend_class_entry ce;
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index 743effe5a1..e7eb9a75e2 100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -38,12 +38,12 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
/* Class entry for the Call PHP class */
extern zend_class_entry *grpc_ce_call;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index c96fb128a6..b8262db162 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -37,19 +37,19 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
#include <stdbool.h>
-#include "grpc/grpc.h"
-#include "grpc/support/log.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/grpc_security.h>
#include "server.h"
#include "credentials.h"
@@ -62,6 +62,7 @@ void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
}
+ efree(channel->target);
efree(channel);
}
diff --git a/src/php/ext/grpc/channel.h b/src/php/ext/grpc/channel.h
index 2c79668a4d..c13fa4c6d7 100755
--- a/src/php/ext/grpc/channel.h
+++ b/src/php/ext/grpc/channel.h
@@ -38,12 +38,12 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
/* Class entry for the PHP Channel class */
extern zend_class_entry *grpc_ce_channel;
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index d1a8decb73..11778e3bb6 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -66,5 +66,5 @@ if test "$PHP_GRPC" != "no"; then
PHP_SUBST(GRPC_SHARED_LIBADD)
- PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -pedantic -std=c99)
+ PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11)
fi
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index a94b0eac2d..a262b9981f 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -37,17 +37,17 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_credentials;
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 1f9edfe881..3e669ecd17 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -42,9 +42,9 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
// ZEND_DECLARE_MODULE_GLOBALS(grpc)
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 86b29958fb..dbb9425619 100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -37,19 +37,19 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
#include <stdbool.h>
-#include "grpc/grpc.h"
-#include "grpc/support/log.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/grpc_security.h>
#include "server.h"
#include "channel.h"
@@ -133,7 +133,7 @@ PHP_METHOD(Server, __construct) {
* @param long $tag_cancel The tag to use if the call is cancelled
* @return Void
*/
-PHP_METHOD(Server, request_call) {
+PHP_METHOD(Server, requestCall) {
grpc_call_error error_code;
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
@@ -178,7 +178,7 @@ cleanup:
* @param string $addr The address to add
* @return true on success, false on failure
*/
-PHP_METHOD(Server, add_http2_port) {
+PHP_METHOD(Server, addHttp2Port) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
@@ -193,7 +193,7 @@ PHP_METHOD(Server, add_http2_port) {
RETURN_LONG(grpc_server_add_http2_port(server->wrapped, addr));
}
-PHP_METHOD(Server, add_secure_http2_port) {
+PHP_METHOD(Server, addSecureHttp2Port) {
wrapped_grpc_server *server =
(wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
@@ -227,9 +227,9 @@ PHP_METHOD(Server, start) {
static zend_function_entry server_methods[] = {
PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
- PHP_ME(Server, request_call, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Server, add_http2_port, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Server, add_secure_http2_port, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, requestCall, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, addHttp2Port, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, addSecureHttp2Port, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
void grpc_init_server(TSRMLS_D) {
diff --git a/src/php/ext/grpc/server.h b/src/php/ext/grpc/server.h
index ebb8d25ae1..a2ee2ff5a9 100755
--- a/src/php/ext/grpc/server.h
+++ b/src/php/ext/grpc/server.h
@@ -38,12 +38,12 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
-#include "grpc/grpc.h"
+#include <grpc/grpc.h>
/* Class entry for the Server PHP class */
extern zend_class_entry *grpc_ce_server;
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index df64e65986..c4c1fabb1a 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -37,17 +37,17 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
-#include "zend_hash.h"
+#include <zend_exceptions.h>
+#include <zend_hash.h>
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
zend_class_entry *grpc_ce_server_credentials;
diff --git a/src/php/ext/grpc/server_credentials.h b/src/php/ext/grpc/server_credentials.h
index 8ed3697150..7101d65000 100755
--- a/src/php/ext/grpc/server_credentials.h
+++ b/src/php/ext/grpc/server_credentials.h
@@ -38,13 +38,13 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
-#include "grpc/grpc.h"
-#include "grpc/grpc_security.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
/* Class entry for the Server_Credentials PHP class */
extern zend_class_entry *grpc_ce_server_credentials;
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index f90f0062ba..8a278d6760 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -37,18 +37,18 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "ext/spl/spl_exceptions.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
#include "php_grpc.h"
-#include "zend_exceptions.h"
+#include <zend_exceptions.h>
#include <stdbool.h>
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
+#include <grpc/grpc.h>
+#include <grpc/support/time.h>
zend_class_entry *grpc_ce_timeval;
@@ -227,7 +227,7 @@ PHP_METHOD(Timeval, zero) {
* Returns the infinite future time value as a timeval object
* @return Timeval Infinite future time value
*/
-PHP_METHOD(Timeval, inf_future) {
+PHP_METHOD(Timeval, infFuture) {
zval *grpc_php_timeval_inf_future = grpc_php_wrap_timeval(gpr_inf_future);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
}
@@ -236,7 +236,7 @@ PHP_METHOD(Timeval, inf_future) {
* Returns the infinite past time value as a timeval object
* @return Timeval Infinite past time value
*/
-PHP_METHOD(Timeval, inf_past) {
+PHP_METHOD(Timeval, infPast) {
zval *grpc_php_timeval_inf_past = grpc_php_wrap_timeval(gpr_inf_past);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
}
@@ -245,7 +245,7 @@ PHP_METHOD(Timeval, inf_past) {
* Sleep until this time, interpreted as an absolute timeout
* @return void
*/
-PHP_METHOD(Timeval, sleep_until) {
+PHP_METHOD(Timeval, sleepUntil) {
wrapped_grpc_timeval *this =
(wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
gpr_sleep_until(this->wrapped);
@@ -255,11 +255,11 @@ static zend_function_entry timeval_methods[] = {
PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(Timeval, inf_future, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(Timeval, inf_past, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, infFuture, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, infPast, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
- PHP_ME(Timeval, sleep_until, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Timeval, sleepUntil, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
diff --git a/src/php/ext/grpc/timeval.h b/src/php/ext/grpc/timeval.h
index e3183f691d..07cef037cb 100755
--- a/src/php/ext/grpc/timeval.h
+++ b/src/php/ext/grpc/timeval.h
@@ -38,13 +38,13 @@
#include "config.h"
#endif
-#include "php.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
#include "php_grpc.h"
-#include "grpc/grpc.h"
-#include "grpc/support/time.h"
+#include <grpc/grpc.h>
+#include <grpc/support/time.h>
/* Class entry for the Timeval PHP Class */
extern zend_class_entry *grpc_ce_timeval;
diff --git a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/AbstractCall.php
index 0459f21e27..1add972589 100755..100644
--- a/src/php/lib/Grpc/BidiStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -32,44 +32,47 @@
*
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-/**
- * Represents an active call that allows for sending and recieving messages in
- * streams in any order.
- */
-class BidiStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+abstract class AbstractCall {
+
+ protected $call;
+ protected $deserialize;
+ protected $metadata;
/**
- * Reads the next value from the server.
- * @return The next value from the server, or null if there is none
+ * Create a new Call wrapper object.
+ * @param Channel $channel The channel to communicate on
+ * @param string $method The method to call on the remote server
*/
- public function read() {
- return $this->_read();
+ public function __construct(Channel $channel, $method, $deserialize) {
+ $this->call = new Call($channel, $method, Timeval::infFuture());
+ $this->deserialize = $deserialize;
+ $this->metadata = null;
}
/**
- * Writes a single message to the server. This cannot be called after
- * writesDone is called.
- * @param $value The message to send
+ * @return The metadata sent by the server.
*/
- public function write($value) {
- $this->_write($value);
+ public function getMetadata() {
+ return $this->metadata;
}
/**
- * Indicate that no more writes will be sent
+ * Cancels the call
*/
- public function writesDone() {
- $this->_writesDone();
+ public function cancel() {
+ $this->call->cancel();
}
/**
- * Wait for the server to send the status, and return it.
- * @return object The status object, with integer $code and string $details
- * members
+ * Deserialize a response value to an object.
+ * @param string $value The binary value to deserialize
+ * @return The deserialized value
*/
- public function getStatus() {
- return $this->_getStatus();
+ protected function deserializeResponse($value) {
+ if ($value === null) {
+ return null;
+ }
+ return call_user_func($this->deserialize, $value);
}
-}
+} \ No newline at end of file
diff --git a/src/php/lib/Grpc/AbstractSurfaceActiveCall.php b/src/php/lib/Grpc/AbstractSurfaceActiveCall.php
deleted file mode 100755
index 9d0af090ce..0000000000
--- a/src/php/lib/Grpc/AbstractSurfaceActiveCall.php
+++ /dev/null
@@ -1,98 +0,0 @@
-<?php
-
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-namespace Grpc;
-
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
-/**
- * Represents an active call that allows sending and recieving messages.
- * Subclasses restrict how data can be sent and recieved.
- */
-abstract class AbstractSurfaceActiveCall {
- private $active_call;
- private $deserialize;
-
- /**
- * Create a new surface active call.
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the remote server
- * @param callable $deserialize The function to deserialize a value
- * @param array $metadata Metadata to send with the call, if applicable
- * @param long $flags Write flags to use with this call
- */
- public function __construct(Channel $channel,
- $method,
- callable $deserialize,
- $metadata = array(),
- $flags = 0) {
- $this->active_call = new ActiveCall($channel, $method, $metadata, $flags);
- $this->deserialize = $deserialize;
- }
-
- /**
- * @return The metadata sent by the server
- */
- public function getMetadata() {
- return $this->metadata();
- }
-
- /**
- * Cancels the call
- */
- public function cancel() {
- $this->active_call->cancel();
- }
-
- protected function _read() {
- $response = $this->active_call->read();
- if ($response === null) {
- return null;
- }
- return call_user_func($this->deserialize, $response);
- }
-
- protected function _write($value) {
- return $this->active_call->write($value->serialize());
- }
-
- protected function _writesDone() {
- $this->active_call->writesDone();
- }
-
- protected function _getStatus() {
- return $this->active_call->getStatus();
- }
-}
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index fde055a3b3..cb2537fe98 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -32,7 +32,6 @@
*
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
/**
* Base class for generated client stubs. Stub methods are expected to call
@@ -42,7 +41,24 @@ class BaseStub {
private $channel;
+ // a callback function
+ private $update_metadata;
+
+ /**
+ * @param $hostname string
+ * @param $opts array
+ * - 'update_metadata': (optional) a callback function which takes in a
+ * metadata array, and returns an updated metadata array
+ */
public function __construct($hostname, $opts) {
+ $this->update_metadata = null;
+ if (isset($opts['update_metadata'])) {
+ if (is_callable($opts['update_metadata'])) {
+ $this->update_metadata = $opts['update_metadata'];
+ }
+ unset($opts['update_metadata']);
+ }
+
$this->channel = new Channel($hostname, $opts);
}
@@ -69,11 +85,14 @@ class BaseStub {
$argument,
callable $deserialize,
$metadata = array()) {
- return new SimpleSurfaceActiveCall($this->channel,
- $method,
- $deserialize,
- $argument,
- $metadata);
+ $call = new UnaryCall($this->channel, $method, $deserialize);
+ $actual_metadata = $metadata;
+ if (is_callable($this->update_metadata)) {
+ $actual_metadata = call_user_func($this->update_metadata,
+ $actual_metadata);
+ }
+ $call->start($argument, $actual_metadata);
+ return $call;
}
/**
@@ -91,11 +110,14 @@ class BaseStub {
$arguments,
callable $deserialize,
$metadata = array()) {
- return new ClientStreamingSurfaceActiveCall($this->channel,
- $method,
- $deserialize,
- $arguments,
- $metadata);
+ $call = new ClientStreamingCall($this->channel, $method, $deserialize);
+ $actual_metadata = $metadata;
+ if (is_callable($this->update_metadata)) {
+ $actual_metadata = call_user_func($this->update_metadata,
+ $actual_metadata);
+ }
+ $call->start($arguments, $actual_metadata);
+ return $call;
}
/**
@@ -112,11 +134,14 @@ class BaseStub {
$argument,
callable $deserialize,
$metadata = array()) {
- return new ServerStreamingSurfaceActiveCall($this->channel,
- $method,
- $deserialize,
- $argument,
- $metadata);
+ $call = new ServerStreamingCall($this->channel, $method, $deserialize);
+ $actual_metadata = $metadata;
+ if (is_callable($this->update_metadata)) {
+ $actual_metadata = call_user_func($this->update_metadata,
+ $actual_metadata);
+ }
+ $call->start($argument, $actual_metadata);
+ return $call;
}
/**
@@ -130,9 +155,13 @@ class BaseStub {
public function _bidiRequest($method,
callable $deserialize,
$metadata = array()) {
- return new BidiStreamingSurfaceActiveCall($this->channel,
- $method,
- $deserialize,
- $metadata);
+ $call = new BidiStreamingCall($this->channel, $method, $deserialize);
+ $actual_metadata = $metadata;
+ if (is_callable($this->update_metadata)) {
+ $actual_metadata = call_user_func($this->update_metadata,
+ $actual_metadata);
+ }
+ $call->start($actual_metadata);
+ return $call;
}
}
diff --git a/src/php/lib/Grpc/ActiveCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index af4dca50d7..76c642bef4 100755..100644
--- a/src/php/lib/Grpc/ActiveCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -32,52 +32,34 @@
*
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
/**
- * Represents an active call that allows sending and recieving binary data
+ * Represents an active call that allows for sending and recieving messages in
+ * streams in any order.
*/
-class ActiveCall {
- private $call;
- private $metadata;
-
+class BidiStreamingCall extends AbstractCall {
/**
- * Create a new active call.
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the remote server
+ * Start the call
* @param array $metadata Metadata to send with the call, if applicable
*/
- public function __construct(Channel $channel,
- $method,
- $metadata = array()) {
- $this->call = new Call($channel, $method, Timeval::inf_future());
-
- $event = $this->call->start_batch([OP_SEND_INITIAL_METADATA => $metadata]);
-
- $this->metadata = $event->metadata;
- }
-
- /**
- * @return The metadata sent by the server.
- */
- public function getMetadata() {
- return $this->metadata;
- }
-
- /**
- * Cancels the call
- */
- public function cancel() {
- $this->call->cancel();
+ public function start($metadata) {
+ $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
}
/**
- * Read a single message from the server.
- * @return The next message from the server, or null if there is none.
+ * Reads the next value from the server.
+ * @return The next value from the server, or null if there is none
*/
public function read() {
- $read_event = $this->call->start_batch([OP_RECV_MESSAGE => true]);
- return $read_event->data;
+ $batch = [OP_RECV_MESSAGE => true];
+ if ($this->metadata === null) {
+ $batch[OP_RECV_INITIAL_METADATA] = true;
+ }
+ $read_event = $this->call->startBatch($batch);
+ if ($this->metadata === null) {
+ $this->metadata = $read_event->metadata;
+ }
+ return $this->deserializeResponse($read_event->message);
}
/**
@@ -86,14 +68,14 @@ class ActiveCall {
* @param ByteBuffer $data The data to write
*/
public function write($data) {
- $this->call->start_batch([OP_SEND_MESSAGE => $data]);
+ $this->call->startBatch([OP_SEND_MESSAGE => $data->serialize()]);
}
/**
* Indicate that no more writes will be sent.
*/
public function writesDone() {
- $this->call->start_batch([OP_SEND_CLOSE_FROM_CLIENT => true]);
+ $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]);
}
/**
@@ -102,7 +84,9 @@ class ActiveCall {
* and array $metadata members
*/
public function getStatus() {
- $status_event = $this->call->start_batch([RECV_STATUS_ON_CLIENT => true]);
- return $status_event->data;
+ $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/ClientStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index d33f09fbe4..61439d3f47 100755..100644
--- a/src/php/lib/Grpc/ClientStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -32,31 +32,23 @@
*
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
/**
* Represents an active call that sends a stream of messages and then gets a
* single response.
*/
-class ClientStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class ClientStreamingCall extends AbstractCall {
/**
- * Create a new simple (single request/single response) active call.
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the remote server
- * @param callable $deserialize The function to deserialize a value
+ * 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 __construct(Channel $channel,
- $method,
- callable $deserialize,
- $arg_iter,
- $metadata = array()) {
- parent::__construct($channel, $method, $deserialize, $metadata, 0);
+ public function start($arg_iter, $metadata = array()) {
+ $event = $this->call->startBatch([OP_SEND_INITIAL_METADATA => $metadata]);
foreach($arg_iter as $arg) {
- $this->_write($arg);
+ $this->call->startBatch([OP_SEND_MESSAGE => $arg->serialize()]);
}
- $this->_writesDone();
+ $this->call->startBatch([OP_SEND_CLOSE_FROM_CLIENT => true]);
}
/**
@@ -64,8 +56,11 @@ class ClientStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
* @return [response data, status]
*/
public function wait() {
- $response = $this->_read();
- $status = $this->_getStatus();
- return array($response, $status);
+ $event = $this->call->startBatch([
+ OP_RECV_INITIAL_METADATA => true,
+ OP_RECV_MESSAGE => true,
+ OP_RECV_STATUS_ON_CLIENT => true]);
+ $this->metadata = $event->metadata;
+ return array($this->deserializeResponse($event->message), $event->status);
}
-}
+} \ No newline at end of file
diff --git a/src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index fd08e86e51..631c863345 100755..100644
--- a/src/php/lib/Grpc/ServerStreamingSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -33,42 +33,45 @@
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
/**
* Represents an active call that sends a single message and then gets a stream
* of reponses
*/
-class ServerStreamingSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class ServerStreamingCall extends AbstractCall {
/**
- * Create a new simple (single request/single response) active call.
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the remote server
- * @param callable $deserialize The function to deserialize a value
+ * Start the call
* @param $arg The argument to send
* @param array $metadata Metadata to send with the call, if applicable
*/
- public function __construct(Channel $channel,
- $method,
- callable $deserialize,
- $arg,
- $metadata = array()) {
- parent::__construct($channel, $method, $deserialize, $metadata,
- \Grpc\WRITE_BUFFER_HINT);
- $this->_write($arg);
- $this->_writesDone();
+ public function start($arg, $metadata = array()) {
+ $event = $this->call->startBatch([
+ OP_SEND_INITIAL_METADATA => $metadata,
+ OP_RECV_INITIAL_METADATA => true,
+ OP_SEND_MESSAGE => $arg->serialize(),
+ OP_SEND_CLOSE_FROM_CLIENT => true]);
+ $this->metadata = $event->metadata;
}
/**
* @return An iterator of response values
*/
public function responses() {
- while(($response = $this->_read()) !== null) {
- yield $response;
+ $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message;
+ while($response !== null) {
+ yield $this->deserializeResponse($response);
+ $response = $this->call->startBatch([OP_RECV_MESSAGE => true])->message;
}
}
+ /**
+ * Wait for the server to send the status, and return it.
+ * @return object The status object, with integer $code, string $details,
+ * and array $metadata members
+ */
public function getStatus() {
- return $this->_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/SimpleSurfaceActiveCall.php b/src/php/lib/Grpc/UnaryCall.php
index ba82f5704f..97a10a40f4 100755..100644
--- a/src/php/lib/Grpc/SimpleSurfaceActiveCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -33,30 +33,23 @@
*/
namespace Grpc;
-require_once realpath(dirname(__FILE__) . '/../autoload.php');
-
/**
* Represents an active call that sends a single message and then gets a single
* response.
*/
-class SimpleSurfaceActiveCall extends AbstractSurfaceActiveCall {
+class UnaryCall extends AbstractCall {
/**
- * Create a new simple (single request/single response) active call.
- * @param Channel $channel The channel to communicate on
- * @param string $method The method to call on the remote server
- * @param callable $deserialize The function to deserialize a value
+ * Start the call
* @param $arg The argument to send
* @param array $metadata Metadata to send with the call, if applicable
*/
- public function __construct(Channel $channel,
- $method,
- callable $deserialize,
- $arg,
- $metadata = array()) {
- parent::__construct($channel, $method, $deserialize, $metadata,
- \Grpc\WRITE_BUFFER_HINT);
- $this->_write($arg);
- $this->_writesDone();
+ public function start($arg, $metadata = array()) {
+ $event = $this->call->startBatch([
+ OP_SEND_INITIAL_METADATA => $metadata,
+ OP_RECV_INITIAL_METADATA => true,
+ OP_SEND_MESSAGE => $arg->serialize(),
+ OP_SEND_CLOSE_FROM_CLIENT => true]);
+ $this->metadata = $event->metadata;
}
/**
@@ -64,8 +57,9 @@ class SimpleSurfaceActiveCall extends AbstractSurfaceActiveCall {
* @return [response data, status]
*/
public function wait() {
- $response = $this->_read();
- $status = $this->_getStatus();
- return array($response, $status);
+ $event = $this->call->startBatch([
+ OP_RECV_MESSAGE => true,
+ 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
new file mode 100644
index 0000000000..2d2352b199
--- /dev/null
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -0,0 +1,97 @@
+<?php
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
+require 'DrSlump/Protobuf.php';
+\DrSlump\Protobuf::autoload();
+require 'math.php';
+abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
+ /* These tests require that a server exporting the math service must be
+ * running on $GRPC_TEST_HOST */
+ protected static $client;
+ protected static $timeout;
+
+ public function testSimpleRequest() {
+ $div_arg = new math\DivArgs();
+ $div_arg->setDividend(7);
+ $div_arg->setDivisor(4);
+ list($response, $status) = self::$client->Div($div_arg)->wait();
+ $this->assertSame(1, $response->getQuotient());
+ $this->assertSame(3, $response->getRemainder());
+ $this->assertSame(\Grpc\STATUS_OK, $status->code);
+ }
+
+ public function testServerStreaming() {
+ $fib_arg = new math\FibArgs();
+ $fib_arg->setLimit(7);
+ $call = self::$client->Fib($fib_arg);
+ $result_array = iterator_to_array($call->responses());
+ $extract_num = function($num){
+ return $num->getNum();
+ };
+ $values = array_map($extract_num, $result_array);
+ $this->assertSame([1, 1, 2, 3, 5, 8, 13], $values);
+ $status = $call->getStatus();
+ $this->assertSame(\Grpc\STATUS_OK, $status->code);
+ }
+
+ 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());
+ list($response, $status) = $call->wait();
+ $this->assertSame(21, $response->getNum());
+ $this->assertSame(\Grpc\STATUS_OK, $status->code);
+ }
+
+ public function testBidiStreaming() {
+ $call = self::$client->DivMany();
+ for ($i = 0; $i < 7; $i++) {
+ $div_arg = new math\DivArgs();
+ $div_arg->setDividend(2 * $i + 1);
+ $div_arg->setDivisor(2);
+ $call->write($div_arg);
+ $response = $call->read();
+ $this->assertSame($i, $response->getQuotient());
+ $this->assertSame(1, $response->getRemainder());
+ }
+ $call->writesDone();
+ $status = $call->getStatus();
+ $this->assertSame(\Grpc\STATUS_OK, $status->code);
+ }
+}
diff --git a/src/php/tests/generated_code/GeneratedCodeTest.php b/src/php/tests/generated_code/GeneratedCodeTest.php
index cb2c0e6d10..1e4742fc80 100755
--- a/src/php/tests/generated_code/GeneratedCodeTest.php
+++ b/src/php/tests/generated_code/GeneratedCodeTest.php
@@ -31,70 +31,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-require_once realpath(dirname(__FILE__) . '/../../lib/autoload.php');
-require 'DrSlump/Protobuf.php';
-\DrSlump\Protobuf::autoload();
-require 'math.php';
-class GeneratedCodeTest extends PHPUnit_Framework_TestCase {
- /* These tests require that a server exporting the math service must be
- * running on $GRPC_TEST_HOST */
- protected static $client;
- protected static $timeout;
- public static function setUpBeforeClass() {
- self::$client = new math\MathClient(getenv('GRPC_TEST_HOST'));
- }
+require 'AbstractGeneratedCodeTest.php';
- public function testSimpleRequest() {
- $div_arg = new math\DivArgs();
- $div_arg->setDividend(7);
- $div_arg->setDivisor(4);
- list($response, $status) = self::$client->Div($div_arg)->wait();
- $this->assertSame(1, $response->getQuotient());
- $this->assertSame(3, $response->getRemainder());
- $this->assertSame(\Grpc\STATUS_OK, $status->code);
- }
-
- public function testServerStreaming() {
- $fib_arg = new math\FibArgs();
- $fib_arg->setLimit(7);
- $call = self::$client->Fib($fib_arg);
- $result_array = iterator_to_array($call->responses());
- $extract_num = function($num){
- return $num->getNum();
- };
- $values = array_map($extract_num, $result_array);
- $this->assertSame([1, 1, 2, 3, 5, 8, 13], $values);
- $status = $call->getStatus();
- $this->assertSame(\Grpc\STATUS_OK, $status->code);
- }
-
- 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());
- list($response, $status) = $call->wait();
- $this->assertSame(21, $response->getNum());
- $this->assertSame(\Grpc\STATUS_OK, $status->code);
- }
-
- public function testBidiStreaming() {
- $call = self::$client->DivMany();
- for ($i = 0; $i < 7; $i++) {
- $div_arg = new math\DivArgs();
- $div_arg->setDividend(2 * $i + 1);
- $div_arg->setDivisor(2);
- $call->write($div_arg);
- $response = $call->read();
- $this->assertSame($i, $response->getQuotient());
- $this->assertSame(1, $response->getRemainder());
- }
- $call->writesDone();
- $status = $call->getStatus();
- $this->assertSame(\Grpc\STATUS_OK, $status->code);
+class GeneratedCodeTest extends AbstractGeneratedCodeTest {
+ public static function setUpBeforeClass() {
+ self::$client = new math\MathClient(new Grpc\BaseStub(
+ getenv('GRPC_TEST_HOST'), []));
}
}
diff --git a/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php
new file mode 100644
index 0000000000..f8ec1e7da8
--- /dev/null
+++ b/src/php/tests/generated_code/GeneratedCodeWithCallbackTest.php
@@ -0,0 +1,47 @@
+<?php
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+require 'AbstractGeneratedCodeTest.php';
+
+class GeneratedCodeWithCallbackTest extends AbstractGeneratedCodeTest {
+ public static function setUpBeforeClass() {
+ self::$client = new math\MathClient(new Grpc\BaseStub(
+ getenv('GRPC_TEST_HOST'), ['update_metadata' =>
+ function($a_hash,
+ $client = array()) {
+ $a_copy = $a_hash;
+ $a_copy['foo'] = ['bar'];
+ return $a_copy;
+ }]));
+ }
+}
diff --git a/src/php/tests/generated_code/math.php b/src/php/tests/generated_code/math.php
deleted file mode 100755
index e97a5cf97e..0000000000
--- a/src/php/tests/generated_code/math.php
+++ /dev/null
@@ -1,479 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: math.proto
-// Date: 2014-11-14 00:00:41
-
-namespace math {
-
- class DivArgs extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $dividend = null;
-
- /** @var int */
- public $divisor = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivArgs');
-
- // REQUIRED INT64 dividend = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "dividend";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- // REQUIRED INT64 divisor = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "divisor";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <dividend> has a value
- *
- * @return boolean
- */
- public function hasDividend(){
- return $this->_has(1);
- }
-
- /**
- * Clear <dividend> value
- *
- * @return \math\DivArgs
- */
- public function clearDividend(){
- return $this->_clear(1);
- }
-
- /**
- * Get <dividend> value
- *
- * @return int
- */
- public function getDividend(){
- return $this->_get(1);
- }
-
- /**
- * Set <dividend> value
- *
- * @param int $value
- * @return \math\DivArgs
- */
- public function setDividend( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <divisor> has a value
- *
- * @return boolean
- */
- public function hasDivisor(){
- return $this->_has(2);
- }
-
- /**
- * Clear <divisor> value
- *
- * @return \math\DivArgs
- */
- public function clearDivisor(){
- return $this->_clear(2);
- }
-
- /**
- * Get <divisor> value
- *
- * @return int
- */
- public function getDivisor(){
- return $this->_get(2);
- }
-
- /**
- * Set <divisor> value
- *
- * @param int $value
- * @return \math\DivArgs
- */
- public function setDivisor( $value){
- return $this->_set(2, $value);
- }
- }
-}
-
-namespace math {
-
- class DivReply extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $quotient = null;
-
- /** @var int */
- public $remainder = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.DivReply');
-
- // REQUIRED INT64 quotient = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "quotient";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- // REQUIRED INT64 remainder = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "remainder";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <quotient> has a value
- *
- * @return boolean
- */
- public function hasQuotient(){
- return $this->_has(1);
- }
-
- /**
- * Clear <quotient> value
- *
- * @return \math\DivReply
- */
- public function clearQuotient(){
- return $this->_clear(1);
- }
-
- /**
- * Get <quotient> value
- *
- * @return int
- */
- public function getQuotient(){
- return $this->_get(1);
- }
-
- /**
- * Set <quotient> value
- *
- * @param int $value
- * @return \math\DivReply
- */
- public function setQuotient( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <remainder> has a value
- *
- * @return boolean
- */
- public function hasRemainder(){
- return $this->_has(2);
- }
-
- /**
- * Clear <remainder> value
- *
- * @return \math\DivReply
- */
- public function clearRemainder(){
- return $this->_clear(2);
- }
-
- /**
- * Get <remainder> value
- *
- * @return int
- */
- public function getRemainder(){
- return $this->_get(2);
- }
-
- /**
- * Set <remainder> value
- *
- * @param int $value
- * @return \math\DivReply
- */
- public function setRemainder( $value){
- return $this->_set(2, $value);
- }
- }
-}
-
-namespace math {
-
- class FibArgs extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $limit = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibArgs');
-
- // OPTIONAL INT64 limit = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "limit";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <limit> has a value
- *
- * @return boolean
- */
- public function hasLimit(){
- return $this->_has(1);
- }
-
- /**
- * Clear <limit> value
- *
- * @return \math\FibArgs
- */
- public function clearLimit(){
- return $this->_clear(1);
- }
-
- /**
- * Get <limit> value
- *
- * @return int
- */
- public function getLimit(){
- return $this->_get(1);
- }
-
- /**
- * Set <limit> value
- *
- * @param int $value
- * @return \math\FibArgs
- */
- public function setLimit( $value){
- return $this->_set(1, $value);
- }
- }
-}
-
-namespace math {
-
- class Num extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $num = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.Num');
-
- // REQUIRED INT64 num = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "num";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <num> has a value
- *
- * @return boolean
- */
- public function hasNum(){
- return $this->_has(1);
- }
-
- /**
- * Clear <num> value
- *
- * @return \math\Num
- */
- public function clearNum(){
- return $this->_clear(1);
- }
-
- /**
- * Get <num> value
- *
- * @return int
- */
- public function getNum(){
- return $this->_get(1);
- }
-
- /**
- * Set <num> value
- *
- * @param int $value
- * @return \math\Num
- */
- public function setNum( $value){
- return $this->_set(1, $value);
- }
- }
-}
-
-namespace math {
-
- class FibReply extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $count = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'math.FibReply');
-
- // REQUIRED INT64 count = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "count";
- $f->type = \DrSlump\Protobuf::TYPE_INT64;
- $f->rule = \DrSlump\Protobuf::RULE_REQUIRED;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <count> has a value
- *
- * @return boolean
- */
- public function hasCount(){
- return $this->_has(1);
- }
-
- /**
- * Clear <count> value
- *
- * @return \math\FibReply
- */
- public function clearCount(){
- return $this->_clear(1);
- }
-
- /**
- * Get <count> value
- *
- * @return int
- */
- public function getCount(){
- return $this->_get(1);
- }
-
- /**
- * Set <count> value
- *
- * @param int $value
- * @return \math\FibReply
- */
- public function setCount( $value){
- return $this->_set(1, $value);
- }
- }
-}
-
-namespace math {
-
- class MathClient extends \Grpc\BaseStub {
- /**
- * @param math\DivArgs $input
- * @return math\DivReply
- */
- public function Div(\math\DivArgs $argument, $metadata = array()) {
- return $this->_simpleRequest('/Math/Div', $argument, '\math\DivReply::deserialize', $metadata);
- }
- /**
- * @param math\DivArgs $input
- * @return math\DivReply
- */
- public function DivMany($metadata = array()) {
- return $this->_bidiRequest('/Math/DivMany', '\math\DivReply::deserialize', $metadata);
- }
- /**
- * @param math\FibArgs $input
- * @return math\Num
- */
- public function Fib($argument, $metadata = array()) {
- return $this->_serverStreamRequest('/Math/Fib', $argument, '\math\Num::deserialize', $metadata);
- }
- /**
- * @param math\Num $input
- * @return math\Num
- */
- public function Sum($arguments, $metadata = array()) {
- return $this->_clientStreamRequest('/Math/Sum', $arguments, '\math\Num::deserialize', $metadata);
- }
- }
-}
diff --git a/src/php/tests/generated_code/math.proto b/src/php/tests/generated_code/math.proto
new file mode 100644
index 0000000000..e34ad5e967
--- /dev/null
+++ b/src/php/tests/generated_code/math.proto
@@ -0,0 +1,80 @@
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package math;
+
+message DivArgs {
+ optional int64 dividend = 1;
+ optional int64 divisor = 2;
+}
+
+message DivReply {
+ optional int64 quotient = 1;
+ optional int64 remainder = 2;
+}
+
+message FibArgs {
+ optional int64 limit = 1;
+}
+
+message Num {
+ optional int64 num = 1;
+}
+
+message FibReply {
+ optional int64 count = 1;
+}
+
+service Math {
+ // Div divides args.dividend by args.divisor and returns the quotient and
+ // remainder.
+ rpc Div (DivArgs) returns (DivReply) {
+ }
+
+ // DivMany accepts an arbitrary number of division args from the client stream
+ // and sends back the results in the reply stream. The stream continues until
+ // the client closes its end; the server does the same after sending all the
+ // replies. The stream ends immediately if either end aborts.
+ rpc DivMany (stream DivArgs) returns (stream DivReply) {
+ }
+
+ // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
+ // generates up to limit numbers; otherwise it continues until the call is
+ // canceled. Unlike Fib above, Fib has no final FibReply.
+ rpc Fib (FibArgs) returns (stream Num) {
+ }
+
+ // Sum sums a stream of numbers, returning the final result once the stream
+ // is closed.
+ rpc Sum (stream Num) returns (Num) {
+ }
+}
diff --git a/src/php/tests/interop/empty.php b/src/php/tests/interop/empty.php
deleted file mode 100755
index 22b11803b6..0000000000
--- a/src/php/tests/interop/empty.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/empty.proto
-// Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
- class EmptyMessage extends \DrSlump\Protobuf\Message {
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.EmptyMessage');
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
- }
-}
diff --git a/src/node/examples/pubsub/empty.proto b/src/php/tests/interop/empty.proto
index 5d6eb10841..4200d7b519 100644
--- a/src/node/examples/pubsub/empty.proto
+++ b/src/php/tests/interop/empty.proto
@@ -1,4 +1,3 @@
-// This file will be moved to a new location.
// Copyright 2015, Google Inc.
// All rights reserved.
@@ -31,14 +30,14 @@
syntax = "proto2";
-package proto2;
+package grpc.testing;
// 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 (proto2.Empty) returns (proto2.Empty) { };
+// rpc Bar (grpc.testing.EmptyMessage) returns (grpc.testing.EmptyMessage) { };
// };
//
-message Empty {}
+message EmptyMessage {}
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 82ca438169..6f81bfa6cd 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -31,7 +31,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-require_once realpath(dirname(__FILE__) . '/../../lib/autoload.php');
+require_once realpath(dirname(__FILE__) . '/../../vendor/autoload.php');
require 'DrSlump/Protobuf.php';
\DrSlump\Protobuf::autoload();
require 'empty.php';
@@ -132,8 +132,6 @@ function serverStreaming($stub) {
}
$call = $stub->StreamingOutputCall($request);
- hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
- 'Call did not complete successfully');
$i = 0;
foreach($call->responses() as $value) {
hardAssert($i < 4, 'Too many responses');
@@ -142,7 +140,10 @@ function serverStreaming($stub) {
'Payload ' . $i . ' had the wrong type');
hardAssert(strlen($payload->getBody()) === $sizes[$i],
'Response ' . $i . ' had the wrong length');
+ $i += 1;
}
+ hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
+ 'Call did not complete successfully');
}
/**
@@ -240,4 +241,7 @@ switch($args['test_case']) {
break;
case 'cancel_after_first_response':
cancelAfterFirstResponse($stub);
+ break;
+ default:
+ exit(1);
}
diff --git a/src/php/tests/interop/messages.php b/src/php/tests/interop/messages.php
deleted file mode 100755
index a626a17ab3..0000000000
--- a/src/php/tests/interop/messages.php
+++ /dev/null
@@ -1,1074 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/messages.proto
-// Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
- class PayloadType extends \DrSlump\Protobuf\Enum {
- const COMPRESSABLE = 0;
- const UNCOMPRESSABLE = 1;
- const RANDOM = 2;
- }
-}
-namespace grpc\testing {
-
- class Payload extends \DrSlump\Protobuf\Message {
-
- /** @var int - \grpc\testing\PayloadType */
- public $type = null;
-
- /** @var string */
- public $body = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.Payload');
-
- // OPTIONAL ENUM type = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "type";
- $f->type = \DrSlump\Protobuf::TYPE_ENUM;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\PayloadType';
- $descriptor->addField($f);
-
- // OPTIONAL BYTES body = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "body";
- $f->type = \DrSlump\Protobuf::TYPE_BYTES;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <type> has a value
- *
- * @return boolean
- */
- public function hasType(){
- return $this->_has(1);
- }
-
- /**
- * Clear <type> value
- *
- * @return \grpc\testing\Payload
- */
- public function clearType(){
- return $this->_clear(1);
- }
-
- /**
- * Get <type> value
- *
- * @return int - \grpc\testing\PayloadType
- */
- public function getType(){
- return $this->_get(1);
- }
-
- /**
- * Set <type> value
- *
- * @param int - \grpc\testing\PayloadType $value
- * @return \grpc\testing\Payload
- */
- public function setType( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <body> has a value
- *
- * @return boolean
- */
- public function hasBody(){
- return $this->_has(2);
- }
-
- /**
- * Clear <body> value
- *
- * @return \grpc\testing\Payload
- */
- public function clearBody(){
- return $this->_clear(2);
- }
-
- /**
- * Get <body> value
- *
- * @return string
- */
- public function getBody(){
- return $this->_get(2);
- }
-
- /**
- * Set <body> value
- *
- * @param string $value
- * @return \grpc\testing\Payload
- */
- public function setBody( $value){
- return $this->_set(2, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class SimpleRequest extends \DrSlump\Protobuf\Message {
-
- /** @var int - \grpc\testing\PayloadType */
- public $response_type = null;
-
- /** @var int */
- public $response_size = null;
-
- /** @var \grpc\testing\Payload */
- public $payload = null;
-
- /** @var boolean */
- public $fill_username = null;
-
- /** @var boolean */
- public $fill_oauth_scope = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.SimpleRequest');
-
- // OPTIONAL ENUM response_type = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "response_type";
- $f->type = \DrSlump\Protobuf::TYPE_ENUM;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\PayloadType';
- $descriptor->addField($f);
-
- // OPTIONAL INT32 response_size = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "response_size";
- $f->type = \DrSlump\Protobuf::TYPE_INT32;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- // OPTIONAL MESSAGE payload = 3
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 3;
- $f->name = "payload";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\Payload';
- $descriptor->addField($f);
-
- // OPTIONAL BOOL fill_username = 4
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 4;
- $f->name = "fill_username";
- $f->type = \DrSlump\Protobuf::TYPE_BOOL;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- // OPTIONAL BOOL fill_oauth_scope = 5
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 5;
- $f->name = "fill_oauth_scope";
- $f->type = \DrSlump\Protobuf::TYPE_BOOL;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <response_type> has a value
- *
- * @return boolean
- */
- public function hasResponseType(){
- return $this->_has(1);
- }
-
- /**
- * Clear <response_type> value
- *
- * @return \grpc\testing\SimpleRequest
- */
- public function clearResponseType(){
- return $this->_clear(1);
- }
-
- /**
- * Get <response_type> value
- *
- * @return int - \grpc\testing\PayloadType
- */
- public function getResponseType(){
- return $this->_get(1);
- }
-
- /**
- * Set <response_type> value
- *
- * @param int - \grpc\testing\PayloadType $value
- * @return \grpc\testing\SimpleRequest
- */
- public function setResponseType( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <response_size> has a value
- *
- * @return boolean
- */
- public function hasResponseSize(){
- return $this->_has(2);
- }
-
- /**
- * Clear <response_size> value
- *
- * @return \grpc\testing\SimpleRequest
- */
- public function clearResponseSize(){
- return $this->_clear(2);
- }
-
- /**
- * Get <response_size> value
- *
- * @return int
- */
- public function getResponseSize(){
- return $this->_get(2);
- }
-
- /**
- * Set <response_size> value
- *
- * @param int $value
- * @return \grpc\testing\SimpleRequest
- */
- public function setResponseSize( $value){
- return $this->_set(2, $value);
- }
-
- /**
- * Check if <payload> has a value
- *
- * @return boolean
- */
- public function hasPayload(){
- return $this->_has(3);
- }
-
- /**
- * Clear <payload> value
- *
- * @return \grpc\testing\SimpleRequest
- */
- public function clearPayload(){
- return $this->_clear(3);
- }
-
- /**
- * Get <payload> value
- *
- * @return \grpc\testing\Payload
- */
- public function getPayload(){
- return $this->_get(3);
- }
-
- /**
- * Set <payload> value
- *
- * @param \grpc\testing\Payload $value
- * @return \grpc\testing\SimpleRequest
- */
- public function setPayload(\grpc\testing\Payload $value){
- return $this->_set(3, $value);
- }
-
- /**
- * Check if <fill_username> has a value
- *
- * @return boolean
- */
- public function hasFillUsername(){
- return $this->_has(4);
- }
-
- /**
- * Clear <fill_username> value
- *
- * @return \grpc\testing\SimpleRequest
- */
- public function clearFillUsername(){
- return $this->_clear(4);
- }
-
- /**
- * Get <fill_username> value
- *
- * @return boolean
- */
- public function getFillUsername(){
- return $this->_get(4);
- }
-
- /**
- * Set <fill_username> value
- *
- * @param boolean $value
- * @return \grpc\testing\SimpleRequest
- */
- public function setFillUsername( $value){
- return $this->_set(4, $value);
- }
-
- /**
- * Check if <fill_oauth_scope> has a value
- *
- * @return boolean
- */
- public function hasFillOauthScope(){
- return $this->_has(5);
- }
-
- /**
- * Clear <fill_oauth_scope> value
- *
- * @return \grpc\testing\SimpleRequest
- */
- public function clearFillOauthScope(){
- return $this->_clear(5);
- }
-
- /**
- * Get <fill_oauth_scope> value
- *
- * @return boolean
- */
- public function getFillOauthScope(){
- return $this->_get(5);
- }
-
- /**
- * Set <fill_oauth_scope> value
- *
- * @param boolean $value
- * @return \grpc\testing\SimpleRequest
- */
- public function setFillOauthScope( $value){
- return $this->_set(5, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class SimpleResponse extends \DrSlump\Protobuf\Message {
-
- /** @var \grpc\testing\Payload */
- public $payload = null;
-
- /** @var string */
- public $username = null;
-
- /** @var string */
- public $oauth_scope = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.SimpleResponse');
-
- // OPTIONAL MESSAGE payload = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "payload";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\Payload';
- $descriptor->addField($f);
-
- // OPTIONAL STRING username = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "username";
- $f->type = \DrSlump\Protobuf::TYPE_STRING;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- // OPTIONAL STRING oauth_scope = 3
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 3;
- $f->name = "oauth_scope";
- $f->type = \DrSlump\Protobuf::TYPE_STRING;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <payload> has a value
- *
- * @return boolean
- */
- public function hasPayload(){
- return $this->_has(1);
- }
-
- /**
- * Clear <payload> value
- *
- * @return \grpc\testing\SimpleResponse
- */
- public function clearPayload(){
- return $this->_clear(1);
- }
-
- /**
- * Get <payload> value
- *
- * @return \grpc\testing\Payload
- */
- public function getPayload(){
- return $this->_get(1);
- }
-
- /**
- * Set <payload> value
- *
- * @param \grpc\testing\Payload $value
- * @return \grpc\testing\SimpleResponse
- */
- public function setPayload(\grpc\testing\Payload $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <username> has a value
- *
- * @return boolean
- */
- public function hasUsername(){
- return $this->_has(2);
- }
-
- /**
- * Clear <username> value
- *
- * @return \grpc\testing\SimpleResponse
- */
- public function clearUsername(){
- return $this->_clear(2);
- }
-
- /**
- * Get <username> value
- *
- * @return string
- */
- public function getUsername(){
- return $this->_get(2);
- }
-
- /**
- * Set <username> value
- *
- * @param string $value
- * @return \grpc\testing\SimpleResponse
- */
- public function setUsername( $value){
- return $this->_set(2, $value);
- }
-
- /**
- * Check if <oauth_scope> has a value
- *
- * @return boolean
- */
- public function hasOauthScope(){
- return $this->_has(3);
- }
-
- /**
- * Clear <oauth_scope> value
- *
- * @return \grpc\testing\SimpleResponse
- */
- public function clearOauthScope(){
- return $this->_clear(3);
- }
-
- /**
- * Get <oauth_scope> value
- *
- * @return string
- */
- public function getOauthScope(){
- return $this->_get(3);
- }
-
- /**
- * Set <oauth_scope> value
- *
- * @param string $value
- * @return \grpc\testing\SimpleResponse
- */
- public function setOauthScope( $value){
- return $this->_set(3, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class StreamingInputCallRequest extends \DrSlump\Protobuf\Message {
-
- /** @var \grpc\testing\Payload */
- public $payload = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingInputCallRequest');
-
- // OPTIONAL MESSAGE payload = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "payload";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\Payload';
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <payload> has a value
- *
- * @return boolean
- */
- public function hasPayload(){
- return $this->_has(1);
- }
-
- /**
- * Clear <payload> value
- *
- * @return \grpc\testing\StreamingInputCallRequest
- */
- public function clearPayload(){
- return $this->_clear(1);
- }
-
- /**
- * Get <payload> value
- *
- * @return \grpc\testing\Payload
- */
- public function getPayload(){
- return $this->_get(1);
- }
-
- /**
- * Set <payload> value
- *
- * @param \grpc\testing\Payload $value
- * @return \grpc\testing\StreamingInputCallRequest
- */
- public function setPayload(\grpc\testing\Payload $value){
- return $this->_set(1, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class StreamingInputCallResponse extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $aggregated_payload_size = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingInputCallResponse');
-
- // OPTIONAL INT32 aggregated_payload_size = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "aggregated_payload_size";
- $f->type = \DrSlump\Protobuf::TYPE_INT32;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <aggregated_payload_size> has a value
- *
- * @return boolean
- */
- public function hasAggregatedPayloadSize(){
- return $this->_has(1);
- }
-
- /**
- * Clear <aggregated_payload_size> value
- *
- * @return \grpc\testing\StreamingInputCallResponse
- */
- public function clearAggregatedPayloadSize(){
- return $this->_clear(1);
- }
-
- /**
- * Get <aggregated_payload_size> value
- *
- * @return int
- */
- public function getAggregatedPayloadSize(){
- return $this->_get(1);
- }
-
- /**
- * Set <aggregated_payload_size> value
- *
- * @param int $value
- * @return \grpc\testing\StreamingInputCallResponse
- */
- public function setAggregatedPayloadSize( $value){
- return $this->_set(1, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class ResponseParameters extends \DrSlump\Protobuf\Message {
-
- /** @var int */
- public $size = null;
-
- /** @var int */
- public $interval_us = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.ResponseParameters');
-
- // OPTIONAL INT32 size = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "size";
- $f->type = \DrSlump\Protobuf::TYPE_INT32;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- // OPTIONAL INT32 interval_us = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "interval_us";
- $f->type = \DrSlump\Protobuf::TYPE_INT32;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <size> has a value
- *
- * @return boolean
- */
- public function hasSize(){
- return $this->_has(1);
- }
-
- /**
- * Clear <size> value
- *
- * @return \grpc\testing\ResponseParameters
- */
- public function clearSize(){
- return $this->_clear(1);
- }
-
- /**
- * Get <size> value
- *
- * @return int
- */
- public function getSize(){
- return $this->_get(1);
- }
-
- /**
- * Set <size> value
- *
- * @param int $value
- * @return \grpc\testing\ResponseParameters
- */
- public function setSize( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <interval_us> has a value
- *
- * @return boolean
- */
- public function hasIntervalUs(){
- return $this->_has(2);
- }
-
- /**
- * Clear <interval_us> value
- *
- * @return \grpc\testing\ResponseParameters
- */
- public function clearIntervalUs(){
- return $this->_clear(2);
- }
-
- /**
- * Get <interval_us> value
- *
- * @return int
- */
- public function getIntervalUs(){
- return $this->_get(2);
- }
-
- /**
- * Set <interval_us> value
- *
- * @param int $value
- * @return \grpc\testing\ResponseParameters
- */
- public function setIntervalUs( $value){
- return $this->_set(2, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class StreamingOutputCallRequest extends \DrSlump\Protobuf\Message {
-
- /** @var int - \grpc\testing\PayloadType */
- public $response_type = null;
-
- /** @var \grpc\testing\ResponseParameters[] */
- public $response_parameters = array();
-
- /** @var \grpc\testing\Payload */
- public $payload = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingOutputCallRequest');
-
- // OPTIONAL ENUM response_type = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "response_type";
- $f->type = \DrSlump\Protobuf::TYPE_ENUM;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\PayloadType';
- $descriptor->addField($f);
-
- // REPEATED MESSAGE response_parameters = 2
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 2;
- $f->name = "response_parameters";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_REPEATED;
- $f->reference = '\grpc\testing\ResponseParameters';
- $descriptor->addField($f);
-
- // OPTIONAL MESSAGE payload = 3
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 3;
- $f->name = "payload";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\Payload';
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <response_type> has a value
- *
- * @return boolean
- */
- public function hasResponseType(){
- return $this->_has(1);
- }
-
- /**
- * Clear <response_type> value
- *
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function clearResponseType(){
- return $this->_clear(1);
- }
-
- /**
- * Get <response_type> value
- *
- * @return int - \grpc\testing\PayloadType
- */
- public function getResponseType(){
- return $this->_get(1);
- }
-
- /**
- * Set <response_type> value
- *
- * @param int - \grpc\testing\PayloadType $value
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function setResponseType( $value){
- return $this->_set(1, $value);
- }
-
- /**
- * Check if <response_parameters> has a value
- *
- * @return boolean
- */
- public function hasResponseParameters(){
- return $this->_has(2);
- }
-
- /**
- * Clear <response_parameters> value
- *
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function clearResponseParameters(){
- return $this->_clear(2);
- }
-
- /**
- * Get <response_parameters> value
- *
- * @param int $idx
- * @return \grpc\testing\ResponseParameters
- */
- public function getResponseParameters($idx = NULL){
- return $this->_get(2, $idx);
- }
-
- /**
- * Set <response_parameters> value
- *
- * @param \grpc\testing\ResponseParameters $value
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function setResponseParameters(\grpc\testing\ResponseParameters $value, $idx = NULL){
- return $this->_set(2, $value, $idx);
- }
-
- /**
- * Get all elements of <response_parameters>
- *
- * @return \grpc\testing\ResponseParameters[]
- */
- public function getResponseParametersList(){
- return $this->_get(2);
- }
-
- /**
- * Add a new element to <response_parameters>
- *
- * @param \grpc\testing\ResponseParameters $value
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function addResponseParameters(\grpc\testing\ResponseParameters $value){
- return $this->_add(2, $value);
- }
-
- /**
- * Check if <payload> has a value
- *
- * @return boolean
- */
- public function hasPayload(){
- return $this->_has(3);
- }
-
- /**
- * Clear <payload> value
- *
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function clearPayload(){
- return $this->_clear(3);
- }
-
- /**
- * Get <payload> value
- *
- * @return \grpc\testing\Payload
- */
- public function getPayload(){
- return $this->_get(3);
- }
-
- /**
- * Set <payload> value
- *
- * @param \grpc\testing\Payload $value
- * @return \grpc\testing\StreamingOutputCallRequest
- */
- public function setPayload(\grpc\testing\Payload $value){
- return $this->_set(3, $value);
- }
- }
-}
-
-namespace grpc\testing {
-
- class StreamingOutputCallResponse extends \DrSlump\Protobuf\Message {
-
- /** @var \grpc\testing\Payload */
- public $payload = null;
-
-
- /** @var \Closure[] */
- protected static $__extensions = array();
-
- public static function descriptor()
- {
- $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'grpc.testing.StreamingOutputCallResponse');
-
- // OPTIONAL MESSAGE payload = 1
- $f = new \DrSlump\Protobuf\Field();
- $f->number = 1;
- $f->name = "payload";
- $f->type = \DrSlump\Protobuf::TYPE_MESSAGE;
- $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL;
- $f->reference = '\grpc\testing\Payload';
- $descriptor->addField($f);
-
- foreach (self::$__extensions as $cb) {
- $descriptor->addField($cb(), true);
- }
-
- return $descriptor;
- }
-
- /**
- * Check if <payload> has a value
- *
- * @return boolean
- */
- public function hasPayload(){
- return $this->_has(1);
- }
-
- /**
- * Clear <payload> value
- *
- * @return \grpc\testing\StreamingOutputCallResponse
- */
- public function clearPayload(){
- return $this->_clear(1);
- }
-
- /**
- * Get <payload> value
- *
- * @return \grpc\testing\Payload
- */
- public function getPayload(){
- return $this->_get(1);
- }
-
- /**
- * Set <payload> value
- *
- * @param \grpc\testing\Payload $value
- * @return \grpc\testing\StreamingOutputCallResponse
- */
- public function setPayload(\grpc\testing\Payload $value){
- return $this->_set(1, $value);
- }
- }
-}
-
diff --git a/src/php/tests/interop/messages.proto b/src/php/tests/interop/messages.proto
new file mode 100644
index 0000000000..de0b1a2320
--- /dev/null
+++ b/src/php/tests/interop/messages.proto
@@ -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.
+
+// Message definitions to be used by integration test service definitions.
+
+syntax = "proto2";
+
+package grpc.testing;
+
+// 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.
+ optional PayloadType type = 1 [default = COMPRESSABLE];
+ // Primary contents of payload.
+ optional 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 [default = COMPRESSABLE];
+
+ // 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;
+
+ // Optional input payload sent along with the request.
+ optional Payload payload = 3;
+
+ // Whether SimpleResponse should include username.
+ optional bool fill_username = 4;
+
+ // Whether SimpleResponse should include OAuth scope.
+ optional bool fill_oauth_scope = 5;
+}
+
+// Unary response, as configured by the request.
+message SimpleResponse {
+ // Payload to increase message size.
+ optional Payload payload = 1;
+ // The user the request came from, for verifying authentication was
+ // successful when the client expected it.
+ optional string username = 2;
+ // OAuth scope.
+ optional string oauth_scope = 3;
+}
+
+// Client-streaming request.
+message StreamingInputCallRequest {
+ // Optional input payload sent along with the request.
+ optional Payload payload = 1;
+
+ // Not expecting any payload from the response.
+}
+
+// Client-streaming response.
+message StreamingInputCallResponse {
+ // Aggregated size of payloads received from the client.
+ optional 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;
+
+ // Desired interval between consecutive responses in the response stream in
+ // microseconds.
+ optional 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.
+ optional PayloadType response_type = 1 [default = COMPRESSABLE];
+
+ // Configuration for each expected response message.
+ repeated ResponseParameters response_parameters = 2;
+
+ // Optional input payload sent along with the request.
+ optional Payload payload = 3;
+}
+
+// Server-streaming response, as configured by the request and parameters.
+message StreamingOutputCallResponse {
+ // Payload to increase response size.
+ optional Payload payload = 1;
+}
diff --git a/src/php/tests/interop/test.php b/src/php/tests/interop/test.php
deleted file mode 100755
index 014bbc9517..0000000000
--- a/src/php/tests/interop/test.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-// DO NOT EDIT! Generated by Protobuf-PHP protoc plugin 1.0
-// Source: test/cpp/interop/test.proto
-// Date: 2015-01-30 23:30:46
-
-namespace grpc\testing {
-
- class TestServiceClient{
-
- private $rpc_impl;
-
- public function __construct($rpc_impl) {
- $this->rpc_impl = $rpc_impl;
- }
- /**
- * @param grpc\testing\EmptyMessage $input
- */
- public function EmptyCall(\grpc\testing\EmptyMessage $argument, $metadata = array()) {
- return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/EmptyCall', $argument, '\grpc\testing\EmptyMessage::deserialize', $metadata);
- }
- /**
- * @param grpc\testing\SimpleRequest $input
- */
- public function UnaryCall(\grpc\testing\SimpleRequest $argument, $metadata = array()) {
- return $this->rpc_impl->_simpleRequest('/grpc.testing.TestService/UnaryCall', $argument, '\grpc\testing\SimpleResponse::deserialize', $metadata);
- }
- /**
- * @param grpc\testing\StreamingOutputCallRequest $input
- */
- public function StreamingOutputCall($argument, $metadata = array()) {
- return $this->rpc_impl->_serverStreamRequest('/grpc.testing.TestService/StreamingOutputCall', $argument, '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
- }
- /**
- * @param grpc\testing\StreamingInputCallRequest $input
- */
- public function StreamingInputCall($arguments, $metadata = array()) {
- return $this->rpc_impl->_clientStreamRequest('/grpc.testing.TestService/StreamingInputCall', $arguments, '\grpc\testing\StreamingInputCallResponse::deserialize', $metadata);
- }
- /**
- * @param grpc\testing\StreamingOutputCallRequest $input
- */
- public function FullDuplexCall($metadata = array()) {
- return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/FullDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
- }
- /**
- * @param grpc\testing\StreamingOutputCallRequest $input
- */
- public function HalfDuplexCall($metadata = array()) {
- return $this->rpc_impl->_bidiRequest('/grpc.testing.TestService/HalfDuplexCall', '\grpc\testing\StreamingOutputCallResponse::deserialize', $metadata);
- }
- }
-}
diff --git a/src/php/tests/interop/test.proto b/src/php/tests/interop/test.proto
new file mode 100644
index 0000000000..39c08f3544
--- /dev/null
+++ b/src/php/tests/interop/test.proto
@@ -0,0 +1,72 @@
+
+// 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 = "proto2";
+
+import "empty.proto";
+import "messages.proto";
+
+package grpc.testing;
+
+// 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.EmptyMessage) returns (grpc.testing.EmptyMessage);
+
+ // 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/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index d361ce0030..77a2d86ce4 100755
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -37,21 +37,21 @@ class CallTest extends PHPUnit_Framework_TestCase{
public static function setUpBeforeClass() {
self::$server = new Grpc\Server([]);
- self::$port = self::$server->add_http2_port('0.0.0.0:0');
+ self::$port = self::$server->addHttp2Port('0.0.0.0:0');
}
public function setUp() {
$this->channel = new Grpc\Channel('localhost:' . self::$port, []);
$this->call = new Grpc\Call($this->channel,
'/foo',
- Grpc\Timeval::inf_future());
+ Grpc\Timeval::infFuture());
}
public function testAddEmptyMetadata() {
$batch = [
Grpc\OP_SEND_INITIAL_METADATA => []
];
- $result = $this->call->start_batch($batch);
+ $result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
}
@@ -59,7 +59,7 @@ class CallTest extends PHPUnit_Framework_TestCase{
$batch = [
Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value']]
];
- $result = $this->call->start_batch($batch);
+ $result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
}
@@ -67,7 +67,7 @@ class CallTest extends PHPUnit_Framework_TestCase{
$batch = [
Grpc\OP_SEND_INITIAL_METADATA => ['key' => ['value1', 'value2']]
];
- $result = $this->call->start_batch($batch);
+ $result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
}
@@ -76,7 +76,7 @@ class CallTest extends PHPUnit_Framework_TestCase{
Grpc\OP_SEND_INITIAL_METADATA => ['key1' => ['value1'],
'key2' => ['value2', 'value3']]
];
- $result = $this->call->start_batch($batch);
+ $result = $this->call->startBatch($batch);
$this->assertTrue($result->send_metadata);
}
}
diff --git a/src/php/tests/unit_tests/EndToEndTest.php b/src/php/tests/unit_tests/EndToEndTest.php
index 3e165b7213..296873fa8f 100755
--- a/src/php/tests/unit_tests/EndToEndTest.php
+++ b/src/php/tests/unit_tests/EndToEndTest.php
@@ -34,7 +34,7 @@
class EndToEndTest extends PHPUnit_Framework_TestCase{
public function setUp() {
$this->server = new Grpc\Server([]);
- $port = $this->server->add_http2_port('0.0.0.0:0');
+ $port = $this->server->addHttp2Port('0.0.0.0:0');
$this->channel = new Grpc\Channel('localhost:' . $port, []);
$this->server->start();
}
@@ -45,13 +45,13 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
}
public function testSimpleRequestBody() {
- $deadline = Grpc\Timeval::inf_future();
+ $deadline = Grpc\Timeval::infFuture();
$status_text = 'xyz';
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
]);
@@ -59,12 +59,12 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_metadata);
$this->assertTrue($event->send_close);
- $event = $this->server->request_call();
+ $event = $this->server->requestCall();
$this->assertSame('dummy_method', $event->method);
$this->assertSame([], $event->metadata);
$server_call = $event->call;
- $event = $server_call->start_batch([
+ $event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_STATUS_FROM_SERVER => [
'metadata' => [],
@@ -78,7 +78,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_status);
$this->assertFalse($event->cancelled);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_RECV_INITIAL_METADATA => true,
Grpc\OP_RECV_STATUS_ON_CLIENT => true
]);
@@ -94,7 +94,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
}
public function testClientServerFullRequestResponse() {
- $deadline = Grpc\Timeval::inf_future();
+ $deadline = Grpc\Timeval::infFuture();
$req_text = 'client_server_full_request_response';
$reply_text = 'reply:client_server_full_request_response';
$status_text = 'status:client_server_full_response_text';
@@ -103,7 +103,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
Grpc\OP_SEND_MESSAGE => $req_text
@@ -113,11 +113,11 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_close);
$this->assertTrue($event->send_message);
- $event = $this->server->request_call();
+ $event = $this->server->requestCall();
$this->assertSame('dummy_method', $event->method);
$server_call = $event->call;
- $event = $server_call->start_batch([
+ $event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_MESSAGE => $reply_text,
Grpc\OP_SEND_STATUS_FROM_SERVER => [
@@ -135,7 +135,7 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertFalse($event->cancelled);
$this->assertSame($req_text, $event->message);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_RECV_INITIAL_METADATA => true,
Grpc\OP_RECV_MESSAGE => true,
Grpc\OP_RECV_STATUS_ON_CLIENT => true,
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index 2d62fe9d5e..0c18cd3e91 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -40,8 +40,8 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
file_get_contents(dirname(__FILE__) . '/../data/server1.key'),
file_get_contents(dirname(__FILE__) . '/../data/server1.pem'));
$this->server = new Grpc\Server();
- $port = $this->server->add_secure_http2_port('0.0.0.0:0',
- $server_credentials);
+ $port = $this->server->addSecureHttp2Port('0.0.0.0:0',
+ $server_credentials);
$this->server->start();
$this->channel = new Grpc\Channel(
'localhost:' . $port,
@@ -57,13 +57,13 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
}
public function testSimpleRequestBody() {
- $deadline = Grpc\Timeval::inf_future();
+ $deadline = Grpc\Timeval::infFuture();
$status_text = 'xyz';
$call = new Grpc\Call($this->channel,
'dummy_method',
$deadline);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true
]);
@@ -71,12 +71,12 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_metadata);
$this->assertTrue($event->send_close);
- $event = $this->server->request_call();
+ $event = $this->server->requestCall();
$this->assertSame('dummy_method', $event->method);
$this->assertSame([], $event->metadata);
$server_call = $event->call;
- $event = $server_call->start_batch([
+ $event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_STATUS_FROM_SERVER => [
'metadata' => [],
@@ -90,7 +90,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_status);
$this->assertFalse($event->cancelled);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_RECV_INITIAL_METADATA => true,
Grpc\OP_RECV_STATUS_ON_CLIENT => true
]);
@@ -106,7 +106,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
}
public function testClientServerFullRequestResponse() {
- $deadline = Grpc\Timeval::inf_future();
+ $deadline = Grpc\Timeval::infFuture();
$req_text = 'client_server_full_request_response';
$reply_text = 'reply:client_server_full_request_response';
$status_text = 'status:client_server_full_response_text';
@@ -115,7 +115,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
'dummy_method',
$deadline);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
Grpc\OP_SEND_MESSAGE => $req_text
@@ -125,11 +125,11 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertTrue($event->send_close);
$this->assertTrue($event->send_message);
- $event = $this->server->request_call();
+ $event = $this->server->requestCall();
$this->assertSame('dummy_method', $event->method);
$server_call = $event->call;
- $event = $server_call->start_batch([
+ $event = $server_call->startBatch([
Grpc\OP_SEND_INITIAL_METADATA => [],
Grpc\OP_SEND_MESSAGE => $reply_text,
Grpc\OP_SEND_STATUS_FROM_SERVER => [
@@ -147,7 +147,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$this->assertFalse($event->cancelled);
$this->assertSame($req_text, $event->message);
- $event = $call->start_batch([
+ $event = $call->startBatch([
Grpc\OP_RECV_INITIAL_METADATA => true,
Grpc\OP_RECV_MESSAGE => true,
Grpc\OP_RECV_STATUS_ON_CLIENT => true,
diff --git a/src/php/tests/unit_tests/TimevalTest.php b/src/php/tests/unit_tests/TimevalTest.php
index d20069afa1..a8bfcf0ac4 100755
--- a/src/php/tests/unit_tests/TimevalTest.php
+++ b/src/php/tests/unit_tests/TimevalTest.php
@@ -39,14 +39,14 @@ class TimevalTest extends PHPUnit_Framework_TestCase{
public function testPastIsLessThanZero() {
$zero = Grpc\Timeval::zero();
- $past = Grpc\Timeval::inf_past();
+ $past = Grpc\Timeval::infPast();
$this->assertLessThan(0, Grpc\Timeval::compare($past, $zero));
$this->assertGreaterThan(0, Grpc\Timeval::compare($zero, $past));
}
public function testFutureIsGreaterThanZero() {
$zero = Grpc\Timeval::zero();
- $future = Grpc\Timeval::inf_future();
+ $future = Grpc\Timeval::infFuture();
$this->assertLessThan(0, Grpc\Timeval::compare($zero, $future));
$this->assertGreaterThan(0, Grpc\Timeval::compare($future, $zero));
}
@@ -56,7 +56,7 @@ class TimevalTest extends PHPUnit_Framework_TestCase{
*/
public function testNowIsBetweenZeroAndFuture() {
$zero = Grpc\Timeval::zero();
- $future = Grpc\Timeval::inf_future();
+ $future = Grpc\Timeval::infFuture();
$now = Grpc\Timeval::now();
$this->assertLessThan(0, Grpc\Timeval::compare($zero, $now));
$this->assertLessThan(0, Grpc\Timeval::compare($now, $future));
diff --git a/src/python/README.md b/src/python/README.md
index c8057be38b..82bc776732 100644
--- a/src/python/README.md
+++ b/src/python/README.md
@@ -42,7 +42,14 @@ $ tools/run_tests/run_python.sh
Installing
-----------------------
-- [Install the gRPC core](https://github.com/grpc/grpc/blob/master/INSTALL)
+- Install the gRPC core
+ - [Debian package](https://github.com/grpc/grpc/releases)
+ ```
+ $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb
+ $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb
+ $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb
+ ```
+ - [From source](https://github.com/grpc/grpc/blob/master/INSTALL)
- Install gRPC Python's dependencies
```
@@ -53,3 +60,16 @@ $ pip install -r src/python/requirements.txt
```
$ pip install src/python/src
```
+
+Packaging to PyPI
+-----------------------
+
+- Install packaging dependencies
+```
+$ pip install setuptools twine
+```
+
+- Push to PyPI
+```
+$ ../../tools/distrib/python/submit.py
+```
diff --git a/src/python/interop/interop/_insecure_interop_test.py b/src/python/interop/interop/_insecure_interop_test.py
index e4ddff1a0b..42e7a4d5c4 100644
--- a/src/python/interop/interop/_insecure_interop_test.py
+++ b/src/python/interop/interop/_insecure_interop_test.py
@@ -42,11 +42,11 @@ class InsecureInteropTest(
unittest.TestCase):
def setUp(self):
- self.server = implementations.insecure_server(
+ self.server = implementations.server(
methods.SERVICE_NAME, methods.SERVER_METHODS, 0)
self.server.start()
port = self.server.port()
- self.stub = implementations.insecure_stub(
+ self.stub = implementations.stub(
methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port)
def tearDown(self):
diff --git a/src/python/interop/interop/_interop_test_case.py b/src/python/interop/interop/_interop_test_case.py
index fec8f1915d..cd6a574e90 100644
--- a/src/python/interop/interop/_interop_test_case.py
+++ b/src/python/interop/interop/_interop_test_case.py
@@ -40,16 +40,16 @@ class InteropTestCase(object):
"""
def testEmptyUnary(self):
- methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub)
+ methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub, None)
def testLargeUnary(self):
- methods.TestCase.LARGE_UNARY.test_interoperability(self.stub)
+ methods.TestCase.LARGE_UNARY.test_interoperability(self.stub, None)
def testServerStreaming(self):
- methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub)
+ methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub, None)
def testClientStreaming(self):
- methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub)
+ methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub, None)
def testPingPong(self):
- methods.TestCase.PING_PONG.test_interoperability(self.stub)
+ methods.TestCase.PING_PONG.test_interoperability(self.stub, None)
diff --git a/src/python/interop/interop/_secure_interop_test.py b/src/python/interop/interop/_secure_interop_test.py
index 214212dca4..27e76315b6 100644
--- a/src/python/interop/interop/_secure_interop_test.py
+++ b/src/python/interop/interop/_secure_interop_test.py
@@ -45,14 +45,15 @@ class SecureInteropTest(
unittest.TestCase):
def setUp(self):
- self.server = implementations.secure_server(
+ self.server = implementations.server(
methods.SERVICE_NAME, methods.SERVER_METHODS, 0,
- resources.private_key(), resources.certificate_chain())
+ private_key=resources.private_key(),
+ certificate_chain=resources.certificate_chain())
self.server.start()
port = self.server.port()
- self.stub = implementations.secure_stub(
+ self.stub = implementations.stub(
methods.SERVICE_NAME, methods.CLIENT_METHODS, 'localhost', port,
- resources.test_root_certificates(), None, None,
+ secure=True, root_certificates=resources.test_root_certificates(),
server_host_override=_SERVER_HOST_OVERRIDE)
def tearDown(self):
diff --git a/src/python/interop/interop/client.py b/src/python/interop/interop/client.py
index fb7dfb5729..41f0d94539 100644
--- a/src/python/interop/interop/client.py
+++ b/src/python/interop/interop/client.py
@@ -30,6 +30,7 @@
"""The Python implementation of the GRPC interoperability test client."""
import argparse
+from oauth2client import client as oauth2client_client
from grpc.early_adopter import implementations
@@ -44,9 +45,6 @@ def _args():
parser.add_argument(
'--server_host', help='the host to which to connect', type=str)
parser.add_argument(
- '--server_host_override',
- help='the server host to which to claim to connect', type=str)
- parser.add_argument(
'--server_port', help='the port to which to connect', type=int)
parser.add_argument(
'--test_case', help='the test case to execute', type=str)
@@ -56,24 +54,40 @@ def _args():
parser.add_argument(
'--use_test_ca', help='replace platform root CAs with ca.pem',
action='store_true')
+ parser.add_argument(
+ '--server_host_override',
+ help='the server host to which to claim to connect', type=str)
+ parser.add_argument('--oauth_scope', help='scope for OAuth tokens', type=str)
+ parser.add_argument(
+ '--default_service_account',
+ help='email address of the default service account', type=str)
return parser.parse_args()
+def _oauth_access_token(args):
+ credentials = oauth2client_client.GoogleCredentials.get_application_default()
+ scoped_credentials = credentials.create_scoped([args.oauth_scope])
+ return scoped_credentials.get_access_token().access_token
def _stub(args):
+ if args.oauth_scope:
+ metadata_transformer = lambda x: [('Authorization', 'Bearer %s' % _oauth_access_token(args))]
+ else:
+ metadata_transformer = lambda x: []
if args.use_tls:
if args.use_test_ca:
root_certificates = resources.test_root_certificates()
else:
root_certificates = resources.prod_root_certificates()
- stub = implementations.secure_stub(
+ stub = implementations.stub(
methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
- args.server_port, root_certificates, None, None,
+ args.server_port, metadata_transformer=metadata_transformer,
+ secure=True, root_certificates=root_certificates,
server_host_override=args.server_host_override)
else:
- stub = implementations.insecure_stub(
+ stub = implementations.stub(
methods.SERVICE_NAME, methods.CLIENT_METHODS, args.server_host,
- args.server_port)
+ args.server_port, secure=False)
return stub
@@ -89,7 +103,7 @@ def _test_interoperability():
args = _args()
stub = _stub(args)
test_case = _test_case_from_arg(args.test_case)
- test_case.test_interoperability(stub)
+ test_case.test_interoperability(stub, args)
if __name__ == '__main__':
diff --git a/src/python/interop/interop/empty_pb2.py b/src/python/interop/interop/empty_pb2.py
index 732a358a36..8c1ce2f13e 100644
--- a/src/python/interop/interop/empty_pb2.py
+++ b/src/python/interop/interop/empty_pb2.py
@@ -57,6 +57,7 @@ Empty = _reflection.GeneratedProtocolMessageType('Empty', (_message.Message,), d
_sym_db.RegisterMessage(Empty)
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/messages_pb2.py b/src/python/interop/interop/messages_pb2.py
index d449a99140..0bf3d86a31 100644
--- a/src/python/interop/interop/messages_pb2.py
+++ b/src/python/interop/interop/messages_pb2.py
@@ -441,6 +441,7 @@ StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('Streamin
_sym_db.RegisterMessage(StreamingOutputCallResponse)
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
index 79550a3789..909b738bd1 100644
--- a/src/python/interop/interop/methods.py
+++ b/src/python/interop/interop/methods.py
@@ -30,8 +30,12 @@
"""Implementations of interoperability test methods."""
import enum
+import json
+import os
import threading
+from oauth2client import client as oauth2client_client
+
from grpc.framework.alpha import utilities
from interop import empty_pb2
@@ -150,19 +154,12 @@ SERVER_METHODS = {
}
-def _empty_unary(stub):
- with stub:
- response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT)
- if not isinstance(response, empty_pb2.Empty):
- raise TypeError(
- 'response is of type "%s", not empty_pb2.Empty!', type(response))
-
-
-def _large_unary(stub):
+def _large_unary_common_behavior(stub, fill_username, fill_oauth_scope):
with stub:
request = messages_pb2.SimpleRequest(
response_type=messages_pb2.COMPRESSABLE, response_size=314159,
- payload=messages_pb2.Payload(body=b'\x00' * 271828))
+ payload=messages_pb2.Payload(body=b'\x00' * 271828),
+ fill_username=fill_username, fill_oauth_scope=fill_oauth_scope)
response_future = stub.UnaryCall.async(request, _TIMEOUT)
response = response_future.result()
if response.payload.type is not messages_pb2.COMPRESSABLE:
@@ -171,6 +168,19 @@ def _large_unary(stub):
if len(response.payload.body) != 314159:
raise ValueError(
'response body of incorrect size %d!' % len(response.payload.body))
+ return response
+
+
+def _empty_unary(stub):
+ with stub:
+ response = stub.EmptyCall(empty_pb2.Empty(), _TIMEOUT)
+ if not isinstance(response, empty_pb2.Empty):
+ raise TypeError(
+ 'response is of type "%s", not empty_pb2.Empty!', type(response))
+
+
+def _large_unary(stub):
+ _large_unary_common_behavior(stub, False, False)
def _client_streaming(stub):
@@ -266,6 +276,28 @@ def _ping_pong(stub):
pipe.close()
+def _compute_engine_creds(stub, args):
+ response = _large_unary_common_behavior(stub, True, True)
+ if args.default_service_account != response.username:
+ raise ValueError(
+ 'expected username %s, got %s' % (args.default_service_account,
+ response.username))
+
+
+def _service_account_creds(stub, args):
+ json_key_filename = os.environ[
+ oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
+ wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
+ response = _large_unary_common_behavior(stub, True, True)
+ if wanted_email != response.username:
+ raise ValueError(
+ 'expected username %s, got %s' % (wanted_email, response.username))
+ if args.oauth_scope.find(response.oauth_scope) == -1:
+ raise ValueError(
+ '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'
@@ -273,8 +305,10 @@ class TestCase(enum.Enum):
SERVER_STREAMING = 'server_streaming'
CLIENT_STREAMING = 'client_streaming'
PING_PONG = 'ping_pong'
+ COMPUTE_ENGINE_CREDS = 'compute_engine_creds'
+ SERVICE_ACCOUNT_CREDS = 'service_account_creds'
- def test_interoperability(self, stub):
+ def test_interoperability(self, stub, args):
if self is TestCase.EMPTY_UNARY:
_empty_unary(stub)
elif self is TestCase.LARGE_UNARY:
@@ -285,5 +319,9 @@ class TestCase(enum.Enum):
_client_streaming(stub)
elif self is TestCase.PING_PONG:
_ping_pong(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)
else:
raise NotImplementedError('Test case "%s" not implemented!' % self.name)
diff --git a/src/python/interop/interop/server.py b/src/python/interop/interop/server.py
index 5791203743..a67d412038 100644
--- a/src/python/interop/interop/server.py
+++ b/src/python/interop/interop/server.py
@@ -53,11 +53,11 @@ def serve():
if args.use_tls:
private_key = resources.private_key()
certificate_chain = resources.certificate_chain()
- server = implementations.secure_server(
- methods.SERVICE_NAME, methods.SERVER_METHODS, args.port, private_key,
- certificate_chain)
+ server = implementations.server(
+ methods.SERVICE_NAME, methods.SERVER_METHODS, args.port,
+ private_key=private_key, certificate_chain=certificate_chain)
else:
- server = implementations.insecure_server(
+ server = implementations.server(
methods.SERVICE_NAME, methods.SERVER_METHODS, args.port)
server.start()
diff --git a/src/python/interop/interop/test_pb2.py b/src/python/interop/interop/test_pb2.py
index e86094611b..71325d5a9f 100644
--- a/src/python/interop/interop/test_pb2.py
+++ b/src/python/interop/interop/test_pb2.py
@@ -29,121 +29,150 @@ _sym_db.RegisterFileDescriptor(DESCRIPTOR)
-from grpc.framework.face import demonstration as _face_testing
-from grpc.framework.face import interfaces as _face_interfaces
-class TestServiceService(object):
+import abc
+from grpc.early_adopter import implementations
+from grpc.framework.alpha import utilities
+class EarlyAdopterTestServiceServicer(object):
"""<fill me in later!>"""
- def __init__(self):
- pass
-class TestServiceServicer(object):
- """<fill me in later!>"""
- def EmptyCall(self, arg):
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def EmptyCall(self, request, context):
+ raise NotImplementedError()
+ @abc.abstractmethod
+ def UnaryCall(self, request, context):
raise NotImplementedError()
- def UnaryCall(self, arg):
+ @abc.abstractmethod
+ def StreamingOutputCall(self, request, context):
raise NotImplementedError()
- def StreamingOutputCall(self, arg):
+ @abc.abstractmethod
+ def StreamingInputCall(self, request_iterator, context):
raise NotImplementedError()
- def StreamingInputCall(self, arg):
+ @abc.abstractmethod
+ def FullDuplexCall(self, request_iterator, context):
raise NotImplementedError()
- def FullDuplexCall(self, arg):
+ @abc.abstractmethod
+ def HalfDuplexCall(self, request_iterator, context):
+ raise NotImplementedError()
+class EarlyAdopterTestServiceServer(object):
+ """<fill me in later!>"""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def start(self):
raise NotImplementedError()
- def HalfDuplexCall(self, arg):
+ @abc.abstractmethod
+ def stop(self):
raise NotImplementedError()
-class TestServiceStub(object):
+class EarlyAdopterTestServiceStub(object):
"""<fill me in later!>"""
- def EmptyCall(self, arg):
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def EmptyCall(self, request):
raise NotImplementedError()
EmptyCall.async = None
- def UnaryCall(self, arg):
+ @abc.abstractmethod
+ def UnaryCall(self, request):
raise NotImplementedError()
UnaryCall.async = None
- def StreamingOutputCall(self, arg):
+ @abc.abstractmethod
+ def StreamingOutputCall(self, request):
raise NotImplementedError()
StreamingOutputCall.async = None
- def StreamingInputCall(self, arg):
+ @abc.abstractmethod
+ def StreamingInputCall(self, request_iterator):
raise NotImplementedError()
StreamingInputCall.async = None
- def FullDuplexCall(self, arg):
+ @abc.abstractmethod
+ def FullDuplexCall(self, request_iterator):
raise NotImplementedError()
FullDuplexCall.async = None
- def HalfDuplexCall(self, arg):
+ @abc.abstractmethod
+ def HalfDuplexCall(self, request_iterator):
raise NotImplementedError()
HalfDuplexCall.async = None
-class _TestServiceStub(TestServiceStub):
- def __init__(self, face_stub, default_timeout):
- self._face_stub = face_stub
- self._default_timeout = default_timeout
- stub_self = self
- class EmptyCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.blocking_value_in_value_out("EmptyCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.future_value_in_value_out("EmptyCall", arg, stub_self._default_timeout)
- self.EmptyCall = EmptyCall()
- class UnaryCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.blocking_value_in_value_out("UnaryCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.future_value_in_value_out("UnaryCall", arg, stub_self._default_timeout)
- self.UnaryCall = UnaryCall()
- class StreamingOutputCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.inline_value_in_stream_out("StreamingOutputCall", arg, stub_self._default_timeout)
- self.StreamingOutputCall = StreamingOutputCall()
- class StreamingInputCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.blocking_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.future_stream_in_value_out("StreamingInputCall", arg, stub_self._default_timeout)
- self.StreamingInputCall = StreamingInputCall()
- class FullDuplexCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.inline_stream_in_stream_out("FullDuplexCall", arg, stub_self._default_timeout)
- self.FullDuplexCall = FullDuplexCall()
- class HalfDuplexCall(object):
- def __call__(self, arg):
- return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout)
- def async(self, arg):
- return stub_self._face_stub.inline_stream_in_stream_out("HalfDuplexCall", arg, stub_self._default_timeout)
- self.HalfDuplexCall = HalfDuplexCall()
-def mock_TestService(servicer, default_timeout):
- value_in_value_out = {}
- value_in_stream_out = {}
- stream_in_value_out = {}
- stream_in_stream_out = {}
- class EmptyCall(_face_interfaces.InlineValueInValueOutMethod):
- def service(self, request, context):
- return servicer.EmptyCall(request)
- value_in_value_out['EmptyCall'] = EmptyCall()
- class UnaryCall(_face_interfaces.InlineValueInValueOutMethod):
- def service(self, request, context):
- return servicer.UnaryCall(request)
- value_in_value_out['UnaryCall'] = UnaryCall()
- class StreamingOutputCall(_face_interfaces.InlineValueInStreamOutMethod):
- def service(self, request, context):
- return servicer.StreamingOutputCall(request)
- value_in_stream_out['StreamingOutputCall'] = StreamingOutputCall()
- class StreamingInputCall(_face_interfaces.InlineStreamInValueOutMethod):
- def service(self, request, context):
- return servicer.StreamingInputCall(request)
- stream_in_value_out['StreamingInputCall'] = StreamingInputCall()
- class FullDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod):
- def service(self, request, context):
- return servicer.FullDuplexCall(request)
- stream_in_stream_out['FullDuplexCall'] = FullDuplexCall()
- class HalfDuplexCall(_face_interfaces.InlineStreamInStreamOutMethod):
- def service(self, request, context):
- return servicer.HalfDuplexCall(request)
- stream_in_stream_out['HalfDuplexCall'] = HalfDuplexCall()
- face_linked_pair = _face_testing.server_and_stub(default_timeout,inline_value_in_value_out_methods=value_in_value_out,inline_value_in_stream_out_methods=value_in_stream_out,inline_stream_in_value_out_methods=stream_in_value_out,inline_stream_in_stream_out_methods=stream_in_stream_out)
- class LinkedPair(object):
- def __init__(self, server, stub):
- self.server = server
- self.stub = stub
- stub = _TestServiceStub(face_linked_pair.stub, default_timeout)
- return LinkedPair(None, stub)
+def early_adopter_create_TestService_server(servicer, port, private_key=None, certificate_chain=None):
+ import test.cpp.interop.empty_pb2
+ import test.cpp.interop.empty_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ method_service_descriptions = {
+ "EmptyCall": utilities.unary_unary_service_description(
+ servicer.EmptyCall,
+ test.cpp.interop.empty_pb2.Empty.FromString,
+ test.cpp.interop.empty_pb2.Empty.SerializeToString,
+ ),
+ "FullDuplexCall": utilities.stream_stream_service_description(
+ servicer.FullDuplexCall,
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ ),
+ "HalfDuplexCall": utilities.stream_stream_service_description(
+ servicer.HalfDuplexCall,
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ ),
+ "StreamingInputCall": utilities.stream_unary_service_description(
+ servicer.StreamingInputCall,
+ test.cpp.interop.messages_pb2.StreamingInputCallRequest.FromString,
+ test.cpp.interop.messages_pb2.StreamingInputCallResponse.SerializeToString,
+ ),
+ "StreamingOutputCall": utilities.unary_stream_service_description(
+ servicer.StreamingOutputCall,
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.FromString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.SerializeToString,
+ ),
+ "UnaryCall": utilities.unary_unary_service_description(
+ servicer.UnaryCall,
+ test.cpp.interop.messages_pb2.SimpleRequest.FromString,
+ test.cpp.interop.messages_pb2.SimpleResponse.SerializeToString,
+ ),
+ }
+ return implementations.server("grpc.testing.TestService", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
+def early_adopter_create_TestService_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
+ import test.cpp.interop.empty_pb2
+ import test.cpp.interop.empty_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ import test.cpp.interop.messages_pb2
+ method_invocation_descriptions = {
+ "EmptyCall": utilities.unary_unary_invocation_description(
+ test.cpp.interop.empty_pb2.Empty.SerializeToString,
+ test.cpp.interop.empty_pb2.Empty.FromString,
+ ),
+ "FullDuplexCall": utilities.stream_stream_invocation_description(
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+ ),
+ "HalfDuplexCall": utilities.stream_stream_invocation_description(
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+ ),
+ "StreamingInputCall": utilities.stream_unary_invocation_description(
+ test.cpp.interop.messages_pb2.StreamingInputCallRequest.SerializeToString,
+ test.cpp.interop.messages_pb2.StreamingInputCallResponse.FromString,
+ ),
+ "StreamingOutputCall": utilities.unary_stream_invocation_description(
+ test.cpp.interop.messages_pb2.StreamingOutputCallRequest.SerializeToString,
+ test.cpp.interop.messages_pb2.StreamingOutputCallResponse.FromString,
+ ),
+ "UnaryCall": utilities.unary_unary_invocation_description(
+ test.cpp.interop.messages_pb2.SimpleRequest.SerializeToString,
+ test.cpp.interop.messages_pb2.SimpleResponse.FromString,
+ ),
+ }
+ return implementations.stub("grpc.testing.TestService", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
# @@protoc_insertion_point(module_scope)
diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py
index 6db5435090..502fcbedd8 100644
--- a/src/python/interop/setup.py
+++ b/src/python/interop/setup.py
@@ -29,7 +29,7 @@
"""A setup module for the GRPC Python interop testing package."""
-from distutils import core as _core
+import setuptools
_PACKAGES = (
'interop',
@@ -45,9 +45,13 @@ _PACKAGE_DATA = {
'credentials/server1.pem',]
}
-_INSTALL_REQUIRES = ['grpc-2015>=0.0.1']
+_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.4.0a4']
-_core.setup(
- name='interop', version='0.0.1', packages=_PACKAGES,
- package_dir=_PACKAGE_DIRECTORIES, package_data=_PACKAGE_DATA,
- install_requires=_INSTALL_REQUIRES)
+setuptools.setup(
+ name='interop',
+ version='0.0.1',
+ packages=_PACKAGES,
+ package_dir=_PACKAGE_DIRECTORIES,
+ package_data=_PACKAGE_DATA,
+ install_requires=_INSTALL_REQUIRES
+)
diff --git a/src/python/src/.gitignore b/src/python/src/.gitignore
new file mode 100644
index 0000000000..bc15a52cf1
--- /dev/null
+++ b/src/python/src/.gitignore
@@ -0,0 +1,3 @@
+MANIFEST
+grpcio.egg-info/
+dist/
diff --git a/src/python/src/MANIFEST.in b/src/python/src/MANIFEST.in
new file mode 100644
index 0000000000..6f32db0548
--- /dev/null
+++ b/src/python/src/MANIFEST.in
@@ -0,0 +1 @@
+graft grpc
diff --git a/src/python/src/README.rst b/src/python/src/README.rst
new file mode 100644
index 0000000000..bc1815febc
--- /dev/null
+++ b/src/python/src/README.rst
@@ -0,0 +1,27 @@
+gRPC Python
+===========
+
+Package for GRPC Python.
+
+Dependencies
+------------
+
+Ensure that you have installed GRPC core.
+
+On debian linux systems, install from our released deb package:
+
+::
+
+ $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc_0.5.0_amd64.deb
+ $ wget https://github.com/grpc/grpc/releases/download/release-0_5_0/libgrpc-dev_0.5.0_amd64.deb
+ $ sudo dpkg -i libgrpc_0.5.0_amd64.deb libgrpc-dev_0.5.0_amd64.deb
+
+Otherwise, install from source:
+
+::
+
+ git clone https://github.com/grpc/grpc.git
+ cd grpc
+ ./configure
+ make && make install
+
diff --git a/src/python/src/grpc/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py
index 437a6730cd..6e15adbda8 100644
--- a/src/python/src/grpc/_adapter/_c_test.py
+++ b/src/python/src/grpc/_adapter/_c_test.py
@@ -83,8 +83,11 @@ class _CTest(unittest.TestCase):
_c.init()
channel = _c.Channel('%s:%d' % (host, 12345), None)
- call = _c.Call(channel, method, host, time.time() + _TIMEOUT)
+ completion_queue = _c.CompletionQueue()
+ call = _c.Call(channel, completion_queue, method, host,
+ time.time() + _TIMEOUT)
del call
+ del completion_queue
del channel
_c.shut_down()
diff --git a/src/python/src/grpc/_adapter/_call.c b/src/python/src/grpc/_adapter/_call.c
index d8806e5680..d833268fc9 100644
--- a/src/python/src/grpc/_adapter/_call.c
+++ b/src/python/src/grpc/_adapter/_call.c
@@ -36,90 +36,166 @@
#include <math.h>
#include <Python.h>
#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
#include "grpc/_adapter/_channel.h"
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_error.h"
+#include "grpc/_adapter/_tag.h"
-static int pygrpc_call_init(Call *self, PyObject *args, PyObject *kwds) {
- const PyObject *channel;
+static PyObject *pygrpc_call_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+ Call *self = (Call *)type->tp_alloc(type, 0);
+ Channel *channel;
+ CompletionQueue *completion_queue;
const char *method;
const char *host;
double deadline;
- static char *kwlist[] = {"channel", "method", "host", "deadline", NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!ssd:Call", kwlist,
- &pygrpc_ChannelType, &channel, &method,
- &host, &deadline)) {
- return -1;
+ static char *kwlist[] = {"channel", "completion_queue",
+ "method", "host", "deadline", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "O!O!ssd:Call", kwlist,
+ &pygrpc_ChannelType, &channel,
+ &pygrpc_CompletionQueueType, &completion_queue,
+ &method, &host, &deadline)) {
+ return NULL;
}
/* TODO(nathaniel): Hoist the gpr_timespec <-> PyFloat arithmetic into its own
* function with its own test coverage.
*/
- self->c_call = grpc_channel_create_call_old(
- ((Channel *)channel)->c_channel, method, host,
+ self->c_call = grpc_channel_create_call(
+ channel->c_channel, completion_queue->c_completion_queue, method, host,
gpr_time_from_nanos(deadline * GPR_NS_PER_SEC));
-
- return 0;
+ self->completion_queue = completion_queue;
+ Py_INCREF(self->completion_queue);
+ self->channel = channel;
+ Py_INCREF(self->channel);
+ grpc_call_details_init(&self->call_details);
+ grpc_metadata_array_init(&self->recv_metadata);
+ grpc_metadata_array_init(&self->recv_trailing_metadata);
+ self->send_metadata = NULL;
+ self->send_metadata_count = 0;
+ self->send_trailing_metadata = NULL;
+ self->send_trailing_metadata_count = 0;
+ self->send_message = NULL;
+ self->recv_message = NULL;
+ self->adding_to_trailing = 0;
+
+ return (PyObject *)self;
}
static void pygrpc_call_dealloc(Call *self) {
if (self->c_call != NULL) {
grpc_call_destroy(self->c_call);
}
+ Py_XDECREF(self->completion_queue);
+ Py_XDECREF(self->channel);
+ Py_XDECREF(self->server);
+ grpc_call_details_destroy(&self->call_details);
+ grpc_metadata_array_destroy(&self->recv_metadata);
+ grpc_metadata_array_destroy(&self->recv_trailing_metadata);
+ if (self->send_message) {
+ grpc_byte_buffer_destroy(self->send_message);
+ }
+ if (self->recv_message) {
+ grpc_byte_buffer_destroy(self->recv_message);
+ }
+ gpr_free(self->status_details);
+ gpr_free(self->send_metadata);
+ gpr_free(self->send_trailing_metadata);
self->ob_type->tp_free((PyObject *)self);
}
static const PyObject *pygrpc_call_invoke(Call *self, PyObject *args) {
- const PyObject *completion_queue;
- const PyObject *metadata_tag;
- const PyObject *finish_tag;
+ PyObject *completion_queue;
+ PyObject *metadata_tag;
+ PyObject *finish_tag;
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_init_metadata_tag;
+ pygrpc_tag *c_metadata_tag;
+ pygrpc_tag *c_finish_tag;
+ grpc_op send_initial_metadata;
+ grpc_op recv_initial_metadata;
+ grpc_op recv_status_on_client;
if (!(PyArg_ParseTuple(args, "O!OO:invoke", &pygrpc_CompletionQueueType,
&completion_queue, &metadata_tag, &finish_tag))) {
return NULL;
}
-
- call_error = grpc_call_invoke_old(
- self->c_call, ((CompletionQueue *)completion_queue)->c_completion_queue,
- (void *)metadata_tag, (void *)finish_tag, 0);
-
+ send_initial_metadata.op = GRPC_OP_SEND_INITIAL_METADATA;
+ send_initial_metadata.data.send_initial_metadata.metadata = self->send_metadata;
+ send_initial_metadata.data.send_initial_metadata.count = self->send_metadata_count;
+ recv_initial_metadata.op = GRPC_OP_RECV_INITIAL_METADATA;
+ recv_initial_metadata.data.recv_initial_metadata = &self->recv_metadata;
+ recv_status_on_client.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+ recv_status_on_client.data.recv_status_on_client.trailing_metadata = &self->recv_trailing_metadata;
+ recv_status_on_client.data.recv_status_on_client.status = &self->status;
+ recv_status_on_client.data.recv_status_on_client.status_details = &self->status_details;
+ recv_status_on_client.data.recv_status_on_client.status_details_capacity = &self->status_details_capacity;
+ c_init_metadata_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self);
+ c_metadata_tag = pygrpc_tag_new(PYGRPC_CLIENT_METADATA_READ, metadata_tag, self);
+ c_finish_tag = pygrpc_tag_new(PYGRPC_FINISHED_CLIENT, finish_tag, self);
+
+ call_error = grpc_call_start_batch(self->c_call, &send_initial_metadata, 1, c_init_metadata_tag);
result = pygrpc_translate_call_error(call_error);
- if (result != NULL) {
- Py_INCREF(metadata_tag);
- Py_INCREF(finish_tag);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_init_metadata_tag);
+ pygrpc_tag_destroy(c_metadata_tag);
+ pygrpc_tag_destroy(c_finish_tag);
+ return result;
}
+ call_error = grpc_call_start_batch(self->c_call, &recv_initial_metadata, 1, c_metadata_tag);
+ result = pygrpc_translate_call_error(call_error);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_metadata_tag);
+ pygrpc_tag_destroy(c_finish_tag);
+ return result;
+ }
+ call_error = grpc_call_start_batch(self->c_call, &recv_status_on_client, 1, c_finish_tag);
+ result = pygrpc_translate_call_error(call_error);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_finish_tag);
+ return result;
+ }
+
return result;
}
static const PyObject *pygrpc_call_write(Call *self, PyObject *args) {
const char *bytes;
int length;
- const PyObject *tag;
+ PyObject *tag;
gpr_slice slice;
grpc_byte_buffer *byte_buffer;
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_tag;
+ grpc_op op;
if (!(PyArg_ParseTuple(args, "s#O:write", &bytes, &length, &tag))) {
return NULL;
}
+ c_tag = pygrpc_tag_new(PYGRPC_WRITE_ACCEPTED, tag, self);
slice = gpr_slice_from_copied_buffer(bytes, length);
byte_buffer = grpc_byte_buffer_create(&slice, 1);
gpr_slice_unref(slice);
- call_error =
- grpc_call_start_write_old(self->c_call, byte_buffer, (void *)tag, 0);
+ if (self->send_message) {
+ grpc_byte_buffer_destroy(self->send_message);
+ }
+ self->send_message = byte_buffer;
+
+ op.op = GRPC_OP_SEND_MESSAGE;
+ op.data.send_message = self->send_message;
- grpc_byte_buffer_destroy(byte_buffer);
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
- if (result != NULL) {
- Py_INCREF(tag);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
}
return result;
}
@@ -127,54 +203,102 @@ static const PyObject *pygrpc_call_write(Call *self, PyObject *args) {
static const PyObject *pygrpc_call_complete(Call *self, PyObject *tag) {
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self);
+ grpc_op op;
- call_error = grpc_call_writes_done_old(self->c_call, (void *)tag);
+ op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
- if (result != NULL) {
- Py_INCREF(tag);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
}
return result;
}
static const PyObject *pygrpc_call_accept(Call *self, PyObject *args) {
- const PyObject *completion_queue;
- const PyObject *tag;
+ PyObject *completion_queue;
+ PyObject *tag;
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_tag;
+ grpc_op op;
if (!(PyArg_ParseTuple(args, "O!O:accept", &pygrpc_CompletionQueueType,
&completion_queue, &tag))) {
return NULL;
}
- call_error = grpc_call_server_accept_old(
- self->c_call, ((CompletionQueue *)completion_queue)->c_completion_queue,
- (void *)tag);
- result = pygrpc_translate_call_error(call_error);
+ op.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+ op.data.recv_close_on_server.cancelled = &self->cancelled;
+ c_tag = pygrpc_tag_new(PYGRPC_FINISHED_SERVER, tag, self);
- if (result != NULL) {
- Py_INCREF(tag);
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
+ result = pygrpc_translate_call_error(call_error);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
}
-
return result;
}
+static const PyObject *pygrpc_call_add_metadata(Call *self, PyObject *args) {
+ const char* key = NULL;
+ const char* value = NULL;
+ int value_length = 0;
+ grpc_metadata metadata;
+ if (!PyArg_ParseTuple(args, "ss#", &key, &value, &value_length)) {
+ return NULL;
+ }
+ metadata.key = key;
+ metadata.value = value;
+ metadata.value_length = value_length;
+ if (self->adding_to_trailing) {
+ self->send_trailing_metadata = gpr_realloc(self->send_trailing_metadata, (self->send_trailing_metadata_count + 1) * sizeof(grpc_metadata));
+ self->send_trailing_metadata[self->send_trailing_metadata_count] = metadata;
+ self->send_trailing_metadata_count = self->send_trailing_metadata_count + 1;
+ } else {
+ self->send_metadata = gpr_realloc(self->send_metadata, (self->send_metadata_count + 1) * sizeof(grpc_metadata));
+ self->send_metadata[self->send_metadata_count] = metadata;
+ self->send_metadata_count = self->send_metadata_count + 1;
+ }
+ return pygrpc_translate_call_error(GRPC_CALL_OK);
+}
+
static const PyObject *pygrpc_call_premetadata(Call *self) {
- /* TODO(nathaniel): Metadata support. */
- return pygrpc_translate_call_error(
- grpc_call_server_end_initial_metadata_old(self->c_call, 0));
+ grpc_op op;
+ grpc_call_error call_error;
+ const PyObject *result;
+ pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_INITIAL_METADATA, NULL, self);
+ op.op = GRPC_OP_SEND_INITIAL_METADATA;
+ op.data.send_initial_metadata.metadata = self->send_metadata;
+ op.data.send_initial_metadata.count = self->send_metadata_count;
+ self->adding_to_trailing = 1;
+
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
+ result = pygrpc_translate_call_error(call_error);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
+ }
+ return result;
}
static const PyObject *pygrpc_call_read(Call *self, PyObject *tag) {
+ grpc_op op;
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_tag = pygrpc_tag_new(PYGRPC_READ, tag, self);
- call_error = grpc_call_start_read_old(self->c_call, (void *)tag);
-
+ op.op = GRPC_OP_RECV_MESSAGE;
+ if (self->recv_message) {
+ grpc_byte_buffer_destroy(self->recv_message);
+ self->recv_message = NULL;
+ }
+ op.data.recv_message = &self->recv_message;
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
- if (result != NULL) {
- Py_INCREF(tag);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
}
return result;
}
@@ -183,15 +307,18 @@ static const PyObject *pygrpc_call_status(Call *self, PyObject *args) {
PyObject *status;
PyObject *code;
PyObject *details;
- const PyObject *tag;
+ PyObject *tag;
grpc_status_code c_code;
char *c_message;
grpc_call_error call_error;
const PyObject *result;
+ pygrpc_tag *c_tag;
+ grpc_op op;
if (!(PyArg_ParseTuple(args, "OO:status", &status, &tag))) {
return NULL;
}
+ c_tag = pygrpc_tag_new(PYGRPC_FINISH_ACCEPTED, tag, self);
code = PyObject_GetAttrString(status, "code");
if (code == NULL) {
@@ -213,13 +340,21 @@ static const PyObject *pygrpc_call_status(Call *self, PyObject *args) {
if (c_message == NULL) {
return NULL;
}
-
- call_error = grpc_call_start_write_status_old(self->c_call, c_code, c_message,
- (void *)tag);
-
+ if (self->status_details) {
+ gpr_free(self->status_details);
+ }
+ self->status_details = gpr_malloc(strlen(c_message)+1);
+ strcpy(self->status_details, c_message);
+ op.op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+ op.data.send_status_from_server.trailing_metadata_count = self->send_trailing_metadata_count;
+ op.data.send_status_from_server.trailing_metadata = self->send_trailing_metadata;
+ op.data.send_status_from_server.status = c_code;
+ op.data.send_status_from_server.status_details = self->status_details;
+
+ call_error = grpc_call_start_batch(self->c_call, &op, 1, c_tag);
result = pygrpc_translate_call_error(call_error);
- if (result != NULL) {
- Py_INCREF(tag);
+ if (result == NULL) {
+ pygrpc_tag_destroy(c_tag);
}
return result;
}
@@ -236,6 +371,11 @@ static PyMethodDef methods[] = {
{"complete", (PyCFunction)pygrpc_call_complete, METH_O,
"Complete writes to this call."},
{"accept", (PyCFunction)pygrpc_call_accept, METH_VARARGS, "Accept an RPC."},
+ {"add_metadata", (PyCFunction)pygrpc_call_add_metadata, METH_VARARGS,
+ "Add metadata to the call. May not be called after invoke on the client "
+ "side. On the server side: when called before premetadata it provides "
+ "'leading' metadata, when called after premetadata but before status it "
+ "provides 'trailing metadata'; may not be called after status."},
{"premetadata", (PyCFunction)pygrpc_call_premetadata, METH_VARARGS,
"Indicate the end of leading metadata in the response."},
{"read", (PyCFunction)pygrpc_call_read, METH_O,
@@ -282,9 +422,9 @@ PyTypeObject pygrpc_CallType = {
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
- (initproc)pygrpc_call_init, /* tp_init */
+ 0, /* tp_init */
0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
+ pygrpc_call_new, /* tp_new */
};
int pygrpc_add_call(PyObject *module) {
diff --git a/src/python/src/grpc/_adapter/_call.h b/src/python/src/grpc/_adapter/_call.h
index a936e23023..fb9160901b 100644
--- a/src/python/src/grpc/_adapter/_call.h
+++ b/src/python/src/grpc/_adapter/_call.h
@@ -37,7 +37,38 @@
#include <Python.h>
#include <grpc/grpc.h>
-typedef struct { PyObject_HEAD grpc_call *c_call; } Call;
+#include "grpc/_adapter/_completion_queue.h"
+#include "grpc/_adapter/_channel.h"
+#include "grpc/_adapter/_server.h"
+
+typedef struct {
+ PyObject_HEAD
+
+ CompletionQueue *completion_queue;
+ Channel *channel;
+ Server *server;
+
+ /* Legacy state. */
+ grpc_call_details call_details;
+ grpc_metadata_array recv_metadata;
+ grpc_metadata_array recv_trailing_metadata;
+ grpc_metadata *send_metadata;
+ size_t send_metadata_count;
+ grpc_metadata *send_trailing_metadata;
+ size_t send_trailing_metadata_count;
+ int adding_to_trailing;
+
+ grpc_byte_buffer *send_message;
+ grpc_byte_buffer *recv_message;
+
+ grpc_status_code status;
+ char *status_details;
+ size_t status_details_capacity;
+
+ int cancelled;
+
+ grpc_call *c_call;
+} Call;
PyTypeObject pygrpc_CallType;
diff --git a/src/python/src/grpc/_adapter/_channel.h b/src/python/src/grpc/_adapter/_channel.h
index 6241ccd02e..afc0f80359 100644
--- a/src/python/src/grpc/_adapter/_channel.h
+++ b/src/python/src/grpc/_adapter/_channel.h
@@ -37,7 +37,10 @@
#include <Python.h>
#include <grpc/grpc.h>
-typedef struct { PyObject_HEAD grpc_channel *c_channel; } Channel;
+typedef struct {
+ PyObject_HEAD
+ grpc_channel *c_channel;
+} Channel;
PyTypeObject pygrpc_ChannelType;
diff --git a/src/python/src/grpc/_adapter/_client_credentials.h b/src/python/src/grpc/_adapter/_client_credentials.h
index 664dc80d75..bb9f7f0c3a 100644
--- a/src/python/src/grpc/_adapter/_client_credentials.h
+++ b/src/python/src/grpc/_adapter/_client_credentials.h
@@ -38,7 +38,8 @@
#include <grpc/grpc_security.h>
typedef struct {
- PyObject_HEAD grpc_credentials *c_client_credentials;
+ PyObject_HEAD
+ grpc_credentials *c_client_credentials;
} ClientCredentials;
PyTypeObject pygrpc_ClientCredentialsType;
diff --git a/src/python/src/grpc/_adapter/_completion_queue.c b/src/python/src/grpc/_adapter/_completion_queue.c
index b56ca1926e..5f1cb2a3a6 100644
--- a/src/python/src/grpc/_adapter/_completion_queue.c
+++ b/src/python/src/grpc/_adapter/_completion_queue.c
@@ -38,6 +38,7 @@
#include <grpc/support/alloc.h>
#include "grpc/_adapter/_call.h"
+#include "grpc/_adapter/_tag.h"
static PyObject *status_class;
static PyObject *service_acceptance_class;
@@ -115,71 +116,93 @@ static PyObject *pygrpc_status_code(grpc_status_code c_status_code) {
}
}
+static PyObject *pygrpc_metadata_collection_get(
+ grpc_metadata *metadata_elements, size_t count) {
+ PyObject *metadata = PyList_New(count);
+ size_t i;
+ for (i = 0; i < count; ++i) {
+ grpc_metadata elem = metadata_elements[i];
+ PyObject *key = PyString_FromString(elem.key);
+ PyObject *value = PyString_FromStringAndSize(elem.value, elem.value_length);
+ PyObject* kvp = PyTuple_Pack(2, key, value);
+ /* n.b. PyList_SetItem *steals* a reference to the set element. */
+ PyList_SetItem(metadata, i, kvp);
+ Py_DECREF(key);
+ Py_DECREF(value);
+ }
+ return metadata;
+}
+
static PyObject *pygrpc_stop_event_args(grpc_event *c_event) {
- return PyTuple_Pack(7, stop_event_kind, Py_None, Py_None, Py_None,
- Py_None, Py_None, Py_None);
+ return PyTuple_Pack(8, stop_event_kind, Py_None, Py_None, Py_None,
+ Py_None, Py_None, Py_None, Py_None);
}
static PyObject *pygrpc_write_event_args(grpc_event *c_event) {
- PyObject *write_accepted =
- c_event->data.write_accepted == GRPC_OP_OK ? Py_True : Py_False;
- return PyTuple_Pack(7, write_event_kind, (PyObject *)c_event->tag,
- write_accepted, Py_None, Py_None, Py_None, Py_None);
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+ PyObject *write_accepted = Py_True;
+ return PyTuple_Pack(8, write_event_kind, user_tag,
+ write_accepted, Py_None, Py_None, Py_None, Py_None,
+ Py_None);
}
static PyObject *pygrpc_complete_event_args(grpc_event *c_event) {
- PyObject *complete_accepted =
- c_event->data.finish_accepted == GRPC_OP_OK ? Py_True : Py_False;
- return PyTuple_Pack(7, complete_event_kind, (PyObject *)c_event->tag,
- Py_None, complete_accepted, Py_None, Py_None, Py_None);
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+ PyObject *complete_accepted = Py_True;
+ return PyTuple_Pack(8, complete_event_kind, user_tag,
+ Py_None, complete_accepted, Py_None, Py_None, Py_None,
+ Py_None);
}
static PyObject *pygrpc_service_event_args(grpc_event *c_event) {
- if (c_event->data.server_rpc_new.method == NULL) {
- return PyTuple_Pack(7, service_event_kind, c_event->tag,
- Py_None, Py_None, Py_None, Py_None, Py_None);
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+ if (tag->call->call_details.method == NULL) {
+ return PyTuple_Pack(
+ 8, service_event_kind, user_tag, Py_None, Py_None, Py_None, Py_None,
+ Py_None, Py_None);
} else {
PyObject *method = NULL;
PyObject *host = NULL;
PyObject *service_deadline = NULL;
- Call *call = NULL;
PyObject *service_acceptance = NULL;
+ PyObject *metadata = NULL;
PyObject *event_args = NULL;
- method = PyBytes_FromString(c_event->data.server_rpc_new.method);
+ method = PyBytes_FromString(tag->call->call_details.method);
if (method == NULL) {
goto error;
}
- host = PyBytes_FromString(c_event->data.server_rpc_new.host);
+ host = PyBytes_FromString(tag->call->call_details.host);
if (host == NULL) {
goto error;
}
service_deadline =
- pygrpc_as_py_time(&c_event->data.server_rpc_new.deadline);
+ pygrpc_as_py_time(&tag->call->call_details.deadline);
if (service_deadline == NULL) {
goto error;
}
- call = PyObject_New(Call, &pygrpc_CallType);
- if (call == NULL) {
- goto error;
- }
- call->c_call = c_event->call;
-
service_acceptance =
- PyObject_CallFunctionObjArgs(service_acceptance_class, call, method,
- host, service_deadline, NULL);
+ PyObject_CallFunctionObjArgs(service_acceptance_class, tag->call,
+ method, host, service_deadline, NULL);
if (service_acceptance == NULL) {
goto error;
}
- event_args = PyTuple_Pack(7, service_event_kind,
- (PyObject *)c_event->tag, Py_None, Py_None,
- service_acceptance, Py_None, Py_None);
+ metadata = pygrpc_metadata_collection_get(
+ tag->call->recv_metadata.metadata,
+ tag->call->recv_metadata.count);
+ event_args = PyTuple_Pack(8, service_event_kind,
+ user_tag, Py_None, Py_None,
+ service_acceptance, Py_None, Py_None,
+ metadata);
Py_DECREF(service_acceptance);
+ Py_DECREF(metadata);
error:
- Py_XDECREF(call);
Py_XDECREF(method);
Py_XDECREF(host);
Py_XDECREF(service_deadline);
@@ -189,9 +212,11 @@ error:
}
static PyObject *pygrpc_read_event_args(grpc_event *c_event) {
- if (c_event->data.read == NULL) {
- return PyTuple_Pack(7, read_event_kind, (PyObject *)c_event->tag,
- Py_None, Py_None, Py_None, Py_None, Py_None);
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+ if (tag->call->recv_message == NULL) {
+ return PyTuple_Pack(8, read_event_kind, user_tag,
+ Py_None, Py_None, Py_None, Py_None, Py_None, Py_None);
} else {
size_t length;
size_t offset;
@@ -201,8 +226,8 @@ static PyObject *pygrpc_read_event_args(grpc_event *c_event) {
PyObject *bytes;
PyObject *event_args;
- length = grpc_byte_buffer_length(c_event->data.read);
- reader = grpc_byte_buffer_reader_create(c_event->data.read);
+ length = grpc_byte_buffer_length(tag->call->recv_message);
+ reader = grpc_byte_buffer_reader_create(tag->call->recv_message);
c_bytes = gpr_malloc(length);
offset = 0;
while (grpc_byte_buffer_reader_next(reader, &slice)) {
@@ -216,34 +241,74 @@ static PyObject *pygrpc_read_event_args(grpc_event *c_event) {
if (bytes == NULL) {
return NULL;
}
- event_args = PyTuple_Pack(7, read_event_kind, (PyObject *)c_event->tag,
- Py_None, Py_None, Py_None, bytes, Py_None);
+ event_args = PyTuple_Pack(8, read_event_kind, user_tag,
+ Py_None, Py_None, Py_None, bytes, Py_None,
+ Py_None);
Py_DECREF(bytes);
return event_args;
}
}
static PyObject *pygrpc_metadata_event_args(grpc_event *c_event) {
- /* TODO(nathaniel): Actual transmission of metadata. */
- return PyTuple_Pack(7, metadata_event_kind, (PyObject *)c_event->tag,
- Py_None, Py_None, Py_None, Py_None, Py_None);
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+ PyObject *metadata = pygrpc_metadata_collection_get(
+ tag->call->recv_metadata.metadata,
+ tag->call->recv_metadata.count);
+ PyObject* result = PyTuple_Pack(
+ 8, metadata_event_kind, user_tag, Py_None, Py_None,
+ Py_None, Py_None, Py_None, metadata);
+ Py_DECREF(metadata);
+ return result;
+}
+
+static PyObject *pygrpc_finished_server_event_args(grpc_event *c_event) {
+ PyObject *code;
+ PyObject *details;
+ PyObject *status;
+ PyObject *event_args;
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
+
+ code = pygrpc_status_code(tag->call->cancelled ? GRPC_STATUS_CANCELLED : GRPC_STATUS_OK);
+ if (code == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!");
+ return NULL;
+ }
+ details = PyBytes_FromString("");
+ if (details == NULL) {
+ return NULL;
+ }
+ status = PyObject_CallFunctionObjArgs(status_class, code, details, NULL);
+ Py_DECREF(details);
+ if (status == NULL) {
+ return NULL;
+ }
+ event_args = PyTuple_Pack(8, finish_event_kind, user_tag,
+ Py_None, Py_None, Py_None, Py_None, status,
+ Py_None);
+ Py_DECREF(status);
+ return event_args;
}
-static PyObject *pygrpc_finished_event_args(grpc_event *c_event) {
+static PyObject *pygrpc_finished_client_event_args(grpc_event *c_event) {
PyObject *code;
PyObject *details;
PyObject *status;
PyObject *event_args;
+ PyObject *metadata;
+ pygrpc_tag *tag = (pygrpc_tag *)(c_event->tag);
+ PyObject *user_tag = tag->user_tag;
- code = pygrpc_status_code(c_event->data.finished.status);
+ code = pygrpc_status_code(tag->call->status);
if (code == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Unrecognized status code!");
return NULL;
}
- if (c_event->data.finished.details == NULL) {
+ if (tag->call->status_details == NULL) {
details = PyBytes_FromString("");
} else {
- details = PyBytes_FromString(c_event->data.finished.details);
+ details = PyBytes_FromString(tag->call->status_details);
}
if (details == NULL) {
return NULL;
@@ -253,9 +318,14 @@ static PyObject *pygrpc_finished_event_args(grpc_event *c_event) {
if (status == NULL) {
return NULL;
}
- event_args = PyTuple_Pack(7, finish_event_kind, (PyObject *)c_event->tag,
- Py_None, Py_None, Py_None, Py_None, status);
+ metadata = pygrpc_metadata_collection_get(
+ tag->call->recv_trailing_metadata.metadata,
+ tag->call->recv_trailing_metadata.count);
+ event_args = PyTuple_Pack(8, finish_event_kind, user_tag,
+ Py_None, Py_None, Py_None, Py_None, status,
+ metadata);
Py_DECREF(status);
+ Py_DECREF(metadata);
return event_args;
}
@@ -310,28 +380,51 @@ static PyObject *pygrpc_completion_queue_get(CompletionQueue *self,
Py_RETURN_NONE;
}
+ pygrpc_tag *tag = (pygrpc_tag *)c_event->tag;
+
switch (c_event->type) {
case GRPC_QUEUE_SHUTDOWN:
event_args = pygrpc_stop_event_args(c_event);
break;
- case GRPC_WRITE_ACCEPTED:
- event_args = pygrpc_write_event_args(c_event);
- break;
- case GRPC_FINISH_ACCEPTED:
- event_args = pygrpc_complete_event_args(c_event);
- break;
- case GRPC_SERVER_RPC_NEW:
- event_args = pygrpc_service_event_args(c_event);
- break;
- case GRPC_READ:
- event_args = pygrpc_read_event_args(c_event);
- break;
- case GRPC_CLIENT_METADATA_READ:
- event_args = pygrpc_metadata_event_args(c_event);
- break;
- case GRPC_FINISHED:
- event_args = pygrpc_finished_event_args(c_event);
+ case GRPC_OP_COMPLETE: {
+ if (!tag) {
+ PyErr_SetString(PyExc_Exception, "Unrecognized event type!");
+ return NULL;
+ }
+ switch (tag->type) {
+ case PYGRPC_INITIAL_METADATA:
+ if (tag) {
+ pygrpc_tag_destroy(tag);
+ }
+ grpc_event_finish(c_event);
+ return pygrpc_completion_queue_get(self, args);
+ case PYGRPC_WRITE_ACCEPTED:
+ event_args = pygrpc_write_event_args(c_event);
+ break;
+ case PYGRPC_FINISH_ACCEPTED:
+ event_args = pygrpc_complete_event_args(c_event);
+ break;
+ case PYGRPC_SERVER_RPC_NEW:
+ event_args = pygrpc_service_event_args(c_event);
+ break;
+ case PYGRPC_READ:
+ event_args = pygrpc_read_event_args(c_event);
+ break;
+ case PYGRPC_CLIENT_METADATA_READ:
+ event_args = pygrpc_metadata_event_args(c_event);
+ break;
+ case PYGRPC_FINISHED_CLIENT:
+ event_args = pygrpc_finished_client_event_args(c_event);
+ break;
+ case PYGRPC_FINISHED_SERVER:
+ event_args = pygrpc_finished_server_event_args(c_event);
+ break;
+ default:
+ PyErr_SetString(PyExc_Exception, "Unrecognized op event type!");
+ return NULL;
+ }
break;
+ }
default:
PyErr_SetString(PyExc_Exception, "Unrecognized event type!");
return NULL;
@@ -344,7 +437,9 @@ static PyObject *pygrpc_completion_queue_get(CompletionQueue *self,
event = PyObject_CallObject(event_class, event_args);
Py_DECREF(event_args);
- Py_XDECREF((PyObject *)c_event->tag);
+ if (tag) {
+ pygrpc_tag_destroy(tag);
+ }
grpc_event_finish(c_event);
return event;
diff --git a/src/python/src/grpc/_adapter/_completion_queue.h b/src/python/src/grpc/_adapter/_completion_queue.h
index 8e5ee9f406..9b377d15d9 100644
--- a/src/python/src/grpc/_adapter/_completion_queue.h
+++ b/src/python/src/grpc/_adapter/_completion_queue.h
@@ -38,7 +38,8 @@
#include <grpc/grpc.h>
typedef struct {
- PyObject_HEAD grpc_completion_queue *c_completion_queue;
+ PyObject_HEAD
+ grpc_completion_queue *c_completion_queue;
} CompletionQueue;
PyTypeObject pygrpc_CompletionQueueType;
diff --git a/src/python/src/grpc/_adapter/_datatypes.py b/src/python/src/grpc/_adapter/_datatypes.py
index e271ec83b9..3b22784243 100644
--- a/src/python/src/grpc/_adapter/_datatypes.py
+++ b/src/python/src/grpc/_adapter/_datatypes.py
@@ -70,7 +70,7 @@ class Event(
collections.namedtuple(
'Event',
['kind', 'tag', 'write_accepted', 'complete_accepted',
- 'service_acceptance', 'bytes', 'status'])):
+ 'service_acceptance', 'bytes', 'status', 'metadata'])):
"""Describes an event emitted from a completion queue."""
@enum.unique
diff --git a/src/python/src/grpc/_adapter/_links_test.py b/src/python/src/grpc/_adapter/_links_test.py
index cfdcc2c4bc..4987be389a 100644
--- a/src/python/src/grpc/_adapter/_links_test.py
+++ b/src/python/src/grpc/_adapter/_links_test.py
@@ -43,6 +43,14 @@ _IDENTITY = lambda x: x
_TIMEOUT = 2
+# TODO(nathaniel): End-to-end metadata testing.
+def _transform_metadata(unused_metadata):
+ return (
+ ('one unused key', 'one unused value'),
+ ('another unused key', 'another unused value'),
+)
+
+
class RoundTripTest(unittest.TestCase):
def setUp(self):
@@ -76,7 +84,8 @@ class RoundTripTest(unittest.TestCase):
rear_link = rear.RearLink(
'localhost', port, self.rear_link_pool, {test_method: None},
- {test_method: None}, False, None, None, None)
+ {test_method: None}, False, None, None, None,
+ metadata_transformer=_transform_metadata)
rear_link.join_fore_link(test_fore_link)
test_fore_link.join_rear_link(rear_link)
rear_link.start()
diff --git a/src/python/src/grpc/_adapter/_low_test.py b/src/python/src/grpc/_adapter/_low_test.py
index b04ac1c950..09c4660a2b 100644
--- a/src/python/src/grpc/_adapter/_low_test.py
+++ b/src/python/src/grpc/_adapter/_low_test.py
@@ -43,7 +43,6 @@ _BYTE_SEQUENCE_SEQUENCE = tuple(
bytes(bytearray((row + column) % 256 for column in range(row)))
for row in range(_STREAM_LENGTH))
-
class LonelyClientTest(unittest.TestCase):
def testLonelyClient(self):
@@ -57,7 +56,7 @@ class LonelyClientTest(unittest.TestCase):
completion_queue = _low.CompletionQueue()
channel = _low.Channel('%s:%d' % (host, port), None)
- client_call = _low.Call(channel, method, host, deadline)
+ client_call = _low.Call(channel, completion_queue, method, host, deadline)
client_call.invoke(completion_queue, metadata_tag, finish_tag)
first_event = completion_queue.get(after_deadline)
@@ -115,6 +114,18 @@ class EchoTest(unittest.TestCase):
def _perform_echo_test(self, test_data):
method = 'test method'
details = 'test details'
+ server_leading_metadata_key = 'my_server_leading_key'
+ server_leading_metadata_value = 'my_server_leading_value'
+ server_trailing_metadata_key = 'my_server_trailing_key'
+ server_trailing_metadata_value = 'my_server_trailing_value'
+ client_metadata_key = 'my_client_key'
+ client_metadata_value = 'my_client_value'
+ server_leading_binary_metadata_key = 'my_server_leading_key-bin'
+ server_leading_binary_metadata_value = b'\0'*2047
+ server_trailing_binary_metadata_key = 'my_server_trailing_key-bin'
+ server_trailing_binary_metadata_value = b'\0'*2047
+ client_binary_metadata_key = 'my_client_key-bin'
+ client_binary_metadata_value = b'\0'*2047
deadline = _FUTURE
metadata_tag = object()
finish_tag = object()
@@ -127,7 +138,11 @@ class EchoTest(unittest.TestCase):
server_data = []
client_data = []
- client_call = _low.Call(self.channel, method, self.host, deadline)
+ client_call = _low.Call(self.channel, self.client_completion_queue,
+ method, self.host, deadline)
+ client_call.add_metadata(client_metadata_key, client_metadata_value)
+ client_call.add_metadata(client_binary_metadata_key,
+ client_binary_metadata_value)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
@@ -139,15 +154,31 @@ class EchoTest(unittest.TestCase):
self.assertEqual(method, service_accepted.service_acceptance.method)
self.assertEqual(self.host, service_accepted.service_acceptance.host)
self.assertIsNotNone(service_accepted.service_acceptance.call)
+ metadata = dict(service_accepted.metadata)
+ self.assertIn(client_metadata_key, metadata)
+ self.assertEqual(client_metadata_value, metadata[client_metadata_key])
+ self.assertIn(client_binary_metadata_key, metadata)
+ self.assertEqual(client_binary_metadata_value,
+ metadata[client_binary_metadata_key])
server_call = service_accepted.service_acceptance.call
server_call.accept(self.server_completion_queue, finish_tag)
+ server_call.add_metadata(server_leading_metadata_key,
+ server_leading_metadata_value)
+ server_call.add_metadata(server_leading_binary_metadata_key,
+ server_leading_binary_metadata_value)
server_call.premetadata()
metadata_accepted = self.client_completion_queue.get(_FUTURE)
self.assertIsNotNone(metadata_accepted)
self.assertEqual(_low.Event.Kind.METADATA_ACCEPTED, metadata_accepted.kind)
self.assertEqual(metadata_tag, metadata_accepted.tag)
- # TODO(nathaniel): Test transmission and reception of metadata.
+ metadata = dict(metadata_accepted.metadata)
+ self.assertIn(server_leading_metadata_key, metadata)
+ self.assertEqual(server_leading_metadata_value,
+ metadata[server_leading_metadata_key])
+ self.assertIn(server_leading_binary_metadata_key, metadata)
+ self.assertEqual(server_leading_binary_metadata_value,
+ metadata[server_leading_binary_metadata_key])
for datum in test_data:
client_call.write(datum, write_tag)
@@ -194,6 +225,11 @@ class EchoTest(unittest.TestCase):
self.assertEqual(read_tag, read_accepted.tag)
self.assertIsNone(read_accepted.bytes)
+ server_call.add_metadata(server_trailing_metadata_key,
+ server_trailing_metadata_value)
+ server_call.add_metadata(server_trailing_binary_metadata_key,
+ server_trailing_binary_metadata_value)
+
server_call.status(_low.Status(_low.Code.OK, details), status_tag)
server_terminal_event_one = self.server_completion_queue.get(_FUTURE)
server_terminal_event_two = self.server_completion_queue.get(_FUTURE)
@@ -229,6 +265,13 @@ class EchoTest(unittest.TestCase):
self.assertEqual(_low.Event.Kind.FINISH, finish_accepted.kind)
self.assertEqual(finish_tag, finish_accepted.tag)
self.assertEqual(_low.Status(_low.Code.OK, details), finish_accepted.status)
+ metadata = dict(finish_accepted.metadata)
+ self.assertIn(server_trailing_metadata_key, metadata)
+ self.assertEqual(server_trailing_metadata_value,
+ metadata[server_trailing_metadata_key])
+ self.assertIn(server_trailing_binary_metadata_key, metadata)
+ self.assertEqual(server_trailing_binary_metadata_value,
+ metadata[server_trailing_binary_metadata_key])
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
@@ -253,7 +296,6 @@ class EchoTest(unittest.TestCase):
def testManyManyByteEchoes(self):
self._perform_echo_test(_BYTE_SEQUENCE_SEQUENCE)
-
class CancellationTest(unittest.TestCase):
def setUp(self):
@@ -294,7 +336,8 @@ class CancellationTest(unittest.TestCase):
server_data = []
client_data = []
- client_call = _low.Call(self.channel, method, self.host, deadline)
+ client_call = _low.Call(self.channel, self.client_completion_queue,
+ method, self.host, deadline)
client_call.invoke(self.client_completion_queue, metadata_tag, finish_tag)
@@ -349,7 +392,8 @@ class CancellationTest(unittest.TestCase):
finish_event = self.client_completion_queue.get(_FUTURE)
self.assertEqual(_low.Event.Kind.FINISH, finish_event.kind)
- self.assertEqual(_low.Status(_low.Code.CANCELLED, ''), finish_event.status)
+ self.assertEqual(_low.Status(_low.Code.CANCELLED, 'Cancelled'),
+ finish_event.status)
server_timeout_none_event = self.server_completion_queue.get(0)
self.assertIsNone(server_timeout_none_event)
diff --git a/src/python/src/grpc/_adapter/_server.c b/src/python/src/grpc/_adapter/_server.c
index 181b6c21fc..e7c5917724 100644
--- a/src/python/src/grpc/_adapter/_server.c
+++ b/src/python/src/grpc/_adapter/_server.c
@@ -36,12 +36,14 @@
#include <Python.h>
#include <grpc/grpc.h>
+#include "grpc/_adapter/_call.h"
#include "grpc/_adapter/_completion_queue.h"
#include "grpc/_adapter/_error.h"
#include "grpc/_adapter/_server_credentials.h"
+#include "grpc/_adapter/_tag.h"
static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) {
- const PyObject *completion_queue;
+ CompletionQueue *completion_queue;
static char *kwlist[] = {"completion_queue", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!:Server", kwlist,
@@ -50,7 +52,9 @@ static int pygrpc_server_init(Server *self, PyObject *args, PyObject *kwds) {
return -1;
}
self->c_server = grpc_server_create(
- ((CompletionQueue *)completion_queue)->c_completion_queue, NULL);
+ completion_queue->c_completion_queue, NULL);
+ self->completion_queue = completion_queue;
+ Py_INCREF(completion_queue);
return 0;
}
@@ -58,6 +62,7 @@ static void pygrpc_server_dealloc(Server *self) {
if (self->c_server != NULL) {
grpc_server_destroy(self->c_server);
}
+ Py_XDECREF(self->completion_queue);
self->ob_type->tp_free((PyObject *)self);
}
@@ -109,8 +114,15 @@ static PyObject *pygrpc_server_start(Server *self) {
static const PyObject *pygrpc_server_service(Server *self, PyObject *tag) {
grpc_call_error call_error;
const PyObject *result;
-
- call_error = grpc_server_request_call_old(self->c_server, (void *)tag);
+ pygrpc_tag *c_tag = pygrpc_tag_new_server_rpc_call(tag);
+ c_tag->call->completion_queue = self->completion_queue;
+ c_tag->call->server = self;
+ Py_INCREF(c_tag->call->completion_queue);
+ Py_INCREF(c_tag->call->server);
+ call_error = grpc_server_request_call(
+ self->c_server, &c_tag->call->c_call, &c_tag->call->call_details,
+ &c_tag->call->recv_metadata, self->completion_queue->c_completion_queue,
+ c_tag);
result = pygrpc_translate_call_error(call_error);
if (result != NULL) {
diff --git a/src/python/src/grpc/_adapter/_server.h b/src/python/src/grpc/_adapter/_server.h
index 0c517e3715..d31d4e678b 100644
--- a/src/python/src/grpc/_adapter/_server.h
+++ b/src/python/src/grpc/_adapter/_server.h
@@ -37,7 +37,14 @@
#include <Python.h>
#include <grpc/grpc.h>
-typedef struct { PyObject_HEAD grpc_server *c_server; } Server;
+#include "grpc/_adapter/_completion_queue.h"
+
+typedef struct {
+ PyObject_HEAD
+
+ CompletionQueue *completion_queue;
+ grpc_server *c_server;
+} Server;
int pygrpc_add_server(PyObject *module);
diff --git a/src/python/src/grpc/_adapter/_server_credentials.h b/src/python/src/grpc/_adapter/_server_credentials.h
index 2e56efdcd9..6090404bd9 100644
--- a/src/python/src/grpc/_adapter/_server_credentials.h
+++ b/src/python/src/grpc/_adapter/_server_credentials.h
@@ -38,7 +38,8 @@
#include <grpc/grpc_security.h>
typedef struct {
- PyObject_HEAD grpc_server_credentials *c_server_credentials;
+ PyObject_HEAD
+ grpc_server_credentials *c_server_credentials;
} ServerCredentials;
PyTypeObject pygrpc_ServerCredentialsType;
diff --git a/src/python/src/grpc/_adapter/_tag.c b/src/python/src/grpc/_adapter/_tag.c
new file mode 100644
index 0000000000..9c6ee19d79
--- /dev/null
+++ b/src/python/src/grpc/_adapter/_tag.c
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "grpc/_adapter/_tag.h"
+
+#include <Python.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag,
+ Call *call) {
+ pygrpc_tag *self = (pygrpc_tag *)gpr_malloc(sizeof(pygrpc_tag));
+ memset(self, 0, sizeof(pygrpc_tag));
+ if (user_tag == NULL) {
+ self->user_tag = Py_None;
+ } else {
+ self->user_tag = user_tag;
+ }
+ Py_INCREF(self->user_tag);
+ self->type = type;
+ self->call = call;
+ Py_INCREF(call);
+ return self;
+}
+
+pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag) {
+ return pygrpc_tag_new(PYGRPC_SERVER_RPC_NEW, user_tag,
+ (Call *)pygrpc_CallType.tp_alloc(&pygrpc_CallType, 0));
+}
+
+void pygrpc_tag_destroy(pygrpc_tag *self) {
+ Py_XDECREF(self->user_tag);
+ Py_XDECREF(self->call);
+ gpr_free(self);
+}
diff --git a/src/python/src/grpc/_adapter/_tag.h b/src/python/src/grpc/_adapter/_tag.h
new file mode 100644
index 0000000000..82987ea102
--- /dev/null
+++ b/src/python/src/grpc/_adapter/_tag.h
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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 _ADAPTER__TAG_H_
+#define _ADAPTER__TAG_H_
+
+#include <Python.h>
+#include <grpc/grpc.h>
+
+#include "grpc/_adapter/_call.h"
+#include "grpc/_adapter/_completion_queue.h"
+
+/* grpc_completion_type is becoming meaningless in grpc_event; this is a partial
+ replacement for its descriptive functionality until Python can move its whole
+ C and C adapter stack to more closely resemble the core batching API. */
+typedef enum {
+ PYGRPC_SERVER_RPC_NEW = 0,
+ PYGRPC_INITIAL_METADATA = 1,
+ PYGRPC_READ = 2,
+ PYGRPC_WRITE_ACCEPTED = 3,
+ PYGRPC_FINISH_ACCEPTED = 4,
+ PYGRPC_CLIENT_METADATA_READ = 5,
+ PYGRPC_FINISHED_CLIENT = 6,
+ PYGRPC_FINISHED_SERVER = 7,
+} pygrpc_tag_type;
+
+typedef struct {
+ pygrpc_tag_type type;
+ PyObject *user_tag;
+
+ Call *call;
+} pygrpc_tag;
+
+pygrpc_tag *pygrpc_tag_new(pygrpc_tag_type type, PyObject *user_tag,
+ Call *call);
+pygrpc_tag *pygrpc_tag_new_server_rpc_call(PyObject *user_tag);
+void pygrpc_tag_destroy(pygrpc_tag *self);
+
+#endif /* _ADAPTER__TAG_H_ */
+
diff --git a/src/python/src/grpc/_adapter/rear.py b/src/python/src/grpc/_adapter/rear.py
index f19321c426..dd0a486117 100644
--- a/src/python/src/grpc/_adapter/rear.py
+++ b/src/python/src/grpc/_adapter/rear.py
@@ -93,7 +93,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
def __init__(
self, host, port, pool, request_serializers, response_deserializers,
secure, root_certificates, private_key, certificate_chain,
- server_host_override=None):
+ metadata_transformer=None, server_host_override=None):
"""Constructor.
Args:
@@ -111,6 +111,9 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
key should be used.
certificate_chain: The PEM-encoded certificate chain to use or None if
no certificate chain should be used.
+ metadata_transformer: A function that given a metadata object produces
+ another metadata to be used in the underlying communication on the
+ wire.
server_host_override: (For testing only) the target name used for SSL
host name checking.
"""
@@ -134,6 +137,7 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
self._root_certificates = root_certificates
self._private_key = private_key
self._certificate_chain = certificate_chain
+ self._metadata_transformer = metadata_transformer
self._server_host_override = server_host_override
def _on_write_event(self, operation_id, event, rpc_state):
@@ -242,7 +246,11 @@ class RearLink(base_interfaces.RearLink, activated.Activated):
timeout: A duration of time in seconds to allow for the RPC.
"""
request_serializer = self._request_serializers[name]
- call = _low.Call(self._channel, name, self._host, time.time() + timeout)
+ call = _low.Call(self._channel, self._completion_queue, name, self._host, time.time() + timeout)
+ if self._metadata_transformer is not None:
+ metadata = self._metadata_transformer([])
+ for metadata_key, metadata_value in metadata:
+ call.add_metadata(metadata_key, metadata_value)
call.invoke(self._completion_queue, operation_id, operation_id)
outstanding = set(_INVOCATION_EVENT_KINDS)
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index cc0b8ec9e8..f3f2a043eb 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -114,7 +114,7 @@ class _Stub(interfaces.Stub):
def __init__(
self, breakdown, host, port, secure, root_certificates, private_key,
- certificate_chain, server_host_override=None):
+ certificate_chain, metadata_transformer=None, server_host_override=None):
self._lock = threading.Lock()
self._breakdown = breakdown
self._host = host
@@ -123,6 +123,7 @@ class _Stub(interfaces.Stub):
self._root_certificates = root_certificates
self._private_key = private_key
self._certificate_chain = certificate_chain
+ self._metadata_transformer = metadata_transformer
self._server_host_override = server_host_override
self._pool = None
@@ -141,6 +142,7 @@ class _Stub(interfaces.Stub):
self._breakdown.request_serializers,
self._breakdown.response_deserializers, self._secure,
self._root_certificates, self._private_key, self._certificate_chain,
+ metadata_transformer=self._metadata_transformer,
server_host_override=self._server_host_override)
self._front.join_rear_link(self._rear_link)
self._rear_link.join_fore_link(self._front)
@@ -188,43 +190,11 @@ class _Stub(interfaces.Stub):
raise AttributeError(attr)
-def _build_stub(
- service_name, methods, host, port, secure, root_certificates, private_key,
- certificate_chain, server_host_override=None):
- breakdown = _face_utilities.break_down_invocation(service_name, methods)
- return _Stub(
- breakdown, host, port, secure, root_certificates, private_key,
- certificate_chain, server_host_override=server_host_override)
-
-
-def _build_server(service_name, methods, port, private_key, certificate_chain):
- breakdown = _face_utilities.break_down_service(service_name, methods)
- return _Server(breakdown, port, private_key, certificate_chain)
-
-
-def insecure_stub(service_name, methods, host, port):
- """Constructs an insecure interfaces.Stub.
-
- Args:
- service_name: The package-qualified full name of the service.
- methods: A dictionary from RPC method name to
- interfaces.RpcMethodInvocationDescription describing the RPCs to be
- supported by the created stub. The RPC method names in the dictionary are
- not qualified by the service name or decorated in any other way.
- host: The host to which to connect for RPC service.
- port: The port to which to connect for RPC service.
-
- Returns:
- An interfaces.Stub affording RPC invocation.
- """
- return _build_stub(
- service_name, methods, host, port, False, None, None, None)
-
-
-def secure_stub(
- service_name, methods, host, port, root_certificates, private_key,
- certificate_chain, server_host_override=None):
- """Constructs an insecure interfaces.Stub.
+def stub(
+ service_name, methods, host, port, metadata_transformer=None, secure=False,
+ root_certificates=None, private_key=None, certificate_chain=None,
+ server_host_override=None):
+ """Constructs an interfaces.Stub.
Args:
service_name: The package-qualified full name of the service.
@@ -234,6 +204,10 @@ def secure_stub(
not qualified by the service name or decorated in any other way.
host: The host to which to connect for RPC service.
port: The port to which to connect for RPC service.
+ metadata_transformer: A callable that given a metadata object produces
+ another metadata object to be used in the underlying communication on the
+ wire.
+ secure: Whether or not to construct the stub with a secure connection.
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
@@ -246,32 +220,16 @@ def secure_stub(
Returns:
An interfaces.Stub affording RPC invocation.
"""
- return _build_stub(
- service_name, methods, host, port, True, root_certificates, private_key,
- certificate_chain, server_host_override=server_host_override)
-
-
-def insecure_server(service_name, methods, port):
- """Constructs an insecure interfaces.Server.
-
- Args:
- service_name: The package-qualified full name of the service.
- methods: A dictionary from RPC method name to
- interfaces.RpcMethodServiceDescription describing the RPCs to
- be serviced by the created server. The RPC method names in the dictionary
- are not qualified by the service name or decorated in any other way.
- port: The desired port on which to serve or zero to ask for a port to
- be automatically selected.
-
- Returns:
- An interfaces.Server that will run with no security and
- service unsecured raw requests.
- """
- return _build_server(service_name, methods, port, None, None)
+ breakdown = _face_utilities.break_down_invocation(service_name, methods)
+ return _Stub(
+ breakdown, host, port, secure, root_certificates, private_key,
+ certificate_chain, server_host_override=server_host_override,
+ metadata_transformer=metadata_transformer)
-def secure_server(service_name, methods, port, private_key, certificate_chain):
- """Constructs a secure interfaces.Server.
+def server(
+ service_name, methods, port, private_key=None, certificate_chain=None):
+ """Constructs an interfaces.Server.
Args:
service_name: The package-qualified full name of the service.
@@ -281,11 +239,12 @@ def secure_server(service_name, methods, port, private_key, certificate_chain):
are not qualified by the service name or decorated in any other way.
port: The port on which to serve or zero to ask for a port to be
automatically selected.
- private_key: A pem-encoded private key.
- certificate_chain: A pem-encoded certificate chain.
+ private_key: A pem-encoded private key, or None for an insecure server.
+ certificate_chain: A pem-encoded certificate chain, or None for an insecure
+ server.
Returns:
An interfaces.Server that will serve secure traffic.
"""
- return _build_server(
- service_name, methods, port, private_key, certificate_chain)
+ breakdown = _face_utilities.break_down_service(service_name, methods)
+ return _Server(breakdown, port, private_key, certificate_chain)
diff --git a/src/python/src/grpc/early_adopter/implementations_test.py b/src/python/src/grpc/early_adopter/implementations_test.py
index ae4adad90f..32b974724c 100644
--- a/src/python/src/grpc/early_adopter/implementations_test.py
+++ b/src/python/src/grpc/early_adopter/implementations_test.py
@@ -106,11 +106,11 @@ _TIMEOUT = 3
class EarlyAdopterImplementationsTest(unittest.TestCase):
def setUp(self):
- self.server = implementations.insecure_server(
+ self.server = implementations.server(
SERVICE_NAME, _SERVICE_DESCRIPTIONS, 0)
self.server.start()
port = self.server.port()
- self.stub = implementations.insecure_stub(
+ self.stub = implementations.stub(
SERVICE_NAME, _INVOCATION_DESCRIPTIONS, 'localhost', port)
def tearDown(self):
diff --git a/src/python/src/setup.py b/src/python/src/setup.py
index bd70634b8f..7149a9eb85 100644
--- a/src/python/src/setup.py
+++ b/src/python/src/setup.py
@@ -30,6 +30,8 @@
"""A setup module for the GRPC Python package."""
from distutils import core as _core
+import setuptools
+import sys
_EXTENSION_SOURCES = (
'grpc/_adapter/_c.c',
@@ -40,6 +42,7 @@ _EXTENSION_SOURCES = (
'grpc/_adapter/_server.c',
'grpc/_adapter/_client_credentials.c',
'grpc/_adapter/_server_credentials.c',
+ 'grpc/_adapter/_tag.c'
)
_EXTENSION_INCLUDE_DIRECTORIES = (
@@ -49,8 +52,9 @@ _EXTENSION_INCLUDE_DIRECTORIES = (
_EXTENSION_LIBRARIES = (
'grpc',
'gpr',
- 'rt',
)
+if not "darwin" in sys.platform:
+ _EXTENSION_LIBRARIES += ('rt',)
_EXTENSION_MODULE = _core.Extension(
'grpc._adapter._c', sources=list(_EXTENSION_SOURCES),
@@ -80,7 +84,15 @@ _PACKAGE_DIRECTORIES = {
'grpc.framework': 'grpc/framework',
}
-_core.setup(
- name='grpc-2015', version='0.4.0',
- ext_modules=[_EXTENSION_MODULE], packages=list(_PACKAGES),
- package_dir=_PACKAGE_DIRECTORIES)
+setuptools.setup(
+ name='grpcio',
+ version='0.5.0a0',
+ ext_modules=[_EXTENSION_MODULE],
+ packages=list(_PACKAGES),
+ package_dir=_PACKAGE_DIRECTORIES,
+ install_requires=[
+ 'enum34==1.0.4',
+ 'futures==2.2.0',
+ 'protobuf==3.0.0-alpha-1'
+ ]
+)
diff --git a/src/ruby/.rspec b/src/ruby/.rspec
index 60a4aad5a2..dd579f7a13 100755
--- a/src/ruby/.rspec
+++ b/src/ruby/.rspec
@@ -1 +1,2 @@
-I.
+--require spec_helper
diff --git a/src/ruby/.rubocop_todo.yml b/src/ruby/.rubocop_todo.yml
index d5bb55e5a8..ed4a4438b3 100644
--- a/src/ruby/.rubocop_todo.yml
+++ b/src/ruby/.rubocop_todo.yml
@@ -1,42 +1,30 @@
# This configuration was generated by `rubocop --auto-gen-config`
-# on 2015-01-16 02:30:04 -0800 using RuboCop version 0.28.0.
+# on 2015-04-17 14:43:27 -0700 using RuboCop version 0.30.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 3
-# Lint/UselessAssignment:
-# Enabled: false
-
-# Offense count: 33
+# Offense count: 30
Metrics/AbcSize:
- Max: 39
+ Max: 40
# Offense count: 3
# Configuration parameters: CountComments.
Metrics/ClassLength:
- Max: 231
-
-# Offense count: 2
-Metrics/CyclomaticComplexity:
- Max: 8
+ Max: 184
-# Offense count: 36
+# Offense count: 35
# Configuration parameters: CountComments.
Metrics/MethodLength:
- Max: 37
+ Max: 36
-# Offense count: 8
+# Offense count: 7
# Configuration parameters: CountKeywordArgs.
Metrics/ParameterLists:
Max: 8
-# Offense count: 2
-Metrics/PerceivedComplexity:
- Max: 10
-
-# Offense count: 7
+# Offense count: 9
# Configuration parameters: AllowedVariables.
Style/GlobalVars:
Enabled: false
@@ -50,3 +38,7 @@ Style/Next:
# Configuration parameters: Methods.
Style/SingleLineBlockParams:
Enabled: false
+
+# Offense count: 1
+Style/StructInheritance:
+ Enabled: false
diff --git a/src/ruby/CHANGELOG.md b/src/ruby/CHANGELOG.md
new file mode 100644
index 0000000000..8ec6e3cfdb
--- /dev/null
+++ b/src/ruby/CHANGELOG.md
@@ -0,0 +1,11 @@
+## 0.6.1 (2015-04-14)
+
+### Changes
+
+* Begins this ChangeLog ([@tbetbetbe][])
+* Updates to version 0.4 of googleauth. ([@tbetbetbe][])
+* Switch the extension to use the call API. ([@tbetbetbe][])
+* Refactor the C extension to avoid identifiers used by ruby ([@yugui][])
+
+[@tbetbetbe]: https://github.com/tbetbetbe
+[@yugui]: https://github.com/yugui
diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile
index afb354e922..02af9a84b8 100755
--- a/src/ruby/Rakefile
+++ b/src/ruby/Rakefile
@@ -26,6 +26,7 @@ namespace :suite do
SPEC_SUITES.each do |suite|
desc "Run all specs in the #{suite[:title]} spec suite"
RSpec::Core::RakeTask.new(suite[:id]) do |t|
+ ENV['COVERAGE_NAME'] = suite[:id].to_s
spec_files = []
suite[:files].each { |f| spec_files += Dir[f] } if suite[:files]
diff --git a/src/ruby/bin/apis/pubsub_demo.rb b/src/ruby/bin/apis/pubsub_demo.rb
index 9bb324ff64..6d69b0f21e 100755
--- a/src/ruby/bin/apis/pubsub_demo.rb
+++ b/src/ruby/bin/apis/pubsub_demo.rb
@@ -71,7 +71,7 @@ end
# Builds the metadata authentication update proc.
def auth_proc(opts)
- auth_creds = Google::Auth.get_application_default(opts.oauth_scope)
+ auth_creds = Google::Auth.get_application_default
return auth_creds.updater_proc
end
@@ -213,17 +213,14 @@ class NamedActions
end
# Args is used to hold the command line info.
-Args = Struct.new(:host, :oauth_scope, :port, :action, :project_id, :topic_name,
+Args = Struct.new(:host, :port, :action, :project_id, :topic_name,
:sub_name)
# validates the the command line options, returning them as an Arg.
def parse_args
args = Args.new('pubsub-staging.googleapis.com',
- 'https://www.googleapis.com/auth/pubsub',
443, 'list_some_topics', 'stoked-keyword-656')
OptionParser.new do |opts|
- opts.on('--oauth_scope scope',
- 'Scope for OAuth tokens') { |v| args['oauth_scope'] = v }
opts.on('--server_host SERVER_HOST', 'server hostname') do |v|
args.host = v
end
@@ -250,7 +247,7 @@ def parse_args
end
def _check_args(args)
- %w(host port action oauth_scope).each do |a|
+ %w(host port action).each do |a|
if args[a].nil?
raise OptionParser::MissingArgument.new("please specify --#{a}")
end
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index b2a8711c79..a388924722 100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -110,6 +110,11 @@ def create_stub(opts)
end
end
+ if opts.test_case == 'jwt_token_creds' # don't use a scope
+ auth_creds = Google::Auth.get_application_default
+ stub_opts[:update_metadata] = auth_creds.updater_proc
+ end
+
logger.info("... connecting securely to #{address}")
Grpc::Testing::TestService::Stub.new(address, **stub_opts)
else
@@ -131,12 +136,14 @@ class PingPongPlayer
include Grpc::Testing::PayloadType
attr_accessor :assertions # required by Minitest::Assertions
attr_accessor :queue
+ attr_accessor :canceller_op
# reqs is the enumerator over the requests
def initialize(msg_sizes)
@queue = Queue.new
@msg_sizes = msg_sizes
@assertions = 0 # required by Minitest::Assertions
+ @canceller_op = nil # used to cancel after the first response
end
def each_item
@@ -150,12 +157,15 @@ class PingPongPlayer
response_parameters: [p_cls.new(size: resp_size)])
yield req
resp = @queue.pop
- assert_equal(:COMPRESSABLE, resp.payload.type,
- 'payload type is wrong')
+ assert_equal(:COMPRESSABLE, resp.payload.type, 'payload type is wrong')
assert_equal(resp_size, resp.payload.body.length,
- 'payload body #{i} has the wrong length')
+ "payload body #{count} has the wrong length")
p "OK: ping_pong #{count}"
count += 1
+ unless @canceller_op.nil?
+ canceller_op.cancel
+ break
+ end
end
end
end
@@ -201,6 +211,15 @@ class NamedTests
p 'OK: service_account_creds'
end
+ def jwt_token_creds
+ json_key = File.read(ENV[AUTH_ENV])
+ wanted_email = MultiJson.load(json_key)['client_email']
+ resp = perform_large_unary(fill_username: true)
+ assert_equal(wanted_email, resp.username,
+ 'service_account_creds: incorrect username')
+ p 'OK: jwt_token_creds'
+ end
+
def compute_engine_creds
resp = perform_large_unary(fill_username: true,
fill_oauth_scope: true)
@@ -246,6 +265,27 @@ class NamedTests
p 'OK: ping_pong'
end
+ def cancel_after_begin
+ msg_sizes = [27_182, 8, 1828, 45_904]
+ reqs = msg_sizes.map do |x|
+ req = Payload.new(body: nulls(x))
+ StreamingInputCallRequest.new(payload: req)
+ end
+ op = @stub.streaming_input_call(reqs, return_op: true)
+ op.cancel
+ assert_raises(GRPC::Cancelled) { op.execute }
+ p 'OK: cancel_after_begin'
+ end
+
+ def cancel_after_first_response
+ msg_sizes = [[27_182, 31_415], [8, 9], [1828, 2653], [45_904, 58_979]]
+ ppp = PingPongPlayer.new(msg_sizes)
+ op = @stub.full_duplex_call(ppp.each_item, return_op: true)
+ ppp.canceller_op = op # causes ppp to cancel after the 1st message
+ assert_raises(GRPC::Cancelled) { op.execute.each { |r| ppp.queue.push(r) } }
+ p 'OK: cancel_after_first_response'
+ end
+
def all
all_methods = NamedTests.instance_methods(false).map(&:to_s)
all_methods.each do |m|
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb
index 0819ba9bbc..72570d92f3 100755
--- a/src/ruby/bin/interop/interop_server.rb
+++ b/src/ruby/bin/interop/interop_server.rb
@@ -185,7 +185,7 @@ def main
logger.info("... running insecurely on #{host}")
end
s.handle(TestTarget)
- s.run
+ s.run_till_terminated
end
main
diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb
index 5cc7613489..1bfe253b85 100755
--- a/src/ruby/bin/math_server.rb
+++ b/src/ruby/bin/math_server.rb
@@ -183,7 +183,7 @@ def main
end
s.handle(Calculator)
- s.run
+ s.run_till_terminated
end
main
diff --git a/src/ruby/bin/noproto_server.rb b/src/ruby/bin/noproto_server.rb
index 9979cb7ebb..f71daeadb3 100755
--- a/src/ruby/bin/noproto_server.rb
+++ b/src/ruby/bin/noproto_server.rb
@@ -105,7 +105,7 @@ def main
end
s.handle(NoProto)
- s.run
+ s.run_till_terminated
end
main
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index ff5a114de5..e3a5277f54 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -39,203 +39,29 @@
#include <grpc/support/slice.h>
#include "rb_grpc.h"
-/* grpc_rb_byte_buffer wraps a grpc_byte_buffer. It provides a peer ruby
- * object, 'mark' to minimize copying when a byte_buffer is created from
- * ruby. */
-typedef struct grpc_rb_byte_buffer {
- /* Holder of ruby objects involved in constructing the status */
- VALUE mark;
- /* The actual status */
- grpc_byte_buffer *wrapped;
-} grpc_rb_byte_buffer;
-
-/* Destroys ByteBuffer instances. */
-static void grpc_rb_byte_buffer_free(void *p) {
- grpc_rb_byte_buffer *bb = NULL;
- if (p == NULL) {
- return;
- };
- bb = (grpc_rb_byte_buffer *)p;
-
- /* Deletes the wrapped object if the mark object is Qnil, which indicates
- * that no other object is the actual owner. */
- if (bb->wrapped != NULL && bb->mark == Qnil) {
- grpc_byte_buffer_destroy(bb->wrapped);
- }
-
- xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_byte_buffer_mark(void *p) {
- grpc_rb_byte_buffer *bb = NULL;
- if (p == NULL) {
- return;
- }
- bb = (grpc_rb_byte_buffer *)p;
-
- /* If it's not already cleaned up, mark the mark object */
- if (bb->mark != Qnil && BUILTIN_TYPE(bb->mark) != T_NONE) {
- rb_gc_mark(bb->mark);
- }
+grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) {
+ gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
+ grpc_byte_buffer *buffer = grpc_byte_buffer_create(&slice, 1);
+ gpr_slice_unref(slice);
+ return buffer;
}
-/* id_source is the name of the hidden ivar the preserves the original
- * byte_buffer source string */
-static ID id_source;
-
-/* Allocates ByteBuffer instances.
-
- Provides safe default values for the byte_buffer fields. */
-static VALUE grpc_rb_byte_buffer_alloc(VALUE cls) {
- grpc_rb_byte_buffer *wrapper = ALLOC(grpc_rb_byte_buffer);
- wrapper->wrapped = NULL;
- wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_byte_buffer_mark,
- grpc_rb_byte_buffer_free, wrapper);
-}
-
-/* Clones ByteBuffer instances.
-
- Gives ByteBuffer a consistent implementation of Ruby's object copy/dup
- protocol. */
-static VALUE grpc_rb_byte_buffer_init_copy(VALUE copy, VALUE orig) {
- grpc_rb_byte_buffer *orig_bb = NULL;
- grpc_rb_byte_buffer *copy_bb = NULL;
-
- if (copy == orig) {
- return copy;
- }
-
- /* Raise an error if orig is not a metadata object or a subclass. */
- if (TYPE(orig) != T_DATA ||
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_byte_buffer_free) {
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cByteBuffer));
- }
-
- Data_Get_Struct(orig, grpc_rb_byte_buffer, orig_bb);
- Data_Get_Struct(copy, grpc_rb_byte_buffer, copy_bb);
-
- /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
- * object. */
- MEMCPY(copy_bb, orig_bb, grpc_rb_byte_buffer, 1);
- return copy;
-}
-
-/* id_empty is used to return the empty string from to_s when necessary. */
-static ID id_empty;
-
-static VALUE grpc_rb_byte_buffer_to_s(VALUE self) {
- grpc_rb_byte_buffer *wrapper = NULL;
- grpc_byte_buffer *bb = NULL;
- grpc_byte_buffer_reader *reader = NULL;
- char *output = NULL;
+VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
size_t length = 0;
+ char *string = NULL;
size_t offset = 0;
- VALUE output_obj = Qnil;
+ grpc_byte_buffer_reader *reader = NULL;
gpr_slice next;
+ if (buffer == NULL) {
+ return Qnil;
- Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
- output_obj = rb_ivar_get(wrapper->mark, id_source);
- if (output_obj != Qnil) {
- /* From ruby, ByteBuffers are immutable so if a source is set, return that
- * as the to_s value */
- return output_obj;
- }
-
- /* Read the bytes. */
- bb = wrapper->wrapped;
- if (bb == NULL) {
- return rb_id2str(id_empty);
- }
- length = grpc_byte_buffer_length(bb);
- if (length == 0) {
- return rb_id2str(id_empty);
}
- reader = grpc_byte_buffer_reader_create(bb);
- output = xmalloc(length);
+ length = grpc_byte_buffer_length(buffer);
+ string = xmalloc(length + 1);
+ reader = grpc_byte_buffer_reader_create(buffer);
while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
- memcpy(output + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
+ memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}
- output_obj = rb_str_new(output, length);
-
- /* Save a references to the computed string in the mark object so that the
- * calling to_s does not do any allocations. */
- wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
- rb_ivar_set(wrapper->mark, id_source, output_obj);
-
- return output_obj;
-}
-
-/* Initializes ByteBuffer instances. */
-static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) {
- gpr_slice a_slice;
- grpc_rb_byte_buffer *wrapper = NULL;
- grpc_byte_buffer *byte_buffer = NULL;
-
- if (TYPE(src) != T_STRING) {
- rb_raise(rb_eTypeError, "bad byte_buffer arg: got <%s>, want <String>",
- rb_obj_classname(src));
- return Qnil;
- }
- Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
- a_slice = gpr_slice_malloc(RSTRING_LEN(src));
- memcpy(GPR_SLICE_START_PTR(a_slice), RSTRING_PTR(src), RSTRING_LEN(src));
- byte_buffer = grpc_byte_buffer_create(&a_slice, 1);
- gpr_slice_unref(a_slice);
-
- if (byte_buffer == NULL) {
- rb_raise(rb_eArgError, "could not create a byte_buffer, not sure why");
- return Qnil;
- }
- wrapper->wrapped = byte_buffer;
-
- /* Save a references to the original string in the mark object so that the
- * pointers used there is valid for the lifetime of the object. */
- wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
- rb_ivar_set(wrapper->mark, id_source, src);
-
- return self;
-}
-
-/* rb_cByteBuffer is the ruby class that proxies grpc_byte_buffer. */
-VALUE rb_cByteBuffer = Qnil;
-
-void Init_grpc_byte_buffer() {
- rb_cByteBuffer =
- rb_define_class_under(rb_mGrpcCore, "ByteBuffer", rb_cObject);
-
- /* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cByteBuffer, grpc_rb_byte_buffer_alloc);
-
- /* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cByteBuffer, "initialize", grpc_rb_byte_buffer_init, 1);
- rb_define_method(rb_cByteBuffer, "initialize_copy",
- grpc_rb_byte_buffer_init_copy, 1);
-
- /* Provides a to_s method that returns the buffer value */
- rb_define_method(rb_cByteBuffer, "to_s", grpc_rb_byte_buffer_to_s, 0);
-
- id_source = rb_intern("__source");
- id_empty = rb_intern("");
-}
-
-VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer *bb) {
- grpc_rb_byte_buffer *byte_buffer = NULL;
- if (bb == NULL) {
- return Qnil;
- }
- byte_buffer = ALLOC(grpc_rb_byte_buffer);
- byte_buffer->wrapped = bb;
- byte_buffer->mark = mark;
- return Data_Wrap_Struct(rb_cByteBuffer, grpc_rb_byte_buffer_mark,
- grpc_rb_byte_buffer_free, byte_buffer);
-}
-
-/* Gets the wrapped byte_buffer from the ruby wrapper */
-grpc_byte_buffer *grpc_rb_get_wrapped_byte_buffer(VALUE v) {
- grpc_rb_byte_buffer *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_byte_buffer, wrapper);
- return wrapper->wrapped;
+ return rb_str_new(string, length);
}
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.h b/src/ruby/ext/grpc/rb_byte_buffer.h
index 6ef72f3e75..96b9009dae 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.h
+++ b/src/ruby/ext/grpc/rb_byte_buffer.h
@@ -37,18 +37,10 @@
#include <grpc/grpc.h>
#include <ruby.h>
-/* rb_cByteBuffer is the ByteBuffer class whose instances proxy
- grpc_byte_buffer. */
-extern VALUE rb_cByteBuffer;
+/* Converts a char* with a length to a grpc_byte_buffer */
+grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length);
-/* Initializes the ByteBuffer class. */
-void Init_grpc_byte_buffer();
-
-/* grpc_rb_byte_buffer_create_with_mark creates a grpc_rb_byte_buffer with a
- * ruby mark object that will be kept alive while the byte_buffer is alive. */
-VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb);
-
-/* Gets the wrapped byte_buffer from its ruby object. */
-grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v);
+/* Converts a grpc_byte_buffer to a ruby string */
+VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer);
#endif /* GRPC_RB_BYTE_BUFFER_H_ */
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index b5a256d5a6..e76bb930ee 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -36,11 +36,31 @@
#include <ruby.h>
#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
#include "rb_byte_buffer.h"
#include "rb_completion_queue.h"
-#include "rb_metadata.h"
#include "rb_grpc.h"
+/* grpc_rb_cCall is the Call class whose instances proxy grpc_call. */
+static VALUE grpc_rb_cCall;
+
+/* grpc_rb_eCallError is the ruby class of the exception thrown during call
+ operations; */
+VALUE grpc_rb_eCallError = Qnil;
+
+/* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
+ a timeout. */
+static VALUE grpc_rb_eOutOfTime = Qnil;
+
+/* grpc_rb_sBatchResult is struct class used to hold the results of a batch
+ * call. */
+static VALUE grpc_rb_sBatchResult;
+
+/* grpc_rb_cMdAry is the MetadataArray class whose instances proxy
+ * grpc_metadata_array. */
+static VALUE grpc_rb_cMdAry;
+
/* id_cq is the name of the hidden ivar that preserves a reference to a
* completion queue */
static ID id_cq;
@@ -62,13 +82,22 @@ static ID id_metadata;
* received by the call and subsequently saved on it. */
static ID id_status;
+/* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */
+static VALUE sym_send_message;
+static VALUE sym_send_metadata;
+static VALUE sym_send_close;
+static VALUE sym_send_status;
+static VALUE sym_message;
+static VALUE sym_status;
+static VALUE sym_cancelled;
+
/* hash_all_calls is a hash of Call address -> reference count that is used to
* track the creation and destruction of rb_call instances.
*/
static VALUE hash_all_calls;
/* Destroys a Call. */
-void grpc_rb_call_destroy(void *p) {
+static void grpc_rb_call_destroy(void *p) {
grpc_call *call = NULL;
VALUE ref_count = Qnil;
if (p == NULL) {
@@ -88,6 +117,38 @@ void grpc_rb_call_destroy(void *p) {
}
}
+static size_t md_ary_datasize(const void *p) {
+ const grpc_metadata_array *const ary = (grpc_metadata_array *)p;
+ size_t i, datasize = sizeof(grpc_metadata_array);
+ for (i = 0; i < ary->count; ++i) {
+ const grpc_metadata *const md = &ary->metadata[i];
+ datasize += strlen(md->key);
+ datasize += md->value_length;
+ }
+ datasize += ary->capacity * sizeof(grpc_metadata);
+ return datasize;
+}
+
+static const rb_data_type_t grpc_rb_md_ary_data_type = {
+ "grpc_metadata_array",
+ {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize},
+ NULL,
+ NULL,
+ 0};
+
+/* Describes grpc_call struct for RTypedData */
+static const rb_data_type_t grpc_call_data_type = {
+ "grpc_call",
+ {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL,
+ NULL,
+ /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
+ * grpc_rb_call_destroy
+ * touches a hash object.
+ * TODO(yugui) Directly use st_table and call the free function earlier?
+ */
+ 0};
+
/* Error code details is a hash containing text strings describing errors */
VALUE rb_error_code_details;
@@ -101,93 +162,15 @@ const char *grpc_call_error_detail_of(grpc_call_error err) {
return detail;
}
-/* grpc_rb_call_add_metadata_hash_cb is the hash iteration callback used by
- grpc_rb_call_add_metadata.
-*/
-int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
- grpc_call *call = NULL;
- grpc_metadata *md = NULL;
- VALUE md_obj = Qnil;
- VALUE md_obj_args[2];
- VALUE flags = rb_ivar_get(call_obj, id_flags);
- grpc_call_error err;
- int array_length;
- int i;
-
- /* Construct a metadata object from key and value and add it */
- Data_Get_Struct(call_obj, grpc_call, call);
- md_obj_args[0] = key;
-
- if (TYPE(val) == T_ARRAY) {
- /* If the value is an array, add each value in the array separately */
- array_length = RARRAY_LEN(val);
- for (i = 0; i < array_length; i++) {
- md_obj_args[1] = rb_ary_entry(val, i);
- md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
- md = grpc_rb_get_wrapped_metadata(md_obj);
- err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
- return ST_STOP;
- }
- }
- } else {
- md_obj_args[1] = val;
- md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
- md = grpc_rb_get_wrapped_metadata(md_obj);
- err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
- return ST_STOP;
- }
- }
-
- return ST_CONTINUE;
-}
-
-/*
- call-seq:
- call.add_metadata(completion_queue, hash_elements, flags=nil)
-
- Add metadata elements to the call from a ruby hash, to be sent upon
- invocation. flags is a bit-field combination of the write flags defined
- above. REQUIRES: grpc_call_invoke/grpc_call_accept have not been
- called on this call. Produces no events. */
-
-static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) {
- VALUE metadata;
- VALUE flags = Qnil;
- ID id_size = rb_intern("size");
-
- /* "11" == 1 mandatory args, 1 (flags) is optional */
- rb_scan_args(argc, argv, "11", &metadata, &flags);
- if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
- }
- if (TYPE(metadata) != T_HASH) {
- rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash");
- return Qnil;
- }
- if (NUM2UINT(rb_funcall(metadata, id_size, 0)) == 0) {
- return Qnil;
- }
- rb_ivar_set(self, id_flags, flags);
- rb_ivar_set(self, id_input_md, metadata);
- rb_hash_foreach(metadata, grpc_rb_call_add_metadata_hash_cb, self);
- return Qnil;
-}
-
/* Called by clients to cancel an RPC on the server.
Can be called multiple times, from any thread. */
static VALUE grpc_rb_call_cancel(VALUE self) {
grpc_call *call = NULL;
grpc_call_error err;
- Data_Get_Struct(self, grpc_call, call);
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
err = grpc_call_cancel(call);
if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "cancel failed: %s (code=%d)",
+ rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
}
@@ -196,77 +179,20 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
/*
call-seq:
- call.invoke(completion_queue, tag, flags=nil)
-
- Invoke the RPC. Starts sending metadata and request headers on the wire.
- flags is a bit-field combination of the write flags defined above.
- REQUIRES: Can be called at most once per call.
- Can only be called on the client.
- Produces a GRPC_INVOKE_ACCEPTED event on completion. */
-static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) {
- VALUE cqueue = Qnil;
- VALUE metadata_read_tag = Qnil;
- VALUE finished_tag = Qnil;
- VALUE flags = Qnil;
- grpc_call *call = NULL;
- grpc_completion_queue *cq = NULL;
- grpc_call_error err;
+ status = call.status
- /* "31" == 3 mandatory args, 1 (flags) is optional */
- rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag,
- &flags);
- if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
- }
- cq = grpc_rb_get_wrapped_completion_queue(cqueue);
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag),
- ROBJECT(finished_tag), NUM2UINT(flags));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
- }
-
- /* Add the completion queue as an instance attribute, prevents it from being
- * GCed until this call object is GCed */
- rb_ivar_set(self, id_cq, cqueue);
-
- return Qnil;
-}
-
-/* Initiate a read on a call. Output event contains a byte buffer with the
- result of the read.
- REQUIRES: No other reads are pending on the call. It is only safe to start
- the next read after the corresponding read event is received. */
-static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) {
- grpc_call *call = NULL;
- grpc_call_error err;
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_start_read_old(call, ROBJECT(tag));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "start read failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
- }
-
- return Qnil;
-}
-
-/*
- call-seq:
- status = call.status
-
- Gets the status object saved the call. */
+ Gets the status object saved the call. */
static VALUE grpc_rb_call_get_status(VALUE self) {
return rb_ivar_get(self, id_status);
}
/*
call-seq:
- call.status = status
+ call.status = status
- Saves a status object on the call. */
+ Saves a status object on the call. */
static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
- if (!NIL_P(status) && rb_obj_class(status) != rb_sStatus) {
+ if (!NIL_P(status) && rb_obj_class(status) != grpc_rb_sStatus) {
rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
rb_obj_classname(status));
return Qnil;
@@ -277,18 +203,18 @@ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
/*
call-seq:
- metadata = call.metadata
+ metadata = call.metadata
- Gets the metadata object saved the call. */
+ Gets the metadata object saved the call. */
static VALUE grpc_rb_call_get_metadata(VALUE self) {
return rb_ivar_get(self, id_metadata);
}
/*
call-seq:
- call.metadata = metadata
+ call.metadata = metadata
- Saves the metadata hash on the call. */
+ Saves the metadata hash on the call. */
static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
@@ -299,176 +225,425 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
return rb_ivar_set(self, id_metadata, metadata);
}
-/*
- call-seq:
- call.start_write(byte_buffer, tag, flags=nil)
-
- Queue a byte buffer for writing.
- flags is a bit-field combination of the write flags defined above.
- A write with byte_buffer null is allowed, and will not send any bytes on the
- wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
- a mechanism to flush any previously buffered writes to outgoing flow control.
- REQUIRES: No other writes are pending on the call. It is only safe to
- start the next write after the corresponding write_accepted event
- is received.
- GRPC_INVOKE_ACCEPTED must have been received by the application
- prior to calling this on the client. On the server,
- grpc_call_accept must have been called successfully.
- Produces a GRPC_WRITE_ACCEPTED event. */
-static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
- VALUE byte_buffer = Qnil;
- VALUE tag = Qnil;
- VALUE flags = Qnil;
- grpc_call *call = NULL;
- grpc_byte_buffer *bfr = NULL;
- grpc_call_error err;
+/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
+ to fill grpc_metadata_array.
+
+ it's capacity should have been computed via a prior call to
+ grpc_rb_md_ary_fill_hash_cb
+*/
+static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
+ grpc_metadata_array *md_ary = NULL;
+ int array_length;
+ int i;
+
+ /* Construct a metadata object from key and value and add it */
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
+ &grpc_rb_md_ary_data_type, md_ary);
- /* "21" == 2 mandatory args, 1 (flags) is optional */
- rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags);
- if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+ if (TYPE(val) == T_ARRAY) {
+ /* If the value is an array, add capacity for each value in the array */
+ array_length = RARRAY_LEN(val);
+ for (i = 0; i < array_length; i++) {
+ if (TYPE(key) == T_SYMBOL) {
+ md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
+ } else { /* StringValueCStr does all other type exclusions for us */
+ md_ary->metadata[md_ary->count].key = StringValueCStr(key);
+ }
+ md_ary->metadata[md_ary->count].value = RSTRING_PTR(rb_ary_entry(val, i));
+ md_ary->metadata[md_ary->count].value_length =
+ RSTRING_LEN(rb_ary_entry(val, i));
+ md_ary->count += 1;
+ }
+ } else {
+ if (TYPE(key) == T_SYMBOL) {
+ md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
+ } else { /* StringValueCStr does all other type exclusions for us */
+ md_ary->metadata[md_ary->count].key = StringValueCStr(key);
+ }
+ md_ary->metadata[md_ary->count].value = RSTRING_PTR(val);
+ md_ary->metadata[md_ary->count].value_length = RSTRING_LEN(val);
+ md_ary->count += 1;
}
- bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "start write failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
+
+ return ST_CONTINUE;
+}
+
+/* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used
+ to pre-compute the capacity a grpc_metadata_array.
+*/
+static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
+ VALUE md_ary_obj) {
+ grpc_metadata_array *md_ary = NULL;
+
+ /* Construct a metadata object from key and value and add it */
+ TypedData_Get_Struct(md_ary_obj, grpc_metadata_array,
+ &grpc_rb_md_ary_data_type, md_ary);
+
+ if (TYPE(val) == T_ARRAY) {
+ /* If the value is an array, add capacity for each value in the array */
+ md_ary->capacity += RARRAY_LEN(val);
+ } else {
+ md_ary->capacity += 1;
}
+ return ST_CONTINUE;
+}
- return Qnil;
+/* grpc_rb_md_ary_convert converts a ruby metadata hash into
+ a grpc_metadata_array.
+*/
+static void grpc_rb_md_ary_convert(VALUE md_ary_hash,
+ grpc_metadata_array *md_ary) {
+ VALUE md_ary_obj = Qnil;
+ if (md_ary_hash == Qnil) {
+ return; /* Do nothing if the expected has value is nil */
+ }
+ if (TYPE(md_ary_hash) != T_HASH) {
+ rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want <Hash>",
+ rb_obj_classname(md_ary_hash));
+ return;
+ }
+
+ /* Initialize the array, compute it's capacity, then fill it. */
+ grpc_metadata_array_init(md_ary);
+ md_ary_obj =
+ TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
+ md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata));
+ rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
}
-/* Queue a status for writing.
-
- call-seq:
- tag = Object.new
- call.write_status(200, "OK", tag)
-
- REQUIRES: No other writes are pending on the call. It is only safe to
- start the next write after the corresponding write_accepted event
- is received.
- GRPC_INVOKE_ACCEPTED must have been received by the application
- prior to calling this.
- Only callable on the server.
- Produces a GRPC_FINISHED event when the status is sent and the stream is
- fully closed */
-static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
- VALUE status, VALUE tag) {
- grpc_call *call = NULL;
- grpc_call_error err;
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_start_write_status_old(call, NUM2UINT(code),
- StringValueCStr(status), ROBJECT(tag));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "start write status: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
+/* Converts a metadata array to a hash. */
+VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) {
+ VALUE key = Qnil;
+ VALUE new_ary = Qnil;
+ VALUE value = Qnil;
+ VALUE result = rb_hash_new();
+ size_t i;
+
+ for (i = 0; i < md_ary->count; i++) {
+ key = rb_str_new2(md_ary->metadata[i].key);
+ value = rb_hash_aref(result, key);
+ if (value == Qnil) {
+ value = rb_str_new(md_ary->metadata[i].value,
+ md_ary->metadata[i].value_length);
+ rb_hash_aset(result, key, value);
+ } else if (TYPE(value) == T_ARRAY) {
+ /* Add the string to the returned array */
+ rb_ary_push(value, rb_str_new(md_ary->metadata[i].value,
+ md_ary->metadata[i].value_length));
+ } else {
+ /* Add the current value with this key and the new one to an array */
+ new_ary = rb_ary_new();
+ rb_ary_push(new_ary, value);
+ rb_ary_push(new_ary, rb_str_new(md_ary->metadata[i].value,
+ md_ary->metadata[i].value_length));
+ rb_hash_aset(result, key, new_ary);
+ }
}
+ return result;
+}
- return Qnil;
+/* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks
+ each key of an ops hash is valid.
+*/
+static int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val,
+ VALUE ops_ary) {
+ /* Update the capacity; the value is an array, add capacity for each value in
+ * the array */
+ if (TYPE(key) != T_FIXNUM) {
+ rb_raise(rb_eTypeError, "invalid operation : got <%s>, want <Fixnum>",
+ rb_obj_classname(key));
+ return ST_STOP;
+ }
+ switch (NUM2INT(key)) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ case GRPC_OP_SEND_MESSAGE:
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ case GRPC_OP_RECV_MESSAGE:
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ rb_ary_push(ops_ary, key);
+ return ST_CONTINUE;
+ default:
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d", NUM2INT(key));
+ };
+ return ST_STOP;
}
-/* No more messages to send.
- REQUIRES: No other writes are pending on the call. */
-static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) {
- grpc_call *call = NULL;
- grpc_call_error err;
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_writes_done_old(call, ROBJECT(tag));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "writes done: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
+/* grpc_rb_op_update_status_from_server adds the values in a ruby status
+ struct to the 'send_status_from_server' portion of an op.
+*/
+static void grpc_rb_op_update_status_from_server(grpc_op *op,
+ grpc_metadata_array *md_ary,
+ VALUE status) {
+ VALUE code = rb_struct_aref(status, sym_code);
+ VALUE details = rb_struct_aref(status, sym_details);
+ VALUE metadata_hash = rb_struct_aref(status, sym_metadata);
+
+ /* TODO: add check to ensure status is the correct struct type */
+ if (TYPE(code) != T_FIXNUM) {
+ rb_raise(rb_eTypeError, "invalid code : got <%s>, want <Fixnum>",
+ rb_obj_classname(code));
+ return;
}
+ if (TYPE(details) != T_STRING) {
+ rb_raise(rb_eTypeError, "invalid details : got <%s>, want <String>",
+ rb_obj_classname(code));
+ return;
+ }
+ op->data.send_status_from_server.status = NUM2INT(code);
+ op->data.send_status_from_server.status_details = StringValueCStr(details);
+ grpc_rb_md_ary_convert(metadata_hash, md_ary);
+ op->data.send_status_from_server.trailing_metadata_count = md_ary->count;
+ op->data.send_status_from_server.trailing_metadata = md_ary->metadata;
+}
- return Qnil;
+/* run_batch_stack holds various values used by the
+ * grpc_rb_call_run_batch function */
+typedef struct run_batch_stack {
+ /* The batch ops */
+ grpc_op ops[8]; /* 8 is the maximum number of operations */
+ size_t op_num; /* tracks the last added operation */
+
+ /* Data being sent */
+ grpc_metadata_array send_metadata;
+ grpc_metadata_array send_trailing_metadata;
+
+ /* Data being received */
+ grpc_byte_buffer *recv_message;
+ grpc_metadata_array recv_metadata;
+ grpc_metadata_array recv_trailing_metadata;
+ int recv_cancelled;
+ grpc_status_code recv_status;
+ char *recv_status_details;
+ size_t recv_status_details_capacity;
+} run_batch_stack;
+
+/* grpc_run_batch_stack_init ensures the run_batch_stack is properly
+ * initialized */
+static void grpc_run_batch_stack_init(run_batch_stack *st) {
+ MEMZERO(st, run_batch_stack, 1);
+ grpc_metadata_array_init(&st->send_metadata);
+ grpc_metadata_array_init(&st->send_trailing_metadata);
+ grpc_metadata_array_init(&st->recv_metadata);
+ grpc_metadata_array_init(&st->recv_trailing_metadata);
+ st->op_num = 0;
}
-/* call-seq:
- call.server_end_initial_metadata(flag)
-
- Only to be called on servers, before sending messages.
- flags is a bit-field combination of the write flags defined above.
-
- REQUIRES: Can be called at most once per call.
- Can only be called on the server, must be called after
- grpc_call_server_accept
- Produces no events */
-static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
- VALUE self) {
- VALUE flags = Qnil;
- grpc_call *call = NULL;
- grpc_call_error err;
+/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
+ * cleaned up */
+static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
+ grpc_metadata_array_destroy(&st->send_metadata);
+ grpc_metadata_array_destroy(&st->send_trailing_metadata);
+ grpc_metadata_array_destroy(&st->recv_metadata);
+ grpc_metadata_array_destroy(&st->recv_trailing_metadata);
+ if (st->recv_status_details != NULL) {
+ gpr_free(st->recv_status_details);
+ }
+}
- /* "01" == 1 (flags) is optional */
- rb_scan_args(argc, argv, "01", &flags);
- if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+/* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
+ * ops_hash */
+static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
+ VALUE this_op = Qnil;
+ VALUE this_value = Qnil;
+ VALUE ops_ary = rb_ary_new();
+ size_t i = 0;
+
+ /* Create a ruby array with just the operation keys */
+ rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary);
+
+ /* Fill the ops array */
+ for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) {
+ this_op = rb_ary_entry(ops_ary, i);
+ this_value = rb_hash_aref(ops_hash, this_op);
+ switch (NUM2INT(this_op)) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ /* N.B. later there is no need to explicitly delete the metadata keys
+ * and values, they are references to data in ruby objects. */
+ grpc_rb_md_ary_convert(this_value, &st->send_metadata);
+ st->ops[st->op_num].data.send_initial_metadata.count =
+ st->send_metadata.count;
+ st->ops[st->op_num].data.send_initial_metadata.metadata =
+ st->send_metadata.metadata;
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ st->ops[st->op_num].data.send_message = grpc_rb_s_to_byte_buffer(
+ RSTRING_PTR(this_value), RSTRING_LEN(this_value));
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ /* N.B. later there is no need to explicitly delete the metadata keys
+ * and values, they are references to data in ruby objects. */
+ grpc_rb_op_update_status_from_server(
+ &st->ops[st->op_num], &st->send_trailing_metadata, this_value);
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata;
+ break;
+ case GRPC_OP_RECV_MESSAGE:
+ st->ops[st->op_num].data.recv_message = &st->recv_message;
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ st->ops[st->op_num].data.recv_status_on_client.trailing_metadata =
+ &st->recv_trailing_metadata;
+ st->ops[st->op_num].data.recv_status_on_client.status =
+ &st->recv_status;
+ st->ops[st->op_num].data.recv_status_on_client.status_details =
+ &st->recv_status_details;
+ st->ops[st->op_num].data.recv_status_on_client.status_details_capacity =
+ &st->recv_status_details_capacity;
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ st->ops[st->op_num].data.recv_close_on_server.cancelled =
+ &st->recv_cancelled;
+ break;
+ default:
+ grpc_run_batch_stack_cleanup(st);
+ rb_raise(rb_eTypeError, "invalid operation : bad value %d",
+ NUM2INT(this_op));
+ };
+ st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
+ st->op_num++;
}
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags));
- if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)",
- grpc_call_error_detail_of(err), err);
+}
+
+/* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct
+ after the results have run */
+static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
+ size_t i = 0;
+ VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil,
+ Qnil, Qnil, Qnil, Qnil, NULL);
+ for (i = 0; i < st->op_num; i++) {
+ switch (st->ops[i].op) {
+ case GRPC_OP_SEND_INITIAL_METADATA:
+ rb_struct_aset(result, sym_send_metadata, Qtrue);
+ break;
+ case GRPC_OP_SEND_MESSAGE:
+ rb_struct_aset(result, sym_send_message, Qtrue);
+ grpc_byte_buffer_destroy(st->ops[i].data.send_message);
+ break;
+ case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+ rb_struct_aset(result, sym_send_close, Qtrue);
+ break;
+ case GRPC_OP_SEND_STATUS_FROM_SERVER:
+ rb_struct_aset(result, sym_send_status, Qtrue);
+ break;
+ case GRPC_OP_RECV_INITIAL_METADATA:
+ rb_struct_aset(result, sym_metadata,
+ grpc_rb_md_ary_to_h(&st->recv_metadata));
+ case GRPC_OP_RECV_MESSAGE:
+ rb_struct_aset(result, sym_message,
+ grpc_rb_byte_buffer_to_s(st->recv_message));
+ break;
+ case GRPC_OP_RECV_STATUS_ON_CLIENT:
+ rb_struct_aset(
+ result, sym_status,
+ rb_struct_new(grpc_rb_sStatus, UINT2NUM(st->recv_status),
+ (st->recv_status_details == NULL
+ ? Qnil
+ : rb_str_new2(st->recv_status_details)),
+ grpc_rb_md_ary_to_h(&st->recv_trailing_metadata),
+ NULL));
+ break;
+ case GRPC_OP_RECV_CLOSE_ON_SERVER:
+ rb_struct_aset(result, sym_send_close, Qtrue);
+ break;
+ default:
+ break;
+ }
}
- return Qnil;
+ return result;
}
/* call-seq:
- call.server_accept(completion_queue, finished_tag)
-
- Accept an incoming RPC, binding a completion queue to it.
- To be called before sending or receiving messages.
-
- REQUIRES: Can be called at most once per call.
- Can only be called on the server.
- Produces a GRPC_FINISHED event with finished_tag when the call has been
- completed (there may be other events for the call pending at this
- time) */
-static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
- VALUE finished_tag) {
+ cq = CompletionQueue.new
+ ops = {
+ GRPC::Core::CallOps::SEND_INITIAL_METADATA => <op_value>,
+ GRPC::Core::CallOps::SEND_MESSAGE => <op_value>,
+ ...
+ }
+ tag = Object.new
+ timeout = 10
+ call.start_batch(cqueue, tag, timeout, ops)
+
+ Start a batch of operations defined in the array ops; when complete, post a
+ completion of type 'tag' to the completion queue bound to the call.
+
+ Also waits for the batch to complete, until timeout is reached.
+ The order of ops specified in the batch has no significance.
+ Only one operation of each type can be active at once in any given
+ batch */
+static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
+ VALUE timeout, VALUE ops_hash) {
+ run_batch_stack st;
grpc_call *call = NULL;
- grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue);
+ grpc_event *ev = NULL;
grpc_call_error err;
- Data_Get_Struct(self, grpc_call, call);
- err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag));
+ VALUE result = Qnil;
+ TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call);
+
+ /* Validate the ops args, adding them to a ruby array */
+ if (TYPE(ops_hash) != T_HASH) {
+ rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash");
+ return Qnil;
+ }
+ grpc_run_batch_stack_init(&st);
+ grpc_run_batch_stack_fill_ops(&st, ops_hash);
+
+ /* call grpc_call_start_batch, then wait for it to complete using
+ * pluck_event */
+ err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag));
if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)",
+ grpc_run_batch_stack_cleanup(&st);
+ rb_raise(grpc_rb_eCallError,
+ "grpc_call_start_batch failed with %s (code=%d)",
grpc_call_error_detail_of(err), err);
+ return Qnil;
+ }
+ ev = grpc_rb_completion_queue_pluck_event(cqueue, tag, timeout);
+ if (ev == NULL) {
+ grpc_run_batch_stack_cleanup(&st);
+ rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
+ return Qnil;
+ }
+ if (ev->data.op_complete != GRPC_OP_OK) {
+ grpc_run_batch_stack_cleanup(&st);
+ rb_raise(grpc_rb_eCallError, "start_batch completion failed, (code=%d)",
+ ev->data.op_complete);
+ return Qnil;
}
- /* Add the completion queue as an instance attribute, prevents it from being
- * GCed until this call object is GCed */
- rb_ivar_set(self, id_cq, cqueue);
- return Qnil;
+ /* Build and return the BatchResult struct result */
+ result = grpc_run_batch_stack_build_result(&st);
+ grpc_run_batch_stack_cleanup(&st);
+ return result;
}
-/* rb_cCall is the ruby class that proxies grpc_call. */
-VALUE rb_cCall = Qnil;
-
-/* rb_eCallError is the ruby class of the exception thrown during call
- operations; */
-VALUE rb_eCallError = Qnil;
-
-void Init_grpc_error_codes() {
+static void Init_grpc_error_codes() {
/* Constants representing the error codes of grpc_call_error in grpc.h */
- VALUE rb_RpcErrors = rb_define_module_under(rb_mGrpcCore, "RpcErrors");
- rb_define_const(rb_RpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
- rb_define_const(rb_RpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
- rb_define_const(rb_RpcErrors, "NOT_ON_SERVER",
+ VALUE grpc_rb_mRpcErrors =
+ rb_define_module_under(grpc_rb_mGrpcCore, "RpcErrors");
+ rb_define_const(grpc_rb_mRpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
+ rb_define_const(grpc_rb_mRpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_SERVER",
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
- rb_define_const(rb_RpcErrors, "NOT_ON_CLIENT",
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_CLIENT",
UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
- rb_define_const(rb_RpcErrors, "ALREADY_ACCEPTED",
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_ACCEPTED",
UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
- rb_define_const(rb_RpcErrors, "ALREADY_INVOKED",
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_INVOKED",
UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
- rb_define_const(rb_RpcErrors, "NOT_INVOKED",
+ rb_define_const(grpc_rb_mRpcErrors, "NOT_INVOKED",
UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
- rb_define_const(rb_RpcErrors, "ALREADY_FINISHED",
+ rb_define_const(grpc_rb_mRpcErrors, "ALREADY_FINISHED",
UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
- rb_define_const(rb_RpcErrors, "TOO_MANY_OPERATIONS",
+ rb_define_const(grpc_rb_mRpcErrors, "TOO_MANY_OPERATIONS",
UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
- rb_define_const(rb_RpcErrors, "INVALID_FLAGS",
+ rb_define_const(grpc_rb_mRpcErrors, "INVALID_FLAGS",
UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
/* Add the detail strings to a Hash */
@@ -496,37 +671,54 @@ void Init_grpc_error_codes() {
rb_str_new2("outstanding read or write present"));
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
rb_str_new2("a bad flag was given"));
- rb_define_const(rb_RpcErrors, "ErrorMessages", rb_error_code_details);
+ rb_define_const(grpc_rb_mRpcErrors, "ErrorMessages", rb_error_code_details);
rb_obj_freeze(rb_error_code_details);
}
+static void Init_grpc_op_codes() {
+ /* Constants representing operation type codes in grpc.h */
+ VALUE grpc_rb_mCallOps = rb_define_module_under(grpc_rb_mGrpcCore, "CallOps");
+ rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA",
+ UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA));
+ rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE",
+ UINT2NUM(GRPC_OP_SEND_MESSAGE));
+ rb_define_const(grpc_rb_mCallOps, "SEND_CLOSE_FROM_CLIENT",
+ UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
+ rb_define_const(grpc_rb_mCallOps, "SEND_STATUS_FROM_SERVER",
+ UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER));
+ rb_define_const(grpc_rb_mCallOps, "RECV_INITIAL_METADATA",
+ UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA));
+ rb_define_const(grpc_rb_mCallOps, "RECV_MESSAGE",
+ UINT2NUM(GRPC_OP_RECV_MESSAGE));
+ rb_define_const(grpc_rb_mCallOps, "RECV_STATUS_ON_CLIENT",
+ UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT));
+ rb_define_const(grpc_rb_mCallOps, "RECV_CLOSE_ON_SERVER",
+ UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
+}
+
void Init_grpc_call() {
/* CallError inherits from Exception to signal that it is non-recoverable */
- rb_eCallError =
- rb_define_class_under(rb_mGrpcCore, "CallError", rb_eException);
- rb_cCall = rb_define_class_under(rb_mGrpcCore, "Call", rb_cObject);
+ grpc_rb_eCallError =
+ rb_define_class_under(grpc_rb_mGrpcCore, "CallError", rb_eException);
+ grpc_rb_eOutOfTime =
+ rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException);
+ grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject);
+ grpc_rb_cMdAry =
+ rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray", rb_cObject);
/* Prevent allocation or inialization of the Call class */
- rb_define_alloc_func(rb_cCall, grpc_rb_cannot_alloc);
- rb_define_method(rb_cCall, "initialize", grpc_rb_cannot_init, 0);
- rb_define_method(rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy, 1);
+ rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc);
+ rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0);
+ rb_define_method(grpc_rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy,
+ 1);
/* Add ruby analogues of the Call methods. */
- rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2);
- rb_define_method(rb_cCall, "server_end_initial_metadata",
- grpc_rb_call_server_end_initial_metadata, -1);
- rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1);
- rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0);
- rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1);
- rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
- rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1);
- rb_define_method(rb_cCall, "start_write_status",
- grpc_rb_call_start_write_status, 3);
- rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1);
- rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0);
- rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1);
- rb_define_method(rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
- rb_define_method(rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
+ rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
+ rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
+ rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
+ rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
+ rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
+ rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
/* Ids used to support call attributes */
id_metadata = rb_intern("metadata");
@@ -537,18 +729,33 @@ void Init_grpc_call() {
id_flags = rb_intern("__flags");
id_input_md = rb_intern("__input_md");
+ /* Ids used in constructing the batch result. */
+ sym_send_message = ID2SYM(rb_intern("send_message"));
+ sym_send_metadata = ID2SYM(rb_intern("send_metadata"));
+ sym_send_close = ID2SYM(rb_intern("send_close"));
+ sym_send_status = ID2SYM(rb_intern("send_status"));
+ sym_message = ID2SYM(rb_intern("message"));
+ sym_status = ID2SYM(rb_intern("status"));
+ sym_cancelled = ID2SYM(rb_intern("cancelled"));
+
+ /* The Struct used to return the run_batch result. */
+ grpc_rb_sBatchResult = rb_struct_define(
+ "BatchResult", "send_message", "send_metadata", "send_close",
+ "send_status", "message", "metadata", "status", "cancelled", NULL);
+
/* The hash for reference counting calls, to ensure they can't be destroyed
* more than once */
hash_all_calls = rb_hash_new();
- rb_define_const(rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
+ rb_define_const(grpc_rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
Init_grpc_error_codes();
+ Init_grpc_op_codes();
}
/* Gets the call from the ruby object */
grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
grpc_call *c = NULL;
- Data_Get_Struct(v, grpc_call, c);
+ TypedData_Get_Struct(v, grpc_call, &grpc_call_data_type, c);
return c;
}
@@ -565,5 +772,5 @@ VALUE grpc_rb_wrap_call(grpc_call *c) {
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
UINT2NUM(NUM2UINT(obj) + 1));
}
- return Data_Wrap_Struct(rb_cCall, GC_NOT_MARKED, grpc_rb_call_destroy, c);
+ return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c);
}
diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h
index bb51759a46..003ce0429e 100644
--- a/src/ruby/ext/grpc/rb_call.h
+++ b/src/ruby/ext/grpc/rb_call.h
@@ -46,12 +46,12 @@ VALUE grpc_rb_wrap_call(grpc_call* c);
/* Provides the details of an call error */
const char* grpc_call_error_detail_of(grpc_call_error err);
-/* rb_cCall is the Call class whose instances proxy grpc_call. */
-extern VALUE rb_cCall;
+/* Converts a metadata array to a hash. */
+VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary);
-/* rb_cCallError is the ruby class of the exception thrown during call
+/* grpc_rb_eCallError is the ruby class of the exception thrown during call
operations. */
-extern VALUE rb_eCallError;
+extern VALUE grpc_rb_eCallError;
/* Initializes the Call class. */
void Init_grpc_call();
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 2a48f46ce2..214675af92 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -49,12 +49,20 @@
static ID id_channel;
/* id_target is the name of the hidden ivar that preserves a reference to the
- * target string used to create the call, preserved so that is does not get
+ * target string used to create the call, preserved so that it does not get
* GCed before the channel */
static ID id_target;
+/* id_cqueue is the name of the hidden ivar that preserves a reference to the
+ * completion queue used to create the call, preserved so that it does not get
+ * GCed before the channel */
+static ID id_cqueue;
+
+/* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */
+static VALUE grpc_rb_cChannel = Qnil;
+
/* Used during the conversion of a hash to channel args during channel setup */
-static VALUE rb_cChannelArgs;
+static VALUE grpc_rb_cChannelArgs;
/* grpc_rb_channel wraps a grpc_channel. It provides a peer ruby object,
* 'mark' to minimize copying when a channel is created from ruby. */
@@ -97,13 +105,19 @@ static void grpc_rb_channel_mark(void *p) {
}
}
+static rb_data_type_t grpc_channel_data_type = {
+ "grpc_channel",
+ {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL, NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY
+};
+
/* Allocates grpc_rb_channel instances. */
static VALUE grpc_rb_channel_alloc(VALUE cls) {
grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_channel_mark, grpc_rb_channel_free,
- wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper);
}
/*
@@ -127,7 +141,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
/* "21" == 2 mandatory args, 1 (credentials) is optional */
rb_scan_args(argc, argv, "21", &target, &channel_args, &credentials);
- Data_Get_Struct(self, grpc_rb_channel, wrapper);
+ TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
target_chars = StringValueCStr(target);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
if (credentials == Qnil) {
@@ -142,6 +156,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
if (ch == NULL) {
rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s",
target_chars);
+ return Qnil;
}
rb_ivar_set(self, id_target, target);
wrapper->wrapped = ch;
@@ -163,11 +178,12 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) {
/* Raise an error if orig is not a channel object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_free) {
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cChannel));
+ rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cChannel));
+ return Qnil;
}
- Data_Get_Struct(orig, grpc_rb_channel, orig_ch);
- Data_Get_Struct(copy, grpc_rb_channel, copy_ch);
+ TypedData_Get_Struct(orig, grpc_rb_channel, &grpc_channel_data_type, orig_ch);
+ TypedData_Get_Struct(copy, grpc_rb_channel, &grpc_channel_data_type, copy_ch);
/* use ruby's MEMCPY to make a byte-for-byte copy of the channel wrapper
* object. */
@@ -177,34 +193,42 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) {
/* Create a call given a grpc_channel, in order to call method. The request
is not sent until grpc_call_invoke is called. */
-static VALUE grpc_rb_channel_create_call(VALUE self, VALUE method, VALUE host,
- VALUE deadline) {
+static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method,
+ VALUE host, VALUE deadline) {
VALUE res = Qnil;
grpc_rb_channel *wrapper = NULL;
- grpc_channel *ch = NULL;
grpc_call *call = NULL;
+ grpc_channel *ch = NULL;
+ grpc_completion_queue *cq = NULL;
char *method_chars = StringValueCStr(method);
char *host_chars = StringValueCStr(host);
- Data_Get_Struct(self, grpc_rb_channel, wrapper);
+ cq = grpc_rb_get_wrapped_completion_queue(cqueue);
+ TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
ch = wrapper->wrapped;
if (ch == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
+ return Qnil;
}
call =
- grpc_channel_create_call_old(ch, method_chars, host_chars,
- grpc_rb_time_timeval(deadline,
- /* absolute time */ 0));
+ grpc_channel_create_call(ch, cq, method_chars, host_chars,
+ grpc_rb_time_timeval(deadline,
+ /* absolute time */ 0));
if (call == NULL) {
rb_raise(rb_eRuntimeError, "cannot create call with method %s",
method_chars);
+ return Qnil;
}
res = grpc_rb_wrap_call(call);
- /* Make this channel an instance attribute of the call so that is is not GCed
+ /* Make this channel an instance attribute of the call so that it is not GCed
* before the call. */
rb_ivar_set(res, id_channel, self);
+
+ /* Make the completion queue an instance attribute of the call so that it is
+ * not GCed before the call. */
+ rb_ivar_set(res, id_cqueue, cqueue);
return res;
}
@@ -213,7 +237,7 @@ static VALUE grpc_rb_channel_destroy(VALUE self) {
grpc_rb_channel *wrapper = NULL;
grpc_channel *ch = NULL;
- Data_Get_Struct(self, grpc_rb_channel, wrapper);
+ TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
ch = wrapper->wrapped;
if (ch != NULL) {
grpc_channel_destroy(ch);
@@ -224,41 +248,41 @@ static VALUE grpc_rb_channel_destroy(VALUE self) {
return Qnil;
}
-/* rb_cChannel is the ruby class that proxies grpc_channel. */
-VALUE rb_cChannel = Qnil;
-
void Init_grpc_channel() {
- rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
- rb_cChannel = rb_define_class_under(rb_mGrpcCore, "Channel", rb_cObject);
+ grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
+ grpc_rb_cChannel =
+ rb_define_class_under(grpc_rb_mGrpcCore, "Channel", rb_cObject);
/* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cChannel, grpc_rb_channel_alloc);
+ rb_define_alloc_func(grpc_rb_cChannel, grpc_rb_channel_alloc);
/* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cChannel, "initialize", grpc_rb_channel_init, -1);
- rb_define_method(rb_cChannel, "initialize_copy", grpc_rb_channel_init_copy,
- 1);
+ rb_define_method(grpc_rb_cChannel, "initialize", grpc_rb_channel_init, -1);
+ rb_define_method(grpc_rb_cChannel, "initialize_copy",
+ grpc_rb_channel_init_copy, 1);
/* Add ruby analogues of the Channel methods. */
- rb_define_method(rb_cChannel, "create_call", grpc_rb_channel_create_call, 3);
- rb_define_method(rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
- rb_define_alias(rb_cChannel, "close", "destroy");
+ rb_define_method(grpc_rb_cChannel, "create_call",
+ grpc_rb_channel_create_call, 4);
+ rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
+ rb_define_alias(grpc_rb_cChannel, "close", "destroy");
id_channel = rb_intern("__channel");
+ id_cqueue = rb_intern("__cqueue");
id_target = rb_intern("__target");
- rb_define_const(rb_cChannel, "SSL_TARGET",
+ rb_define_const(grpc_rb_cChannel, "SSL_TARGET",
ID2SYM(rb_intern(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)));
- rb_define_const(rb_cChannel, "ENABLE_CENSUS",
+ rb_define_const(grpc_rb_cChannel, "ENABLE_CENSUS",
ID2SYM(rb_intern(GRPC_ARG_ENABLE_CENSUS)));
- rb_define_const(rb_cChannel, "MAX_CONCURRENT_STREAMS",
+ rb_define_const(grpc_rb_cChannel, "MAX_CONCURRENT_STREAMS",
ID2SYM(rb_intern(GRPC_ARG_MAX_CONCURRENT_STREAMS)));
- rb_define_const(rb_cChannel, "MAX_MESSAGE_LENGTH",
+ rb_define_const(grpc_rb_cChannel, "MAX_MESSAGE_LENGTH",
ID2SYM(rb_intern(GRPC_ARG_MAX_MESSAGE_LENGTH)));
}
/* Gets the wrapped channel from the ruby wrapper */
grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) {
grpc_rb_channel *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_channel, wrapper);
+ TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper);
return wrapper->wrapped;
}
diff --git a/src/ruby/ext/grpc/rb_channel.h b/src/ruby/ext/grpc/rb_channel.h
index a582869cda..6e3c087689 100644
--- a/src/ruby/ext/grpc/rb_channel.h
+++ b/src/ruby/ext/grpc/rb_channel.h
@@ -37,9 +37,6 @@
#include <ruby.h>
#include <grpc/grpc.h>
-/* rb_cChannel is the Channel class whose instances proxy grpc_channel. */
-extern VALUE rb_cChannel;
-
/* Initializes the Channel class. */
void Init_grpc_channel();
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 532ee5e785..acd545f5d2 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -38,6 +38,13 @@
#include "rb_grpc.h"
+static rb_data_type_t grpc_rb_channel_args_data_type = {
+ "grpc_channel_args",
+ {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL, NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY
+};
+
/* A callback the processes the hash key values in channel_args hash */
static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key,
VALUE val,
@@ -60,7 +67,8 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key,
return ST_STOP;
}
- Data_Get_Struct(args_obj, grpc_channel_args, args);
+ TypedData_Get_Struct(args_obj, grpc_channel_args,
+ &grpc_rb_channel_args_data_type, args);
if (args->num_args <= 0) {
rb_raise(rb_eRuntimeError, "hash_cb bug: num_args is %lu for key:%s",
args->num_args, StringValueCStr(key));
@@ -109,7 +117,7 @@ typedef struct channel_convert_params {
static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) {
ID id_size = rb_intern("size");
- VALUE rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
+ VALUE grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
channel_convert_params* params = (channel_convert_params*)as_value;
size_t num_args = 0;
@@ -126,8 +134,9 @@ static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) {
MEMZERO(params->dst->args, grpc_arg, num_args);
rb_hash_foreach(params->src_hash,
grpc_rb_channel_create_in_process_add_args_hash_cb,
- Data_Wrap_Struct(rb_cChannelArgs, GC_NOT_MARKED,
- GC_DONT_FREE, params->dst));
+ TypedData_Wrap_Struct(grpc_rb_cChannelArgs,
+ &grpc_rb_channel_args_data_type,
+ params->dst));
/* reset num_args as grpc_rb_channel_create_in_process_add_args_hash_cb
* decrements it during has processing */
params->dst->num_args = num_args;
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 3fdbdd837a..3cf6c313ee 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -33,12 +33,16 @@
#include "rb_completion_queue.h"
-#include <ruby.h>
+#include <ruby/ruby.h>
+#include <ruby/thread.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
#include "rb_grpc.h"
-#include "rb_event.h"
+
+/* grpc_rb_cCompletionQueue is the ruby class that proxies
+ * grpc_completion_queue. */
+static VALUE grpc_rb_cCompletionQueue = Qnil;
/* Used to allow grpc_completion_queue_next call to release the GIL */
typedef struct next_call_stack {
@@ -49,14 +53,16 @@ typedef struct next_call_stack {
} next_call_stack;
/* Calls grpc_completion_queue_next without holding the ruby GIL */
-static void *grpc_rb_completion_queue_next_no_gil(next_call_stack *next_call) {
+static void *grpc_rb_completion_queue_next_no_gil(void *param) {
+ next_call_stack *const next_call = (next_call_stack*)param;
next_call->event =
grpc_completion_queue_next(next_call->cq, next_call->timeout);
return NULL;
}
/* Calls grpc_completion_queue_pluck without holding the ruby GIL */
-static void *grpc_rb_completion_queue_pluck_no_gil(next_call_stack *next_call) {
+static void *grpc_rb_completion_queue_pluck_no_gil(void *param) {
+ next_call_stack *const next_call = (next_call_stack*)param;
next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag,
next_call->timeout);
return NULL;
@@ -113,21 +119,31 @@ static void grpc_rb_completion_queue_destroy(void *p) {
grpc_completion_queue_destroy(cq);
}
+static rb_data_type_t grpc_rb_completion_queue_data_type = {
+ "grpc_completion_queue",
+ {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
+ GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL, NULL,
+ /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain
+ * calls rb_thread_call_without_gvl. */
+ 0
+};
+
/* Allocates a completion queue. */
static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
grpc_completion_queue *cq = grpc_completion_queue_create();
if (cq == NULL) {
rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
}
- return Data_Wrap_Struct(cls, GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
- cq);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_completion_queue_data_type, cq);
}
/* Blocks until the next event is available, and returns the event. */
static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) {
next_call_stack next_call;
MEMZERO(&next_call, next_call_stack, 1);
- Data_Get_Struct(self, grpc_completion_queue, next_call.cq);
+ TypedData_Get_Struct(self, grpc_completion_queue,
+ &grpc_rb_completion_queue_data_type, next_call.cq);
next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
next_call.event = NULL;
rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
@@ -140,46 +156,57 @@ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) {
/* Blocks until the next event for given tag is available, and returns the
* event. */
-static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
- VALUE timeout) {
+VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
+ VALUE timeout) {
+ grpc_event *ev = grpc_rb_completion_queue_pluck_event(self, tag, timeout);
+ if (ev == NULL) {
+ return Qnil;
+ }
+ return grpc_rb_new_event(ev);
+}
+
+/* Blocks until the next event for given tag is available, and returns the
+ * event. */
+grpc_event* grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
+ VALUE timeout) {
next_call_stack next_call;
MEMZERO(&next_call, next_call_stack, 1);
- Data_Get_Struct(self, grpc_completion_queue, next_call.cq);
+ TypedData_Get_Struct(self, grpc_completion_queue,
+ &grpc_rb_completion_queue_data_type, next_call.cq);
next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0);
next_call.tag = ROBJECT(tag);
next_call.event = NULL;
rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil,
(void *)&next_call, NULL, NULL);
if (next_call.event == NULL) {
- return Qnil;
+ return NULL;
}
- return grpc_rb_new_event(next_call.event);
+ return next_call.event;
}
-/* rb_cCompletionQueue is the ruby class that proxies grpc_completion_queue. */
-VALUE rb_cCompletionQueue = Qnil;
-
void Init_grpc_completion_queue() {
- rb_cCompletionQueue =
- rb_define_class_under(rb_mGrpcCore, "CompletionQueue", rb_cObject);
+ grpc_rb_cCompletionQueue =
+ rb_define_class_under(grpc_rb_mGrpcCore, "CompletionQueue", rb_cObject);
/* constructor: uses an alloc func without an initializer. Using a simple
alloc func works here as the grpc header does not specify any args for
this func, so no separate initialization step is necessary. */
- rb_define_alloc_func(rb_cCompletionQueue, grpc_rb_completion_queue_alloc);
+ rb_define_alloc_func(grpc_rb_cCompletionQueue,
+ grpc_rb_completion_queue_alloc);
/* Add the next method that waits for the next event. */
- rb_define_method(rb_cCompletionQueue, "next", grpc_rb_completion_queue_next,
- 1);
+ rb_define_method(grpc_rb_cCompletionQueue, "next",
+ grpc_rb_completion_queue_next, 1);
/* Add the pluck method that waits for the next event of given tag */
- rb_define_method(rb_cCompletionQueue, "pluck", grpc_rb_completion_queue_pluck,
- 2);
+ rb_define_method(grpc_rb_cCompletionQueue, "pluck",
+ grpc_rb_completion_queue_pluck, 2);
}
/* Gets the wrapped completion queue from the ruby wrapper */
grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) {
grpc_completion_queue *cq = NULL;
- Data_Get_Struct(v, grpc_completion_queue, cq);
+ TypedData_Get_Struct(v, grpc_completion_queue,
+ &grpc_rb_completion_queue_data_type, cq);
return cq;
}
diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h
index 38025ea2d2..4d0f49ac47 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.h
+++ b/src/ruby/ext/grpc/rb_completion_queue.h
@@ -40,9 +40,13 @@
/* Gets the wrapped completion queue from the ruby wrapper */
grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v);
-/* rb_cCompletionQueue is the CompletionQueue class whose instances proxy
- grpc_completion_queue. */
-extern VALUE rb_cCompletionQueue;
+/**
+ * Makes the implementation of CompletionQueue#pluck available in other files
+ *
+ * This avoids having code that holds the GIL repeated at multiple sites.
+ */
+grpc_event* grpc_rb_completion_queue_pluck_event(VALUE cqueue, VALUE tag,
+ VALUE timeout);
/* Initializes the CompletionQueue class. */
void Init_grpc_completion_queue();
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
index 4ee5d6b51c..1ec88914e4 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_credentials.c
@@ -40,6 +40,9 @@
#include "rb_grpc.h"
+/* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */
+static VALUE grpc_rb_cCredentials = Qnil;
+
/* grpc_rb_credentials wraps a grpc_credentials. It provides a
* peer ruby object, 'mark' to minimize copying when a credential is
* created from ruby. */
@@ -83,14 +86,21 @@ static void grpc_rb_credentials_mark(void *p) {
}
}
+static rb_data_type_t grpc_rb_credentials_data_type = {
+ "grpc_credentials",
+ {grpc_rb_credentials_mark, grpc_rb_credentials_free,
+ GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL,
+ NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY};
+
/* Allocates Credential instances.
Provides safe initial defaults for the instance fields. */
static VALUE grpc_rb_credentials_alloc(VALUE cls) {
grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_credentials_mark,
- grpc_rb_credentials_free, wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
}
/* Clones Credentials instances.
@@ -107,11 +117,13 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) {
/* Raise an error if orig is not a credentials object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) {
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cCredentials));
+ rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials));
}
- Data_Get_Struct(orig, grpc_rb_credentials, orig_cred);
- Data_Get_Struct(copy, grpc_rb_credentials, copy_cred);
+ TypedData_Get_Struct(orig, grpc_rb_credentials,
+ &grpc_rb_credentials_data_type, orig_cred);
+ TypedData_Get_Struct(copy, grpc_rb_credentials,
+ &grpc_rb_credentials_data_type, copy_cred);
/* use ruby's MEMCPY to make a byte-for-byte copy of the credentials
* wrapper object. */
@@ -133,8 +145,7 @@ static VALUE grpc_rb_default_credentials_create(VALUE cls) {
}
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_credentials_mark,
- grpc_rb_credentials_free, wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
}
/*
@@ -151,8 +162,7 @@ static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) {
}
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_credentials_mark,
- grpc_rb_credentials_free, wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
}
/*
@@ -166,8 +176,10 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) {
grpc_rb_credentials *other_wrapper = NULL;
grpc_rb_credentials *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_credentials, self_wrapper);
- Data_Get_Struct(other, grpc_rb_credentials, other_wrapper);
+ TypedData_Get_Struct(self, grpc_rb_credentials,
+ &grpc_rb_credentials_data_type, self_wrapper);
+ 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);
@@ -178,8 +190,8 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) {
}
wrapper->mark = Qnil;
- return Data_Wrap_Struct(rb_cCredentials, grpc_rb_credentials_mark,
- grpc_rb_credentials_free, wrapper);
+ return TypedData_Wrap_Struct(grpc_rb_cCredentials,
+ &grpc_rb_credentials_data_type, wrapper);
}
/* The attribute used on the mark object to hold the pem_root_certs. */
@@ -214,7 +226,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key,
&pem_cert_chain);
- Data_Get_Struct(self, grpc_rb_credentials, wrapper);
+ TypedData_Get_Struct(self, grpc_rb_credentials,
+ &grpc_rb_credentials_data_type, wrapper);
if (pem_root_certs == Qnil) {
rb_raise(rb_eRuntimeError,
"could not create a credential: nil pem_root_certs");
@@ -225,8 +238,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
} 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);
+ creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs),
+ &key_cert_pair);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
@@ -242,30 +255,28 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
return self;
}
-/* rb_cCredentials is the ruby class that proxies grpc_credentials. */
-VALUE rb_cCredentials = Qnil;
-
void Init_grpc_credentials() {
- rb_cCredentials =
- rb_define_class_under(rb_mGrpcCore, "Credentials", rb_cObject);
+ grpc_rb_cCredentials =
+ rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject);
/* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cCredentials, grpc_rb_credentials_alloc);
+ rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc);
/* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cCredentials, "initialize", grpc_rb_credentials_init, -1);
- rb_define_method(rb_cCredentials, "initialize_copy",
+ rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init,
+ -1);
+ rb_define_method(grpc_rb_cCredentials, "initialize_copy",
grpc_rb_credentials_init_copy, 1);
/* Provide static funcs that create new special instances. */
- rb_define_singleton_method(rb_cCredentials, "default",
+ rb_define_singleton_method(grpc_rb_cCredentials, "default",
grpc_rb_default_credentials_create, 0);
- rb_define_singleton_method(rb_cCredentials, "compute_engine",
+ rb_define_singleton_method(grpc_rb_cCredentials, "compute_engine",
grpc_rb_compute_engine_credentials_create, 0);
/* Provide other methods. */
- rb_define_method(rb_cCredentials, "compose",
+ rb_define_method(grpc_rb_cCredentials, "compose",
grpc_rb_composite_credentials_create, 1);
id_pem_cert_chain = rb_intern("__pem_cert_chain");
@@ -276,6 +287,7 @@ void Init_grpc_credentials() {
/* Gets the wrapped grpc_credentials from the ruby wrapper */
grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) {
grpc_rb_credentials *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_credentials, wrapper);
+ TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type,
+ wrapper);
return wrapper->wrapped;
}
diff --git a/src/ruby/ext/grpc/rb_credentials.h b/src/ruby/ext/grpc/rb_credentials.h
index 3b24397173..e7c43c9c78 100644
--- a/src/ruby/ext/grpc/rb_credentials.h
+++ b/src/ruby/ext/grpc/rb_credentials.h
@@ -37,10 +37,6 @@
#include <ruby.h>
#include <grpc/grpc_security.h>
-/* rb_cCredentials is the ruby class whose instances proxy
- grpc_credentials. */
-extern VALUE rb_cCredentials;
-
/* Initializes the ruby Credentials class. */
void Init_grpc_credentials();
diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c
deleted file mode 100644
index 2e64af4c84..0000000000
--- a/src/ruby/ext/grpc/rb_event.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "rb_event.h"
-
-#include <ruby.h>
-
-#include <grpc/grpc.h>
-#include "rb_grpc.h"
-#include "rb_byte_buffer.h"
-#include "rb_call.h"
-#include "rb_metadata.h"
-
-/* grpc_rb_event wraps a grpc_event. It provides a peer ruby object,
- * 'mark' to minimize copying when an event is created from ruby. */
-typedef struct grpc_rb_event {
- /* Holder of ruby objects involved in constructing the channel */
- VALUE mark;
- /* The actual event */
- grpc_event *wrapped;
-} grpc_rb_event;
-
-/* rb_mCompletionType is a ruby module that holds the completion type values */
-VALUE rb_mCompletionType = Qnil;
-
-/* Destroys Event instances. */
-static void grpc_rb_event_free(void *p) {
- grpc_rb_event *ev = NULL;
- if (p == NULL) {
- return;
- };
- ev = (grpc_rb_event *)p;
-
- /* Deletes the wrapped object if the mark object is Qnil, which indicates
- * that no other object is the actual owner. */
- if (ev->wrapped != NULL && ev->mark == Qnil) {
- grpc_event_finish(ev->wrapped);
- rb_warning("event gc: destroyed the c event");
- } else {
- rb_warning("event gc: did not destroy the c event");
- }
-
- xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_event_mark(void *p) {
- grpc_rb_event *event = NULL;
- if (p == NULL) {
- return;
- }
- event = (grpc_rb_event *)p;
- if (event->mark != Qnil) {
- rb_gc_mark(event->mark);
- }
-}
-
-static VALUE grpc_rb_event_result(VALUE self);
-
-/* Obtains the type of an event. */
-static VALUE grpc_rb_event_type(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) {
- rb_raise(rb_eRuntimeError, "finished!");
- return Qnil;
- }
-
- event = wrapper->wrapped;
- switch (event->type) {
- case GRPC_QUEUE_SHUTDOWN:
- return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN"));
-
- case GRPC_READ:
- return rb_const_get(rb_mCompletionType, rb_intern("READ"));
-
- case GRPC_WRITE_ACCEPTED:
- grpc_rb_event_result(self); /* validates the result */
- return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED"));
-
- case GRPC_FINISH_ACCEPTED:
- grpc_rb_event_result(self); /* validates the result */
- return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED"));
-
- case GRPC_CLIENT_METADATA_READ:
- return rb_const_get(rb_mCompletionType,
- rb_intern("CLIENT_METADATA_READ"));
-
- case GRPC_FINISHED:
- return rb_const_get(rb_mCompletionType, rb_intern("FINISHED"));
-
- case GRPC_SERVER_RPC_NEW:
- return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW"));
-
- default:
- rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
- event->type);
- }
- return Qnil; /* should not be reached */
-}
-
-/* Obtains the tag associated with an event. */
-static VALUE grpc_rb_event_tag(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) {
- rb_raise(rb_eRuntimeError, "finished!");
- return Qnil;
- }
-
- event = wrapper->wrapped;
- if (event->tag == NULL) {
- return Qnil;
- }
- return (VALUE)event->tag;
-}
-
-/* Obtains the call associated with an event. */
-static VALUE grpc_rb_event_call(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) {
- rb_raise(rb_eRuntimeError, "finished!");
- return Qnil;
- }
-
- event = wrapper->wrapped;
- if (event->call != NULL) {
- return grpc_rb_wrap_call(event->call);
- }
- return Qnil;
-}
-
-/* Obtains the metadata associated with an event. */
-static VALUE grpc_rb_event_metadata(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- grpc_metadata *metadata = NULL;
- VALUE key = Qnil;
- VALUE new_ary = Qnil;
- VALUE result = Qnil;
- VALUE value = Qnil;
- size_t count = 0;
- size_t i = 0;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) {
- rb_raise(rb_eRuntimeError, "finished!");
- return Qnil;
- }
-
- /* Figure out which metadata to read. */
- event = wrapper->wrapped;
- switch (event->type) {
- case GRPC_CLIENT_METADATA_READ:
- count = event->data.client_metadata_read.count;
- metadata = event->data.client_metadata_read.elements;
- break;
-
- case GRPC_FINISHED:
- count = event->data.finished.metadata_count;
- metadata = event->data.finished.metadata_elements;
- break;
-
- case GRPC_SERVER_RPC_NEW:
- count = event->data.server_rpc_new.metadata_count;
- metadata = event->data.server_rpc_new.metadata_elements;
- break;
-
- default:
- rb_raise(rb_eRuntimeError,
- "bug: bad event type metadata. got %d; want %d|%d:%d",
- event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED,
- GRPC_SERVER_RPC_NEW);
- return Qnil;
- }
-
- result = rb_hash_new();
- for (i = 0; i < count; i++) {
- key = rb_str_new2(metadata[i].key);
- value = rb_hash_aref(result, key);
- if (value == Qnil) {
- value = rb_str_new(metadata[i].value, metadata[i].value_length);
- rb_hash_aset(result, key, value);
- } else if (TYPE(value) == T_ARRAY) {
- /* Add the string to the returned array */
- rb_ary_push(value,
- rb_str_new(metadata[i].value, metadata[i].value_length));
- } else {
- /* Add the current value with this key and the new one to an array */
- new_ary = rb_ary_new();
- rb_ary_push(new_ary, value);
- rb_ary_push(new_ary,
- rb_str_new(metadata[i].value, metadata[i].value_length));
- rb_hash_aset(result, key, new_ary);
- }
- }
- return result;
-}
-
-/* Obtains the data associated with an event. */
-static VALUE grpc_rb_event_result(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) {
- rb_raise(rb_eRuntimeError, "finished!");
- return Qnil;
- }
- event = wrapper->wrapped;
-
- switch (event->type) {
- case GRPC_QUEUE_SHUTDOWN:
- return Qnil;
-
- case GRPC_READ:
- return grpc_rb_byte_buffer_create_with_mark(self, event->data.read);
-
- case GRPC_FINISH_ACCEPTED:
- if (event->data.finish_accepted == GRPC_OP_OK) {
- return Qnil;
- }
- rb_raise(rb_eEventError, "finish failed, not sure why (code=%d)",
- event->data.finish_accepted);
- break;
-
- case GRPC_WRITE_ACCEPTED:
- if (event->data.write_accepted == GRPC_OP_OK) {
- return Qnil;
- }
- rb_raise(rb_eEventError, "write failed, not sure why (code=%d)",
- event->data.write_accepted);
- break;
-
- case GRPC_CLIENT_METADATA_READ:
- return grpc_rb_event_metadata(self);
-
- case GRPC_FINISHED:
- return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status),
- (event->data.finished.details == NULL
- ? Qnil
- : rb_str_new2(event->data.finished.details)),
- grpc_rb_event_metadata(self), NULL);
- break;
-
- case GRPC_SERVER_RPC_NEW:
- return rb_struct_new(
- rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method),
- rb_str_new2(event->data.server_rpc_new.host),
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
- (void *)&event->data.server_rpc_new.deadline),
- grpc_rb_event_metadata(self), NULL);
-
- default:
- rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
- event->type);
- }
-
- return Qfalse;
-}
-
-static VALUE grpc_rb_event_finish(VALUE self) {
- grpc_event *event = NULL;
- grpc_rb_event *wrapper = NULL;
- Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) { /* already closed */
- return Qnil;
- }
- event = wrapper->wrapped;
- grpc_event_finish(event);
- wrapper->wrapped = NULL;
- wrapper->mark = Qnil;
- return Qnil;
-}
-
-/* rb_cEvent is the Event class whose instances proxy grpc_event */
-VALUE rb_cEvent = Qnil;
-
-/* rb_eEventError is the ruby class of the exception thrown on failures during
- rpc event processing. */
-VALUE rb_eEventError = Qnil;
-
-void Init_grpc_event() {
- rb_eEventError =
- rb_define_class_under(rb_mGrpcCore, "EventError", rb_eStandardError);
- rb_cEvent = rb_define_class_under(rb_mGrpcCore, "Event", rb_cObject);
-
- /* Prevent allocation or inialization from ruby. */
- rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);
- rb_define_method(rb_cEvent, "initialize", grpc_rb_cannot_init, 0);
- rb_define_method(rb_cEvent, "initialize_copy", grpc_rb_cannot_init_copy, 1);
-
- /* Accessors for the data available in an event. */
- rb_define_method(rb_cEvent, "call", grpc_rb_event_call, 0);
- rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0);
- rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0);
- rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0);
- rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0);
- rb_define_alias(rb_cEvent, "close", "finish");
-
- /* Constants representing the completion types */
- rb_mCompletionType =
- rb_define_module_under(rb_mGrpcCore, "CompletionType");
- rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN",
- INT2NUM(GRPC_QUEUE_SHUTDOWN));
- rb_define_const(rb_mCompletionType, "OP_COMPLETE", INT2NUM(GRPC_OP_COMPLETE));
- rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ));
- rb_define_const(rb_mCompletionType, "WRITE_ACCEPTED",
- INT2NUM(GRPC_WRITE_ACCEPTED));
- rb_define_const(rb_mCompletionType, "FINISH_ACCEPTED",
- INT2NUM(GRPC_FINISH_ACCEPTED));
- rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ",
- INT2NUM(GRPC_CLIENT_METADATA_READ));
- rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED));
- rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW",
- INT2NUM(GRPC_SERVER_RPC_NEW));
- rb_define_const(rb_mCompletionType, "SERVER_SHUTDOWN",
- INT2NUM(GRPC_SERVER_SHUTDOWN));
- rb_define_const(rb_mCompletionType, "RESERVED",
- INT2NUM(GRPC_COMPLETION_DO_NOT_USE));
-}
-
-VALUE grpc_rb_new_event(grpc_event *ev) {
- grpc_rb_event *wrapper = ALLOC(grpc_rb_event);
- wrapper->wrapped = ev;
- wrapper->mark = Qnil;
- return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free,
- wrapper);
-}
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 400efd0dfa..699548b940 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -34,26 +34,27 @@
#include "rb_grpc.h"
#include <math.h>
-#include <ruby.h>
+#include <ruby/ruby.h>
+#include <ruby/vm.h>
#include <sys/time.h>
#include <grpc/grpc.h>
#include <grpc/support/time.h>
-#include "rb_byte_buffer.h"
#include "rb_call.h"
#include "rb_channel.h"
#include "rb_completion_queue.h"
-#include "rb_event.h"
-#include "rb_metadata.h"
#include "rb_server.h"
#include "rb_credentials.h"
#include "rb_server_credentials.h"
-/* Define common vars and funcs declared in rb.h */
-const RUBY_DATA_FUNC GC_NOT_MARKED = NULL;
-const RUBY_DATA_FUNC GC_DONT_FREE = NULL;
+static VALUE grpc_rb_cTimeVal = Qnil;
-VALUE rb_cTimeVal = Qnil;
+static rb_data_type_t grpc_rb_timespec_data_type = {
+ "gpr_timespec",
+ {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL,
+ NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY};
/* Alloc func that blocks allocation of a given object by raising an
* exception. */
@@ -99,8 +100,9 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
switch (TYPE(time)) {
case T_DATA:
- if (CLASS_OF(time) == rb_cTimeVal) {
- Data_Get_Struct(time, gpr_timespec, time_const);
+ if (CLASS_OF(time) == grpc_rb_cTimeVal) {
+ TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type,
+ time_const);
t = *time_const;
} else if (CLASS_OF(time) == rb_cTime) {
t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
@@ -153,37 +155,43 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
return t;
}
-void Init_grpc_status_codes() {
+static void Init_grpc_status_codes() {
/* Constants representing the status codes or grpc_status_code in status.h */
- VALUE rb_mStatusCodes =
- rb_define_module_under(rb_mGrpcCore, "StatusCodes");
- rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
- rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED));
- rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN));
- rb_define_const(rb_mStatusCodes, "INVALID_ARGUMENT",
+ VALUE grpc_rb_mStatusCodes =
+ rb_define_module_under(grpc_rb_mGrpcCore, "StatusCodes");
+ rb_define_const(grpc_rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
+ rb_define_const(grpc_rb_mStatusCodes, "CANCELLED",
+ INT2NUM(GRPC_STATUS_CANCELLED));
+ rb_define_const(grpc_rb_mStatusCodes, "UNKNOWN",
+ INT2NUM(GRPC_STATUS_UNKNOWN));
+ rb_define_const(grpc_rb_mStatusCodes, "INVALID_ARGUMENT",
INT2NUM(GRPC_STATUS_INVALID_ARGUMENT));
- rb_define_const(rb_mStatusCodes, "DEADLINE_EXCEEDED",
+ rb_define_const(grpc_rb_mStatusCodes, "DEADLINE_EXCEEDED",
INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED));
- rb_define_const(rb_mStatusCodes, "NOT_FOUND", INT2NUM(GRPC_STATUS_NOT_FOUND));
- rb_define_const(rb_mStatusCodes, "ALREADY_EXISTS",
+ rb_define_const(grpc_rb_mStatusCodes, "NOT_FOUND",
+ INT2NUM(GRPC_STATUS_NOT_FOUND));
+ rb_define_const(grpc_rb_mStatusCodes, "ALREADY_EXISTS",
INT2NUM(GRPC_STATUS_ALREADY_EXISTS));
- rb_define_const(rb_mStatusCodes, "PERMISSION_DENIED",
+ rb_define_const(grpc_rb_mStatusCodes, "PERMISSION_DENIED",
INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
- rb_define_const(rb_mStatusCodes, "UNAUTHENTICATED",
+ rb_define_const(grpc_rb_mStatusCodes, "UNAUTHENTICATED",
INT2NUM(GRPC_STATUS_UNAUTHENTICATED));
- rb_define_const(rb_mStatusCodes, "RESOURCE_EXHAUSTED",
+ rb_define_const(grpc_rb_mStatusCodes, "RESOURCE_EXHAUSTED",
INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED));
- rb_define_const(rb_mStatusCodes, "FAILED_PRECONDITION",
+ rb_define_const(grpc_rb_mStatusCodes, "FAILED_PRECONDITION",
INT2NUM(GRPC_STATUS_FAILED_PRECONDITION));
- rb_define_const(rb_mStatusCodes, "ABORTED", INT2NUM(GRPC_STATUS_ABORTED));
- rb_define_const(rb_mStatusCodes, "OUT_OF_RANGE",
+ rb_define_const(grpc_rb_mStatusCodes, "ABORTED",
+ INT2NUM(GRPC_STATUS_ABORTED));
+ rb_define_const(grpc_rb_mStatusCodes, "OUT_OF_RANGE",
INT2NUM(GRPC_STATUS_OUT_OF_RANGE));
- rb_define_const(rb_mStatusCodes, "UNIMPLEMENTED",
+ rb_define_const(grpc_rb_mStatusCodes, "UNIMPLEMENTED",
INT2NUM(GRPC_STATUS_UNIMPLEMENTED));
- rb_define_const(rb_mStatusCodes, "INTERNAL", INT2NUM(GRPC_STATUS_INTERNAL));
- rb_define_const(rb_mStatusCodes, "UNAVAILABLE",
+ rb_define_const(grpc_rb_mStatusCodes, "INTERNAL",
+ INT2NUM(GRPC_STATUS_INTERNAL));
+ rb_define_const(grpc_rb_mStatusCodes, "UNAVAILABLE",
INT2NUM(GRPC_STATUS_UNAVAILABLE));
- rb_define_const(rb_mStatusCodes, "DATA_LOSS", INT2NUM(GRPC_STATUS_DATA_LOSS));
+ rb_define_const(grpc_rb_mStatusCodes, "DATA_LOSS",
+ INT2NUM(GRPC_STATUS_DATA_LOSS));
}
/* id_at is the constructor method of the ruby standard Time class. */
@@ -195,42 +203,46 @@ static ID id_inspect;
/* id_to_s is the to_s method found on various ruby objects. */
static ID id_to_s;
-/* Converts `a wrapped time constant to a standard time. */
-VALUE grpc_rb_time_val_to_time(VALUE self) {
+/* Converts a wrapped time constant to a standard time. */
+static VALUE grpc_rb_time_val_to_time(VALUE self) {
gpr_timespec *time_const = NULL;
- Data_Get_Struct(self, gpr_timespec, time_const);
+ TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type,
+ time_const);
return rb_funcall(rb_cTime, id_at, 2, INT2NUM(time_const->tv_sec),
INT2NUM(time_const->tv_nsec));
}
/* Invokes inspect on the ctime version of the time val. */
-VALUE grpc_rb_time_val_inspect(VALUE self) {
+static VALUE grpc_rb_time_val_inspect(VALUE self) {
return rb_funcall(grpc_rb_time_val_to_time(self), id_inspect, 0);
}
/* Invokes to_s on the ctime version of the time val. */
-VALUE grpc_rb_time_val_to_s(VALUE self) {
+static VALUE grpc_rb_time_val_to_s(VALUE self) {
return rb_funcall(grpc_rb_time_val_to_time(self), id_to_s, 0);
}
/* Adds a module with constants that map to gpr's static timeval structs. */
-void Init_grpc_time_consts() {
- VALUE rb_mTimeConsts =
- rb_define_module_under(rb_mGrpcCore, "TimeConsts");
- rb_cTimeVal =
- rb_define_class_under(rb_mGrpcCore, "TimeSpec", rb_cObject);
- rb_define_const(rb_mTimeConsts, "ZERO",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
- (void *)&gpr_time_0));
- rb_define_const(rb_mTimeConsts, "INFINITE_FUTURE",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
- (void *)&gpr_inf_future));
- rb_define_const(rb_mTimeConsts, "INFINITE_PAST",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
- (void *)&gpr_inf_past));
- rb_define_method(rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
- rb_define_method(rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
- rb_define_method(rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
+static void Init_grpc_time_consts() {
+ VALUE grpc_rb_mTimeConsts =
+ rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
+ grpc_rb_cTimeVal =
+ rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
+ rb_define_const(
+ grpc_rb_mTimeConsts, "ZERO",
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
+ (void *)&gpr_time_0));
+ rb_define_const(
+ grpc_rb_mTimeConsts, "INFINITE_FUTURE",
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
+ (void *)&gpr_inf_future));
+ rb_define_const(
+ grpc_rb_mTimeConsts, "INFINITE_PAST",
+ TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type,
+ (void *)&gpr_inf_past));
+ rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
+ rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
+ rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
id_at = rb_intern("at");
id_inspect = rb_intern("inspect");
id_to_s = rb_intern("to_s");
@@ -238,35 +250,42 @@ void Init_grpc_time_consts() {
id_tv_nsec = rb_intern("tv_nsec");
}
-void grpc_rb_shutdown(void *vm) { grpc_shutdown(); }
+static void grpc_rb_shutdown(ruby_vm_t *vm) { grpc_shutdown(); }
/* Initialize the GRPC module structs */
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-VALUE rb_sNewServerRpc = Qnil;
-/* rb_sStatus is the struct that holds status details. */
-VALUE rb_sStatus = Qnil;
+/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
+VALUE grpc_rb_sNewServerRpc = Qnil;
+/* grpc_rb_sStatus is the struct that holds status details. */
+VALUE grpc_rb_sStatus = Qnil;
/* Initialize the GRPC module. */
-VALUE rb_mGRPC = Qnil;
-VALUE rb_mGrpcCore = Qnil;
+VALUE grpc_rb_mGRPC = Qnil;
+VALUE grpc_rb_mGrpcCore = Qnil;
+
+/* cached Symbols for members in Status struct */
+VALUE sym_code = Qundef;
+VALUE sym_details = Qundef;
+VALUE sym_metadata = Qundef;
void Init_grpc() {
grpc_init();
ruby_vm_at_exit(grpc_rb_shutdown);
- rb_mGRPC = rb_define_module("GRPC");
- rb_mGrpcCore = rb_define_module_under(rb_mGRPC, "Core");
- rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host",
- "deadline", "metadata", NULL);
- rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL);
+ grpc_rb_mGRPC = rb_define_module("GRPC");
+ grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
+ grpc_rb_sNewServerRpc =
+ rb_struct_define("NewServerRpc", "method", "host",
+ "deadline", "metadata", "call", NULL);
+ grpc_rb_sStatus =
+ rb_struct_define("Status", "code", "details", "metadata", NULL);
+ sym_code = ID2SYM(rb_intern("code"));
+ sym_details = ID2SYM(rb_intern("details"));
+ sym_metadata = ID2SYM(rb_intern("metadata"));
- Init_grpc_byte_buffer();
- Init_grpc_event();
Init_grpc_channel();
Init_grpc_completion_queue();
Init_grpc_call();
Init_grpc_credentials();
- Init_grpc_metadata();
Init_grpc_server();
Init_grpc_server_credentials();
Init_grpc_status_codes();
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index 851f5ee69f..a502273de1 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -38,26 +38,36 @@
#include <ruby.h>
#include <grpc/support/time.h>
-/* rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */
-extern VALUE rb_mGrpcCore;
+/* grpc_rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */
+extern VALUE grpc_rb_mGrpcCore;
-/* Class used to wrap timeval structs. */
-extern VALUE rb_cTimeVal;
+/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
+extern VALUE grpc_rb_sNewServerRpc;
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-extern VALUE rb_sNewServerRpc;
+/* grpc_rb_sStruct is the struct that holds status details. */
+extern VALUE grpc_rb_sStatus;
-/* rb_sStruct is the struct that holds status details. */
-extern VALUE rb_sStatus;
+/* sym_code is the symbol for the code attribute of grpc_rb_sStatus. */
+extern VALUE sym_code;
+
+/* sym_details is the symbol for the details attribute of grpc_rb_sStatus. */
+extern VALUE sym_details;
+
+/* sym_metadata is the symbol for the metadata attribute of grpc_rb_sStatus. */
+extern VALUE sym_metadata;
/* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the
wrapped struct does not need to participate in ruby gc. */
-extern const RUBY_DATA_FUNC GC_NOT_MARKED;
+#define GRPC_RB_GC_NOT_MARKED (RUBY_DATA_FUNC)(NULL)
/* GC_DONT_FREED is used in calls to Data_Wrap_Struct to indicate that the
wrapped struct should not be freed the wrapped ruby object is released by
the garbage collector. */
-extern const RUBY_DATA_FUNC GC_DONT_FREE;
+#define GRPC_RB_GC_DONT_FREE (RUBY_DATA_FUNC)(NULL)
+
+/* GRPC_RB_MEMSIZE_UNAVAILABLE is used in rb_data_type_t to indicate that the
+ * number of bytes used by the wrapped struct is not available. */
+#define GRPC_RB_MEMSIZE_UNAVAILABLE (size_t (*)(const void*))(NULL)
/* A ruby object alloc func that fails by raising an exception. */
VALUE grpc_rb_cannot_alloc(VALUE cls);
diff --git a/src/ruby/ext/grpc/rb_metadata.c b/src/ruby/ext/grpc/rb_metadata.c
deleted file mode 100644
index 7622a8c57e..0000000000
--- a/src/ruby/ext/grpc/rb_metadata.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "rb_metadata.h"
-
-#include <ruby.h>
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include "rb_grpc.h"
-
-/* grpc_rb_metadata wraps a grpc_metadata. It provides a peer ruby object,
- * 'mark' to minimize copying when a metadata is created from ruby. */
-typedef struct grpc_rb_metadata {
- /* Holder of ruby objects involved in constructing the metadata */
- VALUE mark;
- /* The actual metadata */
- grpc_metadata *wrapped;
-} grpc_rb_metadata;
-
-/* Destroys Metadata instances. */
-static void grpc_rb_metadata_free(void *p) {
- if (p == NULL) {
- return;
- };
-
- /* Because metadata is only created during a call to grpc_call_add_metadata,
- * and the call takes ownership of the metadata, this does not free the
- * wrapped struct, only the wrapper */
- xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_metadata_mark(void *p) {
- grpc_rb_metadata *md = NULL;
- if (p == NULL) {
- return;
- }
-
- md = (grpc_rb_metadata *)p;
- /* If it's not already cleaned up, mark the mark object */
- if (md->mark != Qnil && BUILTIN_TYPE(md->mark) != T_NONE) {
- rb_gc_mark(md->mark);
- }
-}
-
-/* Allocates Metadata instances.
-
- Provides safe default values for the Metadata fields. */
-static VALUE grpc_rb_metadata_alloc(VALUE cls) {
- grpc_rb_metadata *wrapper = ALLOC(grpc_rb_metadata);
- wrapper->wrapped = NULL;
- wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_metadata_mark, grpc_rb_metadata_free,
- wrapper);
-}
-
-/* id_key and id_value are the names of the hidden ivars that preserve the
- * original byte_buffer source string */
-static ID id_key;
-static ID id_value;
-
-/* Initializes Metadata instances. */
-static VALUE grpc_rb_metadata_init(VALUE self, VALUE key, VALUE value) {
- grpc_rb_metadata *wrapper = NULL;
- grpc_metadata *md = ALLOC(grpc_metadata);
-
- /* Use direct pointers to the strings wrapped by the ruby object to avoid
- * copying */
- Data_Get_Struct(self, grpc_rb_metadata, wrapper);
- wrapper->wrapped = md;
- if (TYPE(key) == T_SYMBOL) {
- md->key = (char *)rb_id2name(SYM2ID(key));
- } else { /* StringValueCStr does all other type exclusions for us */
- md->key = StringValueCStr(key);
- }
- md->value = RSTRING_PTR(value);
- md->value_length = RSTRING_LEN(value);
-
- /* Save references to the original values on the mark object so that the
- * pointers used there are valid for the lifetime of the object. */
- wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
- rb_ivar_set(wrapper->mark, id_key, key);
- rb_ivar_set(wrapper->mark, id_value, value);
-
- return self;
-}
-
-/* Clones Metadata instances.
-
- Gives Metadata a consistent implementation of Ruby's object copy/dup
- protocol. */
-static VALUE grpc_rb_metadata_init_copy(VALUE copy, VALUE orig) {
- grpc_rb_metadata *orig_md = NULL;
- grpc_rb_metadata *copy_md = NULL;
-
- if (copy == orig) {
- return copy;
- }
-
- /* Raise an error if orig is not a metadata object or a subclass. */
- if (TYPE(orig) != T_DATA ||
- RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_metadata_free) {
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cMetadata));
- }
-
- Data_Get_Struct(orig, grpc_rb_metadata, orig_md);
- Data_Get_Struct(copy, grpc_rb_metadata, copy_md);
-
- /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
- * object. */
- MEMCPY(copy_md, orig_md, grpc_rb_metadata, 1);
- return copy;
-}
-
-/* Gets the key from a metadata instance. */
-static VALUE grpc_rb_metadata_key(VALUE self) {
- VALUE key = Qnil;
- grpc_rb_metadata *wrapper = NULL;
- grpc_metadata *md = NULL;
-
- Data_Get_Struct(self, grpc_rb_metadata, wrapper);
- if (wrapper->mark != Qnil) {
- key = rb_ivar_get(wrapper->mark, id_key);
- if (key != Qnil) {
- return key;
- }
- }
-
- md = wrapper->wrapped;
- if (md == NULL || md->key == NULL) {
- return Qnil;
- }
- return rb_str_new2(md->key);
-}
-
-/* Gets the value from a metadata instance. */
-static VALUE grpc_rb_metadata_value(VALUE self) {
- VALUE val = Qnil;
- grpc_rb_metadata *wrapper = NULL;
- grpc_metadata *md = NULL;
-
- Data_Get_Struct(self, grpc_rb_metadata, wrapper);
- if (wrapper->mark != Qnil) {
- val = rb_ivar_get(wrapper->mark, id_value);
- if (val != Qnil) {
- return val;
- }
- }
-
- md = wrapper->wrapped;
- if (md == NULL || md->value == NULL) {
- return Qnil;
- }
- return rb_str_new2(md->value);
-}
-
-/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
-VALUE rb_cMetadata = Qnil;
-void Init_grpc_metadata() {
- rb_cMetadata =
- rb_define_class_under(rb_mGrpcCore, "Metadata", rb_cObject);
-
- /* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cMetadata, grpc_rb_metadata_alloc);
-
- /* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cMetadata, "initialize", grpc_rb_metadata_init, 2);
- rb_define_method(rb_cMetadata, "initialize_copy", grpc_rb_metadata_init_copy,
- 1);
-
- /* Provides accessors for the code and details. */
- rb_define_method(rb_cMetadata, "key", grpc_rb_metadata_key, 0);
- rb_define_method(rb_cMetadata, "value", grpc_rb_metadata_value, 0);
-
- id_key = rb_intern("__key");
- id_value = rb_intern("__value");
-}
-
-/* Gets the wrapped metadata from the ruby wrapper */
-grpc_metadata *grpc_rb_get_wrapped_metadata(VALUE v) {
- grpc_rb_metadata *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_metadata, wrapper);
- return wrapper->wrapped;
-}
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index c54f02e87a..bc0878af05 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -43,8 +43,11 @@
#include "rb_server_credentials.h"
#include "rb_grpc.h"
-/* rb_cServer is the ruby class that proxies grpc_server. */
-VALUE rb_cServer = Qnil;
+/* grpc_rb_cServer is the ruby class that proxies grpc_server. */
+static VALUE grpc_rb_cServer = Qnil;
+
+/* id_at is the constructor method of the ruby standard Time class. */
+static ID id_at;
/* grpc_rb_server wraps a grpc_server. It provides a peer ruby object,
'mark' to minimize copying when a server is created from ruby. */
@@ -85,13 +88,23 @@ static void grpc_rb_server_mark(void *p) {
}
}
+static const rb_data_type_t grpc_rb_server_data_type = {
+ "grpc_server",
+ {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL,
+ NULL,
+ /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block
+ * and we might want to unlock GVL
+ * TODO(yugui) Unlock GVL?
+ */
+ 0};
+
/* Allocates grpc_rb_server instances. */
static VALUE grpc_rb_server_alloc(VALUE cls) {
grpc_rb_server *wrapper = ALLOC(grpc_rb_server);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_server_mark, grpc_rb_server_free,
- wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper);
}
/*
@@ -107,7 +120,8 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) {
grpc_channel_args args;
MEMZERO(&args, grpc_channel_args, 1);
cq = grpc_rb_get_wrapped_completion_queue(cqueue);
- Data_Get_Struct(self, grpc_rb_server, wrapper);
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type,
+ wrapper);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
srv = grpc_server_create(cq, &args);
@@ -140,11 +154,13 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) {
/* Raise an error if orig is not a server object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_free) {
- rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cServer));
+ rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer));
}
- Data_Get_Struct(orig, grpc_rb_server, orig_srv);
- Data_Get_Struct(copy, grpc_rb_server, copy_srv);
+ TypedData_Get_Struct(orig, grpc_rb_server, &grpc_rb_server_data_type,
+ orig_srv);
+ TypedData_Get_Struct(copy, grpc_rb_server, &grpc_rb_server_data_type,
+ copy_srv);
/* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper
object. */
@@ -152,25 +168,97 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) {
return copy;
}
-static VALUE grpc_rb_server_request_call(VALUE self, VALUE tag_new) {
- grpc_call_error err;
+/* request_call_stack holds various values used by the
+ * grpc_rb_server_request_call function */
+typedef struct request_call_stack {
+ grpc_call_details details;
+ grpc_metadata_array md_ary;
+} request_call_stack;
+
+/* grpc_request_call_stack_init ensures the request_call_stack is properly
+ * initialized */
+static void grpc_request_call_stack_init(request_call_stack* st) {
+ MEMZERO(st, request_call_stack, 1);
+ grpc_metadata_array_init(&st->md_ary);
+ grpc_call_details_init(&st->details);
+ st->details.method = NULL;
+ st->details.host = NULL;
+}
+
+/* grpc_request_call_stack_cleanup ensures the request_call_stack is properly
+ * cleaned up */
+static void grpc_request_call_stack_cleanup(request_call_stack* st) {
+ grpc_metadata_array_destroy(&st->md_ary);
+ grpc_call_details_destroy(&st->details);
+}
+
+/* call-seq:
+ cq = CompletionQueue.new
+ tag = Object.new
+ timeout = 10
+ server.request_call(cqueue, tag, timeout)
+
+ Requests notification of a new call on a server. */
+static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue,
+ VALUE tag_new, VALUE timeout) {
grpc_rb_server *s = NULL;
- Data_Get_Struct(self, grpc_rb_server, s);
+ grpc_call *call = NULL;
+ grpc_event *ev = NULL;
+ grpc_call_error err;
+ request_call_stack st;
+ VALUE result;
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
+ return Qnil;
} else {
- err = grpc_server_request_call_old(s->wrapped, ROBJECT(tag_new));
+ grpc_request_call_stack_init(&st);
+ /* call grpc_server_request_call, then wait for it to complete using
+ * pluck_event */
+ err = grpc_server_request_call(
+ s->wrapped, &call, &st.details, &st.md_ary,
+ grpc_rb_get_wrapped_completion_queue(cqueue),
+ ROBJECT(tag_new));
if (err != GRPC_CALL_OK) {
- rb_raise(rb_eCallError, "server request failed: %s (code=%d)",
+ grpc_request_call_stack_cleanup(&st);
+ rb_raise(grpc_rb_eCallError,
+ "grpc_server_request_call failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
+ return Qnil;
}
+ ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout);
+ if (ev == NULL) {
+ grpc_request_call_stack_cleanup(&st);
+ return Qnil;
+ }
+ if (ev->data.op_complete != GRPC_OP_OK) {
+ grpc_request_call_stack_cleanup(&st);
+ grpc_event_finish(ev);
+ rb_raise(grpc_rb_eCallError, "request_call completion failed: (code=%d)",
+ ev->data.op_complete);
+ return Qnil;
+ }
+
+ /* build the NewServerRpc struct result */
+ result = rb_struct_new(
+ grpc_rb_sNewServerRpc,
+ rb_str_new2(st.details.method),
+ rb_str_new2(st.details.host),
+ rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec),
+ INT2NUM(st.details.deadline.tv_nsec)),
+ grpc_rb_md_ary_to_h(&st.md_ary),
+ grpc_rb_wrap_call(call),
+ NULL);
+ grpc_event_finish(ev);
+ grpc_request_call_stack_cleanup(&st);
+ return result;
}
return Qnil;
}
static VALUE grpc_rb_server_start(VALUE self) {
grpc_rb_server *s = NULL;
- Data_Get_Struct(self, grpc_rb_server, s);
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
} else {
@@ -181,7 +269,7 @@ static VALUE grpc_rb_server_start(VALUE self) {
static VALUE grpc_rb_server_destroy(VALUE self) {
grpc_rb_server *s = NULL;
- Data_Get_Struct(self, grpc_rb_server, s);
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
if (s->wrapped != NULL) {
grpc_server_shutdown(s->wrapped);
grpc_server_destroy(s->wrapped);
@@ -213,7 +301,7 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
/* "11" == 1 mandatory args, 1 (rb_creds) is optional */
rb_scan_args(argc, argv, "11", &port, &rb_creds);
- Data_Get_Struct(self, grpc_rb_server, s);
+ TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s);
if (s->wrapped == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
@@ -239,27 +327,32 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
}
void Init_grpc_server() {
- rb_cServer = rb_define_class_under(rb_mGrpcCore, "Server", rb_cObject);
+ grpc_rb_cServer =
+ rb_define_class_under(grpc_rb_mGrpcCore, "Server", rb_cObject);
/* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cServer, grpc_rb_server_alloc);
+ rb_define_alloc_func(grpc_rb_cServer, grpc_rb_server_alloc);
/* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cServer, "initialize", grpc_rb_server_init, 2);
- rb_define_method(rb_cServer, "initialize_copy", grpc_rb_server_init_copy, 1);
+ rb_define_method(grpc_rb_cServer, "initialize", grpc_rb_server_init, 2);
+ rb_define_method(grpc_rb_cServer, "initialize_copy",
+ grpc_rb_server_init_copy, 1);
/* Add the server methods. */
- rb_define_method(rb_cServer, "request_call", grpc_rb_server_request_call, 1);
- rb_define_method(rb_cServer, "start", grpc_rb_server_start, 0);
- rb_define_method(rb_cServer, "destroy", grpc_rb_server_destroy, 0);
- rb_define_alias(rb_cServer, "close", "destroy");
- rb_define_method(rb_cServer, "add_http2_port", grpc_rb_server_add_http2_port,
+ rb_define_method(grpc_rb_cServer, "request_call",
+ grpc_rb_server_request_call, 3);
+ rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0);
+ rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, 0);
+ rb_define_alias(grpc_rb_cServer, "close", "destroy");
+ rb_define_method(grpc_rb_cServer, "add_http2_port",
+ grpc_rb_server_add_http2_port,
-1);
+ id_at = rb_intern("at");
}
/* Gets the wrapped server from the ruby wrapper */
grpc_server *grpc_rb_get_wrapped_server(VALUE v) {
grpc_rb_server *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_server, wrapper);
+ TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper);
return wrapper->wrapped;
}
diff --git a/src/ruby/ext/grpc/rb_server.h b/src/ruby/ext/grpc/rb_server.h
index 2726b9a50a..5e4b711d35 100644
--- a/src/ruby/ext/grpc/rb_server.h
+++ b/src/ruby/ext/grpc/rb_server.h
@@ -37,10 +37,6 @@
#include <ruby.h>
#include <grpc/grpc.h>
-/* rb_cServer is the Server class whose instances proxy
- grpc_byte_buffer. */
-extern VALUE rb_cServer;
-
/* Initializes the Server class. */
void Init_grpc_server();
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index fb02987870..a86389445f 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -40,6 +40,10 @@
#include "rb_grpc.h"
+/* grpc_rb_cServerCredentials is the ruby class that proxies
+ grpc_server_credentials. */
+static VALUE grpc_rb_cServerCredentials = Qnil;
+
/* grpc_rb_server_credentials wraps a grpc_server_credentials. It provides a
peer ruby object, 'mark' to minimize copying when a server credential is
created from ruby. */
@@ -82,6 +86,14 @@ static void grpc_rb_server_credentials_mark(void *p) {
}
}
+static const rb_data_type_t grpc_rb_server_credentials_data_type = {
+ "grpc_server_credentials",
+ {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free,
+ GRPC_RB_MEMSIZE_UNAVAILABLE},
+ NULL, NULL,
+ RUBY_TYPED_FREE_IMMEDIATELY
+};
+
/* Allocates ServerCredential instances.
Provides safe initial defaults for the instance fields. */
@@ -89,8 +101,8 @@ static VALUE grpc_rb_server_credentials_alloc(VALUE cls) {
grpc_rb_server_credentials *wrapper = ALLOC(grpc_rb_server_credentials);
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
- return Data_Wrap_Struct(cls, grpc_rb_server_credentials_mark,
- grpc_rb_server_credentials_free, wrapper);
+ return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type,
+ wrapper);
}
/* Clones ServerCredentials instances.
@@ -109,11 +121,13 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) {
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_credentials_free) {
rb_raise(rb_eTypeError, "not a %s",
- rb_obj_classname(rb_cServerCredentials));
+ rb_obj_classname(grpc_rb_cServerCredentials));
}
- Data_Get_Struct(orig, grpc_rb_server_credentials, orig_ch);
- Data_Get_Struct(copy, grpc_rb_server_credentials, copy_ch);
+ TypedData_Get_Struct(orig, grpc_rb_server_credentials,
+ &grpc_rb_server_credentials_data_type, orig_ch);
+ TypedData_Get_Struct(copy, grpc_rb_server_credentials,
+ &grpc_rb_server_credentials_data_type, copy_ch);
/* use ruby's MEMCPY to make a byte-for-byte copy of the server_credentials
wrapper object. */
@@ -149,7 +163,8 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
grpc_rb_server_credentials *wrapper = NULL;
grpc_server_credentials *creds = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
- Data_Get_Struct(self, grpc_rb_server_credentials, wrapper);
+ 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");
@@ -180,21 +195,18 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
return self;
}
-/* rb_cServerCredentials is the ruby class that proxies
- grpc_server_credentials. */
-VALUE rb_cServerCredentials = Qnil;
-
void Init_grpc_server_credentials() {
- rb_cServerCredentials =
- rb_define_class_under(rb_mGrpcCore, "ServerCredentials", rb_cObject);
+ grpc_rb_cServerCredentials =
+ rb_define_class_under(grpc_rb_mGrpcCore, "ServerCredentials", rb_cObject);
/* Allocates an object managed by the ruby runtime */
- rb_define_alloc_func(rb_cServerCredentials, grpc_rb_server_credentials_alloc);
+ rb_define_alloc_func(grpc_rb_cServerCredentials,
+ grpc_rb_server_credentials_alloc);
/* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cServerCredentials, "initialize",
+ rb_define_method(grpc_rb_cServerCredentials, "initialize",
grpc_rb_server_credentials_init, 3);
- rb_define_method(rb_cServerCredentials, "initialize_copy",
+ rb_define_method(grpc_rb_cServerCredentials, "initialize_copy",
grpc_rb_server_credentials_init_copy, 1);
id_pem_cert_chain = rb_intern("__pem_cert_chain");
@@ -205,6 +217,7 @@ void Init_grpc_server_credentials() {
/* Gets the wrapped grpc_server_credentials from the ruby wrapper */
grpc_server_credentials *grpc_rb_get_wrapped_server_credentials(VALUE v) {
grpc_rb_server_credentials *wrapper = NULL;
- Data_Get_Struct(v, grpc_rb_server_credentials, wrapper);
+ TypedData_Get_Struct(v, grpc_rb_server_credentials,
+ &grpc_rb_server_credentials_data_type, wrapper);
return wrapper->wrapped;
}
diff --git a/src/ruby/ext/grpc/rb_server_credentials.h b/src/ruby/ext/grpc/rb_server_credentials.h
index ef377195a0..35b395ad5c 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.h
+++ b/src/ruby/ext/grpc/rb_server_credentials.h
@@ -37,10 +37,6 @@
#include <ruby.h>
#include <grpc/grpc_security.h>
-/* rb_cServerCredentials is the ruby class whose instances proxy
- grpc_server_credentials. */
-extern VALUE rb_cServerCredentials;
-
/* Initializes the ruby ServerCredentials class. */
void Init_grpc_server_credentials();
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 45cbacfeb0..19b3e21cb6 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -13,6 +13,9 @@ Gem::Specification.new do |s|
s.description = 'Send RPCs from Ruby using GRPC'
s.license = 'BSD-3-Clause'
+ s.required_ruby_version = '>= 2.0.0'
+ s.requirements << 'libgrpc ~> 0.6.0 needs to be installed'
+
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- spec/*`.split("\n")
s.executables = `git ls-files -- bin/*.rb`.split("\n").map do |f|
@@ -22,16 +25,16 @@ Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
- s.add_dependency 'googleauth', '~> 0.1'
- s.add_dependency 'logging', '~> 1.8'
+ s.add_dependency 'googleauth', '~> 0.4' # reqd for interop tests
+ s.add_dependency 'logging', '~> 2.0'
s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests
- s.add_dependency 'xray', '~> 1.1'
- s.add_development_dependency 'bundler', '~> 1.7'
- s.add_development_dependency 'rake', '~> 10.0'
- s.add_development_dependency 'rake-compiler', '~> 0'
- s.add_development_dependency 'rubocop', '~> 0.28.0'
- s.add_development_dependency 'rspec', '~> 3.0'
+ s.add_development_dependency 'simplecov', '~> 0.9'
+ s.add_development_dependency 'bundler', '~> 1.9'
+ s.add_development_dependency 'rake', '~> 10.4'
+ s.add_development_dependency 'rake-compiler', '~> 0.9'
+ s.add_development_dependency 'rspec', '~> 3.2'
+ s.add_development_dependency 'rubocop', '~> 0.30'
s.extensions = %w(ext/grpc/extconf.rb)
end
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index dd02ef7666..80b5743e91 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -30,8 +30,8 @@
require 'grpc/errors'
require 'grpc/grpc'
require 'grpc/logconfig'
+require 'grpc/notifier'
require 'grpc/version'
-require 'grpc/core/event'
require 'grpc/core/time_consts'
require 'grpc/generic/active_call'
require 'grpc/generic/client_stub'
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 58944872b5..f1201c1704 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -31,23 +31,20 @@ require 'grpc'
# GRPC contains the General RPC module.
module GRPC
- # OutOfTime is an exception class that indicates that an RPC exceeded its
- # deadline.
- OutOfTime = Class.new(StandardError)
-
# BadStatus is an exception class that indicates that an error occurred at
# either end of a GRPC connection. When raised, it indicates that a status
# error should be returned to the other end of a GRPC connection; when
# caught it means that this end received a status error.
class BadStatus < StandardError
- attr_reader :code, :details
+ attr_reader :code, :details, :metadata
# @param code [Numeric] the status code
# @param details [String] the details of the exception
- def initialize(code, details = 'unknown cause')
+ def initialize(code, details = 'unknown cause', **kw)
super("#{code}:#{details}")
@code = code
@details = details
+ @metadata = kw
end
# Converts the exception to a GRPC::Status for use in the networking
@@ -55,7 +52,11 @@ module GRPC
#
# @return [Status] with the same code and details
def to_status
- Status.new(code, details)
+ Struct::Status.new(code, details, @metadata)
end
end
+
+ # Cancelled is an exception class that indicates that an rpc was cancelled.
+ class Cancelled < StandardError
+ end
end
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 6256330e88..947c39cd22 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -30,10 +30,23 @@
require 'forwardable'
require 'grpc/generic/bidi_call'
-def assert_event_type(ev, want)
- fail OutOfTime if ev.nil?
- got = ev.type
- fail "Unexpected rpc event: got #{got}, want #{want}" unless got == want
+class Struct
+ # BatchResult is the struct returned by calls to call#start_batch.
+ class BatchResult
+ # check_status returns the status, raising an error if the status
+ # is non-nil and not OK.
+ def check_status
+ return nil if status.nil?
+ fail GRPC::Cancelled if status.code == GRPC::Core::StatusCodes::CANCELLED
+ if status.code != GRPC::Core::StatusCodes::OK
+ # raise BadStatus, propagating the metadata if present.
+ md = status.metadata
+ with_sym_keys = Hash[md.each_pair.collect { |x, y| [x.to_sym, y] }]
+ fail GRPC::BadStatus.new(status.code, status.details, **with_sym_keys)
+ end
+ status
+ end
+ end
end
# GRPC contains the General RPC module.
@@ -41,10 +54,12 @@ module GRPC
# The ActiveCall class provides simple methods for sending marshallable
# data to a call
class ActiveCall
- include Core::CompletionType
include Core::StatusCodes
include Core::TimeConsts
+ include Core::CallOps
+ extend Forwardable
attr_reader(:deadline)
+ def_delegators :@call, :cancel, :metadata
# client_invoke begins a client invocation.
#
@@ -61,15 +76,14 @@ module GRPC
# @param q [CompletionQueue] the completion queue
# @param deadline [Fixnum,TimeSpec] the deadline
def self.client_invoke(call, q, _deadline, **kw)
- fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
+ fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
unless q.is_a? Core::CompletionQueue
- fail(ArgumentError, 'not a CompletionQueue')
+ fail(TypeError, '!Core::CompletionQueue')
end
- call.add_metadata(kw) if kw.length > 0
- client_metadata_read = Object.new
- finished_tag = Object.new
- call.invoke(q, client_metadata_read, finished_tag)
- [finished_tag, client_metadata_read]
+ metadata_tag = Object.new
+ call.run_batch(q, metadata_tag, INFINITE_FUTURE,
+ SEND_INITIAL_METADATA => kw)
+ metadata_tag
end
# Creates an ActiveCall.
@@ -91,69 +105,27 @@ module GRPC
# @param marshal [Function] f(obj)->string that marshal requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
# @param deadline [Fixnum] the deadline for the call to complete
- # @param finished_tag [Object] the object used as the call's finish tag,
- # if the call has begun
- # @param read_metadata_tag [Object] the object used as the call's finish
- # tag, if the call has begun
+ # @param metadata_tag [Object] the object use obtain metadata for clients
# @param started [true|false] indicates if the call has begun
- def initialize(call, q, marshal, unmarshal, deadline, finished_tag: nil,
- read_metadata_tag: nil, started: true)
- fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
+ def initialize(call, q, marshal, unmarshal, deadline, started: true,
+ metadata_tag: nil)
+ fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
unless q.is_a? Core::CompletionQueue
- fail(ArgumentError, 'not a CompletionQueue')
+ fail(TypeError, '!Core::CompletionQueue')
end
@call = call
@cq = q
@deadline = deadline
- @finished_tag = finished_tag
- @read_metadata_tag = read_metadata_tag
@marshal = marshal
@started = started
@unmarshal = unmarshal
+ @metadata_tag = metadata_tag
end
- # Obtains the status of the call.
- #
- # this value is nil until the call completes
- # @return this call's status
- def status
- @call.status
- end
-
- # Obtains the metadata of the call.
- #
- # At the start of the call this will be nil. During the call this gets
- # some values as soon as the other end of the connection acknowledges the
- # request.
- #
- # @return this calls's metadata
- def metadata
- @call.metadata
- end
-
- # Cancels the call.
- #
- # Cancels the call. The call does not return any result, but once this it
- # has been called, the call should eventually terminate. Due to potential
- # races between the execution of the cancel and the in-flight request, the
- # result of the call after calling #cancel is indeterminate:
- #
- # - the call may terminate with a BadStatus exception, with code=CANCELLED
- # - the call may terminate with OK Status, and return a response
- # - the call may terminate with a different BadStatus exception if that
- # was happening
- def cancel
- @call.cancel
- end
-
- # indicates if the call is shutdown
- def shutdown
- @shutdown ||= false
- end
-
- # indicates if the call is cancelled.
- def cancelled
- @cancelled ||= false
+ # output_metadata are provides access to hash that can be used to
+ # save metadata to be sent as trailer
+ def output_metadata
+ @output_metadata ||= {}
end
# multi_req_view provides a restricted view of this ActiveCall for use
@@ -176,128 +148,94 @@ module GRPC
# writes_done indicates that all writes are completed.
#
- # It blocks until the remote endpoint acknowledges by sending a FINISHED
- # event, unless assert_finished is set to false. Any calls to
- # #remote_send after this call will fail.
+ # It blocks until the remote endpoint acknowledges with at status unless
+ # assert_finished is set to false. Any calls to #remote_send after this
+ # call will fail.
#
# @param assert_finished [true, false] when true(default), waits for
# FINISHED.
def writes_done(assert_finished = true)
- @call.writes_done(self)
- ev = @cq.pluck(self, INFINITE_FUTURE)
- begin
- assert_event_type(ev, FINISH_ACCEPTED)
- logger.debug("Writes done: waiting for finish? #{assert_finished}")
- ensure
- ev.close
- end
-
+ ops = {
+ SEND_CLOSE_FROM_CLIENT => nil
+ }
+ ops[RECV_STATUS_ON_CLIENT] = nil if assert_finished
+ batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
return unless assert_finished
- ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
- fail 'unexpected nil event' if ev.nil?
- ev.close
- @call.status
+ batch_result.check_status
end
- # finished waits until the call is completed.
+ # finished waits until a client call is completed.
#
- # It blocks until the remote endpoint acknowledges by sending a FINISHED
- # event.
+ # It blocks until the remote endpoint acknowledges by sending a status.
def finished
- ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
- begin
- fail "unexpected event: #{ev.inspect}" unless ev.type == FINISHED
+ batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE,
+ RECV_STATUS_ON_CLIENT => nil)
+ unless batch_result.status.nil?
if @call.metadata.nil?
- @call.metadata = ev.result.metadata
+ @call.metadata = batch_result.status.metadata
else
- @call.metadata.merge!(ev.result.metadata)
+ @call.metadata.merge!(batch_result.status.metadata)
end
-
- if ev.result.code != Core::StatusCodes::OK
- fail BadStatus.new(ev.result.code, ev.result.details)
- end
- res = ev.result
- ensure
- ev.close
end
- res
+ batch_result.check_status
end
# remote_send sends a request to the remote endpoint.
#
- # It blocks until the remote endpoint acknowledges by sending a
- # WRITE_ACCEPTED. req can be marshalled already.
+ # It blocks until the remote endpoint accepts the message.
#
# @param req [Object, String] the object to send or it's marshal form.
# @param marshalled [false, true] indicates if the object is already
# marshalled.
def remote_send(req, marshalled = false)
- assert_queue_is_ready
- logger.debug("sending #{req.inspect}, marshalled? #{marshalled}")
+ logger.debug("sending #{req}, marshalled? #{marshalled}")
if marshalled
payload = req
else
payload = @marshal.call(req)
end
- @call.start_write(Core::ByteBuffer.new(payload), self)
-
- # call queue#pluck, and wait for WRITE_ACCEPTED, so as not to return
- # until the flow control allows another send on this call.
- ev = @cq.pluck(self, INFINITE_FUTURE)
- begin
- assert_event_type(ev, WRITE_ACCEPTED)
- ensure
- ev.close
- end
+ @call.run_batch(@cq, self, INFINITE_FUTURE, SEND_MESSAGE => payload)
end
- # send_status sends a status to the remote endpoint
+ # send_status sends a status to the remote endpoint.
#
# @param code [int] the status code to send
# @param details [String] details
# @param assert_finished [true, false] when true(default), waits for
# FINISHED.
- def send_status(code = OK, details = '', assert_finished = false)
- assert_queue_is_ready
- @call.start_write_status(code, details, self)
- ev = @cq.pluck(self, INFINITE_FUTURE)
- begin
- assert_event_type(ev, FINISH_ACCEPTED)
- ensure
- ev.close
- end
- logger.debug("Status sent: #{code}:'#{details}'")
- return finished if assert_finished
+ #
+ # == Keyword Arguments ==
+ # any keyword arguments are treated as metadata to be sent to the server
+ # if a keyword value is a list, multiple metadata for it's key are sent
+ def send_status(code = OK, details = '', assert_finished = false, **kw)
+ ops = {
+ SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details, kw)
+ }
+ ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished
+ @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
nil
end
# remote_read reads a response from the remote endpoint.
#
- # It blocks until the remote endpoint sends a READ or FINISHED event. On
- # a READ, it returns the response after unmarshalling it. On
- # FINISHED, it returns nil if the status is OK, otherwise raising
- # BadStatus
+ # It blocks until the remote endpoint replies with a message or status.
+ # On receiving a message, it returns the response after unmarshalling it.
+ # On receiving a status, it returns nil if the status is OK, otherwise
+ # raising BadStatus
def remote_read
- if @call.metadata.nil? && !@read_metadata_tag.nil?
- ev = @cq.pluck(@read_metadata_tag, INFINITE_FUTURE)
- assert_event_type(ev, CLIENT_METADATA_READ)
- @call.metadata = ev.result
- @read_metadata_tag = nil
+ ops = { RECV_MESSAGE => nil }
+ ops[RECV_INITIAL_METADATA] = nil unless @metadata_tag.nil?
+ batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
+ unless @metadata_tag.nil?
+ @call.metadata = batch_result.metadata
+ @metadata_tag = nil
end
-
- @call.start_read(self)
- ev = @cq.pluck(self, INFINITE_FUTURE)
- begin
- assert_event_type(ev, READ)
- logger.debug("received req: #{ev.result.inspect}")
- unless ev.result.nil?
- logger.debug("received req.to_s: #{ev.result}")
- res = @unmarshal.call(ev.result.to_s)
- logger.debug("received_req (unmarshalled): #{res.inspect}")
- return res
- end
- ensure
- ev.close
+ logger.debug("received req: #{batch_result}")
+ unless batch_result.nil? || batch_result.message.nil?
+ logger.debug("received req.to_s: #{batch_result.message}")
+ res = @unmarshal.call(batch_result.message)
+ logger.debug("received_req (unmarshalled): #{res.inspect}")
+ return res
end
logger.debug('found nil; the final response has been sent')
nil
@@ -324,7 +262,6 @@ module GRPC
return enum_for(:each_remote_read) unless block_given?
loop do
resp = remote_read
- break if resp.is_a? Struct::Status # is an OK status
break if resp.nil? # the last response was received
yield resp
end
@@ -379,6 +316,9 @@ module GRPC
response = remote_read
finished unless response.is_a? Struct::Status
response
+ rescue GRPC::Core::CallError => e
+ finished # checks for Cancelled
+ raise e
end
# client_streamer sends a stream of requests to a GRPC server, and
@@ -402,6 +342,9 @@ module GRPC
response = remote_read
finished unless response.is_a? Struct::Status
response
+ rescue GRPC::Core::CallError => e
+ finished # checks for Cancelled
+ raise e
end
# server_streamer sends one request to the GRPC server, which yields a
@@ -428,6 +371,9 @@ module GRPC
replies = enum_for(:each_remote_read_then_finish)
return replies unless block_given?
replies.each { |r| yield r }
+ rescue GRPC::Core::CallError => e
+ finished # checks for Cancelled
+ raise e
end
# bidi_streamer sends a stream of requests to the GRPC server, and yields
@@ -461,9 +407,11 @@ module GRPC
# @return [Enumerator, nil] a response Enumerator
def bidi_streamer(requests, **kw, &blk)
start_call(**kw) unless @started
- bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline,
- @finished_tag)
+ bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
bd.run_on_client(requests, &blk)
+ rescue GRPC::Core::CallError => e
+ finished # checks for Cancelled
+ raise e
end
# run_server_bidi orchestrates a BiDi stream processing on a server.
@@ -478,16 +426,16 @@ module GRPC
#
# @param gen_each_reply [Proc] generates the BiDi stream replies
def run_server_bidi(gen_each_reply)
- bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline,
- @finished_tag)
+ bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
bd.run_on_server(gen_each_reply)
end
private
+ # Starts the call if not already started
def start_call(**kw)
- tags = ActiveCall.client_invoke(@call, @cq, @deadline, **kw)
- @finished_tag, @read_metadata_tag = tags
+ return if @started
+ @metadata_tag = ActiveCall.client_invoke(@call, @cq, @deadline, **kw)
@started = true
end
@@ -505,32 +453,17 @@ module GRPC
# SingleReqView limits access to an ActiveCall's methods for use in server
# handlers that receive just one request.
- SingleReqView = view_class(:cancelled, :deadline, :metadata)
+ SingleReqView = view_class(:cancelled, :deadline, :metadata,
+ :output_metadata)
# MultiReqView limits access to an ActiveCall's methods for use in
# server client_streamer handlers.
MultiReqView = view_class(:cancelled, :deadline, :each_queued_msg,
- :each_remote_read, :metadata)
+ :each_remote_read, :metadata, :output_metadata)
# Operation limits access to an ActiveCall's methods for use as
# a Operation on the client.
Operation = view_class(:cancel, :cancelled, :deadline, :execute,
- :metadata, :status)
-
- # confirms that no events are enqueued, and that the queue is not
- # shutdown.
- def assert_queue_is_ready
- ev = nil
- begin
- ev = @cq.pluck(self, ZERO)
- fail "unexpected event #{ev.inspect}" unless ev.nil?
- rescue OutOfTime
- logging.debug('timed out waiting for next event')
- # expected, nothing should be on the queue and the deadline was ZERO,
- # except things using another tag
- ensure
- ev.close unless ev.nil?
- end
- end
+ :metadata, :status, :start_call)
end
end
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index c66deaae60..4ca3004d6f 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -30,18 +30,12 @@
require 'forwardable'
require 'grpc/grpc'
-def assert_event_type(ev, want)
- fail OutOfTime if ev.nil?
- got = ev.type
- fail("Unexpected rpc event: got #{got}, want #{want}") unless got == want
-end
-
# GRPC contains the General RPC module.
module GRPC
# The BiDiCall class orchestrates exection of a BiDi stream on a client or
# server.
class BidiCall
- include Core::CompletionType
+ include Core::CallOps
include Core::StatusCodes
include Core::TimeConsts
@@ -63,8 +57,7 @@ module GRPC
# @param marshal [Function] f(obj)->string that marshal requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
# @param deadline [Fixnum] the deadline for the call to complete
- # @param finished_tag [Object] the object used as the call's finish tag,
- def initialize(call, q, marshal, unmarshal, deadline, finished_tag)
+ def initialize(call, q, marshal, unmarshal, deadline)
fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
unless q.is_a? Core::CompletionQueue
fail(ArgumentError, 'not a CompletionQueue')
@@ -72,7 +65,6 @@ module GRPC
@call = call
@cq = q
@deadline = deadline
- @finished_tag = finished_tag
@marshal = marshal
@readq = Queue.new
@unmarshal = unmarshal
@@ -86,13 +78,11 @@ module GRPC
# @param requests the Enumerable of requests to send
# @return an Enumerator of requests to yield
def run_on_client(requests, &blk)
- enq_th = start_write_loop(requests)
- loop_th = start_read_loop
+ @enq_th = start_write_loop(requests)
+ @loop_th = start_read_loop
replies = each_queued_msg
return replies if blk.nil?
replies.each { |r| blk.call(r) }
- enq_th.join
- loop_th.join
end
# Begins orchestration of the Bidi stream for a server generating replies.
@@ -108,10 +98,8 @@ module GRPC
# @param gen_each_reply [Proc] generates the BiDi stream replies.
def run_on_server(gen_each_reply)
replys = gen_each_reply.call(each_queued_msg)
- enq_th = start_write_loop(replys, is_client: false)
- loop_th = start_read_loop
- loop_th.join
- enq_th.join
+ @enq_th = start_write_loop(replys, is_client: false)
+ @loop_th = start_read_loop
end
private
@@ -130,10 +118,12 @@ module GRPC
logger.debug("each_queued_msg: msg##{count}")
count += 1
req = @readq.pop
+ logger.debug("each_queued_msg: req = #{req}")
throw req if req.is_a? StandardError
break if req.equal?(END_OF_READS)
yield req
end
+ @enq_th.join if @enq_th.alive?
end
# during bidi-streaming, read the requests to send from a separate thread
@@ -144,36 +134,23 @@ module GRPC
begin
count = 0
requests.each do |req|
+ logger.debug("bidi-write_loop: #{count}")
count += 1
payload = @marshal.call(req)
- @call.start_write(Core::ByteBuffer.new(payload), write_tag)
- ev = @cq.pluck(write_tag, INFINITE_FUTURE)
- begin
- assert_event_type(ev, WRITE_ACCEPTED)
- ensure
- ev.close
- end
+ @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+ SEND_MESSAGE => payload)
end
if is_client
- @call.writes_done(write_tag)
- ev = @cq.pluck(write_tag, INFINITE_FUTURE)
- begin
- assert_event_type(ev, FINISH_ACCEPTED)
- ensure
- ev.close
- end
- logger.debug("bidi-client: sent #{count} reqs, waiting to finish")
- ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
- begin
- assert_event_type(ev, FINISHED)
- ensure
- ev.close
- end
- logger.debug('bidi-client: finished received')
+ logger.debug("bidi-write-loop: sent #{count}, waiting to finish")
+ batch_result = @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+ SEND_CLOSE_FROM_CLIENT => nil,
+ RECV_STATUS_ON_CLIENT => nil)
+ batch_result.check_status
end
rescue StandardError => e
- logger.warn('bidi: write_loop failed')
+ logger.warn('bidi-write_loop: failed')
logger.warn(e)
+ raise e
end
end
end
@@ -187,27 +164,22 @@ module GRPC
# queue the initial read before beginning the loop
loop do
- logger.debug("waiting for read #{count}")
+ logger.debug("bidi-read_loop: #{count}")
count += 1
- @call.start_read(read_tag)
- ev = @cq.pluck(read_tag, INFINITE_FUTURE)
- begin
- assert_event_type(ev, READ)
-
- # handle the next event.
- if ev.result.nil?
- @readq.push(END_OF_READS)
- logger.debug('done reading!')
- break
- end
-
- # push the latest read onto the queue and continue reading
- logger.debug("received req: #{ev.result}")
- res = @unmarshal.call(ev.result.to_s)
- @readq.push(res)
- ensure
- ev.close
+ # TODO: ensure metadata is read if available, currently it's not
+ batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
+ RECV_MESSAGE => nil)
+ # handle the next message
+ if batch_result.message.nil?
+ @readq.push(END_OF_READS)
+ logger.debug('bidi-read-loop: done reading!')
+ break
end
+
+ # push the latest read onto the queue and continue reading
+ logger.debug("received req: #{batch_result.message}")
+ res = @unmarshal.call(batch_result.message)
+ @readq.push(res)
end
rescue StandardError => e
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 01328d4a5b..7b2c04aa22 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -28,16 +28,16 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc/generic/active_call'
-require 'xray/thread_dump_signal_handler'
# GRPC contains the General RPC module.
module GRPC
# ClientStub represents an endpoint used to send requests to GRPC servers.
class ClientStub
include Core::StatusCodes
+ include Core::TimeConsts
- # Default deadline is 5 seconds.
- DEFAULT_DEADLINE = 5
+ # Default timeout is 5 seconds.
+ DEFAULT_TIMEOUT = 5
# setup_channel is used by #initialize to constuct a channel from its
# arguments.
@@ -51,6 +51,14 @@ module GRPC
Core::Channel.new(host, kw, creds)
end
+ def self.update_with_jwt_aud_uri(a_hash, host, method)
+ last_slash_idx, res = method.rindex('/'), a_hash.clone
+ return res if last_slash_idx.nil?
+ service_name = method[0..(last_slash_idx - 1)]
+ res[:jwt_aud_uri] = "https://#{host}#{service_name}"
+ res
+ end
+
# check_update_metadata is used by #initialize verify that it's a Proc.
def self.check_update_metadata(update_metadata)
return update_metadata if update_metadata.nil?
@@ -76,8 +84,8 @@ module GRPC
# present the host and arbitrary keyword arg areignored, and the RPC
# connection uses this channel.
#
- # - :deadline
- # when present, this is the default deadline used for calls
+ # - :timeout
+ # when present, this is the default timeout used for calls
#
# - :update_metadata
# when present, this a func that takes a hash and returns a hash
@@ -87,13 +95,13 @@ module GRPC
# @param host [String] the host the stub connects to
# @param q [Core::CompletionQueue] used to wait for events
# @param channel_override [Core::Channel] a pre-created channel
- # @param deadline [Number] the default deadline to use in requests
+ # @param timeout [Number] the default timeout to use in requests
# @param creds [Core::Credentials] the channel
# @param update_metadata a func that updates metadata as described above
# @param kw [KeywordArgs]the channel arguments
def initialize(host, q,
channel_override: nil,
- deadline: DEFAULT_DEADLINE,
+ timeout: nil,
creds: nil,
update_metadata: nil,
**kw)
@@ -103,7 +111,7 @@ module GRPC
@update_metadata = ClientStub.check_update_metadata(update_metadata)
alt_host = kw[Core::Channel::SSL_TARGET]
@host = alt_host.nil? ? host : alt_host
- @deadline = deadline
+ @timeout = timeout.nil? ? DEFAULT_TIMEOUT : timeout
end
# request_response sends a request to a GRPC server, and returns the
@@ -140,13 +148,14 @@ module GRPC
# @param req [Object] the request sent to the server
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [Numeric] (optional) the max completion time in seconds
+ # @param timeout [Numeric] (optional) the max completion time in seconds
# @param return_op [true|false] return an Operation if true
# @return [Object] the response received from the server
- def request_response(method, req, marshal, unmarshal, deadline = nil,
+ def request_response(method, req, marshal, unmarshal, timeout = nil,
return_op: false, **kw)
- c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
+ c = new_active_call(method, marshal, unmarshal, timeout)
+ kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
+ md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.request_response(req, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@@ -197,13 +206,14 @@ module GRPC
# @param requests [Object] an Enumerable of requests to send
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [Numeric] the max completion time in seconds
+ # @param timeout [Numeric] the max completion time in seconds
# @param return_op [true|false] return an Operation if true
# @return [Object|Operation] the response received from the server
- def client_streamer(method, requests, marshal, unmarshal, deadline = nil,
+ def client_streamer(method, requests, marshal, unmarshal, timeout = nil,
return_op: false, **kw)
- c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
+ c = new_active_call(method, marshal, unmarshal, timeout)
+ kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
+ md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.client_streamer(requests, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@@ -262,14 +272,15 @@ module GRPC
# @param req [Object] the request sent to the server
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [Numeric] the max completion time in seconds
+ # @param timeout [Numeric] the max completion time in seconds
# @param return_op [true|false]return an Operation if true
# @param blk [Block] when provided, is executed for each response
# @return [Enumerator|Operation|nil] as discussed above
- def server_streamer(method, req, marshal, unmarshal, deadline = nil,
+ def server_streamer(method, req, marshal, unmarshal, timeout = nil,
return_op: false, **kw, &blk)
- c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
+ c = new_active_call(method, marshal, unmarshal, timeout)
+ kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
+ md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.server_streamer(req, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@@ -367,14 +378,15 @@ module GRPC
# @param requests [Object] an Enumerable of requests to send
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [Numeric] (optional) the max completion time in seconds
+ # @param timeout [Numeric] (optional) the max completion time in seconds
# @param blk [Block] when provided, is executed for each response
# @param return_op [true|false] return an Operation if true
# @return [Enumerator|nil|Operation] as discussed above
- def bidi_streamer(method, requests, marshal, unmarshal, deadline = nil,
+ def bidi_streamer(method, requests, marshal, unmarshal, timeout = nil,
return_op: false, **kw, &blk)
- c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
+ c = new_active_call(method, marshal, unmarshal, timeout)
+ kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
+ md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
return c.bidi_streamer(requests, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@@ -390,15 +402,14 @@ module GRPC
# Creates a new active stub
#
- # @param ch [GRPC::Channel] the channel used to create the stub.
+ # @param method [string] the method being called.
# @param marshal [Function] f(obj)->string that marshals requests
# @param unmarshal [Function] f(string)->obj that unmarshals responses
- # @param deadline [TimeConst]
- def new_active_call(ch, marshal, unmarshal, deadline = nil)
- absolute_deadline = Core::TimeConsts.from_relative_time(deadline)
- call = @ch.create_call(ch, @host, absolute_deadline)
- ActiveCall.new(call, @queue, marshal, unmarshal, absolute_deadline,
- started: false)
+ # @param timeout [TimeConst]
+ def new_active_call(method, marshal, unmarshal, timeout = nil)
+ deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
+ call = @ch.create_call(@queue, method, @host, deadline)
+ ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false)
end
end
end
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 2cb3d2eebf..10211ae239 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -80,26 +80,21 @@ module GRPC
else # is a bidi_stream
active_call.run_server_bidi(mth)
end
- send_status(active_call, OK, 'OK')
- active_call.finished
+ send_status(active_call, OK, 'OK', **active_call.output_metadata)
rescue BadStatus => e
- # this is raised by handlers that want GRPC to send an application
- # error code and detail message.
+ # this is raised by handlers that want GRPC to send an application error
+ # code and detail message and some additional app-specific metadata.
logger.debug("app err: #{active_call}, status:#{e.code}:#{e.details}")
- send_status(active_call, e.code, e.details)
+ send_status(active_call, e.code, e.details, **e.metadata)
rescue Core::CallError => e
# This is raised by GRPC internals but should rarely, if ever happen.
# Log it, but don't notify the other endpoint..
logger.warn("failed call: #{active_call}\n#{e}")
- rescue OutOfTime
+ rescue Core::OutOfTime
# This is raised when active_call#method.call exceeeds the deadline
# event. Send a status of deadline exceeded
logger.warn("late call: #{active_call}")
send_status(active_call, DEADLINE_EXCEEDED, 'late')
- rescue Core::EventError => e
- # This is raised by GRPC internals but should rarely, if ever happen.
- # Log it, but don't notify the other endpoint..
- logger.warn("failed call: #{active_call}\n#{e}")
rescue StandardError => e
# This will usuaally be an unhandled error in the handling code.
# Send back a UNKNOWN status to the client
@@ -140,9 +135,9 @@ module GRPC
"##{mth.name}: bad arg count; got:#{mth.arity}, want:#{want}, #{msg}"
end
- def send_status(active_client, code, details)
+ def send_status(active_client, code, details, **kw)
details = 'Not sure why' if details.nil?
- active_client.send_status(code, details)
+ active_client.send_status(code, details, code == OK, **kw)
rescue StandardError => e
logger.warn("Could not send status #{code}:#{details}")
logger.warn(e)
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 35e84023be..3375fcf20a 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -31,14 +31,142 @@ require 'grpc/grpc'
require 'grpc/generic/active_call'
require 'grpc/generic/service'
require 'thread'
-require 'xray/thread_dump_signal_handler'
+
+# A global that contains signals the gRPC servers should respond to.
+$grpc_signals = []
# GRPC contains the General RPC module.
module GRPC
+ # Handles the signals in $grpc_signals.
+ #
+ # @return false if the server should exit, true if not.
+ def handle_signals
+ loop do
+ sig = $grpc_signals.shift
+ case sig
+ when 'INT'
+ return false
+ when 'TERM'
+ return false
+ end
+ end
+ true
+ end
+ module_function :handle_signals
+
+ # Sets up a signal handler that adds signals to the signal handling global.
+ #
+ # Signal handlers should do as little as humanly possible.
+ # Here, they just add themselves to $grpc_signals
+ #
+ # RpcServer (and later other parts of gRPC) monitors the signals
+ # $grpc_signals in its own non-signal context.
+ def trap_signals
+ %w(INT TERM).each { |sig| trap(sig) { $grpc_signals << sig } }
+ end
+ module_function :trap_signals
+
+ # Pool is a simple thread pool.
+ class Pool
+ # Default keep alive period is 1s
+ DEFAULT_KEEP_ALIVE = 1
+
+ def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
+ fail 'pool size must be positive' unless size > 0
+ @jobs = Queue.new
+ @size = size
+ @stopped = false
+ @stop_mutex = Mutex.new
+ @stop_cond = ConditionVariable.new
+ @workers = []
+ @keep_alive = keep_alive
+ end
+
+ # Returns the number of jobs waiting
+ def jobs_waiting
+ @jobs.size
+ end
+
+ # Runs the given block on the queue with the provided args.
+ #
+ # @param args the args passed blk when it is called
+ # @param blk the block to call
+ def schedule(*args, &blk)
+ fail 'already stopped' if @stopped
+ return if blk.nil?
+ logger.info('schedule another job')
+ @jobs << [blk, args]
+ end
+
+ # Starts running the jobs in the thread pool.
+ def start
+ fail 'already stopped' if @stopped
+ until @workers.size == @size.to_i
+ next_thread = Thread.new do
+ catch(:exit) do # allows { throw :exit } to kill a thread
+ loop_execute_jobs
+ end
+ remove_current_thread
+ end
+ @workers << next_thread
+ end
+ end
+
+ # Stops the jobs in the pool
+ def stop
+ logger.info('stopping, will wait for all the workers to exit')
+ @workers.size.times { schedule { throw :exit } }
+ @stopped = true
+ @stop_mutex.synchronize do # wait @keep_alive for works to stop
+ @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
+ end
+ forcibly_stop_workers
+ logger.info('stopped, all workers are shutdown')
+ end
+
+ protected
+
+ # Forcibly shutdown any threads that are still alive.
+ def forcibly_stop_workers
+ return unless @workers.size > 0
+ logger.info("forcibly terminating #{@workers.size} worker(s)")
+ @workers.each do |t|
+ next unless t.alive?
+ begin
+ t.exit
+ rescue StandardError => e
+ logger.warn('error while terminating a worker')
+ logger.warn(e)
+ end
+ end
+ end
+
+ # removes the threads from workers, and signal when all the
+ # threads are complete.
+ def remove_current_thread
+ @stop_mutex.synchronize do
+ @workers.delete(Thread.current)
+ @stop_cond.signal if @workers.size == 0
+ end
+ end
+
+ def loop_execute_jobs
+ loop do
+ begin
+ blk, args = @jobs.pop
+ blk.call(*args)
+ rescue StandardError => e
+ logger.warn('Error in worker thread')
+ logger.warn(e)
+ end
+ end
+ end
+ end
+
# RpcServer hosts a number of services and makes them available on the
# network.
class RpcServer
- include Core::CompletionType
+ include Core::CallOps
include Core::TimeConsts
extend ::Forwardable
@@ -50,6 +178,38 @@ module GRPC
# Default max_waiting_requests size is 20
DEFAULT_MAX_WAITING_REQUESTS = 20
+ # Default poll period is 1s
+ DEFAULT_POLL_PERIOD = 1
+
+ # Signal check period is 0.25s
+ SIGNAL_CHECK_PERIOD = 0.25
+
+ # setup_cq is used by #initialize to constuct a Core::CompletionQueue from
+ # its arguments.
+ def self.setup_cq(alt_cq)
+ return Core::CompletionQueue.new if alt_cq.nil?
+ unless alt_cq.is_a? Core::CompletionQueue
+ fail(TypeError, '!CompletionQueue')
+ end
+ alt_cq
+ end
+
+ # setup_srv is used by #initialize to constuct a Core::Server from its
+ # arguments.
+ def self.setup_srv(alt_srv, cq, **kw)
+ return Core::Server.new(cq, kw) if alt_srv.nil?
+ fail(TypeError, '!Server') unless alt_srv.is_a? Core::Server
+ alt_srv
+ end
+
+ # setup_connect_md_proc is used by #initialize to validate the
+ # connect_md_proc.
+ def self.setup_connect_md_proc(a_proc)
+ return nil if a_proc.nil?
+ fail(TypeError, '!Proc') unless a_proc.is_a? Proc
+ a_proc
+ end
+
# Creates a new RpcServer.
#
# The RPC server is configured using keyword arguments.
@@ -77,30 +237,21 @@ module GRPC
# * max_waiting_requests: the maximum number of requests that are not
# being handled to allow. When this limit is exceeded, the server responds
# with not available to new requests
+ #
+ # * connect_md_proc:
+ # when non-nil is a proc for determining metadata to to send back the client
+ # on receiving an invocation req. The proc signature is:
+ # {key: val, ..} func(method_name, {key: val, ...})
def initialize(pool_size:DEFAULT_POOL_SIZE,
max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS,
- poll_period:INFINITE_FUTURE,
+ poll_period:DEFAULT_POLL_PERIOD,
completion_queue_override:nil,
server_override:nil,
+ connect_md_proc:nil,
**kw)
- if completion_queue_override.nil?
- cq = Core::CompletionQueue.new
- else
- cq = completion_queue_override
- unless cq.is_a? Core::CompletionQueue
- fail(ArgumentError, 'not a CompletionQueue')
- end
- end
- @cq = cq
-
- if server_override.nil?
- srv = Core::Server.new(@cq, kw)
- else
- srv = server_override
- fail(ArgumentError, 'not a Server') unless srv.is_a? Core::Server
- end
- @server = srv
-
+ @cq = RpcServer.setup_cq(completion_queue_override)
+ @server = RpcServer.setup_srv(server_override, @cq, **kw)
+ @connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
@pool_size = pool_size
@max_waiting_requests = max_waiting_requests
@poll_period = poll_period
@@ -117,6 +268,13 @@ module GRPC
return unless @running
@stopped = true
@pool.stop
+
+ # TODO: uncomment this:
+ #
+ # This segfaults in the c layer, so its commented out for now. Shutdown
+ # still occurs, but the c layer has to do the cleanup.
+ #
+ # @server.close
end
# determines if the server is currently running
@@ -139,7 +297,21 @@ module GRPC
running?
end
- # determines if the server is currently stopped
+ # Runs the server in its own thread, then waits for signal INT or TERM on
+ # the current thread to terminate it.
+ def run_till_terminated
+ GRPC.trap_signals
+ t = Thread.new { run }
+ wait_till_running
+ loop do
+ sleep SIGNAL_CHECK_PERIOD
+ break unless GRPC.handle_signals
+ end
+ stop
+ t.join
+ end
+
+ # Determines if the server is currently stopped
def stopped?
@stopped ||= false
end
@@ -202,154 +374,71 @@ module GRPC
end
@pool.start
@server.start
- server_tag = Object.new
- until stopped?
- @server.request_call(server_tag)
- ev = @cq.pluck(server_tag, @poll_period)
- next if ev.nil?
- if ev.type != SERVER_RPC_NEW
- logger.warn("bad evt: got:#{ev.type}, want:#{SERVER_RPC_NEW}")
- ev.close
- next
- end
- c = new_active_server_call(ev.call, ev.result)
- unless c.nil?
- mth = ev.result.method.to_sym
- ev.close
- @pool.schedule(c) do |call|
- rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
- end
- end
- end
+ loop_handle_server_calls
@running = false
end
- def new_active_server_call(call, new_server_rpc)
- # Accept the call. This is necessary even if a status is to be sent
- # back immediately
- finished_tag = Object.new
- call_queue = Core::CompletionQueue.new
- call.metadata = new_server_rpc.metadata # store the metadata
- call.server_accept(call_queue, finished_tag)
- call.server_end_initial_metadata
-
- # Send UNAVAILABLE if there are too many unprocessed jobs
+ # Sends UNAVAILABLE if there are too many unprocessed jobs
+ def available?(an_rpc)
jobs_count, max = @pool.jobs_waiting, @max_waiting_requests
logger.info("waiting: #{jobs_count}, max: #{max}")
- if @pool.jobs_waiting > @max_waiting_requests
- logger.warn("NOT AVAILABLE: too many jobs_waiting: #{new_server_rpc}")
- noop = proc { |x| x }
- c = ActiveCall.new(call, call_queue, noop, noop,
- new_server_rpc.deadline,
- finished_tag: finished_tag)
- c.send_status(StatusCodes::UNAVAILABLE, '')
- return nil
- end
-
- # Send NOT_FOUND if the method does not exist
- mth = new_server_rpc.method.to_sym
- unless rpc_descs.key?(mth)
- logger.warn("NOT_FOUND: #{new_server_rpc}")
- noop = proc { |x| x }
- c = ActiveCall.new(call, call_queue, noop, noop,
- new_server_rpc.deadline,
- finished_tag: finished_tag)
- c.send_status(StatusCodes::NOT_FOUND, '')
- return nil
- end
-
- # Create the ActiveCall
- rpc_desc = rpc_descs[mth]
- logger.info("deadline is #{new_server_rpc.deadline}; (now=#{Time.now})")
- ActiveCall.new(call, call_queue,
- rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input),
- new_server_rpc.deadline, finished_tag: finished_tag)
+ return an_rpc if @pool.jobs_waiting <= @max_waiting_requests
+ logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
+ noop = proc { |x| x }
+ c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
+ c.send_status(StatusCodes::UNAVAILABLE, '')
+ nil
end
- # Pool is a simple thread pool for running server requests.
- class Pool
- def initialize(size)
- fail 'pool size must be positive' unless size > 0
- @jobs = Queue.new
- @size = size
- @stopped = false
- @stop_mutex = Mutex.new
- @stop_cond = ConditionVariable.new
- @workers = []
- end
-
- # Returns the number of jobs waiting
- def jobs_waiting
- @jobs.size
- end
-
- # Runs the given block on the queue with the provided args.
- #
- # @param args the args passed blk when it is called
- # @param blk the block to call
- def schedule(*args, &blk)
- fail 'already stopped' if @stopped
- return if blk.nil?
- logger.info('schedule another job')
- @jobs << [blk, args]
- end
+ # Sends NOT_FOUND if the method can't be found
+ def found?(an_rpc)
+ mth = an_rpc.method.to_sym
+ return an_rpc if rpc_descs.key?(mth)
+ logger.warn("NOT_FOUND: #{an_rpc}")
+ noop = proc { |x| x }
+ c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
+ c.send_status(StatusCodes::NOT_FOUND, '')
+ nil
+ end
- # Starts running the jobs in the thread pool.
- def start
- fail 'already stopped' if @stopped
- until @workers.size == @size.to_i
- next_thread = Thread.new do
- catch(:exit) do # allows { throw :exit } to kill a thread
- loop do
- begin
- blk, args = @jobs.pop
- blk.call(*args)
- rescue StandardError => e
- logger.warn('Error in worker thread')
- logger.warn(e)
- end
- end
- end
-
- # removes the threads from workers, and signal when all the
- # threads are complete.
- @stop_mutex.synchronize do
- @workers.delete(Thread.current)
- @stop_cond.signal if @workers.size == 0
- end
+ # handles calls to the server
+ def loop_handle_server_calls
+ fail 'not running' unless @running
+ request_call_tag = Object.new
+ until stopped?
+ deadline = from_relative_time(@poll_period)
+ an_rpc = @server.request_call(@cq, request_call_tag, deadline)
+ 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
- @workers << next_thread
end
end
+ end
- # Stops the jobs in the pool
- def stop
- logger.info('stopping, will wait for all the workers to exit')
- @workers.size.times { schedule { throw :exit } }
- @stopped = true
-
- # TODO: allow configuration of the keepalive period
- keep_alive = 5
- @stop_mutex.synchronize do
- @stop_cond.wait(@stop_mutex, keep_alive) if @workers.size > 0
- end
-
- # Forcibly shutdown any threads that are still alive.
- if @workers.size > 0
- logger.warn("forcibly terminating #{@workers.size} worker(s)")
- @workers.each do |t|
- next unless t.alive?
- begin
- t.exit
- rescue StandardError => e
- logger.warn('error while terminating a worker')
- logger.warn(e)
- end
- end
- end
+ def new_active_server_call(an_rpc)
+ return nil if an_rpc.nil? || an_rpc.call.nil?
- logger.info('stopped, all workers are shutdown')
+ # allow the metadata to be accessed from the call
+ handle_call_tag = Object.new
+ an_rpc.call.metadata = an_rpc.metadata # attaches md to call for handlers
+ connect_md = nil
+ unless @connect_md_proc.nil?
+ connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata)
end
+ an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE,
+ SEND_INITIAL_METADATA => connect_md)
+ return nil unless available?(an_rpc)
+ return nil unless found?(an_rpc)
+
+ # Create the ActiveCall
+ logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
+ rpc_desc = rpc_descs[an_rpc.method.to_sym]
+ ActiveCall.new(an_rpc.call, @cq,
+ rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input),
+ an_rpc.deadline)
end
protected
@@ -362,11 +451,9 @@ module GRPC
@rpc_handlers ||= {}
end
- private
-
def assert_valid_service_class(cls)
unless cls.include?(GenericService)
- fail "#{cls} should 'include GenericService'"
+ fail "#{cls} must 'include GenericService'"
end
if cls.rpc_descs.size == 0
fail "#{cls} should specify some rpc descriptions"
@@ -376,21 +463,17 @@ module GRPC
def add_rpc_descs_for(service)
cls = service.is_a?(Class) ? service : service.class
- specs = rpc_descs
- handlers = rpc_handlers
+ specs, handlers = rpc_descs, rpc_handlers
cls.rpc_descs.each_pair do |name, spec|
route = "/#{cls.service_name}/#{name}".to_sym
- if specs.key? route
- fail "Cannot add rpc #{route} from #{spec}, already registered"
+ fail "already registered: rpc #{route} from #{spec}" if specs.key? route
+ specs[route] = spec
+ if service.is_a?(Class)
+ handlers[route] = cls.new.method(name.to_s.underscore.to_sym)
else
- specs[route] = spec
- if service.is_a?(Class)
- handlers[route] = cls.new.method(name.to_s.underscore.to_sym)
- else
- handlers[route] = service.method(name.to_s.underscore.to_sym)
- end
- logger.info("handling #{route} with #{handlers[route]}")
+ handlers[route] = service.method(name.to_s.underscore.to_sym)
end
+ logger.info("handling #{route} with #{handlers[route]}")
end
end
end
diff --git a/src/ruby/spec/alloc_spec.rb b/src/ruby/lib/grpc/notifier.rb
index 88e7e2b3e7..caa18bbed6 100644
--- a/src/ruby/spec/alloc_spec.rb
+++ b/src/ruby/lib/grpc/notifier.rb
@@ -27,18 +27,34 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-require 'grpc'
+# GRPC contains the General RPC module.
+module GRPC
+ # Notifier is useful high-level synchronization primitive.
+ class Notifier
+ attr_reader :payload, :notified
+ alias_method :notified?, :notified
-describe 'Wrapped classes where .new cannot create an instance' do
- describe GRPC::Core::Event do
- it 'should fail .new fail with a runtime error' do
- expect { GRPC::Core::Event.new }.to raise_error(TypeError)
+ def initialize
+ @mutex = Mutex.new
+ @cvar = ConditionVariable.new
+ @notified = false
+ @payload = nil
+ end
+
+ def wait
+ @mutex.synchronize do
+ @cvar.wait(@mutex) until notified?
+ end
end
- end
- describe GRPC::Core::Call do
- it 'should fail .new fail with a runtime error' do
- expect { GRPC::Core::Event.new }.to raise_error(TypeError)
+ def notify(payload)
+ @mutex.synchronize do
+ return Error.new('already notified') if notified?
+ @payload = payload
+ @notified = true
+ @cvar.signal
+ return nil
+ end
end
end
end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 513a53724f..072fb9b1aa 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.5.0'
+ VERSION = '0.6.1'
end
diff --git a/src/ruby/spec/byte_buffer_spec.rb b/src/ruby/spec/byte_buffer_spec.rb
deleted file mode 100644
index e1833ebb3a..0000000000
--- a/src/ruby/spec/byte_buffer_spec.rb
+++ /dev/null
@@ -1,67 +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.
-
-require 'grpc'
-
-describe GRPC::Core::ByteBuffer do
- describe '#new' do
- it 'is constructed from a string' do
- expect { GRPC::Core::ByteBuffer.new('#new') }.not_to raise_error
- end
-
- it 'can be constructed from the empty string' do
- expect { GRPC::Core::ByteBuffer.new('') }.not_to raise_error
- end
-
- it 'cannot be constructed from nil' do
- expect { GRPC::Core::ByteBuffer.new(nil) }.to raise_error TypeError
- end
-
- it 'cannot be constructed from non-strings' do
- [1, Object.new, :a_symbol].each do |x|
- expect { GRPC::Core::ByteBuffer.new(x) }.to raise_error TypeError
- end
- end
- end
-
- describe '#to_s' do
- it 'is the string value the ByteBuffer was constructed with' do
- expect(GRPC::Core::ByteBuffer.new('#to_s').to_s).to eq('#to_s')
- end
- end
-
- describe '#dup' do
- it 'makes an instance whose #to_s is the original string value' do
- bb = GRPC::Core::ByteBuffer.new('#dup')
- a_copy = bb.dup
- expect(a_copy.to_s).to eq('#dup')
- expect(a_copy.dup.to_s).to eq('#dup')
- end
- end
-end
diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb
index 2617564571..4977c10a7e 100644
--- a/src/ruby/spec/call_spec.rb
+++ b/src/ruby/spec/call_spec.rb
@@ -66,51 +66,34 @@ describe GRPC::Core::RpcErrors do
end
end
-describe GRPC::Core::Call do
+describe GRPC::Core::CallOps do
before(:each) do
- @tag = Object.new
- @client_queue = GRPC::Core::CompletionQueue.new
- fake_host = 'localhost:10101'
- @ch = GRPC::Core::Channel.new(fake_host, nil)
- end
-
- describe '#start_read' do
- xit 'should fail if called immediately' do
- blk = proc { make_test_call.start_read(@tag) }
- expect(&blk).to raise_error GRPC::Core::CallError
- end
- end
-
- describe '#start_write' do
- xit 'should fail if called immediately' do
- bytes = GRPC::Core::ByteBuffer.new('test string')
- blk = proc { make_test_call.start_write(bytes, @tag) }
- expect(&blk).to raise_error GRPC::Core::CallError
- end
+ @known_types = {
+ SEND_INITIAL_METADATA: 0,
+ SEND_MESSAGE: 1,
+ SEND_CLOSE_FROM_CLIENT: 2,
+ SEND_STATUS_FROM_SERVER: 3,
+ RECV_INITIAL_METADATA: 4,
+ RECV_MESSAGE: 5,
+ RECV_STATUS_ON_CLIENT: 6,
+ RECV_CLOSE_ON_SERVER: 7
+ }
end
- describe '#start_write_status' do
- xit 'should fail if called immediately' do
- blk = proc { make_test_call.start_write_status(153, 'x', @tag) }
- expect(&blk).to raise_error GRPC::Core::CallError
- end
+ it 'should have symbols for all the known operation types' do
+ m = GRPC::Core::CallOps
+ syms_and_codes = m.constants.collect { |c| [c, m.const_get(c)] }
+ expect(Hash[syms_and_codes]).to eq(@known_types)
end
+end
- describe '#writes_done' do
- xit 'should fail if called immediately' do
- blk = proc { make_test_call.writes_done(Object.new) }
- expect(&blk).to raise_error GRPC::Core::CallError
- end
- end
+describe GRPC::Core::Call do
+ let(:client_queue) { GRPC::Core::CompletionQueue.new }
+ let(:test_tag) { Object.new }
+ let(:fake_host) { 'localhost:10101' }
- describe '#add_metadata' do
- it 'adds metadata to a call without fail' do
- call = make_test_call
- n = 37
- one_md = proc { |x| [sprintf('key%d', x), sprintf('value%d', x)] }
- metadata = Hash[n.times.collect { |i| one_md.call i }]
- expect { call.add_metadata(metadata) }.to_not raise_error
- end
+ before(:each) do
+ @ch = GRPC::Core::Channel.new(fake_host, nil)
end
describe '#status' do
@@ -154,7 +137,7 @@ describe GRPC::Core::Call do
end
def make_test_call
- @ch.create_call('dummy_method', 'dummy_host', deadline)
+ @ch.create_call(client_queue, 'dummy_method', 'dummy_host', deadline)
end
def deadline
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index af73294abe..d471ff5db6 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -36,16 +36,13 @@ def load_test_certs
end
describe GRPC::Core::Channel do
- FAKE_HOST = 'localhost:0'
+ let(:fake_host) { 'localhost:0' }
+ let(:cq) { GRPC::Core::CompletionQueue.new }
def create_test_cert
GRPC::Core::Credentials.new(load_test_certs[0])
end
- before(:each) do
- @cq = GRPC::Core::CompletionQueue.new
- end
-
shared_examples '#new' do
it 'take a host name without channel args' do
expect { GRPC::Core::Channel.new('dummy_host', nil) }.not_to raise_error
@@ -61,7 +58,7 @@ describe GRPC::Core::Channel do
it 'does not take a hash with bad values as channel args' do
blk = construct_with_args(symbol: Object.new)
expect(&blk).to raise_error TypeError
- blk = construct_with_args('1' => Hash.new)
+ blk = construct_with_args('1' => {})
expect(&blk).to raise_error TypeError
end
@@ -115,25 +112,23 @@ describe GRPC::Core::Channel do
describe '#create_call' do
it 'creates a call OK' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
deadline = Time.now + 5
blk = proc do
- ch.create_call('dummy_method', 'dummy_host', deadline)
+ ch.create_call(cq, 'dummy_method', 'dummy_host', deadline)
end
expect(&blk).to_not raise_error
end
it 'raises an error if called on a closed channel' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
ch.close
deadline = Time.now + 5
blk = proc do
- ch.create_call('dummy_method', 'dummy_host', deadline)
+ ch.create_call(cq, 'dummy_method', 'dummy_host', deadline)
end
expect(&blk).to raise_error(RuntimeError)
end
@@ -141,15 +136,13 @@ describe GRPC::Core::Channel do
describe '#destroy' do
it 'destroys a channel ok' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
blk = proc { ch.destroy }
expect(&blk).to_not raise_error
end
it 'can be called more than once without error' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
blk = proc { ch.destroy }
blk.call
expect(&blk).to_not raise_error
@@ -164,15 +157,13 @@ describe GRPC::Core::Channel do
describe '#close' do
it 'closes a channel ok' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
blk = proc { ch.close }
expect(&blk).to_not raise_error
end
it 'can be called more than once without error' do
- host = FAKE_HOST
- ch = GRPC::Core::Channel.new(host, nil)
+ ch = GRPC::Core::Channel.new(fake_host, nil)
blk = proc { ch.close }
blk.call
expect(&blk).to_not raise_error
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 49a2d3bb4d..68af79f907 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -30,7 +30,6 @@
require 'grpc'
require 'spec_helper'
-include GRPC::Core::CompletionType
include GRPC::Core
def load_test_certs
@@ -40,6 +39,8 @@ def load_test_certs
end
shared_context 'setup: tags' do
+ let(:sent_message) { 'sent message' }
+ let(:reply_text) { 'the reply' }
before(:example) do
@server_finished_tag = Object.new
@client_finished_tag = Object.new
@@ -52,153 +53,136 @@ shared_context 'setup: tags' do
Time.now + 2
end
- def expect_next_event_on(queue, type, tag)
- ev = queue.pluck(tag, deadline)
- if type.nil?
- expect(ev).to be_nil
- else
- expect(ev).to_not be_nil
- expect(ev.type).to be(type)
- end
- ev
- end
-
def server_allows_client_to_proceed
- @server.request_call(@server_tag)
- ev = @server_queue.pluck(@server_tag, deadline)
- expect(ev).not_to be_nil
- expect(ev.type).to be(SERVER_RPC_NEW)
- server_call = ev.call
- server_call.server_accept(@server_queue, @server_finished_tag)
- server_call.server_end_initial_metadata
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ server_call = recvd_rpc.call
+ ops = { CallOps::SEND_INITIAL_METADATA => {} }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, ops)
+ expect(svr_batch.send_metadata).to be true
server_call
end
- def server_responds_with(server_call, reply_text)
- reply = ByteBuffer.new(reply_text)
- server_call.start_read(@server_tag)
- ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
- expect(ev.type).to be(READ)
- server_call.start_write(reply, @server_tag)
- ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
- expect(ev).not_to be_nil
- expect(ev.type).to be(WRITE_ACCEPTED)
- end
-
- def client_sends(call, sent = 'a message')
- req = ByteBuffer.new(sent)
- call.start_write(req, @tag)
- ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE)
- expect(ev).not_to be_nil
- expect(ev.type).to be(WRITE_ACCEPTED)
- sent
- end
-
def new_client_call
- @ch.create_call('/method', 'foo.test.google.fr', deadline)
+ @ch.create_call(@client_queue, '/method', 'foo.test.google.fr', deadline)
end
end
shared_examples 'basic GRPC message delivery is OK' do
+ include GRPC::Core
include_context 'setup: tags'
- it 'servers receive requests from clients and start responding' do
- reply = ByteBuffer.new('the server payload')
+ it 'servers receive requests from clients and can respond' do
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
- # check the server rpc new was received
- # @server.request_call(@server_tag)
- # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-
- # accept the call
- # server_call = ev.call
- # server_call.server_accept(@server_queue, @server_finished_tag)
- # server_call.server_end_initial_metadata
- server_call = server_allows_client_to_proceed
-
- # client sends a message
- msg = client_sends(call)
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => {},
+ CallOps::SEND_MESSAGE => sent_message
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+ expect(batch_result.send_message).to be true
# confirm the server can read the inbound message
- server_call.start_read(@server_tag)
- ev = expect_next_event_on(@server_queue, READ, @server_tag)
- expect(ev.result.to_s).to eq(msg)
-
- # the server response
- server_call.start_write(reply, @server_tag)
- expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag)
+ server_call = server_allows_client_to_proceed
+ server_ops = {
+ CallOps::RECV_MESSAGE => nil
+ }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ expect(svr_batch.message).to eq(sent_message)
end
it 'responses written by servers are received by the client' do
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
- server_call = server_allows_client_to_proceed
- client_sends(call)
- server_responds_with(server_call, 'server_response')
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => {},
+ CallOps::SEND_MESSAGE => sent_message
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+ expect(batch_result.send_message).to be true
- call.start_read(@tag)
- ev = expect_next_event_on(@client_queue, READ, @tag)
- expect(ev.result.to_s).to eq('server_response')
+ # confirm the server can read the inbound message
+ server_call = server_allows_client_to_proceed
+ server_ops = {
+ CallOps::RECV_MESSAGE => nil,
+ CallOps::SEND_MESSAGE => reply_text
+ }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ expect(svr_batch.message).to eq(sent_message)
+ expect(svr_batch.send_message).to be true
end
it 'servers can ignore a client write and send a status' do
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
- # check the server rpc new was received
- @server.request_call(@server_tag)
- ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
- expect(ev.tag).to be(@server_tag)
-
- # accept the call - need to do this to sent status.
- server_call = ev.call
- server_call.server_accept(@server_queue, @server_finished_tag)
- server_call.server_end_initial_metadata
- server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found',
- @server_tag)
-
- # Client sends some data
- client_sends(call)
-
- # client gets an empty response for the read, preceeded by some metadata.
- call.start_read(@tag)
- expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
- @client_metadata_tag)
- ev = expect_next_event_on(@client_queue, READ, @tag)
- expect(ev.tag).to be(@tag)
- expect(ev.result.to_s).to eq('')
-
- # finally, after client sends writes_done, they get the finished.
- call.writes_done(@tag)
- expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
- ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
- expect(ev.result.code).to eq(StatusCodes::NOT_FOUND)
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => {},
+ CallOps::SEND_MESSAGE => sent_message
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+ expect(batch_result.send_message).to be true
+
+ # confirm the server can read the inbound message
+ the_status = Struct::Status.new(StatusCodes::OK, 'OK')
+ server_call = server_allows_client_to_proceed
+ server_ops = {
+ CallOps::SEND_STATUS_FROM_SERVER => the_status
+ }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ expect(svr_batch.message).to eq nil
+ expect(svr_batch.send_status).to be true
end
it 'completes calls by sending status to client and server' do
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => {},
+ CallOps::SEND_MESSAGE => sent_message
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+ expect(batch_result.send_message).to be true
+
+ # confirm the server can read the inbound message and respond
+ the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})
server_call = server_allows_client_to_proceed
- client_sends(call)
- server_responds_with(server_call, 'server_response')
- server_call.start_write_status(10_101, 'status code is 10101', @server_tag)
-
- # first the client says writes are done
- call.start_read(@tag)
- expect_next_event_on(@client_queue, READ, @tag)
- call.writes_done(@tag)
-
- # but nothing happens until the server sends a status
- expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag)
- ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag)
- expect(ev.result).to be_a(Struct::Status)
-
- # client gets FINISHED
- expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
- ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
- expect(ev.result.details).to eq('status code is 10101')
- expect(ev.result.code).to eq(10_101)
+ server_ops = {
+ CallOps::RECV_MESSAGE => nil,
+ CallOps::SEND_MESSAGE => reply_text,
+ CallOps::SEND_STATUS_FROM_SERVER => the_status
+ }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ expect(svr_batch.message).to eq sent_message
+ expect(svr_batch.send_status).to be true
+ expect(svr_batch.send_message).to be true
+
+ # confirm the client can receive the server response and status.
+ client_ops = {
+ CallOps::SEND_CLOSE_FROM_CLIENT => nil,
+ CallOps::RECV_MESSAGE => nil,
+ CallOps::RECV_STATUS_ON_CLIENT => nil
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_close).to be true
+ expect(batch_result.message).to eq reply_text
+ expect(batch_result.status).to eq the_status
+
+ # confirm the server can receive the client close.
+ server_ops = {
+ CallOps::RECV_CLOSE_ON_SERVER => nil
+ }
+ svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ expect(svr_batch.send_close).to be true
end
end
@@ -208,11 +192,11 @@ shared_examples 'GRPC metadata delivery works OK' do
describe 'from client => server' do
before(:example) do
n = 7 # arbitrary number of metadata
- diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
+ diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] }
diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
- null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
+ null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] }
null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
- same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
+ same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] }
same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
symbol_key = { a_key: 'a val' }
@valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
@@ -224,25 +208,33 @@ shared_examples 'GRPC metadata delivery works OK' do
it 'raises an exception if a metadata key is invalid' do
@bad_keys.each do |md|
call = new_client_call
- expect { call.add_metadata(md) }.to raise_error
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => md
+ }
+ blk = proc do
+ call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ end
+ expect(&blk).to raise_error
end
end
it 'sends all the metadata pairs when keys and values are valid' do
@valid_metadata.each do |md|
call = new_client_call
- call.add_metadata(md)
-
- # Client begins a call OK
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
- # ... server has all metadata available even though the client did not
- # send a write
- @server.request_call(@server_tag)
- ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => md
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.send_metadata).to be true
+
+ # confirm the server can receive the client metadata
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ recvd_md = recvd_rpc.metadata
replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
- result = ev.result.metadata
- expect(result.merge(replace_symbols)).to eq(result)
+ expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
end
end
end
@@ -250,11 +242,11 @@ shared_examples 'GRPC metadata delivery works OK' do
describe 'from server => client' do
before(:example) do
n = 7 # arbitrary number of metadata
- diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
+ diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] }
diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
- null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
+ null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] }
null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
- same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
+ same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] }
same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
symbol_key = { a_key: 'a val' }
@valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
@@ -266,55 +258,81 @@ shared_examples 'GRPC metadata delivery works OK' do
it 'raises an exception if a metadata key is invalid' do
@bad_keys.each do |md|
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
+ # client signals that it's done sending metadata to allow server to
+ # respond
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => nil
+ }
+ call.run_batch(@client_queue, @client_tag, deadline, client_ops)
# server gets the invocation
- @server.request_call(@server_tag)
- ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
- expect { ev.call.add_metadata(md) }.to raise_error
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ server_ops = {
+ CallOps::SEND_INITIAL_METADATA => md
+ }
+ blk = proc do
+ recvd_rpc.call.run_batch(@server_queue, @server_tag, deadline,
+ server_ops)
+ end
+ expect(&blk).to raise_error
end
end
- it 'sends a hash that contains the status when no metadata is added' do
+ it 'sends an empty hash if no metadata is added' do
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
- # server gets the invocation
- @server.request_call(@server_tag)
- ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
- server_call = ev.call
-
- # ... server accepts the call without adding metadata
- server_call.server_accept(@server_queue, @server_finished_tag)
- server_call.server_end_initial_metadata
-
- # there is the HTTP status metadata, though there should not be any
- # TODO: update this with the bug number to be resolved
- ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
- @client_metadata_tag)
- expect(ev.result).to eq({})
+ # client signals that it's done sending metadata to allow server to
+ # respond
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => nil
+ }
+ call.run_batch(@client_queue, @client_tag, deadline, client_ops)
+
+ # server gets the invocation but sends no metadata back
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ server_call = recvd_rpc.call
+ server_ops = {
+ CallOps::SEND_INITIAL_METADATA => nil
+ }
+ server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+
+ # client receives nothing as expected
+ client_ops = {
+ CallOps::RECV_INITIAL_METADATA => nil
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
+ expect(batch_result.metadata).to eq({})
end
it 'sends all the pairs when keys and values are valid' do
@valid_metadata.each do |md|
call = new_client_call
- call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
- # server gets the invocation
- @server.request_call(@server_tag)
- ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
- server_call = ev.call
-
- # ... server adds metadata and accepts the call
- server_call.add_metadata(md)
- server_call.server_accept(@server_queue, @server_finished_tag)
- server_call.server_end_initial_metadata
-
- # Now the client can read the metadata
- ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
- @client_metadata_tag)
+ # client signals that it's done sending metadata to allow server to
+ # respond
+ client_ops = {
+ CallOps::SEND_INITIAL_METADATA => nil
+ }
+ call.run_batch(@client_queue, @client_tag, deadline, client_ops)
+
+ # server gets the invocation but sends no metadata back
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ server_call = recvd_rpc.call
+ server_ops = {
+ CallOps::SEND_INITIAL_METADATA => md
+ }
+ server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+
+ # client receives nothing as expected
+ client_ops = {
+ CallOps::RECV_INITIAL_METADATA => nil
+ }
+ batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+ client_ops)
replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
- expect(ev.result).to eq(replace_symbols)
+ expect(batch_result.metadata).to eq(replace_symbols)
end
end
end
diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/credentials_spec.rb
index fc97d11a87..8e72e85d54 100644
--- a/src/ruby/spec/credentials_spec.rb
+++ b/src/ruby/spec/credentials_spec.rb
@@ -61,11 +61,11 @@ describe Credentials do
end
describe '#compose' do
- it 'can be completed OK' do
+ it 'cannot be completed OK with 2 SSL creds' do
certs = load_test_certs
cred1 = Credentials.new(*certs)
cred2 = Credentials.new(*certs)
- expect { cred1.compose(cred2) }.to_not raise_error
+ expect { cred1.compose(cred2) }.to raise_error
end
end
end
diff --git a/src/ruby/spec/event_spec.rb b/src/ruby/spec/event_spec.rb
deleted file mode 100644
index 7d92fcd792..0000000000
--- a/src/ruby/spec/event_spec.rb
+++ /dev/null
@@ -1,53 +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.
-
-require 'grpc'
-
-describe GRPC::Core::CompletionType do
- before(:each) do
- @known_types = {
- QUEUE_SHUTDOWN: 0,
- OP_COMPLETE: 1,
- READ: 2,
- WRITE_ACCEPTED: 3,
- FINISH_ACCEPTED: 4,
- CLIENT_METADATA_READ: 5,
- FINISHED: 6,
- SERVER_RPC_NEW: 7,
- SERVER_SHUTDOWN: 8,
- RESERVED: 9
- }
- end
-
- it 'should have all the known types' do
- mod = GRPC::Core::CompletionType
- blk = proc { Hash[mod.constants.collect { |c| [c, mod.const_get(c)] }] }
- expect(blk.call).to eq(@known_types)
- end
-end
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 96e07cacb4..575871afb1 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -34,12 +34,11 @@ include GRPC::Core::StatusCodes
describe GRPC::ActiveCall do
ActiveCall = GRPC::ActiveCall
Call = GRPC::Core::Call
- CompletionType = GRPC::Core::CompletionType
+ CallOps = GRPC::Core::CallOps
before(:each) do
@pass_through = proc { |x| x }
@server_tag = Object.new
- @server_done_tag = Object.new
@tag = Object.new
@client_queue = GRPC::Core::CompletionQueue.new
@@ -48,7 +47,7 @@ describe GRPC::ActiveCall do
@server = GRPC::Core::Server.new(@server_queue, nil)
server_port = @server.add_http2_port(host)
@server.start
- @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil)
+ @ch = GRPC::Core::Channel.new("0.0.0.0:#{server_port}", nil)
end
after(:each) do
@@ -58,12 +57,10 @@ describe GRPC::ActiveCall do
describe 'restricted view methods' do
before(:each) do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
@client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
end
describe '#multi_req_view' do
@@ -90,48 +87,45 @@ describe GRPC::ActiveCall do
describe '#remote_send' do
it 'allows a client to send a payload to the server' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
@client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
@client_call.remote_send(msg)
# check that server rpc new was received
- @server.request_call(@server_tag)
- ev = @server_queue.next(deadline)
- expect(ev.type).to be(CompletionType::SERVER_RPC_NEW)
- expect(ev.call).to be_a(Call)
- expect(ev.tag).to be(@server_tag)
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ recvd_call = recvd_rpc.call
# Accept the call, and verify that the server reads the response ok.
- ev.call.server_accept(@client_queue, @server_tag)
- ev.call.server_end_initial_metadata
- server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
+ server_ops = {
+ CallOps::SEND_INITIAL_METADATA => {}
+ }
+ recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+ server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through,
@pass_through, deadline)
expect(server_call.remote_read).to eq(msg)
end
it 'marshals the payload using the marshal func' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ ActiveCall.client_invoke(call, @client_queue, deadline)
marshal = proc { |x| 'marshalled:' + x }
client_call = ActiveCall.new(call, @client_queue, marshal,
- @pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ @pass_through, deadline)
msg = 'message is a string'
client_call.remote_send(msg)
# confirm that the message was marshalled
- @server.request_call(@server_tag)
- ev = @server_queue.next(deadline)
- ev.call.server_accept(@client_queue, @server_tag)
- ev.call.server_end_initial_metadata
- server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ recvd_call = recvd_rpc.call
+ server_ops = {
+ CallOps::SEND_INITIAL_METADATA => nil
+ }
+ recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+ server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through,
@pass_through, deadline)
expect(server_call.remote_read).to eq('marshalled:' + msg)
end
@@ -142,23 +136,22 @@ describe GRPC::ActiveCall do
call = make_test_call
ActiveCall.client_invoke(call, @client_queue, deadline,
k1: 'v1', k2: 'v2')
- @server.request_call(@server_tag)
- ev = @server_queue.next(deadline)
- expect(ev).to_not be_nil
- expect(ev.result.metadata['k1']).to eq('v1')
- expect(ev.result.metadata['k2']).to eq('v2')
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ recvd_call = recvd_rpc.call
+ expect(recvd_call).to_not be_nil
+ expect(recvd_rpc.metadata).to_not be_nil
+ expect(recvd_rpc.metadata['k1']).to eq('v1')
+ expect(recvd_rpc.metadata['k2']).to eq('v2')
end
end
describe '#remote_read' do
it 'reads the response sent by a server' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg)
@@ -168,12 +161,10 @@ describe GRPC::ActiveCall do
it 'saves no metadata when the server adds no metadata' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg)
@@ -185,12 +176,10 @@ describe GRPC::ActiveCall do
it 'saves metadata add by the server' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg, k1: 'v1', k2: 'v2')
@@ -203,12 +192,10 @@ describe GRPC::ActiveCall do
it 'get a nil msg before a status when an OK status is sent' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
client_call.writes_done(false)
@@ -222,13 +209,11 @@ describe GRPC::ActiveCall do
it 'unmarshals the response using the unmarshal func' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
unmarshal = proc { |x| 'unmarshalled:' + x }
client_call = ActiveCall.new(call, @client_queue, @pass_through,
unmarshal, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
# confirm the client receives the unmarshalled message
msg = 'message is a string'
@@ -249,13 +234,11 @@ describe GRPC::ActiveCall do
it 'the returns an enumerator that can read n responses' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
- msg = 'message is 4a string'
+ metadata_tag: md_tag)
+ msg = 'message is a string'
reply = 'server_response'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg)
@@ -269,12 +252,10 @@ describe GRPC::ActiveCall do
it 'the returns an enumerator that stops after an OK Status' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- read_metadata_tag: meta_tag,
- finished_tag: done_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
reply = 'server_response'
client_call.remote_send(msg)
@@ -294,12 +275,10 @@ describe GRPC::ActiveCall do
describe '#writes_done' do
it 'finishes ok if the server sends a status response' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- finished_tag: done_tag,
- read_metadata_tag: meta_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
expect { client_call.writes_done(false) }.to_not raise_error
@@ -312,12 +291,10 @@ describe GRPC::ActiveCall do
it 'finishes ok if the server sends an early status response' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- read_metadata_tag: meta_tag,
- finished_tag: done_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg)
@@ -330,12 +307,10 @@ describe GRPC::ActiveCall do
it 'finishes ok if writes_done is true' do
call = make_test_call
- done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
- deadline)
+ md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
client_call = ActiveCall.new(call, @client_queue, @pass_through,
@pass_through, deadline,
- read_metadata_tag: meta_tag,
- finished_tag: done_tag)
+ metadata_tag: md_tag)
msg = 'message is a string'
client_call.remote_send(msg)
server_call = expect_server_to_receive(msg)
@@ -353,21 +328,20 @@ describe GRPC::ActiveCall do
end
def expect_server_to_be_invoked(**kw)
- @server.request_call(@server_tag)
- ev = @server_queue.next(deadline)
- ev.call.add_metadata(kw)
- ev.call.server_accept(@client_queue, @server_done_tag)
- ev.call.server_end_initial_metadata
- ActiveCall.new(ev.call, @client_queue, @pass_through,
- @pass_through, deadline,
- finished_tag: @server_done_tag)
+ recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+ expect(recvd_rpc).to_not eq nil
+ recvd_call = recvd_rpc.call
+ recvd_call.run_batch(@server_queue, @server_tag, deadline,
+ CallOps::SEND_INITIAL_METADATA => kw)
+ ActiveCall.new(recvd_call, @server_queue, @pass_through,
+ @pass_through, deadline)
end
def make_test_call
- @ch.create_call('dummy_method', 'dummy_host', deadline)
+ @ch.create_call(@client_queue, '/method', 'a.dummy.host', deadline)
end
def deadline
- Time.now + 1 # in 1 second; arbitrary
+ Time.now + 2 # in 2 seconds; arbitrary
end
end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 0c98fc40d9..98d68ccfbb 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -28,17 +28,13 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
-require 'xray/thread_dump_signal_handler'
-
-NOOP = proc { |x| x }
-FAKE_HOST = 'localhost:0'
def wakey_thread(&blk)
- awake_mutex, awake_cond = Mutex.new, ConditionVariable.new
+ n = GRPC::Notifier.new
t = Thread.new do
- blk.call(awake_mutex, awake_cond)
+ blk.call(n)
end
- awake_mutex.synchronize { awake_cond.wait(awake_mutex) }
+ n.wait
t
end
@@ -50,8 +46,11 @@ end
include GRPC::Core::StatusCodes
include GRPC::Core::TimeConsts
+include GRPC::Core::CallOps
describe 'ClientStub' do
+ let(:noop) { proc { |x| x } }
+
before(:each) do
Thread.abort_on_exception = true
@server = nil
@@ -66,61 +65,56 @@ describe 'ClientStub' do
end
describe '#new' do
+ let(:fake_host) { 'localhost:0' }
it 'can be created from a host and args' do
- host = FAKE_HOST
opts = { a_channel_arg: 'an_arg' }
blk = proc do
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).not_to raise_error
end
it 'can be created with a default deadline' do
- host = FAKE_HOST
opts = { a_channel_arg: 'an_arg', deadline: 5 }
blk = proc do
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).not_to raise_error
end
it 'can be created with an channel override' do
- host = FAKE_HOST
opts = { a_channel_arg: 'an_arg', channel_override: @ch }
blk = proc do
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).not_to raise_error
end
it 'cannot be created with a bad channel override' do
- host = FAKE_HOST
blk = proc do
opts = { a_channel_arg: 'an_arg', channel_override: Object.new }
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).to raise_error
end
it 'cannot be created with bad credentials' do
- host = FAKE_HOST
blk = proc do
opts = { a_channel_arg: 'an_arg', creds: Object.new }
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).to raise_error
end
it 'can be created with test test credentials' do
certs = load_test_certs
- host = FAKE_HOST
blk = proc do
opts = {
GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr',
a_channel_arg: 'an_arg',
creds: GRPC::Core::Credentials.new(certs[0], nil, nil)
}
- GRPC::ClientStub.new(host, @cq, **opts)
+ GRPC::ClientStub.new(fake_host, @cq, **opts)
end
expect(&blk).to_not raise_error
end
@@ -187,7 +181,7 @@ describe 'ClientStub' do
describe 'without a call operation' do
def get_response(stub)
- stub.request_response(@method, @sent_msg, NOOP, NOOP,
+ stub.request_response(@method, @sent_msg, noop, noop,
k1: 'v1', k2: 'v2')
end
@@ -196,7 +190,7 @@ describe 'ClientStub' do
describe 'via a call operation' do
def get_response(stub)
- op = stub.request_response(@method, @sent_msg, NOOP, NOOP,
+ op = stub.request_response(@method, @sent_msg, noop, noop,
return_op: true, k1: 'v1', k2: 'v2')
expect(op).to be_a(GRPC::ActiveCall::Operation)
op.execute
@@ -259,7 +253,7 @@ describe 'ClientStub' do
describe 'without a call operation' do
def get_response(stub)
- stub.client_streamer(@method, @sent_msgs, NOOP, NOOP,
+ stub.client_streamer(@method, @sent_msgs, noop, noop,
k1: 'v1', k2: 'v2')
end
@@ -268,7 +262,7 @@ describe 'ClientStub' do
describe 'via a call operation' do
def get_response(stub)
- op = stub.client_streamer(@method, @sent_msgs, NOOP, NOOP,
+ op = stub.client_streamer(@method, @sent_msgs, noop, noop,
return_op: true, k1: 'v1', k2: 'v2')
expect(op).to be_a(GRPC::ActiveCall::Operation)
op.execute
@@ -333,7 +327,7 @@ describe 'ClientStub' do
describe 'without a call operation' do
def get_responses(stub)
- e = stub.server_streamer(@method, @sent_msg, NOOP, NOOP,
+ e = stub.server_streamer(@method, @sent_msg, noop, noop,
k1: 'v1', k2: 'v2')
expect(e).to be_a(Enumerator)
e
@@ -344,7 +338,7 @@ describe 'ClientStub' do
describe 'via a call operation' do
def get_responses(stub)
- op = stub.server_streamer(@method, @sent_msg, NOOP, NOOP,
+ op = stub.server_streamer(@method, @sent_msg, noop, noop,
return_op: true, k1: 'v1', k2: 'v2')
expect(op).to be_a(GRPC::ActiveCall::Operation)
e = op.execute
@@ -361,34 +355,30 @@ describe 'ClientStub' do
before(:each) do
@sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
@replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
+ server_port = create_test_server
+ @host = "localhost:#{server_port}"
end
it 'supports sending all the requests first', bidi: true do
- server_port = create_test_server
- host = "localhost:#{server_port}"
th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys,
@pass)
- stub = GRPC::ClientStub.new(host, @cq)
+ stub = GRPC::ClientStub.new(@host, @cq)
e = get_responses(stub)
expect(e.collect { |r| r }).to eq(@replys)
th.join
end
it 'supports client-initiated ping pong', bidi: true do
- server_port = create_test_server
- host = "localhost:#{server_port}"
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true)
- stub = GRPC::ClientStub.new(host, @cq)
+ stub = GRPC::ClientStub.new(@host, @cq)
e = get_responses(stub)
expect(e.collect { |r| r }).to eq(@sent_msgs)
th.join
end
it 'supports a server-initiated ping pong', bidi: true do
- server_port = create_test_server
- host = "localhost:#{server_port}"
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
- stub = GRPC::ClientStub.new(host, @cq)
+ stub = GRPC::ClientStub.new(@host, @cq)
e = get_responses(stub)
expect(e.collect { |r| r }).to eq(@sent_msgs)
th.join
@@ -397,7 +387,7 @@ describe 'ClientStub' do
describe 'without a call operation' do
def get_responses(stub)
- e = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP)
+ e = stub.bidi_streamer(@method, @sent_msgs, noop, noop)
expect(e).to be_a(Enumerator)
e
end
@@ -407,7 +397,7 @@ describe 'ClientStub' do
describe 'via a call operation' do
def get_responses(stub)
- op = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP,
+ op = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
return_op: true)
expect(op).to be_a(GRPC::ActiveCall::Operation)
e = op.execute
@@ -421,8 +411,8 @@ describe 'ClientStub' do
def run_server_streamer(expected_input, replys, status, **kw)
wanted_metadata = kw.clone
- wakey_thread do |mtx, cnd|
- c = expect_server_to_be_invoked(mtx, cnd)
+ wakey_thread do |notifier|
+ c = expect_server_to_be_invoked(notifier)
wanted_metadata.each do |k, v|
expect(c.metadata[k.to_s]).to eq(v)
end
@@ -434,8 +424,8 @@ describe 'ClientStub' do
def run_bidi_streamer_handle_inputs_first(expected_inputs, replys,
status)
- wakey_thread do |mtx, cnd|
- c = expect_server_to_be_invoked(mtx, cnd)
+ wakey_thread do |notifier|
+ c = expect_server_to_be_invoked(notifier)
expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
replys.each { |r| c.remote_send(r) }
c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
@@ -443,8 +433,8 @@ describe 'ClientStub' do
end
def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts)
- wakey_thread do |mtx, cnd|
- c = expect_server_to_be_invoked(mtx, cnd)
+ wakey_thread do |notifier|
+ c = expect_server_to_be_invoked(notifier)
expected_inputs.each do |i|
if client_starts
expect(c.remote_read).to eq(i)
@@ -460,8 +450,8 @@ describe 'ClientStub' do
def run_client_streamer(expected_inputs, resp, status, **kw)
wanted_metadata = kw.clone
- wakey_thread do |mtx, cnd|
- c = expect_server_to_be_invoked(mtx, cnd)
+ wakey_thread do |notifier|
+ c = expect_server_to_be_invoked(notifier)
expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
wanted_metadata.each do |k, v|
expect(c.metadata[k.to_s]).to eq(v)
@@ -473,8 +463,8 @@ describe 'ClientStub' do
def run_request_response(expected_input, resp, status, **kw)
wanted_metadata = kw.clone
- wakey_thread do |mtx, cnd|
- c = expect_server_to_be_invoked(mtx, cnd)
+ wakey_thread do |notifier|
+ c = expect_server_to_be_invoked(notifier)
expect(c.remote_read).to eq(expected_input)
wanted_metadata.each do |k, v|
expect(c.metadata[k.to_s]).to eq(v)
@@ -490,24 +480,16 @@ describe 'ClientStub' do
@server.add_http2_port('0.0.0.0:0')
end
- def start_test_server(awake_mutex, awake_cond)
+ def expect_server_to_be_invoked(notifier)
@server.start
- @server_tag = Object.new
- @server.request_call(@server_tag)
- awake_mutex.synchronize { awake_cond.signal }
- end
-
- def expect_server_to_be_invoked(awake_mutex, awake_cond)
- start_test_server(awake_mutex, awake_cond)
- ev = @server_queue.pluck(@server_tag, INFINITE_FUTURE)
- fail OutOfTime if ev.nil?
- server_call = ev.call
- server_call.metadata = ev.result.metadata
- finished_tag = Object.new
- server_call.server_accept(@server_queue, finished_tag)
- server_call.server_end_initial_metadata
- GRPC::ActiveCall.new(server_call, @server_queue, NOOP, NOOP,
- INFINITE_FUTURE,
- finished_tag: finished_tag)
+ notifier.notify(nil)
+ server_tag = Object.new
+ recvd_rpc = @server.request_call(@server_queue, server_tag,
+ INFINITE_FUTURE)
+ recvd_call = recvd_rpc.call
+ recvd_call.metadata = recvd_rpc.metadata
+ recvd_call.run_batch(@server_queue, server_tag, Time.now + 2,
+ SEND_INITIAL_METADATA => nil)
+ GRPC::ActiveCall.new(recvd_call, @server_queue, noop, noop, INFINITE_FUTURE)
end
end
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index 39d1e83748..083632a080 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -37,7 +37,6 @@ describe GRPC::RpcDesc do
INTERNAL = GRPC::Core::StatusCodes::INTERNAL
UNKNOWN = GRPC::Core::StatusCodes::UNKNOWN
CallError = GRPC::Core::CallError
- EventError = GRPC::Core::EventError
before(:each) do
@request_response = RpcDesc.new('rr', Object.new, Object.new, 'encode',
@@ -53,49 +52,49 @@ describe GRPC::RpcDesc do
@ok_response = Object.new
end
+ shared_examples 'it handles errors' do
+ it 'sends the specified status if BadStatus is raised' do
+ expect(@call).to receive(:remote_read).once.and_return(Object.new)
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+ {})
+ this_desc.run_server_method(@call, method(:bad_status))
+ end
+
+ it 'sends status UNKNOWN if other StandardErrors are raised' do
+ expect(@call).to receive(:remote_read).once.and_return(Object.new)
+ expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+ false, {})
+ this_desc.run_server_method(@call, method(:other_error))
+ end
+
+ it 'absorbs CallError with no further action' do
+ expect(@call).to receive(:remote_read).once.and_raise(CallError)
+ blk = proc do
+ this_desc.run_server_method(@call, method(:fake_reqresp))
+ end
+ expect(&blk).to_not raise_error
+ end
+ end
+
describe '#run_server_method' do
+ let(:fake_md) { { k1: 'v1', k2: 'v2' } }
describe 'for request responses' do
+ let(:this_desc) { @request_response }
before(:each) do
@call = double('active_call')
allow(@call).to receive(:single_req_view).and_return(@call)
- allow(@call).to receive(:gc)
- end
-
- it 'sends the specified status if BadStatus is raised' do
- expect(@call).to receive(:remote_read).once.and_return(Object.new)
- expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
- @request_response.run_server_method(@call, method(:bad_status))
- end
-
- it 'sends status UNKNOWN if other StandardErrors are raised' do
- expect(@call).to receive(:remote_read).once.and_return(Object.new)
- expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
- @request_response.run_server_method(@call, method(:other_error))
- end
-
- it 'absorbs EventError with no further action' do
- expect(@call).to receive(:remote_read).once.and_raise(EventError)
- blk = proc do
- @request_response.run_server_method(@call, method(:fake_reqresp))
- end
- expect(&blk).to_not raise_error
end
- it 'absorbs CallError with no further action' do
- expect(@call).to receive(:remote_read).once.and_raise(CallError)
- blk = proc do
- @request_response.run_server_method(@call, method(:fake_reqresp))
- end
- expect(&blk).to_not raise_error
- end
+ it_behaves_like 'it handles errors'
it 'sends a response and closes the stream if there no errors' do
req = Object.new
expect(@call).to receive(:remote_read).once.and_return(req)
expect(@call).to receive(:remote_send).once.with(@ok_response)
- expect(@call).to receive(:send_status).once.with(OK, 'OK')
- expect(@call).to receive(:finished).once
- @request_response.run_server_method(@call, method(:fake_reqresp))
+ expect(@call).to receive(:output_metadata).and_return(fake_md)
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+ **fake_md)
+ this_desc.run_server_method(@call, method(:fake_reqresp))
end
end
@@ -103,27 +102,20 @@ describe GRPC::RpcDesc do
before(:each) do
@call = double('active_call')
allow(@call).to receive(:multi_req_view).and_return(@call)
- allow(@call).to receive(:gc)
end
it 'sends the specified status if BadStatus is raised' do
- expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+ {})
@client_streamer.run_server_method(@call, method(:bad_status_alt))
end
it 'sends status UNKNOWN if other StandardErrors are raised' do
- expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
+ expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+ false, {})
@client_streamer.run_server_method(@call, method(:other_error_alt))
end
- it 'absorbs EventError with no further action' do
- expect(@call).to receive(:remote_send).once.and_raise(EventError)
- blk = proc do
- @client_streamer.run_server_method(@call, method(:fake_clstream))
- end
- expect(&blk).to_not raise_error
- end
-
it 'absorbs CallError with no further action' do
expect(@call).to receive(:remote_send).once.and_raise(CallError)
blk = proc do
@@ -134,53 +126,29 @@ describe GRPC::RpcDesc do
it 'sends a response and closes the stream if there no errors' do
expect(@call).to receive(:remote_send).once.with(@ok_response)
- expect(@call).to receive(:send_status).once.with(OK, 'OK')
- expect(@call).to receive(:finished).once
+ expect(@call).to receive(:output_metadata).and_return(fake_md)
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+ **fake_md)
@client_streamer.run_server_method(@call, method(:fake_clstream))
end
end
describe 'for server streaming' do
+ let(:this_desc) { @request_response }
before(:each) do
@call = double('active_call')
allow(@call).to receive(:single_req_view).and_return(@call)
- allow(@call).to receive(:gc)
- end
-
- it 'sends the specified status if BadStatus is raised' do
- expect(@call).to receive(:remote_read).once.and_return(Object.new)
- expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
- @server_streamer.run_server_method(@call, method(:bad_status))
- end
-
- it 'sends status UNKNOWN if other StandardErrors are raised' do
- expect(@call).to receive(:remote_read).once.and_return(Object.new)
- expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
- @server_streamer.run_server_method(@call, method(:other_error))
- end
-
- it 'absorbs EventError with no further action' do
- expect(@call).to receive(:remote_read).once.and_raise(EventError)
- blk = proc do
- @server_streamer.run_server_method(@call, method(:fake_svstream))
- end
- expect(&blk).to_not raise_error
end
- it 'absorbs CallError with no further action' do
- expect(@call).to receive(:remote_read).once.and_raise(CallError)
- blk = proc do
- @server_streamer.run_server_method(@call, method(:fake_svstream))
- end
- expect(&blk).to_not raise_error
- end
+ it_behaves_like 'it handles errors'
it 'sends a response and closes the stream if there no errors' do
req = Object.new
expect(@call).to receive(:remote_read).once.and_return(req)
expect(@call).to receive(:remote_send).twice.with(@ok_response)
- expect(@call).to receive(:send_status).once.with(OK, 'OK')
- expect(@call).to receive(:finished).once
+ expect(@call).to receive(:output_metadata).and_return(fake_md)
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+ **fake_md)
@server_streamer.run_server_method(@call, method(:fake_svstream))
end
end
@@ -191,26 +159,28 @@ describe GRPC::RpcDesc do
enq_th, rwl_th = double('enqueue_th'), ('read_write_loop_th')
allow(enq_th).to receive(:join)
allow(rwl_th).to receive(:join)
- allow(@call).to receive(:gc)
end
it 'sends the specified status if BadStatus is raised' do
e = GRPC::BadStatus.new(@bs_code, 'NOK')
expect(@call).to receive(:run_server_bidi).and_raise(e)
- expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+ expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false,
+ {})
@bidi_streamer.run_server_method(@call, method(:bad_status_alt))
end
it 'sends status UNKNOWN if other StandardErrors are raised' do
expect(@call).to receive(:run_server_bidi).and_raise(StandardError)
- expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason)
+ expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason,
+ false, {})
@bidi_streamer.run_server_method(@call, method(:other_error_alt))
end
it 'closes the stream if there no errors' do
expect(@call).to receive(:run_server_bidi)
- expect(@call).to receive(:send_status).once.with(OK, 'OK')
- expect(@call).to receive(:finished).once
+ expect(@call).to receive(:output_metadata).and_return(fake_md)
+ expect(@call).to receive(:send_status).once.with(OK, 'OK', true,
+ **fake_md)
@bidi_streamer.run_server_method(@call, method(:fake_bidistream))
end
end
diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb
index 8383dc1533..aae3a7d7cb 100644
--- a/src/ruby/spec/generic/rpc_server_pool_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb
@@ -28,11 +28,10 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
-require 'xray/thread_dump_signal_handler'
-Pool = GRPC::RpcServer::Pool
+describe GRPC::Pool do
+ Pool = GRPC::Pool
-describe Pool do
describe '#new' do
it 'raises if a non-positive size is used' do
expect { Pool.new(0) }.to raise_error
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 34e5cdcd04..2cd21a15e3 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -28,7 +28,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc'
-require 'xray/thread_dump_signal_handler'
def load_test_certs
test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata')
@@ -58,18 +57,20 @@ class NoRpcImplementation
rpc :an_rpc, EchoMsg, EchoMsg
end
-# A test service with an implementation.
+# A test service with an echo implementation.
class EchoService
include GRPC::GenericService
rpc :an_rpc, EchoMsg, EchoMsg
attr_reader :received_md
- def initialize(_default_var = 'ignored')
+ def initialize(**kw)
+ @trailing_metadata = kw
@received_md = []
end
def an_rpc(req, call)
logger.info('echo service received a request')
+ call.output_metadata.update(@trailing_metadata)
@received_md << call.metadata unless call.metadata.nil?
req
end
@@ -77,6 +78,25 @@ end
EchoStub = EchoService.rpc_stub_class
+# A test service with an implementation that fails with BadStatus
+class FailingService
+ include GRPC::GenericService
+ rpc :an_rpc, EchoMsg, EchoMsg
+ attr_reader :details, :code, :md
+
+ def initialize(_default_var = 'ignored')
+ @details = 'app error'
+ @code = 101
+ @md = { failed_method: 'an_rpc' }
+ end
+
+ def an_rpc(_req, _call)
+ fail GRPC::BadStatus.new(@code, @details, **@md)
+ end
+end
+
+FailingStub = FailingService.rpc_stub_class
+
# A slow test service.
class SlowService
include GRPC::GenericService
@@ -301,21 +321,20 @@ describe GRPC::RpcServer do
end
describe '#run' do
- before(:each) do
- @client_opts = {
- channel_override: @ch
- }
- @marshal = EchoService.rpc_descs[:an_rpc].marshal_proc
- @unmarshal = EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output)
- server_opts = {
- server_override: @server,
- completion_queue_override: @server_queue,
- poll_period: 1
- }
- @srv = RpcServer.new(**server_opts)
- end
+ let(:client_opts) { { channel_override: @ch } }
+ let(:marshal) { EchoService.rpc_descs[:an_rpc].marshal_proc }
+ let(:unmarshal) { EchoService.rpc_descs[:an_rpc].unmarshal_proc(:output) }
+
+ context 'with no connect_metadata' do
+ before(:each) do
+ server_opts = {
+ server_override: @server,
+ completion_queue_override: @server_queue,
+ poll_period: 1
+ }
+ @srv = RpcServer.new(**server_opts)
+ end
- describe 'when running' do
it 'should return NOT_FOUND status on unknown methods', server: true do
@srv.handle(EchoService)
t = Thread.new { @srv.run }
@@ -323,8 +342,8 @@ describe GRPC::RpcServer do
req = EchoMsg.new
blk = proc do
cq = GRPC::Core::CompletionQueue.new
- stub = GRPC::ClientStub.new(@host, cq, **@client_opts)
- stub.request_response('/unknown', req, @marshal, @unmarshal)
+ stub = GRPC::ClientStub.new(@host, cq, **client_opts)
+ stub.request_response('/unknown', req, marshal, unmarshal)
end
expect(&blk).to raise_error GRPC::BadStatus
@srv.stop
@@ -337,7 +356,7 @@ describe GRPC::RpcServer do
@srv.wait_till_running
req = EchoMsg.new
n = 5 # arbitrary
- stub = EchoStub.new(@host, **@client_opts)
+ stub = EchoStub.new(@host, **client_opts)
n.times { expect(stub.an_rpc(req)).to be_a(EchoMsg) }
@srv.stop
t.join
@@ -349,7 +368,7 @@ describe GRPC::RpcServer do
t = Thread.new { @srv.run }
@srv.wait_till_running
req = EchoMsg.new
- stub = EchoStub.new(@host, **@client_opts)
+ stub = EchoStub.new(@host, **client_opts)
expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
expect(service.received_md).to eq(wanted_md)
@@ -363,8 +382,8 @@ describe GRPC::RpcServer do
t = Thread.new { @srv.run }
@srv.wait_till_running
req = EchoMsg.new
- stub = SlowStub.new(@host, **@client_opts)
- deadline = service.delay + 0.5 # wait for long enough
+ stub = SlowStub.new(@host, **client_opts)
+ deadline = service.delay + 1.0 # wait for long enough
expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
expect(service.received_md).to eq(wanted_md)
@@ -378,7 +397,7 @@ describe GRPC::RpcServer do
t = Thread.new { @srv.run }
@srv.wait_till_running
req = EchoMsg.new
- stub = SlowStub.new(@host, **@client_opts)
+ stub = SlowStub.new(@host, **client_opts)
deadline = 0.1 # too short for SlowService to respond
blk = proc { stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2') }
expect(&blk).to raise_error GRPC::BadStatus
@@ -388,19 +407,37 @@ describe GRPC::RpcServer do
t.join
end
+ it 'should handle cancellation correctly', server: true do
+ service = SlowService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = SlowStub.new(@host, **client_opts)
+ op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
+ Thread.new do # cancel the call
+ sleep 0.1
+ op.cancel
+ end
+ expect { op.execute }.to raise_error GRPC::Cancelled
+ @srv.stop
+ t.join
+ end
+
it 'should receive updated metadata', server: true do
service = EchoService.new
@srv.handle(service)
t = Thread.new { @srv.run }
@srv.wait_till_running
req = EchoMsg.new
- @client_opts[:update_metadata] = proc do |md|
+ client_opts[:update_metadata] = proc do |md|
md[:k1] = 'updated-v1'
md
end
- stub = EchoStub.new(@host, **@client_opts)
+ stub = EchoStub.new(@host, **client_opts)
expect(stub.an_rpc(req, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
- wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2' }]
+ wanted_md = [{ 'k1' => 'updated-v1', 'k2' => 'v2',
+ 'jwt_aud_uri' => "https://#{@host}/EchoService" }]
expect(service.received_md).to eq(wanted_md)
@srv.stop
t.join
@@ -415,7 +452,7 @@ describe GRPC::RpcServer do
threads = []
n.times do
threads << Thread.new do
- stub = EchoStub.new(@host, **@client_opts)
+ stub = EchoStub.new(@host, **client_opts)
q << stub.an_rpc(req)
end
end
@@ -443,7 +480,7 @@ describe GRPC::RpcServer do
one_failed_as_unavailable = false
n.times do
threads << Thread.new do
- stub = SlowStub.new(@host, **@client_opts)
+ stub = SlowStub.new(@host, **client_opts)
begin
stub.an_rpc(req)
rescue GRPC::BadStatus => e
@@ -456,5 +493,97 @@ describe GRPC::RpcServer do
expect(one_failed_as_unavailable).to be(true)
end
end
+
+ context 'with connect metadata' do
+ let(:test_md_proc) do
+ proc do |mth, md|
+ res = md.clone
+ res['method'] = mth
+ res['connect_k1'] = 'connect_v1'
+ res
+ end
+ end
+ before(:each) do
+ server_opts = {
+ server_override: @server,
+ completion_queue_override: @server_queue,
+ poll_period: 1,
+ connect_md_proc: test_md_proc
+ }
+ @srv = RpcServer.new(**server_opts)
+ end
+
+ it 'should send connect metadata to the client', server: true do
+ service = EchoService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = EchoStub.new(@host, **client_opts)
+ op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
+ expect(op.metadata).to be nil
+ expect(op.execute).to be_a(EchoMsg)
+ wanted_md = {
+ 'k1' => 'v1',
+ 'k2' => 'v2',
+ 'method' => '/EchoService/an_rpc',
+ 'connect_k1' => 'connect_v1'
+ }
+ expect(op.metadata).to eq(wanted_md)
+ @srv.stop
+ t.join
+ end
+ end
+
+ context 'with trailing metadata' do
+ before(:each) do
+ server_opts = {
+ server_override: @server,
+ completion_queue_override: @server_queue,
+ poll_period: 1
+ }
+ @srv = RpcServer.new(**server_opts)
+ end
+
+ it 'should be added to BadStatus when requests fail', server: true do
+ service = FailingService.new
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = FailingStub.new(@host, **client_opts)
+ blk = proc { stub.an_rpc(req) }
+
+ # confirm it raise the expected error
+ expect(&blk).to raise_error GRPC::BadStatus
+
+ # call again and confirm exception contained the trailing metadata.
+ begin
+ blk.call
+ rescue GRPC::BadStatus => e
+ expect(e.code).to eq(service.code)
+ expect(e.details).to eq(service.details)
+ expect(e.metadata).to eq(service.md)
+ end
+ @srv.stop
+ t.join
+ end
+
+ it 'should be received by the client', server: true do
+ wanted_trailers = { 'k1' => 'out_v1', 'k2' => 'out_v2' }
+ service = EchoService.new(k1: 'out_v1', k2: 'out_v2')
+ @srv.handle(service)
+ t = Thread.new { @srv.run }
+ @srv.wait_till_running
+ req = EchoMsg.new
+ stub = EchoStub.new(@host, **client_opts)
+ op = stub.an_rpc(req, k1: 'v1', k2: 'v2', return_op: true)
+ expect(op.metadata).to be nil
+ expect(op.execute).to be_a(EchoMsg)
+ expect(op.metadata).to eq(wanted_trailers)
+ @srv.stop
+ t.join
+ end
+ end
end
end
diff --git a/src/ruby/spec/metadata_spec.rb b/src/ruby/spec/metadata_spec.rb
deleted file mode 100644
index 2472866692..0000000000
--- a/src/ruby/spec/metadata_spec.rb
+++ /dev/null
@@ -1,64 +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.
-
-require 'grpc'
-
-describe GRPC::Core::Metadata do
- describe '#new' do
- it 'should create instances' do
- expect { GRPC::Core::Metadata.new('a key', 'a value') }.to_not raise_error
- end
- end
-
- describe '#key' do
- md = GRPC::Core::Metadata.new('a key', 'a value')
- it 'should be the constructor value' do
- expect(md.key).to eq('a key')
- end
- end
-
- describe '#value' do
- md = GRPC::Core::Metadata.new('a key', 'a value')
- it 'should be the constuctor value' do
- expect(md.value).to eq('a value')
- end
- end
-
- describe '#dup' do
- it 'should create a copy that returns the correct key' do
- md = GRPC::Core::Metadata.new('a key', 'a value')
- expect(md.dup.key).to eq('a key')
- end
-
- it 'should create a copy that returns the correct value' do
- md = GRPC::Core::Metadata.new('a key', 'a value')
- expect(md.dup.value).to eq('a value')
- end
- end
-end
diff --git a/src/ruby/spec/server_spec.rb b/src/ruby/spec/server_spec.rb
index a47e484f97..bb566d1b1f 100644
--- a/src/ruby/spec/server_spec.rb
+++ b/src/ruby/spec/server_spec.rb
@@ -152,7 +152,7 @@ describe Server do
it 'does not take a hash with bad values as channel args' do
blk = construct_with_args(symbol: Object.new)
expect(&blk).to raise_error TypeError
- blk = construct_with_args('1' => Hash.new)
+ blk = construct_with_args('1' => {})
expect(&blk).to raise_error TypeError
end
diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb
index 837d2fc42a..101165c146 100644
--- a/src/ruby/spec/spec_helper.rb
+++ b/src/ruby/spec/spec_helper.rb
@@ -35,14 +35,18 @@ $LOAD_PATH.unshift(spec_dir)
$LOAD_PATH.unshift(lib_dir)
$LOAD_PATH.uniq!
-require 'faraday'
+# set up coverage
+require 'simplecov'
+SimpleCov.start do
+ add_filter 'spec'
+ add_filter 'bin'
+ SimpleCov.command_name ENV['COVERAGE_NAME']
+end if ENV['COVERAGE_NAME']
+
require 'rspec'
require 'logging'
require 'rspec/logging_helper'
-# Allow Faraday to support test stubs
-Faraday::Adapter.load_middleware(:test)
-
# Configure RSpec to capture log messages for each test. The output from the
# logs will be stored in the @log_output variable. It is a StringIO instance.
RSpec.configure do |config|