Merge branch 'master' of github.com:google/grpc into private_build

pull/1317/head
Donna Dionne 10 years ago
commit d0a162dc78
  1. 11
      BUILD
  2. 15782
      Makefile
  3. 65
      build.json
  4. 94
      doc/interop-test-descriptions.md
  5. 1
      examples/pubsub/README
  6. 79
      examples/pubsub/label.proto
  7. 10
      examples/pubsub/main.cc
  8. 729
      examples/pubsub/pubsub.proto
  9. 69
      gRPC.podspec
  10. 1
      include/grpc++/channel_interface.h
  11. 9
      include/grpc++/impl/internal_stub.h
  12. 10
      include/grpc++/impl/rpc_method.h
  13. 2
      include/grpc++/impl/rpc_service_method.h
  14. 22
      include/grpc/grpc.h
  15. 2
      include/grpc/support/atm_win32.h
  16. 4
      include/grpc/support/port_platform.h
  17. 149
      src/compiler/cpp_generator.cc
  18. 13
      src/core/httpcli/httpcli.c
  19. 42
      src/core/httpcli/httpcli_security_connector.c
  20. 12
      src/core/httpcli/httpcli_security_connector.h
  21. 9
      src/core/iomgr/iocp_windows.c
  22. 4
      src/core/iomgr/resolve_address_windows.c
  23. 3
      src/core/iomgr/socket_windows.c
  24. 6
      src/core/iomgr/tcp_client_windows.c
  25. 11
      src/core/iomgr/tcp_posix.c
  26. 12
      src/core/iomgr/tcp_server_windows.c
  27. 29
      src/core/iomgr/tcp_windows.c
  28. 8
      src/core/profiling/timers.c
  29. 9
      src/core/profiling/timers.h
  30. 30
      src/core/security/auth.c
  31. 189
      src/core/security/credentials.c
  32. 46
      src/core/security/credentials.h
  33. 4
      src/core/security/google_default_credentials.c
  34. 14
      src/core/security/secure_transport_setup.c
  35. 4
      src/core/security/secure_transport_setup.h
  36. 305
      src/core/security/security_connector.c
  37. 201
      src/core/security/security_connector.h
  38. 214
      src/core/security/security_context.h
  39. 19
      src/core/security/server_secure_chttp2.c
  40. 38
      src/core/support/file.c
  41. 6
      src/core/support/file.h
  42. 87
      src/core/surface/channel.c
  43. 2
      src/core/surface/init.c
  44. 43
      src/core/surface/secure_channel_create.c
  45. 1
      src/core/transport/chttp2/frame.h
  46. 8
      src/core/transport/chttp2/frame_settings.c
  47. 24
      src/core/transport/chttp2_transport.c
  48. 23
      src/cpp/client/channel.cc
  49. 1
      src/cpp/client/channel.h
  50. 12
      src/cpp/client/generic_stub.cc
  51. 5
      src/cpp/common/call.cc
  52. 4
      src/cpp/server/async_server_context.cc
  53. 5
      src/cpp/server/server.cc
  54. 1
      src/cpp/util/byte_buffer.cc
  55. 3
      src/csharp/Grpc.Core/.gitignore
  56. 25
      src/csharp/Grpc.Core/Grpc.Core.csproj
  57. 8
      src/csharp/Grpc.Core/Grpc.Core.nuspec
  58. 4
      src/csharp/Grpc.Core/packages.config
  59. 2
      src/csharp/Grpc.Examples.MathServer/MathServer.cs
  60. 5
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  61. 2
      src/csharp/Grpc.IntegrationTesting/packages.config
  62. 44
      src/node/examples/pubsub/empty.proto
  63. 79
      src/node/examples/pubsub/label.proto
  64. 734
      src/node/examples/pubsub/pubsub.proto
  65. 285
      src/node/examples/pubsub/pubsub_demo.js
  66. 19
      src/node/index.js
  67. 22
      src/node/test/surface_test.js
  68. 55
      src/node/test/test_service.json
  69. 2
      src/objective-c/GRPCClient/GRPCCall.h
  70. 4
      src/objective-c/GRPCClient/GRPCCall.m
  71. 14
      src/objective-c/GRPCClient/GRPCClient.podspec
  72. 5
      src/objective-c/GRPCClient/private/GRPCChannel.h
  73. 41
      src/objective-c/GRPCClient/private/GRPCChannel.m
  74. 2
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  75. 2
      src/objective-c/GRPCClient/private/GRPCDelegateWrapper.m
  76. 18
      src/objective-c/GRPCClient/private/GRPCSecureChannel.h
  77. 52
      src/objective-c/GRPCClient/private/GRPCSecureChannel.m
  78. 38
      src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
  79. 36
      src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
  80. 2
      src/objective-c/GRPCClient/private/NSData+GRPC.m
  81. 13
      src/objective-c/RxLibrary/RxLibrary.podspec
  82. 9
      src/objective-c/examples/Sample/Podfile
  83. 23094
      src/objective-c/examples/Sample/Pods/Pods.xcodeproj/project.pbxproj
  84. 103
      src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.h
  85. 179
      src/objective-c/examples/Sample/RemoteTestClient/Empty.pb.m
  86. 578
      src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.h
  87. 2256
      src/objective-c/examples/Sample/RemoteTestClient/Messages.pb.m
  88. 17
      src/objective-c/examples/Sample/RemoteTestClient/RemoteTest.podspec
  89. 81
      src/objective-c/examples/Sample/RemoteTestClient/Test.pb.h
  90. 27
      src/objective-c/examples/Sample/RemoteTestClient/Test.pb.m
  91. 10
      src/objective-c/examples/Sample/RemoteTestClient/empty.proto
  92. 135
      src/objective-c/examples/Sample/RemoteTestClient/messages.proto
  93. 74
      src/objective-c/examples/Sample/RemoteTestClient/test.proto
  94. 387
      src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.h
  95. 1435
      src/objective-c/examples/Sample/RouteGuideClient/Route_guide.pb.m
  96. 17
      src/objective-c/examples/Sample/RouteGuideClient/Route_guide.podspec
  97. 121
      src/objective-c/examples/Sample/RouteGuideClient/route_guide.proto
  98. 1487
      src/objective-c/examples/Sample/Sample.xcodeproj/project.pbxproj
  99. 1
      src/objective-c/examples/Sample/Sample/AppDelegate.h
  100. 25
      src/objective-c/examples/Sample/Sample/AppDelegate.m
  101. Some files were not shown because too many files have changed in this diff Show More

11
BUILD

@ -1,5 +1,7 @@
# GRPC Bazel BUILD file. # GRPC Bazel BUILD file.
# This currently builds C and C++ code. # This currently builds C and C++ code.
# This file has been automatically generated from a template file.
# Please look at the templates directory instead.
# Copyright 2015, Google Inc. # Copyright 2015, Google Inc.
# All rights reserved. # All rights reserved.
@ -124,7 +126,7 @@ cc_library(
srcs = [ srcs = [
"src/core/httpcli/format_request.h", "src/core/httpcli/format_request.h",
"src/core/httpcli/httpcli.h", "src/core/httpcli/httpcli.h",
"src/core/httpcli/httpcli_security_context.h", "src/core/httpcli/httpcli_security_connector.h",
"src/core/httpcli/parser.h", "src/core/httpcli/parser.h",
"src/core/security/auth.h", "src/core/security/auth.h",
"src/core/security/base64.h", "src/core/security/base64.h",
@ -132,7 +134,7 @@ cc_library(
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.h", "src/core/security/secure_transport_setup.h",
"src/core/security/security_context.h", "src/core/security/security_connector.h",
"src/core/tsi/fake_transport_security.h", "src/core/tsi/fake_transport_security.h",
"src/core/tsi/ssl_transport_security.h", "src/core/tsi/ssl_transport_security.h",
"src/core/tsi/transport_security.h", "src/core/tsi/transport_security.h",
@ -228,19 +230,18 @@ cc_library(
"src/core/transport/transport_impl.h", "src/core/transport/transport_impl.h",
"src/core/httpcli/format_request.c", "src/core/httpcli/format_request.c",
"src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli.c",
"src/core/httpcli/httpcli_security_context.c", "src/core/httpcli/httpcli_security_connector.c",
"src/core/httpcli/parser.c", "src/core/httpcli/parser.c",
"src/core/security/auth.c", "src/core/security/auth.c",
"src/core/security/base64.c", "src/core/security/base64.c",
"src/core/security/credentials.c", "src/core/security/credentials.c",
"src/core/security/credentials_posix.c", "src/core/security/credentials_posix.c",
"src/core/security/credentials_win32.c", "src/core/security/credentials_win32.c",
"src/core/security/factories.c",
"src/core/security/google_default_credentials.c", "src/core/security/google_default_credentials.c",
"src/core/security/json_token.c", "src/core/security/json_token.c",
"src/core/security/secure_endpoint.c", "src/core/security/secure_endpoint.c",
"src/core/security/secure_transport_setup.c", "src/core/security/secure_transport_setup.c",
"src/core/security/security_context.c", "src/core/security/security_connector.c",
"src/core/security/server_secure_chttp2.c", "src/core/security/server_secure_chttp2.c",
"src/core/surface/init_secure.c", "src/core/surface/init_secure.c",
"src/core/surface/secure_channel_create.c", "src/core/surface/secure_channel_create.c",

15782
Makefile

File diff suppressed because one or more lines are too long

@ -386,7 +386,7 @@
"headers": [ "headers": [
"src/core/httpcli/format_request.h", "src/core/httpcli/format_request.h",
"src/core/httpcli/httpcli.h", "src/core/httpcli/httpcli.h",
"src/core/httpcli/httpcli_security_context.h", "src/core/httpcli/httpcli_security_connector.h",
"src/core/httpcli/parser.h", "src/core/httpcli/parser.h",
"src/core/security/auth.h", "src/core/security/auth.h",
"src/core/security/base64.h", "src/core/security/base64.h",
@ -394,7 +394,7 @@
"src/core/security/json_token.h", "src/core/security/json_token.h",
"src/core/security/secure_endpoint.h", "src/core/security/secure_endpoint.h",
"src/core/security/secure_transport_setup.h", "src/core/security/secure_transport_setup.h",
"src/core/security/security_context.h", "src/core/security/security_connector.h",
"src/core/tsi/fake_transport_security.h", "src/core/tsi/fake_transport_security.h",
"src/core/tsi/ssl_transport_security.h", "src/core/tsi/ssl_transport_security.h",
"src/core/tsi/transport_security.h", "src/core/tsi/transport_security.h",
@ -403,19 +403,18 @@
"src": [ "src": [
"src/core/httpcli/format_request.c", "src/core/httpcli/format_request.c",
"src/core/httpcli/httpcli.c", "src/core/httpcli/httpcli.c",
"src/core/httpcli/httpcli_security_context.c", "src/core/httpcli/httpcli_security_connector.c",
"src/core/httpcli/parser.c", "src/core/httpcli/parser.c",
"src/core/security/auth.c", "src/core/security/auth.c",
"src/core/security/base64.c", "src/core/security/base64.c",
"src/core/security/credentials.c", "src/core/security/credentials.c",
"src/core/security/credentials_posix.c", "src/core/security/credentials_posix.c",
"src/core/security/credentials_win32.c", "src/core/security/credentials_win32.c",
"src/core/security/factories.c",
"src/core/security/google_default_credentials.c", "src/core/security/google_default_credentials.c",
"src/core/security/json_token.c", "src/core/security/json_token.c",
"src/core/security/secure_endpoint.c", "src/core/security/secure_endpoint.c",
"src/core/security/secure_transport_setup.c", "src/core/security/secure_transport_setup.c",
"src/core/security/security_context.c", "src/core/security/security_connector.c",
"src/core/security/server_secure_chttp2.c", "src/core/security/server_secure_chttp2.c",
"src/core/surface/init_secure.c", "src/core/surface/init_secure.c",
"src/core/surface/secure_channel_create.c", "src/core/surface/secure_channel_create.c",
@ -498,6 +497,14 @@
"secure": "check", "secure": "check",
"vs_project_guid": "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}" "vs_project_guid": "{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}"
}, },
{
"name": "grpc++_test_config",
"build": "private",
"language": "c++",
"src": [
"test/cpp/util/test_config.cc"
]
},
{ {
"name": "grpc++_test_util", "name": "grpc++_test_util",
"build": "private", "build": "private",
@ -570,9 +577,9 @@
"build": "private", "build": "private",
"language": "c++", "language": "c++",
"src": [ "src": [
"test/cpp/interop/empty.proto", "test/proto/empty.proto",
"test/cpp/interop/messages.proto", "test/proto/messages.proto",
"test/cpp/interop/test.proto", "test/proto/test.proto",
"test/cpp/interop/client.cc", "test/cpp/interop/client.cc",
"test/cpp/interop/interop_client.cc" "test/cpp/interop/interop_client.cc"
], ],
@ -582,7 +589,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
@ -604,9 +612,9 @@
"build": "private", "build": "private",
"language": "c++", "language": "c++",
"src": [ "src": [
"test/cpp/interop/empty.proto", "test/proto/empty.proto",
"test/cpp/interop/messages.proto", "test/proto/messages.proto",
"test/cpp/interop/test.proto", "test/proto/test.proto",
"test/cpp/interop/server.cc" "test/cpp/interop/server.cc"
], ],
"deps": [ "deps": [
@ -615,12 +623,13 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
"name": "pubsub_client_lib", "name": "pubsub_client_lib",
"build": "private", "build": "do_not_build",
"language": "c++", "language": "c++",
"src": [ "src": [
"examples/pubsub/label.proto", "examples/pubsub/label.proto",
@ -655,6 +664,10 @@
"test/cpp/qps/server_async.cc", "test/cpp/qps/server_async.cc",
"test/cpp/qps/server_sync.cc", "test/cpp/qps/server_sync.cc",
"test/cpp/qps/timer.cc" "test/cpp/qps/timer.cc"
],
"deps": [
"grpc_test_util",
"grpc++_test_util"
] ]
}, },
{ {
@ -1929,7 +1942,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
@ -1994,7 +2008,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
@ -2011,7 +2026,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
@ -2030,7 +2046,7 @@
}, },
{ {
"name": "pubsub_client", "name": "pubsub_client",
"build": "test", "build": "do_not_build",
"run": false, "run": false,
"language": "c++", "language": "c++",
"src": [ "src": [
@ -2042,12 +2058,13 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
"name": "pubsub_publisher_test", "name": "pubsub_publisher_test",
"build": "test", "build": "do_not_build",
"language": "c++", "language": "c++",
"src": [ "src": [
"examples/pubsub/publisher_test.cc" "examples/pubsub/publisher_test.cc"
@ -2064,7 +2081,7 @@
}, },
{ {
"name": "pubsub_subscriber_test", "name": "pubsub_subscriber_test",
"build": "test", "build": "do_not_build",
"language": "c++", "language": "c++",
"src": [ "src": [
"examples/pubsub/subscriber_test.cc" "examples/pubsub/subscriber_test.cc"
@ -2094,7 +2111,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {
@ -2134,7 +2152,8 @@
"grpc++", "grpc++",
"grpc", "grpc",
"gpr_test_util", "gpr_test_util",
"gpr" "gpr",
"grpc++_test_config"
] ]
}, },
{ {

@ -2,7 +2,7 @@ Interoperability Test Case Descriptions
======================================= =======================================
Client and server use Client and server use
[test.proto](https://github.com/grpc/grpc/blob/master/test/cpp/interop/test.proto) [test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto)
and the [gRPC over HTTP/2 v2 and the [gRPC over HTTP/2 v2
protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md). protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md).
@ -30,6 +30,14 @@ Clients should accept these arguments:
* Whether to replace platform root CAs with * Whether to replace platform root CAs with
[ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem) [ca.pem](https://github.com/grpc/grpc/blob/master/src/core/tsi/test_creds/ca.pem)
as the CA root as the CA root
* --default_service_account=ACCOUNT_EMAIL
* Email of the GCE default service account. Only applicable
for compute_engine_creds test.
* --oauth_scope=SCOPE
* OAuth scope. For example, "https://www.googleapis.com/auth/xapi.zoo"
* --service_account_key_file=PATH
* The path to the service account JSON key file generated from GCE developer
console.
Clients must support TLS with ALPN. Clients must not disable certificate Clients must support TLS with ALPN. Clients must not disable certificate
checking. checking.
@ -259,25 +267,26 @@ Asserts:
### compute_engine_creds ### compute_engine_creds
Status: Not yet implementable
This test is only for cloud-to-prod path. This test is only for cloud-to-prod path.
This test verifies unary calls succeed in sending messages while using Service This test verifies unary calls succeed in sending messages while using Service
Credentials from GCE metadata server. The client instance needs to be created Credentials from GCE metadata server. The client instance needs to be created
with desired oauth scope. with desired oauth scope.
The test uses `--default_service_account` with GCE service account email and
`--oauth_scope` with the OAuth scope to use. For testing against
grpc-test.sandbox.google.com, "https://www.googleapis.com/auth/xapi.zoo" should
be passed in as `--oauth_scope`.
Server features: Server features:
* [UnaryCall][] * [UnaryCall][]
* [Compressable Payload][] * [Compressable Payload][]
* SimpeResponse.username * [Echo Authenticated Username][]
* SimpleResponse.oauth_scope * [Echo OAuth Scope][]
Procedure: Procedure:
1. Client sets flags default_service_account with GCE service account name and 1. Client configures channel to use GCECredentials
oauth_scope with the oauth scope to use. 2. Client calls UnaryCall on the channel with:
2. Client configures channel to use GCECredentials
3. Client calls UnaryCall on the channel with:
``` ```
{ {
@ -293,32 +302,34 @@ Procedure:
Asserts: Asserts:
* call was successful * call was successful
* received SimpleResponse.username equals FLAGS_default_service_account * received SimpleResponse.username equals the value of `--default_service_account` flag
* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope * received SimpleResponse.oauth_scope is in `--oauth_scope`
* response payload body is 314159 bytes in size * response payload body is 314159 bytes in size
* clients are free to assert that the response payload body contents are zero * clients are free to assert that the response payload body contents are zero
and comparing the entire response message against a golden response and comparing the entire response message against a golden response
### service_account_creds ### service_account_creds
Status: Not yet implementable
This test is only for cloud-to-prod path. This test is only for cloud-to-prod path.
This test verifies unary calls succeed in sending messages while using JWT This test verifies unary calls succeed in sending messages while using JWT
signing keys (redeemed for OAuth2 access tokens by the auth implementation) signing keys (redeemed for OAuth2 access tokens by the auth implementation)
The test uses `--service_account_key_file` with the path to a json key file
downloaded from https://console.developers.google.com, and `--oauth_scope`
to the oauth scope. For testing against grpc-test.sandbox.google.com,
"https://www.googleapis.com/auth/xapi.zoo" should be passed in
as `--oauth_scope`.
Server features: Server features:
* [UnaryCall][] * [UnaryCall][]
* [Compressable Payload][] * [Compressable Payload][]
* SimpleResponse.username * [Echo Authenticated Username][]
* SimpleResponse.oauth_scope * [Echo OAuth Scope][]
Procedure: Procedure:
1. Client sets flags service_account_key_file with the path to json key file, 1. Client configures the channel to use ServiceAccountCredentials.
oauth_scope to the oauth scope. 2. Client calls UnaryCall with:
2. Client configures the channel to use ServiceAccountCredentials.
3. Client calls UnaryCall with:
``` ```
{ {
@ -335,31 +346,32 @@ Procedure:
Asserts: Asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file read from * received SimpleResponse.username is in the json key file read from
FLAGS_service_account_key_file `--service_account_key_file`
* received SimpleResponse.oauth_scope is in FLAGS_oauth_scope * received SimpleResponse.oauth_scope is in `--oauth_scope`
* response payload body is 314159 bytes in size * response payload body is 314159 bytes in size
* clients are free to assert that the response payload body contents are zero * clients are free to assert that the response payload body contents are zero
and comparing the entire response message against a golden response and comparing the entire response message against a golden response
### jwt_token_creds ### jwt_token_creds
Status: Not yet implementable
This test is only for cloud-to-prod path. This test is only for cloud-to-prod path.
This test verifies unary calls succeed in sending messages while using JWT This test verifies unary calls succeed in sending messages while using JWT
token (created by the project's key file) token (created by the project's key file)
Test caller should set flag `--service_account_key_file` with the
path to json key file downloaded from
https://console.developers.google.com.
Server features: Server features:
* [UnaryCall][] * [UnaryCall][]
* [Compressable Payload][] * [Compressable Payload][]
* SimpleResponse.username * [Echo Authenticated Username][]
* SimpleResponse.oauth_scope * [Echo OAuth Scope][]
Procedure: Procedure:
1. Client sets flags service_account_key_file with the path to json key file 1. Client configures the channel to use JWTTokenCredentials.
2. Client configures the channel to use JWTTokenCredentials. 2. Client calls UnaryCall with:
3. Client calls UnaryCall with:
``` ```
{ {
@ -375,7 +387,7 @@ Procedure:
Asserts: Asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file read from * received SimpleResponse.username is in the json key file read from
FLAGS_service_account_key_file `--service_account_key_file`
* response payload body is 314159 bytes in size * response payload body is 314159 bytes in size
* clients are free to assert that the response payload body contents are zero * clients are free to assert that the response payload body contents are zero
and comparing the entire response message against a golden response and comparing the entire response message against a golden response
@ -394,7 +406,8 @@ Server features:
back to client in both header and trailer. (TODO: this is not defined) back to client in both header and trailer. (TODO: this is not defined)
Procedure: Procedure:
1. While sending custom metadata (ascii + binary) in the header, client calls UnaryCall with: 1. While sending custom metadata (ascii + binary) in the header, client calls
UnaryCall with:
``` ```
{ {
@ -619,11 +632,6 @@ payload body of size SimpleRequest.response_size bytes and type as appropriate
for the SimpleRequest.response_type. If the server does not support the for the SimpleRequest.response_type. If the server does not support the
response_type, then it should fail the RPC with INVALID_ARGUMENT. response_type, then it should fail the RPC with INVALID_ARGUMENT.
If the request sets fill_username, the server should return the client username
it sees in field SimpleResponse.username. If the request sets fill_oauth_scope,
the server should return the oauth scope of the rpc in the form of "xapi_zoo"
in field SimpleResponse.oauth_scope.
### StreamingInputCall ### StreamingInputCall
[StreamingInputCall]: #streaminginputcall [StreamingInputCall]: #streaminginputcall
@ -672,14 +680,30 @@ Interaction with flow control is unspecified.
Status: Pending Status: Pending
#### Echo Authenticated Username
[Echo Authenticated Username]: #echo-authenticated-username
If a SimpleRequest has fill_username=true and that request was successfully If a SimpleRequest has fill_username=true and that request was successfully
authenticated, then the SimpleResponse should have username filled with the authenticated, then the SimpleResponse should have username filled with the
canonical form of the authenticated source. The canonical form is dependent on canonical form of the authenticated source. The canonical form is dependent on
the authentication method, but is likely to be a base 10 integer identifier or the authentication method, but is likely to be a base 10 integer identifier or
an email address. an email address.
#### Echo OAuth scope
[Echo OAuth Scope]: #echo-oauth-scope
If a SimpleRequest has fill_oauth_scope=true and that request was successfully
authenticated via OAuth, then the SimpleResponse should have oauth_scope filled
with the scope of the method being invoked.
Although a general server-side feature, most test servers won't implement this
feature. The TLS server grpc-test.sandbox.google.com:443 supports this feature.
It requires at least the OAuth scope
`https://www.googleapis.com/auth/xapi.zoo` for authentication to succeed.
Discussion: Discussion:
Ideally, this would be communicated via metadata and not in the Ideally, this would be communicated via metadata and not in the
request/response, but we want to use this test in code paths that don't yet request/response, but we want to use this test in code paths that don't yet
fully communicate metadata. fully communicate metadata.

@ -1,3 +1,4 @@
NOTE: This example does not build and is being updated.
Experimental example code, likely to change. Experimental example code, likely to change.
Users should not attempt to run this code till this warning is removed. Users should not attempt to run this code till this warning is removed.

@ -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;
}

@ -46,6 +46,7 @@
#include <grpc++/create_channel.h> #include <grpc++/create_channel.h>
#include <grpc++/credentials.h> #include <grpc++/credentials.h>
#include <grpc++/status.h> #include <grpc++/status.h>
#include "test/cpp/util/test_config.h"
#include "examples/pubsub/publisher.h" #include "examples/pubsub/publisher.h"
#include "examples/pubsub/subscriber.h" #include "examples/pubsub/subscriber.h"
@ -55,13 +56,6 @@ DEFINE_string(server_host, "pubsub-staging.googleapis.com",
"Server host to connect to"); "Server host to connect to");
DEFINE_string(project_id, "", "GCE project id such as stoked-keyword-656"); DEFINE_string(project_id, "", "GCE project id such as stoked-keyword-656");
// In some distros, gflags is in the namespace google, and in some others,
// in gflags. This hack is enabling us to find both.
namespace google {}
namespace gflags {}
using namespace google;
using namespace gflags;
namespace { namespace {
const char kTopic[] = "testtopics"; const char kTopic[] = "testtopics";
@ -72,7 +66,7 @@ const char kMessageData[] = "Test Data";
int main(int argc, char** argv) { int main(int argc, char** argv) {
grpc_init(); grpc_init();
ParseCommandLineFlags(&argc, &argv, true); grpc::testing::InitTest(&argc, &argv, true);
gpr_log(GPR_INFO, "Start PUBSUB client"); gpr_log(GPR_INFO, "Start PUBSUB client");
std::ostringstream ss; std::ostringstream ss;

@ -1,729 +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 "examples/pubsub/empty.proto";
import "examples/pubsub/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:
//
// The port 'machinename:8888' must be bound to a 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.
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.
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.
// (-- Which labels are required or supported is implementation-specific. --)
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.
// (-- The query syntax is described in label_query.proto --)
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);
}

@ -0,0 +1,69 @@
Pod::Spec.new do |s|
s.name = 'gRPC'
s.version = '0.0.1'
s.summary = 'Generic gRPC client library for iOS'
s.homepage = 'https://www.grpc.io'
s.license = 'New BSD'
s.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
# s.source = { :git => 'https://github.com/grpc/grpc.git', :tag => 'release-0_5_0' }
s.source_files = 'src/objective-c/GRPCClient/*.{h,m}', 'src/objective-c/GRPCClient/private/*.{h,m}'
s.private_header_files = 'src/objective-c/GRPCClient/private/*.h'
s.platform = :ios
s.ios.deployment_target = '6.0'
s.requires_arc = true
s.subspec 'RxLibrary' do |rs|
rs.summary = 'Reactive Extensions library for iOS'
rs.authors = { 'Jorge Canizales' => 'jcanizales@google.com' }
rs.source_files = 'src/objective-c/RxLibrary/*.{h,m}', 'src/objective-c/RxLibrary/transformations/*.{h,m}', 'src/objective-c/RxLibrary/private/*.{h,m}'
rs.private_header_files = 'src/objective-c/RxLibrary/private/*.h'
end
s.subspec 'C-Core' do |cs|
cs.summary = 'Core gRPC library, written in C'
cs.authors = { 'Craig Tiller' => 'ctiller@google.com',
'David Klempner' => 'klempner@google.com',
'Nicolas Noble' => 'nnoble@google.com',
'Vijay Pai' => 'vpai@google.com',
'Yang Gao' => 'yangg@google.com' }
cs.source_files = 'src/core/**/*.{h,c}', 'include/grpc/*.h', 'include/grpc/**/*.h'
cs.private_header_files = 'src/core/**/*.h'
cs.header_mappings_dir = '.'
cs.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Build/gRPC" "$(PODS_ROOT)/Headers/Build/gRPC/include"' }
cs.requires_arc = false
cs.libraries = 'z'
cs.dependency 'OpenSSL', '~> 1.0.200'
end
# This is a workaround for Cocoapods Issue #1437.
# It renames time.h and string.h to grpc_time.h and grpc_string.h.
s.prepare_command = <<-CMD
DIR_TIME="grpc/support"
BAD_TIME="$DIR_TIME/time.h"
GOOD_TIME="$DIR_TIME/grpc_time.h"
if [ -f "include/$BAD_TIME" ];
then
grep -rl "$BAD_TIME" include/grpc src/core | xargs sed -i '' -e s@$BAD_TIME@$GOOD_TIME@g
mv "include/$BAD_TIME" "include/$GOOD_TIME"
fi
DIR_STRING="src/core/support"
BAD_STRING="$DIR_STRING/string.h"
GOOD_STRING="$DIR_STRING/grpc_string.h"
if [ -f "$BAD_STRING" ];
then
grep -rl "$BAD_STRING" include/grpc src/core | xargs sed -i '' -e s@$BAD_STRING@$GOOD_STRING@g
mv "$BAD_STRING" "$GOOD_STRING"
fi
CMD
s.xcconfig = { 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers/Public/gRPC/include"' }
# Certificates, to be able to establish TLS connections:
s.resource_bundles = { 'gRPC' => ['etc/roots.pem'] }
end

@ -51,6 +51,7 @@ class ChannelInterface : public CallHook {
public: public:
virtual ~ChannelInterface() {} virtual ~ChannelInterface() {}
virtual void *RegisterMethod(const char *method_name) = 0;
virtual Call CreateCall(const RpcMethod& method, ClientContext* context, virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) = 0; CompletionQueue* cq) = 0;
}; };

@ -42,17 +42,14 @@ namespace grpc {
class InternalStub { class InternalStub {
public: public:
InternalStub() {} InternalStub(const std::shared_ptr<ChannelInterface>& channel)
: channel_(channel) {}
virtual ~InternalStub() {} virtual ~InternalStub() {}
void set_channel(const std::shared_ptr<ChannelInterface>& channel) {
channel_ = channel;
}
ChannelInterface* channel() { return channel_.get(); } ChannelInterface* channel() { return channel_.get(); }
private: private:
std::shared_ptr<ChannelInterface> channel_; const std::shared_ptr<ChannelInterface> channel_;
}; };
} // namespace grpc } // namespace grpc

@ -45,17 +45,17 @@ class RpcMethod {
BIDI_STREAMING BIDI_STREAMING
}; };
explicit RpcMethod(const char* name) RpcMethod(const char* name, RpcType type, void* channel_tag)
: name_(name), method_type_(NORMAL_RPC) {} : name_(name), method_type_(type), channel_tag_(channel_tag) {}
RpcMethod(const char* name, RpcType type) : name_(name), method_type_(type) {}
const char* name() const { return name_; } const char* name() const { return name_; }
RpcType method_type() const { return method_type_; } RpcType method_type() const { return method_type_; }
void* channel_tag() const { return channel_tag_; }
private: private:
const char* name_; const char* const name_;
const RpcType method_type_; const RpcType method_type_;
void* const channel_tag_;
}; };
} // namespace grpc } // namespace grpc

@ -167,7 +167,7 @@ class RpcServiceMethod : public RpcMethod {
MethodHandler* handler, MethodHandler* handler,
grpc::protobuf::Message* request_prototype, grpc::protobuf::Message* request_prototype,
grpc::protobuf::Message* response_prototype) grpc::protobuf::Message* response_prototype)
: RpcMethod(name, type), : RpcMethod(name, type, nullptr),
handler_(handler), handler_(handler),
request_prototype_(request_prototype), request_prototype_(request_prototype),
response_prototype_(response_prototype) {} response_prototype_(response_prototype) {}

@ -361,7 +361,7 @@ typedef struct grpc_op {
library). */ library). */
void grpc_init(void); void grpc_init(void);
/* Shut down the grpc library. /* Shut down the grpc library.
No memory is used by grpc after this call returns, nor are any instructions No memory is used by grpc after this call returns, nor are any instructions
executing within the grpc library. executing within the grpc library.
Prior to calling, all application owned grpc objects must have been Prior to calling, all application owned grpc objects must have been
@ -395,9 +395,9 @@ void grpc_event_finish(grpc_event *event);
/* Begin destruction of a completion queue. Once all possible events are /* Begin destruction of a completion queue. Once all possible events are
drained then grpc_completion_queue_next will start to produce drained then grpc_completion_queue_next will start to produce
GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call GRPC_QUEUE_SHUTDOWN events only. At that point it's safe to call
grpc_completion_queue_destroy. grpc_completion_queue_destroy.
After calling this function applications should ensure that no After calling this function applications should ensure that no
NEW work is added to be published on this completion queue. */ NEW work is added to be published on this completion queue. */
void grpc_completion_queue_shutdown(grpc_completion_queue *cq); void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
@ -421,6 +421,15 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
const char *method, const char *host, const char *method, const char *host,
gpr_timespec deadline); gpr_timespec deadline);
/* Pre-register a method/host pair on a channel. */
void *grpc_channel_register_call(grpc_channel *channel, const char *method,
const char *host);
/* Create a call given a handle returned from grpc_channel_register_call */
grpc_call *grpc_channel_create_registered_call(
grpc_channel *channel, grpc_completion_queue *completion_queue,
void *registered_call_handle, gpr_timespec deadline);
/* Start a batch of operations defined in the array ops; when complete, post a /* 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. completion of type 'tag' to the completion queue bound to the call.
The order of ops specified in the batch has no significance. The order of ops specified in the batch has no significance.
@ -579,8 +588,7 @@ grpc_call_error grpc_server_request_call_old(grpc_server *server,
grpc_call_error grpc_server_request_call( grpc_call_error grpc_server_request_call(
grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_server *server, grpc_call **call, grpc_call_details *details,
grpc_metadata_array *request_metadata, grpc_metadata_array *request_metadata,
grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_bound_to_call, void *tag_new);
void *tag_new);
/* Registers a method in the server. /* Registers a method in the server.
Methods to this (host, method) pair will not be reported by Methods to this (host, method) pair will not be reported by
@ -635,4 +643,4 @@ void grpc_server_destroy(grpc_server *server);
} }
#endif #endif
#endif /* GRPC_GRPC_H */ #endif /* GRPC_GRPC_H */

@ -73,7 +73,7 @@ static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) { static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
#ifdef GPR_ARCH_64 #ifdef GPR_ARCH_64
return o == (gpr_atm)InterlockedCompareExchangeAcquire64((volatile LONGLONG) p, return o == (gpr_atm)InterlockedCompareExchangeAcquire64((volatile LONGLONG *) p,
(LONGLONG) n, (LONGLONG) o); (LONGLONG) n, (LONGLONG) o);
#else #else
return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *) p, return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *) p,

@ -45,8 +45,10 @@
#define GPR_WINSOCK_SOCKET 1 #define GPR_WINSOCK_SOCKET 1
#ifdef __GNUC__ #ifdef __GNUC__
#define GPR_GCC_ATOMIC 1 #define GPR_GCC_ATOMIC 1
#define GPR_GCC_TLS 1
#else #else
#define GPR_WIN32_ATOMIC 1 #define GPR_WIN32_ATOMIC 1
#define GPR_MSVC_TLS 1
#endif #endif
#elif defined(_WIN32) || defined(WIN32) #elif defined(_WIN32) || defined(WIN32)
#define GPR_ARCH_32 1 #define GPR_ARCH_32 1
@ -233,7 +235,7 @@
#endif #endif
#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + defined(GPR_CUSTOM_TLS) != 1 #if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + defined(GPR_CUSTOM_TLS) != 1
#error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, defined(GPR_CUSTOM_TLS) #error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, GPR_CUSTOM_TLS
#endif #endif
typedef int16_t gpr_int16; typedef int16_t gpr_int16;

@ -110,7 +110,7 @@ bool HasBidiStreaming(const grpc::protobuf::FileDescriptor *file) {
return false; return false;
} }
grpc::string FilenameIdentifier(const grpc::string& filename) { grpc::string FilenameIdentifier(const grpc::string &filename) {
grpc::string result; grpc::string result;
for (unsigned i = 0; i < filename.size(); i++) { for (unsigned i = 0; i < filename.size(); i++) {
char c = filename[i]; char c = filename[i];
@ -154,6 +154,7 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
const Parameters &params) { const Parameters &params) {
grpc::string temp = grpc::string temp =
"#include <grpc++/impl/internal_stub.h>\n" "#include <grpc++/impl/internal_stub.h>\n"
"#include <grpc++/impl/rpc_method.h>\n"
"#include <grpc++/impl/service_type.h>\n" "#include <grpc++/impl/service_type.h>\n"
"#include <grpc++/status.h>\n" "#include <grpc++/status.h>\n"
"\n" "\n"
@ -172,7 +173,9 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
temp.append("template <class OutMessage> class ClientWriter;\n"); temp.append("template <class OutMessage> class ClientWriter;\n");
temp.append("template <class InMessage> class ServerReader;\n"); temp.append("template <class InMessage> class ServerReader;\n");
temp.append("template <class OutMessage> class ClientAsyncWriter;\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)) { if (HasServerOnlyStreaming(file)) {
temp.append("template <class InMessage> class ClientReader;\n"); temp.append("template <class InMessage> class ClientReader;\n");
@ -246,11 +249,11 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
*vars, *vars,
"std::unique_ptr< ::grpc::ClientReader< $Response$>> $Method$(" "std::unique_ptr< ::grpc::ClientReader< $Response$>> $Method$("
"::grpc::ClientContext* context, const $Request$& request);\n"); "::grpc::ClientContext* context, const $Request$& request);\n");
printer->Print( printer->Print(*vars,
*vars, "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
"std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> Async$Method$(" "Async$Method$("
"::grpc::ClientContext* context, const $Request$& request, " "::grpc::ClientContext* context, const $Request$& request, "
"::grpc::CompletionQueue* cq, void* tag);\n"); "::grpc::CompletionQueue* cq, void* tag);\n");
} else if (BidiStreaming(method)) { } else if (BidiStreaming(method)) {
printer->Print( printer->Print(
*vars, *vars,
@ -264,10 +267,16 @@ void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer,
} }
} }
void PrintHeaderServerMethodSync( void PrintHeaderClientMethodData(grpc::protobuf::io::Printer *printer,
grpc::protobuf::io::Printer *printer, const grpc::protobuf::MethodDescriptor *method,
const grpc::protobuf::MethodDescriptor *method, std::map<grpc::string, grpc::string> *vars) {
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)["Method"] = method->name();
(*vars)["Request"] = (*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true); grpc_cpp_generator::ClassName(method->input_type(), true);
@ -351,10 +360,18 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
"class Stub GRPC_FINAL : public ::grpc::InternalStub {\n" "class Stub GRPC_FINAL : public ::grpc::InternalStub {\n"
" public:\n"); " public:\n");
printer->Indent(); printer->Indent();
printer->Print(
"Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i), vars); PrintHeaderClientMethod(printer, service->method(i), vars);
} }
printer->Outdent(); 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("};\n");
printer->Print( printer->Print(
"static std::unique_ptr<Stub> NewStub(const std::shared_ptr< " "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
@ -479,7 +496,6 @@ grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
printer.Print(vars, "#include <grpc++/async_unary_call.h>\n"); printer.Print(vars, "#include <grpc++/async_unary_call.h>\n");
printer.Print(vars, "#include <grpc++/channel_interface.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/client_unary_call.h>\n");
printer.Print(vars, "#include <grpc++/impl/rpc_method.h>\n");
printer.Print(vars, "#include <grpc++/impl/rpc_service_method.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++/impl/service_type.h>\n");
printer.Print(vars, "#include <grpc++/stream.h>\n"); printer.Print(vars, "#include <grpc++/stream.h>\n");
@ -513,8 +529,8 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ClientContext* context, " "::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response) {\n"); "const $Request$& request, $Response$* response) {\n");
printer->Print(*vars, printer->Print(*vars,
" return ::grpc::BlockingUnaryCall(channel()," " return ::grpc::BlockingUnaryCall(channel(), "
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), " "rpcmethod_$Method$_, "
"context, request, response);\n" "context, request, response);\n"
"}\n\n"); "}\n\n");
printer->Print( printer->Print(
@ -528,7 +544,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
"::grpc::ClientAsyncResponseReader< $Response$>>(new " "::grpc::ClientAsyncResponseReader< $Response$>>(new "
"::grpc::ClientAsyncResponseReader< $Response$>(" "::grpc::ClientAsyncResponseReader< $Response$>("
"channel(), cq, " "channel(), cq, "
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$]), " "rpcmethod_$Method$_, "
"context, request, tag));\n" "context, request, tag));\n"
"}\n\n"); "}\n\n");
} else if (ClientOnlyStreaming(method)) { } else if (ClientOnlyStreaming(method)) {
@ -540,8 +556,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
" return std::unique_ptr< ::grpc::ClientWriter< " " return std::unique_ptr< ::grpc::ClientWriter< "
"$Request$>>(new ::grpc::ClientWriter< $Request$>(" "$Request$>>(new ::grpc::ClientWriter< $Request$>("
"channel()," "channel(),"
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
"context, response));\n" "context, response));\n"
"}\n\n"); "}\n\n");
printer->Print(*vars, printer->Print(*vars,
@ -553,8 +568,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
" return std::unique_ptr< ::grpc::ClientAsyncWriter< " " return std::unique_ptr< ::grpc::ClientAsyncWriter< "
"$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>(" "$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>("
"channel(), cq, " "channel(), cq, "
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::CLIENT_STREAMING), "
"context, response, tag));\n" "context, response, tag));\n"
"}\n\n"); "}\n\n");
} else if (ServerOnlyStreaming(method)) { } else if (ServerOnlyStreaming(method)) {
@ -567,8 +581,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
" return std::unique_ptr< ::grpc::ClientReader< " " return std::unique_ptr< ::grpc::ClientReader< "
"$Response$>>(new ::grpc::ClientReader< $Response$>(" "$Response$>>(new ::grpc::ClientReader< $Response$>("
"channel()," "channel(),"
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
"context, request));\n" "context, request));\n"
"}\n\n"); "}\n\n");
printer->Print(*vars, printer->Print(*vars,
@ -580,8 +593,7 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
" return std::unique_ptr< ::grpc::ClientAsyncReader< " " return std::unique_ptr< ::grpc::ClientAsyncReader< "
"$Response$>>(new ::grpc::ClientAsyncReader< $Response$>(" "$Response$>>(new ::grpc::ClientAsyncReader< $Response$>("
"channel(), cq, " "channel(), cq, "
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::SERVER_STREAMING), "
"context, request, tag));\n" "context, request, tag));\n"
"}\n\n"); "}\n\n");
} else if (BidiStreaming(method)) { } else if (BidiStreaming(method)) {
@ -594,22 +606,21 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer,
"$Request$, $Response$>>(new ::grpc::ClientReaderWriter< " "$Request$, $Response$>>(new ::grpc::ClientReaderWriter< "
"$Request$, $Response$>(" "$Request$, $Response$>("
"channel()," "channel(),"
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
"context));\n" "context));\n"
"}\n\n"); "}\n\n");
printer->Print(*vars, printer->Print(
"std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " *vars,
"$Request$, $Response$>> " "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
"$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, " "$Request$, $Response$>> "
"::grpc::CompletionQueue* cq, void* tag) {\n"); "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, "
"::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print(*vars, printer->Print(*vars,
" return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " " return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
"$Request$, $Response$>>(new " "$Request$, $Response$>>(new "
"::grpc::ClientAsyncReaderWriter< $Request$, $Response$>(" "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
"channel(), cq, " "channel(), cq, "
"::grpc::RpcMethod($prefix$$Service$_method_names[$Idx$], " "rpcmethod_$Method$_, "
"::grpc::RpcMethod::RpcType::BIDI_STREAMING), "
"context, tag));\n" "context, tag));\n"
"}\n\n"); "}\n\n");
} }
@ -681,9 +692,9 @@ void PrintSourceServerAsyncMethod(
"$Request$* request, " "$Request$* request, "
"::grpc::ServerAsyncResponseWriter< $Response$>* response, " "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
"::grpc::CompletionQueue* cq, void* tag) {\n"); "::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print( printer->Print(*vars,
*vars, " AsynchronousService::RequestAsyncUnary($Idx$, context, "
" AsynchronousService::RequestAsyncUnary($Idx$, context, request, response, cq, tag);\n"); "request, response, cq, tag);\n");
printer->Print("}\n\n"); printer->Print("}\n\n");
} else if (ClientOnlyStreaming(method)) { } else if (ClientOnlyStreaming(method)) {
printer->Print(*vars, printer->Print(*vars,
@ -691,9 +702,9 @@ void PrintSourceServerAsyncMethod(
"::grpc::ServerContext* context, " "::grpc::ServerContext* context, "
"::grpc::ServerAsyncReader< $Response$, $Request$>* reader, " "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
"::grpc::CompletionQueue* cq, void* tag) {\n"); "::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print( printer->Print(*vars,
*vars, " AsynchronousService::RequestClientStreaming($Idx$, "
" AsynchronousService::RequestClientStreaming($Idx$, context, reader, cq, tag);\n"); "context, reader, cq, tag);\n");
printer->Print("}\n\n"); printer->Print("}\n\n");
} else if (ServerOnlyStreaming(method)) { } else if (ServerOnlyStreaming(method)) {
printer->Print(*vars, printer->Print(*vars,
@ -702,9 +713,9 @@ void PrintSourceServerAsyncMethod(
"$Request$* request, " "$Request$* request, "
"::grpc::ServerAsyncWriter< $Response$>* writer, " "::grpc::ServerAsyncWriter< $Response$>* writer, "
"::grpc::CompletionQueue* cq, void* tag) {\n"); "::grpc::CompletionQueue* cq, void* tag) {\n");
printer->Print( printer->Print(*vars,
*vars, " AsynchronousService::RequestServerStreaming($Idx$, "
" AsynchronousService::RequestServerStreaming($Idx$, context, request, writer, cq, tag);\n"); "context, request, writer, cq, tag);\n");
printer->Print("}\n\n"); printer->Print("}\n\n");
} else if (BidiStreaming(method)) { } else if (BidiStreaming(method)) {
printer->Print( printer->Print(
@ -713,9 +724,9 @@ void PrintSourceServerAsyncMethod(
"::grpc::ServerContext* context, " "::grpc::ServerContext* context, "
"::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, " "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
"::grpc::CompletionQueue* cq, void *tag) {\n"); "::grpc::CompletionQueue* cq, void *tag) {\n");
printer->Print( printer->Print(*vars,
*vars, " AsynchronousService::RequestBidiStreaming($Idx$, "
" AsynchronousService::RequestBidiStreaming($Idx$, context, stream, cq, tag);\n"); "context, stream, cq, tag);\n");
printer->Print("}\n\n"); printer->Print("}\n\n");
} }
} }
@ -725,7 +736,8 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
std::map<grpc::string, grpc::string> *vars) { std::map<grpc::string, grpc::string> *vars) {
(*vars)["Service"] = service->name(); (*vars)["Service"] = service->name();
printer->Print(*vars, "static const char* $prefix$$Service$_method_names[] = {\n"); printer->Print(*vars,
"static const char* $prefix$$Service$_method_names[] = {\n");
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Method"] = service->method(i)->name(); (*vars)["Method"] = service->method(i)->name();
printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n"); printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
@ -736,21 +748,51 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
*vars, *vars,
"std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub(" "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
"const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n" "const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
" std::unique_ptr< $ns$$Service$::Stub> stub(new $ns$$Service$::Stub());\n" " std::unique_ptr< $ns$$Service$::Stub> stub(new "
" stub->set_channel(channel);\n" "$ns$$Service$::Stub(channel));\n"
" return stub;\n" " return stub;\n"
"}\n\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) { for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Idx"] = as_string(i); (*vars)["Idx"] = as_string(i);
PrintSourceClientMethod(printer, service->method(i), vars); PrintSourceClientMethod(printer, service->method(i), vars);
} }
(*vars)["MethodCount"] = as_string(service->method_count()); (*vars)["MethodCount"] = as_string(service->method_count());
printer->Print( printer->Print(*vars,
*vars, "$ns$$Service$::AsyncService::AsyncService(::grpc::"
"$ns$$Service$::AsyncService::AsyncService(::grpc::CompletionQueue* cq) : " "CompletionQueue* cq) : "
"::grpc::AsynchronousService(cq, $prefix$$Service$_method_names, $MethodCount$) " "::grpc::AsynchronousService(cq, "
"{}\n\n"); "$prefix$$Service$_method_names, $MethodCount$) "
"{}\n\n");
printer->Print(*vars, printer->Print(*vars,
"$ns$$Service$::Service::~Service() {\n" "$ns$$Service$::Service::~Service() {\n"
@ -783,7 +825,8 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
"service_->AddMethod(new ::grpc::RpcServiceMethod(\n" "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
" $prefix$$Service$_method_names[$Idx$],\n" " $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::RpcMethod::NORMAL_RPC,\n" " ::grpc::RpcMethod::NORMAL_RPC,\n"
" new ::grpc::RpcMethodHandler< $ns$$Service$::Service, $Request$, " " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, "
"$Request$, "
"$Response$>(\n" "$Response$>(\n"
" std::function< ::grpc::Status($ns$$Service$::Service*, " " std::function< ::grpc::Status($ns$$Service$::Service*, "
"::grpc::ServerContext*, const $Request$*, $Response$*)>(" "::grpc::ServerContext*, const $Request$*, $Response$*)>("

@ -40,9 +40,8 @@
#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_client.h"
#include "src/core/httpcli/format_request.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/httpcli/parser.h"
#include "src/core/security/security_context.h"
#include "src/core/security/secure_transport_setup.h" #include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
@ -180,7 +179,7 @@ static void on_connected(void *arg, grpc_endpoint *tcp) {
} }
req->ep = tcp; req->ep = tcp;
if (req->use_ssl) { if (req->use_ssl) {
grpc_channel_security_context *ctx = NULL; grpc_channel_security_connector *sc = NULL;
const unsigned char *pem_root_certs = NULL; const unsigned char *pem_root_certs = NULL;
size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs); size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
if (pem_root_certs == NULL || pem_root_certs_size == 0) { 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); finish(req, 0);
return; return;
} }
GPR_ASSERT(grpc_httpcli_ssl_channel_security_context_create( GPR_ASSERT(grpc_httpcli_ssl_channel_security_connector_create(
pem_root_certs, pem_root_certs_size, req->host, &ctx) == pem_root_certs, pem_root_certs_size, req->host, &sc) ==
GRPC_SECURITY_OK); 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); req);
grpc_security_context_unref(&ctx->base); grpc_security_connector_unref(&sc->base);
} else { } else {
start_write(req); start_write(req);
} }

@ -31,7 +31,7 @@
* *
*/ */
#include "src/core/httpcli/httpcli_security_context.h" #include "src/core/httpcli/httpcli_security_connector.h"
#include <string.h> #include <string.h>
@ -42,25 +42,25 @@
#include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/ssl_transport_security.h"
typedef struct { typedef struct {
grpc_channel_security_context base; grpc_channel_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory; tsi_ssl_handshaker_factory *handshaker_factory;
char *secure_peer_name; 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) { static void httpcli_ssl_destroy(grpc_security_connector *sc) {
grpc_httpcli_ssl_channel_security_context *c = grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_context *)ctx; (grpc_httpcli_ssl_channel_security_connector *)sc;
if (c->handshaker_factory != NULL) { if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
} }
if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name); 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( static grpc_security_status httpcli_ssl_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) { grpc_security_connector *sc, tsi_handshaker **handshaker) {
grpc_httpcli_ssl_channel_security_context *c = grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_context *)ctx; (grpc_httpcli_ssl_channel_security_connector *)sc;
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR; if (c->handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
result = tsi_ssl_handshaker_factory_create_handshaker( result = tsi_ssl_handshaker_factory_create_handshaker(
@ -73,12 +73,12 @@ static grpc_security_status httpcli_ssl_create_handshaker(
return GRPC_SECURITY_OK; 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, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
void *user_data) { void *user_data) {
grpc_httpcli_ssl_channel_security_context *c = grpc_httpcli_ssl_channel_security_connector *c =
(grpc_httpcli_ssl_channel_security_context *)ctx; (grpc_httpcli_ssl_channel_security_connector *)sc;
grpc_security_status status = GRPC_SECURITY_OK; grpc_security_status status = GRPC_SECURITY_OK;
/* Check the peer name. */ /* Check the peer name. */
@ -92,14 +92,14 @@ static grpc_security_status httpcli_ssl_check_peer(grpc_security_context *ctx,
return status; 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}; 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 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; 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) { if (secure_peer_name != NULL && pem_root_certs == NULL) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
@ -107,8 +107,8 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
c = gpr_malloc(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_context)); memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 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.", gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
httpcli_ssl_destroy(&c->base.base); httpcli_ssl_destroy(&c->base.base);
*ctx = NULL; *sc = NULL;
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
*ctx = &c->base; *sc = &c->base;
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }

@ -31,13 +31,13 @@
* *
*/ */
#ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H #ifndef GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONNECTOR_H
#define GRPC_INTERNAL_CORE_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_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 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 */

@ -78,7 +78,6 @@ static void do_iocp_work() {
if (overlapped == &g_iocp_custom_overlap) { if (overlapped == &g_iocp_custom_overlap) {
if (completion_key == (ULONG_PTR) &g_iocp_kick_token) { if (completion_key == (ULONG_PTR) &g_iocp_kick_token) {
/* We were awoken from a kick. */ /* We were awoken from a kick. */
gpr_log(GPR_DEBUG, "do_iocp_work - got a kick");
return; return;
} }
gpr_log(GPR_ERROR, "Unknown custom completion key."); gpr_log(GPR_ERROR, "Unknown custom completion key.");
@ -87,10 +86,8 @@ static void do_iocp_work() {
socket = (grpc_winsocket*) completion_key; socket = (grpc_winsocket*) completion_key;
if (overlapped == &socket->write_info.overlapped) { if (overlapped == &socket->write_info.overlapped) {
gpr_log(GPR_DEBUG, "do_iocp_work - got write packet");
info = &socket->write_info; info = &socket->write_info;
} else if (overlapped == &socket->read_info.overlapped) { } else if (overlapped == &socket->read_info.overlapped) {
gpr_log(GPR_DEBUG, "do_iocp_work - got read packet");
info = &socket->read_info; info = &socket->read_info;
} else { } else {
gpr_log(GPR_ERROR, "Unknown IOCP operation"); gpr_log(GPR_ERROR, "Unknown IOCP operation");
@ -98,8 +95,6 @@ static void do_iocp_work() {
} }
success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes, success = WSAGetOverlappedResult(socket->socket, &info->overlapped, &bytes,
FALSE, &flags); FALSE, &flags);
gpr_log(GPR_DEBUG, "bytes: %u, flags: %u - op %s %s", bytes, flags,
success ? "succeeded" : "failed", socket->orphan ? "orphan" : "");
if (socket->orphan) { if (socket->orphan) {
grpc_winsocket_destroy(socket); grpc_winsocket_destroy(socket);
gpr_atm_full_fetch_add(&g_orphans, -1); gpr_atm_full_fetch_add(&g_orphans, -1);
@ -189,11 +184,9 @@ static void socket_notify_on_iocp(grpc_winsocket *socket,
if (info->has_pending_iocp) { if (info->has_pending_iocp) {
run_now = 1; run_now = 1;
info->has_pending_iocp = 0; info->has_pending_iocp = 0;
gpr_log(GPR_DEBUG, "socket_notify_on_iocp - runs now");
} else { } else {
info->cb = cb; info->cb = cb;
info->opaque = opaque; info->opaque = opaque;
gpr_log(GPR_DEBUG, "socket_notify_on_iocp - queued");
} }
gpr_mu_unlock(&socket->state_mu); gpr_mu_unlock(&socket->state_mu);
if (run_now) cb(opaque, 1); if (run_now) cb(opaque, 1);
@ -201,13 +194,11 @@ static void socket_notify_on_iocp(grpc_winsocket *socket,
void grpc_socket_notify_on_write(grpc_winsocket *socket, void grpc_socket_notify_on_write(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque) { 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); socket_notify_on_iocp(socket, cb, opaque, &socket->write_info);
} }
void grpc_socket_notify_on_read(grpc_winsocket *socket, void grpc_socket_notify_on_read(grpc_winsocket *socket,
void(*cb)(void *, int), void *opaque) { 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); socket_notify_on_iocp(socket, cb, opaque, &socket->read_info);
} }

@ -107,18 +107,14 @@ grpc_resolved_addresses *grpc_blocking_resolve_address(
i++; i++;
} }
/* Temporary logging, to help identify flakiness in dualstack_socket_test. */
{ {
const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time); const gpr_timespec delay = gpr_time_sub(gpr_now(), start_time);
const int delay_ms = const int delay_ms =
delay.tv_sec * GPR_MS_PER_SEC + delay.tv_nsec / GPR_NS_PER_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++) { for (i = 0; i < addrs->naddrs; i++) {
char *buf; char *buf;
grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr, grpc_sockaddr_to_string(&buf, (struct sockaddr *)&addrs->addrs[i].addr,
0); 0);
gpr_log(GPR_INFO, "logspam: [%d] %s", i, buf);
gpr_free(buf); gpr_free(buf);
} }
} }

@ -46,7 +46,6 @@
grpc_winsocket *grpc_winsocket_create(SOCKET socket) { grpc_winsocket *grpc_winsocket_create(SOCKET socket) {
grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket)); grpc_winsocket *r = gpr_malloc(sizeof(grpc_winsocket));
gpr_log(GPR_DEBUG, "grpc_winsocket_create");
memset(r, 0, sizeof(grpc_winsocket)); memset(r, 0, sizeof(grpc_winsocket));
r->socket = socket; r->socket = socket;
gpr_mu_init(&r->state_mu); gpr_mu_init(&r->state_mu);
@ -61,13 +60,11 @@ static void shutdown_op(grpc_winsocket_callback_info *info) {
} }
void grpc_winsocket_shutdown(grpc_winsocket *socket) { void grpc_winsocket_shutdown(grpc_winsocket *socket) {
gpr_log(GPR_DEBUG, "grpc_winsocket_shutdown");
shutdown_op(&socket->read_info); shutdown_op(&socket->read_info);
shutdown_op(&socket->write_info); shutdown_op(&socket->write_info);
} }
void grpc_winsocket_orphan(grpc_winsocket *socket) { void grpc_winsocket_orphan(grpc_winsocket *socket) {
gpr_log(GPR_DEBUG, "grpc_winsocket_orphan");
grpc_iocp_socket_orphan(socket); grpc_iocp_socket_orphan(socket);
socket->orphan = 1; socket->orphan = 1;
grpc_iomgr_unref(); grpc_iomgr_unref();

@ -102,7 +102,6 @@ static void on_connect(void *acp, int success) {
gpr_free(utf8_message); gpr_free(utf8_message);
goto finish; goto finish;
} else { } else {
gpr_log(GPR_DEBUG, "on_connect: connection established");
ep = grpc_tcp_create(ac->socket); ep = grpc_tcp_create(ac->socket);
goto finish; goto finish;
} }
@ -179,9 +178,7 @@ void grpc_tcp_client_connect(void(*cb)(void *arg, grpc_endpoint *tcp),
info = &socket->write_info; info = &socket->write_info;
success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped); success = ConnectEx(sock, addr, addr_len, NULL, 0, NULL, &info->overlapped);
if (success) { if (!success) {
gpr_log(GPR_DEBUG, "connected immediately - but we still go to sleep");
} else {
int error = WSAGetLastError(); int error = WSAGetLastError();
if (error != ERROR_IO_PENDING) { if (error != ERROR_IO_PENDING) {
message = "ConnectEx failed: %s"; 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 = gpr_malloc(sizeof(async_connect));
ac->cb = cb; ac->cb = cb;
ac->cb_arg = arg; ac->cb_arg = arg;

@ -46,6 +46,7 @@
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/debug/trace.h" #include "src/core/debug/trace.h"
#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/slice.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; gpr_slice *final_slices;
size_t final_nslices; size_t final_nslices;
GRPC_TIMER_MARK(HANDLE_READ_BEGIN, 0);
slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE, slice_state_init(&read_state, static_read_slices, INLINE_SLICE_BUFFER_SIZE,
0); 0);
@ -348,9 +350,11 @@ static void grpc_tcp_handle_read(void *arg /* grpc_tcp */, int success) {
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
GRPC_TIMER_MARK(RECVMSG_BEGIN, 0);
do { do {
read_bytes = recvmsg(tcp->fd, &msg, 0); read_bytes = recvmsg(tcp->fd, &msg, 0);
} while (read_bytes < 0 && errno == EINTR); } while (read_bytes < 0 && errno == EINTR);
GRPC_TIMER_MARK(RECVMSG_END, 0);
if (read_bytes < allocated_bytes) { if (read_bytes < allocated_bytes) {
/* TODO(klempner): Consider a second read first, in hopes of getting a /* 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; ++iov_size;
} }
} }
GRPC_TIMER_MARK(HANDLE_READ_END, 0);
} }
static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, 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_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
GRPC_TIMER_MARK(SENDMSG_BEGIN, 0);
do { do {
/* TODO(klempner): Cork if this is a partial write */ /* TODO(klempner): Cork if this is a partial write */
sent_length = sendmsg(tcp->fd, &msg, 0); sent_length = sendmsg(tcp->fd, &msg, 0);
} while (sent_length < 0 && errno == EINTR); } while (sent_length < 0 && errno == EINTR);
GRPC_TIMER_MARK(SENDMSG_END, 0);
if (sent_length < 0) { if (sent_length < 0) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
@ -472,6 +479,7 @@ static void grpc_tcp_handle_write(void *arg /* grpc_tcp */, int success) {
return; return;
} }
GRPC_TIMER_MARK(CB_WRITE_BEGIN, 0);
write_status = grpc_tcp_flush(tcp); write_status = grpc_tcp_flush(tcp);
if (write_status == GRPC_ENDPOINT_WRITE_PENDING) { if (write_status == GRPC_ENDPOINT_WRITE_PENDING) {
grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_closure); 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); cb(tcp->write_user_data, cb_status);
grpc_tcp_unref(tcp); grpc_tcp_unref(tcp);
} }
GRPC_TIMER_MARK(CB_WRITE_END, 0);
} }
static grpc_endpoint_write_status grpc_tcp_write(grpc_endpoint *ep, 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); GPR_ASSERT(tcp->write_cb == NULL);
slice_state_init(&tcp->write_state, slices, nslices, nslices); 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_fd_notify_on_write(tcp->em_fd, &tcp->write_closure);
} }
GRPC_TIMER_MARK(WRITE_END, 0);
return status; return status;
} }

@ -191,13 +191,13 @@ static void start_accept(server_port *port) {
goto failure; goto failure;
} }
/* TODO(jtattermusch): probably a race here, we regularly get use-after-free on server shutdown */
GPR_ASSERT(port->socket != 0xfeeefeee);
success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0, success = port->AcceptEx(port->socket->socket, sock, port->addresses, 0,
addrlen, addrlen, &bytes_received, addrlen, addrlen, &bytes_received,
&port->socket->read_info.overlapped); &port->socket->read_info.overlapped);
if (success) { if (!success) {
gpr_log(GPR_DEBUG, "accepted immediately - but we still go to sleep");
} else {
int error = WSAGetLastError(); int error = WSAGetLastError();
if (error != ERROR_IO_PENDING) { if (error != ERROR_IO_PENDING) {
message = "AcceptEx failed: %s"; message = "AcceptEx failed: %s";
@ -234,11 +234,9 @@ static void on_accept(void *arg, int success) {
gpr_free(utf8_message); gpr_free(utf8_message);
closesocket(sock); closesocket(sock);
} else { } else {
gpr_log(GPR_DEBUG, "on_accept: accepted connection");
ep = grpc_tcp_create(grpc_winsocket_create(sock)); ep = grpc_tcp_create(grpc_winsocket_create(sock));
} }
} else { } else {
gpr_log(GPR_DEBUG, "on_accept: shutting down");
closesocket(sock); closesocket(sock);
gpr_mu_lock(&sp->server->mu); gpr_mu_lock(&sp->server->mu);
if (0 == --sp->server->active_ports) { if (0 == --sp->server->active_ports) {
@ -248,7 +246,9 @@ static void on_accept(void *arg, int success) {
} }
if (ep) sp->server->cb(sp->server->cb_arg, ep); 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, static int add_socket_to_server(grpc_tcp_server *s, SOCKET sock,

@ -93,14 +93,11 @@ typedef struct grpc_tcp {
} grpc_tcp; } grpc_tcp;
static void tcp_ref(grpc_tcp *tcp) { static void tcp_ref(grpc_tcp *tcp) {
gpr_log(GPR_DEBUG, "tcp_ref");
gpr_ref(&tcp->refcount); gpr_ref(&tcp->refcount);
} }
static void tcp_unref(grpc_tcp *tcp) { static void tcp_unref(grpc_tcp *tcp) {
gpr_log(GPR_DEBUG, "tcp_unref");
if (gpr_unref(&tcp->refcount)) { if (gpr_unref(&tcp->refcount)) {
gpr_log(GPR_DEBUG, "tcp_unref: destroying");
gpr_slice_buffer_destroy(&tcp->write_slices); gpr_slice_buffer_destroy(&tcp->write_slices);
grpc_winsocket_orphan(tcp->socket); grpc_winsocket_orphan(tcp->socket);
gpr_free(tcp); gpr_free(tcp);
@ -126,24 +123,20 @@ static void on_read(void *tcpp, int success) {
return; return;
} }
gpr_log(GPR_DEBUG, "on_read");
tcp->outstanding_read = 0; tcp->outstanding_read = 0;
if (socket->read_info.wsa_error != 0) { if (socket->read_info.wsa_error != 0) {
char *utf8_message = gpr_format_message(info->wsa_error); char *utf8_message = gpr_format_message(info->wsa_error);
__debugbreak();
gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message); gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
gpr_free(utf8_message); gpr_free(utf8_message);
status = GRPC_ENDPOINT_CB_ERROR; status = GRPC_ENDPOINT_CB_ERROR;
} else { } else {
if (info->bytes_transfered != 0) { if (info->bytes_transfered != 0) {
sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered); sub = gpr_slice_sub(tcp->read_slice, 0, info->bytes_transfered);
gpr_log(GPR_DEBUG, "on_read: calling callback");
status = GRPC_ENDPOINT_CB_OK; status = GRPC_ENDPOINT_CB_OK;
slice = &sub; slice = &sub;
nslices = 1; nslices = 1;
} else { } else {
gpr_log(GPR_DEBUG, "on_read: closed socket");
gpr_slice_unref(tcp->read_slice); gpr_slice_unref(tcp->read_slice);
status = GRPC_ENDPOINT_CB_EOF; 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.len = GPR_SLICE_LENGTH(tcp->read_slice);
buffer.buf = (char *)GPR_SLICE_START_PTR(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, status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
NULL, NULL); NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError(); info->wsa_error = status == 0 ? 0 : WSAGetLastError();
if (info->wsa_error != WSAEWOULDBLOCK) { if (info->wsa_error != WSAEWOULDBLOCK) {
gpr_log(GPR_DEBUG, "got response immediately, calling on_read");
info->bytes_transfered = bytes_read; info->bytes_transfered = bytes_read;
/* This might heavily recurse. */ /* This might heavily recurse. */
on_read(tcp, 1); on_read(tcp, 1);
return; return;
} }
gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSARecv with overlap");
memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED)); memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags, status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
&info->overlapped, NULL); &info->overlapped, NULL);
if (status == 0) { 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); grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
return; return;
} }
@ -213,7 +201,6 @@ static void win_notify_on_read(grpc_endpoint *ep,
return; return;
} }
gpr_log(GPR_DEBUG, "waiting on the IO completion port now");
grpc_socket_notify_on_read(tcp->socket, on_read, tcp); 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_ASSERT(tcp->outstanding_write);
gpr_log(GPR_DEBUG, "on_write");
if (!success) { if (!success) {
tcp_unref(tcp); tcp_unref(tcp);
cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN); cb(opaque, GRPC_ENDPOINT_CB_SHUTDOWN);
@ -265,13 +250,9 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
WSABUF *allocated = NULL; WSABUF *allocated = NULL;
WSABUF *buffers = local_buffers; WSABUF *buffers = local_buffers;
GPR_ASSERT(nslices != 0);
GPR_ASSERT(GPR_SLICE_LENGTH(slices[0]) != 0);
GPR_ASSERT(!tcp->outstanding_write); GPR_ASSERT(!tcp->outstanding_write);
tcp_ref(tcp); tcp_ref(tcp);
gpr_log(GPR_DEBUG, "win_write");
tcp->outstanding_write = 1; tcp->outstanding_write = 1;
tcp->write_cb = cb; tcp->write_cb = cb;
tcp->write_user_data = arg; 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]); 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, status = WSASend(socket->socket, buffers, tcp->write_slices.count,
&bytes_sent, 0, NULL, NULL); &bytes_sent, 0, NULL, NULL);
info->wsa_error = status == 0 ? 0 : WSAGetLastError(); info->wsa_error = status == 0 ? 0 : WSAGetLastError();
if (info->wsa_error != WSAEWOULDBLOCK) { if (info->wsa_error != WSAEWOULDBLOCK) {
grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR; grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
gpr_log(GPR_DEBUG, "got response immediately, cleaning up and leaving");
if (status == 0) { if (status == 0) {
ret = GRPC_ENDPOINT_WRITE_DONE; ret = GRPC_ENDPOINT_WRITE_DONE;
GPR_ASSERT(bytes_sent == tcp->write_slices.length); GPR_ASSERT(bytes_sent == tcp->write_slices.length);
@ -310,8 +289,6 @@ static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
return ret; return ret;
} }
gpr_log(GPR_DEBUG, "got WSAEWOULDBLOCK - calling WSASend with overlap");
memset(&socket->write_info, 0, sizeof(OVERLAPPED)); memset(&socket->write_info, 0, sizeof(OVERLAPPED));
status = WSASend(socket->socket, buffers, tcp->write_slices.count, status = WSASend(socket->socket, buffers, tcp->write_slices.count,
&bytes_sent, 0, &socket->write_info.overlapped, NULL); &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); tcp_unref(tcp);
return GRPC_ENDPOINT_WRITE_ERROR; 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); 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) { static void win_add_to_pollset(grpc_endpoint *ep, grpc_pollset *pollset) {
grpc_tcp *tcp = (grpc_tcp *) ep; grpc_tcp *tcp = (grpc_tcp *) ep;
gpr_log(GPR_DEBUG, "win_add_to_pollset");
grpc_iocp_add_socket(tcp->socket); grpc_iocp_add_socket(tcp->socket);
} }
static void win_shutdown(grpc_endpoint *ep) { static void win_shutdown(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *) ep; grpc_tcp *tcp = (grpc_tcp *) ep;
gpr_log(GPR_DEBUG, "win_shutdown");
grpc_winsocket_shutdown(tcp->socket); grpc_winsocket_shutdown(tcp->socket);
} }
static void win_destroy(grpc_endpoint *ep) { static void win_destroy(grpc_endpoint *ep) {
grpc_tcp *tcp = (grpc_tcp *) ep; grpc_tcp *tcp = (grpc_tcp *) ep;
gpr_log(GPR_DEBUG, "win_destroy");
tcp_unref(tcp); tcp_unref(tcp);
} }

@ -45,7 +45,7 @@
typedef struct grpc_timer_entry { typedef struct grpc_timer_entry {
grpc_precise_clock tm; grpc_precise_clock tm;
const char* tag; const char* tag;
int seq; void* id;
const char* file; const char* file;
int line; int line;
} grpc_timer_entry; } grpc_timer_entry;
@ -85,7 +85,7 @@ static void log_report_locked(grpc_timers_log* log) {
grpc_timer_entry* entry = &(log->log[i]); grpc_timer_entry* entry = &(log->log[i]);
fprintf(fp, "GRPC_LAT_PROF "); fprintf(fp, "GRPC_LAT_PROF ");
grpc_precise_clock_print(&entry->tm, fp); grpc_precise_clock_print(&entry->tm, fp);
fprintf(fp, " %s#%d,%s:%d\n", entry->tag, entry->seq, entry->file, fprintf(fp, " %s %p %s %d\n", entry->tag, entry->id, entry->file,
entry->line); entry->line);
} }
@ -104,7 +104,7 @@ void grpc_timers_log_destroy(grpc_timers_log* log) {
gpr_free(log); gpr_free(log);
} }
void grpc_timers_log_add(grpc_timers_log* log, const char* tag, int seq, void grpc_timers_log_add(grpc_timers_log* log, const char* tag, void* id,
const char* file, int line) { const char* file, int line) {
grpc_timer_entry* entry; grpc_timer_entry* entry;
@ -118,7 +118,7 @@ void grpc_timers_log_add(grpc_timers_log* log, const char* tag, int seq,
grpc_precise_clock_now(&entry->tm); grpc_precise_clock_now(&entry->tm);
entry->tag = tag; entry->tag = tag;
entry->seq = seq; entry->id = id;
entry->file = file; entry->file = file;
entry->line = line; entry->line = line;

@ -44,15 +44,16 @@ extern "C" {
typedef struct grpc_timers_log grpc_timers_log; typedef struct grpc_timers_log grpc_timers_log;
grpc_timers_log *grpc_timers_log_create(int capacity_limit, FILE *dump); grpc_timers_log* grpc_timers_log_create(int capacity_limit, FILE* dump);
void grpc_timers_log_add(grpc_timers_log *, const char *tag, int seq, void grpc_timers_log_add(grpc_timers_log*, const char* tag, void* id,
const char *file, int line); const char* file, int line);
void grpc_timers_log_destroy(grpc_timers_log *); void grpc_timers_log_destroy(grpc_timers_log *);
extern grpc_timers_log *grpc_timers_log_global; extern grpc_timers_log *grpc_timers_log_global;
#define GRPC_TIMER_MARK(x, s) \ #define GRPC_TIMER_MARK(x, s) \
grpc_timers_log_add(grpc_timers_log_global, #x, s, __FILE__, __LINE__) grpc_timers_log_add(grpc_timers_log_global, #x, ((void *)(gpr_intptr)(s)), \
__FILE__, __LINE__)
#else /* !GRPC_LATENCY_PROFILER */ #else /* !GRPC_LATENCY_PROFILER */
#define GRPC_TIMER_MARK(x, s) \ #define GRPC_TIMER_MARK(x, s) \

@ -40,7 +40,7 @@
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/channel/channel_stack.h" #include "src/core/channel/channel_stack.h"
#include "src/core/security/security_context.h" #include "src/core/security/security_connector.h"
#include "src/core/security/credentials.h" #include "src/core/security/credentials.h"
#include "src/core/surface/call.h" #include "src/core/surface/call.h"
@ -54,7 +54,7 @@ typedef struct {
/* We can have a per-channel credentials. */ /* We can have a per-channel credentials. */
typedef struct { typedef struct {
grpc_channel_security_context *security_context; grpc_channel_security_connector *security_connector;
grpc_mdctx *md_ctx; grpc_mdctx *md_ctx;
grpc_mdstr *authority_string; grpc_mdstr *authority_string;
grpc_mdstr *path_string; grpc_mdstr *path_string;
@ -126,7 +126,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
channel_data *channeld = elem->channel_data; channel_data *channeld = elem->channel_data;
grpc_credentials *channel_creds = grpc_credentials *channel_creds =
channeld->security_context->request_metadata_creds; channeld->security_connector->request_metadata_creds;
/* TODO(jboeuf): /* TODO(jboeuf):
Decide on the policy in this case: Decide on the policy in this case:
- populate both channel and call? - populate both channel and call?
@ -138,7 +138,7 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
if (channel_creds != NULL && if (channel_creds != NULL &&
grpc_credentials_has_request_metadata(channel_creds)) { grpc_credentials_has_request_metadata(channel_creds)) {
char *service_url = 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). */ calld->op = *op; /* Copy op (originates from the caller's stack). */
grpc_credentials_get_request_metadata(channel_creds, service_url, grpc_credentials_get_request_metadata(channel_creds, service_url,
on_credentials_metadata, elem); on_credentials_metadata, elem);
@ -193,8 +193,8 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
grpc_security_status status; grpc_security_status status;
const char *call_host = grpc_mdstr_as_c_string(calld->host); const char *call_host = grpc_mdstr_as_c_string(calld->host);
calld->op = *op; /* Copy op (originates from the caller's stack). */ calld->op = *op; /* Copy op (originates from the caller's stack). */
status = grpc_channel_security_context_check_call_host( status = grpc_channel_security_connector_check_call_host(
channeld->security_context, call_host, on_host_checked, elem); channeld->security_connector, call_host, on_host_checked, elem);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
if (status == GRPC_SECURITY_ERROR) { if (status == GRPC_SECURITY_ERROR) {
char *error_msg; char *error_msg;
@ -255,7 +255,7 @@ static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, const grpc_channel_args *args,
grpc_mdctx *metadata_context, int is_first, grpc_mdctx *metadata_context, int is_first,
int is_last) { 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 */ /* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data; channel_data *channeld = elem->channel_data;
@ -268,23 +268,24 @@ static void init_channel_elem(grpc_channel_element *elem,
/* initialize members */ /* initialize members */
GPR_ASSERT(ctx->is_client_side); GPR_ASSERT(ctx->is_client_side);
channeld->security_context = channeld->security_connector =
(grpc_channel_security_context *)grpc_security_context_ref(ctx); (grpc_channel_security_connector *)grpc_security_connector_ref(ctx);
channeld->md_ctx = metadata_context; channeld->md_ctx = metadata_context;
channeld->authority_string = channeld->authority_string =
grpc_mdstr_from_string(channeld->md_ctx, ":authority"); grpc_mdstr_from_string(channeld->md_ctx, ":authority");
channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path"); channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
channeld->error_msg_key = channeld->error_msg_key =
grpc_mdstr_from_string(channeld->md_ctx, "grpc-message"); 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 */ /* Destructor for channel data */
static void destroy_channel_elem(grpc_channel_element *elem) { static void destroy_channel_elem(grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */ /* grab pointers to our data from the channel element */
channel_data *channeld = elem->channel_data; channel_data *channeld = elem->channel_data;
grpc_channel_security_context *ctx = channeld->security_context; grpc_channel_security_connector *ctx = channeld->security_connector;
if (ctx != NULL) grpc_security_context_unref(&ctx->base); if (ctx != NULL) grpc_security_connector_unref(&ctx->base);
if (channeld->authority_string != NULL) { if (channeld->authority_string != NULL) {
grpc_mdstr_unref(channeld->authority_string); grpc_mdstr_unref(channeld->authority_string);
} }
@ -300,6 +301,5 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
} }
const grpc_channel_filter grpc_client_auth_filter = { const grpc_channel_filter grpc_client_auth_filter = {
call_op, channel_op, sizeof(call_data), call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
init_call_elem, destroy_call_elem, sizeof(channel_data), sizeof(channel_data), init_channel_elem, destroy_channel_elem, "auth"};
init_channel_elem, destroy_channel_elem, "auth"};

@ -36,11 +36,14 @@
#include <string.h> #include <string.h>
#include <stdio.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/json/json.h"
#include "src/core/httpcli/httpcli.h" #include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h" #include "src/core/security/json_token.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
@ -111,9 +114,33 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
creds->vtable->get_request_metadata(creds, service_url, cb, user_data); creds->vtable->get_request_metadata(creds, service_url, cb, user_data);
} }
grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds) { grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
if (creds == NULL) return NULL; grpc_credentials *creds) {
return creds->vtable->get_metadata_context(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) { void grpc_server_credentials_release(grpc_server_credentials *creds) {
@ -121,6 +148,15 @@ void grpc_server_credentials_release(grpc_server_credentials *creds) {
creds->vtable->destroy(creds); 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. -- */ /* -- Ssl credentials. -- */
typedef struct { typedef struct {
@ -176,32 +212,49 @@ static grpc_mdctx *ssl_get_metadata_context(grpc_credentials *creds) {
return NULL; return NULL;
} }
static grpc_credentials_vtable ssl_vtable = { static grpc_security_status ssl_create_security_connector(
ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, grpc_credentials *creds, const char *target, const grpc_channel_args *args,
ssl_get_metadata_context, NULL}; grpc_credentials *request_metadata_creds,
grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy}; grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
grpc_security_status status = GRPC_SECURITY_OK;
const grpc_ssl_config *grpc_ssl_credentials_get_config( size_t i = 0;
const grpc_credentials *creds) { const char *overridden_target_name = NULL;
if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { grpc_arg arg;
return NULL;
} else { for (i = 0; args && i < args->num_args; i++) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds; grpc_arg *arg = &args->args[i];
return &c->config; 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( static grpc_security_status ssl_server_create_security_connector(
const grpc_server_credentials *creds) { grpc_server_credentials *creds, grpc_security_connector **sc) {
if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
return NULL; return grpc_ssl_server_security_connector_create(&c->config, sc);
} else {
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
return &c->config;
}
} }
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, static void ssl_copy_key_material(const char *input, unsigned char **output,
size_t *output_size) { size_t *output_size) {
*output_size = strlen(input); *output_size = strlen(input);
@ -388,7 +441,7 @@ static grpc_mdctx *jwt_get_metadata_context(grpc_credentials *creds) {
static grpc_credentials_vtable jwt_vtable = { static grpc_credentials_vtable jwt_vtable = {
jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
jwt_get_metadata_context, jwt_get_request_metadata}; jwt_get_metadata_context, jwt_get_request_metadata, NULL};
grpc_credentials *grpc_jwt_credentials_create(const char *json_key, grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
gpr_timespec token_lifetime) { gpr_timespec token_lifetime) {
@ -613,7 +666,7 @@ static grpc_credentials_vtable compute_engine_vtable = {
oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_has_request_metadata_only,
oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_metadata_context,
oauth2_token_fetcher_get_request_metadata}; oauth2_token_fetcher_get_request_metadata, NULL};
static void compute_engine_fetch_oauth2( static void compute_engine_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req, grpc_credentials_metadata_request *metadata_req,
@ -657,7 +710,7 @@ static grpc_credentials_vtable service_account_vtable = {
service_account_destroy, oauth2_token_fetcher_has_request_metadata, service_account_destroy, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_has_request_metadata_only,
oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_metadata_context,
oauth2_token_fetcher_get_request_metadata}; oauth2_token_fetcher_get_request_metadata, NULL};
static void service_account_fetch_oauth2( static void service_account_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req, grpc_credentials_metadata_request *metadata_req,
@ -731,7 +784,7 @@ static grpc_credentials_vtable refresh_token_vtable = {
refresh_token_destroy, oauth2_token_fetcher_has_request_metadata, refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
oauth2_token_fetcher_has_request_metadata_only, oauth2_token_fetcher_has_request_metadata_only,
oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_metadata_context,
oauth2_token_fetcher_get_request_metadata}; oauth2_token_fetcher_get_request_metadata, NULL};
static void refresh_token_fetch_oauth2( static void refresh_token_fetch_oauth2(
grpc_credentials_metadata_request *metadata_req, grpc_credentials_metadata_request *metadata_req,
@ -834,7 +887,7 @@ static grpc_mdctx *fake_oauth2_get_metadata_context(grpc_credentials *creds) {
static grpc_credentials_vtable fake_oauth2_vtable = { static grpc_credentials_vtable fake_oauth2_vtable = {
fake_oauth2_destroy, fake_oauth2_has_request_metadata, fake_oauth2_destroy, fake_oauth2_has_request_metadata,
fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context, fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context,
fake_oauth2_get_request_metadata}; fake_oauth2_get_request_metadata, NULL};
grpc_credentials *grpc_fake_oauth2_credentials_create( grpc_credentials *grpc_fake_oauth2_credentials_create(
const char *token_md_value, int is_async) { const char *token_md_value, int is_async) {
@ -878,15 +931,33 @@ static grpc_mdctx *fake_transport_security_get_metadata_context(
return NULL; 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 = { static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
fake_transport_security_credentials_destroy, fake_transport_security_credentials_destroy,
fake_transport_security_has_request_metadata, fake_transport_security_has_request_metadata,
fake_transport_security_has_request_metadata_only, fake_transport_security_has_request_metadata_only,
fake_transport_security_get_metadata_context, NULL}; fake_transport_security_get_metadata_context, NULL,
fake_transport_security_create_security_connector};
static grpc_server_credentials_vtable static grpc_server_credentials_vtable
fake_transport_security_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 *grpc_fake_transport_security_credentials_create(void) {
grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials)); grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
@ -911,6 +982,7 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
typedef struct { typedef struct {
grpc_credentials base; grpc_credentials base;
grpc_credentials_array inner; grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials; } grpc_composite_credentials;
typedef struct { typedef struct {
@ -1038,7 +1110,10 @@ static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) {
size_t i; size_t i;
for (i = 0; i < c->inner.num_creds; i++) { for (i = 0; i < c->inner.num_creds; i++) {
grpc_credentials *inner_creds = c->inner.creds_array[i]; grpc_credentials *inner_creds = c->inner.creds_array[i];
grpc_mdctx *inner_ctx = grpc_credentials_get_metadata_context(inner_creds); 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) { if (inner_ctx) {
GPR_ASSERT(ctx == NULL && GPR_ASSERT(ctx == NULL &&
"can only have one metadata context per composite credential"); "can only have one metadata context per composite credential");
@ -1048,10 +1123,24 @@ static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) {
return 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 = { static grpc_credentials_vtable composite_credentials_vtable = {
composite_destroy, composite_has_request_metadata, composite_destroy, composite_has_request_metadata,
composite_has_request_metadata_only, composite_get_metadata_context, composite_has_request_metadata_only, composite_get_metadata_context,
composite_get_request_metadata}; composite_get_request_metadata, composite_create_security_connector};
static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
grpc_credentials_array result; grpc_credentials_array result;
@ -1067,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 *grpc_composite_credentials_create(grpc_credentials *creds1,
grpc_credentials *creds2) { grpc_credentials *creds2) {
size_t i; size_t i;
size_t creds_array_byte_size;
grpc_credentials_array creds1_array; grpc_credentials_array creds1_array;
grpc_credentials_array creds2_array; grpc_credentials_array creds2_array;
grpc_composite_credentials *c; grpc_composite_credentials *c;
@ -1080,16 +1170,39 @@ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
creds1_array = get_creds_array(&creds1); creds1_array = get_creds_array(&creds1);
creds2_array = get_creds_array(&creds2); creds2_array = get_creds_array(&creds2);
c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds; c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
c->inner.creds_array = creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
gpr_malloc(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++) { 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++) { 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] = 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; return &c->base;
fail:
grpc_credentials_unref(&c->base);
return NULL;
} }
const grpc_credentials_array *grpc_composite_credentials_get_credentials( const grpc_credentials_array *grpc_composite_credentials_get_credentials(
@ -1163,7 +1276,7 @@ static grpc_mdctx *iam_get_metadata_context(grpc_credentials *creds) {
static grpc_credentials_vtable iam_vtable = { static grpc_credentials_vtable iam_vtable = {
iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only, iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
iam_get_metadata_context, iam_get_request_metadata}; iam_get_metadata_context, iam_get_request_metadata, NULL};
grpc_credentials *grpc_iam_credentials_create(const char *token, grpc_credentials *grpc_iam_credentials_create(const char *token,
const char *authority_selector) { const char *authority_selector) {

@ -39,6 +39,8 @@
#include <grpc/grpc_security.h> #include <grpc/grpc_security.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include "src/core/security/security_connector.h"
struct grpc_httpcli_response; struct grpc_httpcli_response;
/* --- Constants. --- */ /* --- Constants. --- */
@ -99,6 +101,11 @@ typedef struct {
const char *service_url, const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data); 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; } grpc_credentials_vtable;
struct grpc_credentials { struct grpc_credentials {
@ -115,19 +122,20 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds,
const char *service_url, const char *service_url,
grpc_credentials_metadata_cb cb, grpc_credentials_metadata_cb cb,
void *user_data); void *user_data);
grpc_mdctx *grpc_credentials_get_metadata_context(grpc_credentials *creds);
typedef struct { /* Gets the mdctx from the credentials and increase the refcount if it exists,
unsigned char *pem_private_key; otherwise, create a new one. */
size_t pem_private_key_size; grpc_mdctx *grpc_credentials_get_or_create_metadata_context(
unsigned char *pem_cert_chain; grpc_credentials *creds);
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( /* Creates a security connector for the channel. May also create new channel
const grpc_credentials *ssl_creds); 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 { typedef struct {
grpc_credentials **creds_array; grpc_credentials **creds_array;
@ -159,6 +167,8 @@ grpc_credentials *grpc_fake_oauth2_credentials_create(
typedef struct { typedef struct {
void (*destroy)(grpc_server_credentials *c); void (*destroy)(grpc_server_credentials *c);
grpc_security_status (*create_security_connector)(
grpc_server_credentials *c, grpc_security_connector **sc);
} grpc_server_credentials_vtable; } grpc_server_credentials_vtable;
struct grpc_server_credentials { struct grpc_server_credentials {
@ -166,17 +176,7 @@ struct grpc_server_credentials {
const char *type; const char *type;
}; };
typedef struct { grpc_security_status grpc_server_credentials_create_security_connector(
unsigned char **pem_private_keys; grpc_server_credentials *creds, grpc_security_connector **sc);
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);
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */ #endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */

@ -127,7 +127,7 @@ static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
gpr_slice creds_data; gpr_slice creds_data;
int file_ok = 0; int file_ok = 0;
if (creds_path == NULL) return NULL; 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); gpr_free(creds_path);
if (file_ok) { if (file_ok) {
result = grpc_jwt_credentials_create( result = grpc_jwt_credentials_create(
@ -145,7 +145,7 @@ static grpc_credentials *create_refresh_token_creds_from_path(
gpr_slice creds_data; gpr_slice creds_data;
int file_ok = 0; int file_ok = 0;
if (creds_path == NULL) return NULL; 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); gpr_free(creds_path);
if (file_ok) { if (file_ok) {
result = grpc_refresh_token_credentials_create( result = grpc_refresh_token_credentials_create(

@ -43,7 +43,7 @@
#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
typedef struct { typedef struct {
grpc_security_context *ctx; grpc_security_connector *connector;
tsi_handshaker *handshaker; tsi_handshaker *handshaker;
unsigned char *handshake_buffer; unsigned char *handshake_buffer;
size_t handshake_buffer_size; 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->handshaker != NULL) tsi_handshaker_destroy(s->handshaker);
if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer); if (s->handshake_buffer != NULL) gpr_free(s->handshake_buffer);
gpr_slice_buffer_destroy(&s->left_overs); gpr_slice_buffer_destroy(&s->left_overs);
grpc_security_context_unref(s->ctx); grpc_security_connector_unref(s->connector);
gpr_free(s); gpr_free(s);
} }
@ -112,8 +112,8 @@ static void check_peer(grpc_secure_transport_setup *s) {
secure_transport_setup_done(s, 0); secure_transport_setup_done(s, 0);
return; return;
} }
peer_status = peer_status = grpc_security_connector_check_peer(s->connector, peer,
grpc_security_context_check_peer(s->ctx, peer, on_peer_checked, s); on_peer_checked, s);
if (peer_status == GRPC_SECURITY_ERROR) { if (peer_status == GRPC_SECURITY_ERROR) {
gpr_log(GPR_ERROR, "Peer check failed."); gpr_log(GPR_ERROR, "Peer check failed.");
secure_transport_setup_done(s, 0); 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_endpoint *nonsecure_endpoint,
grpc_secure_transport_setup_done_cb cb, grpc_secure_transport_setup_done_cb cb,
void *user_data) { void *user_data) {
@ -270,12 +270,12 @@ void grpc_setup_secure_transport(grpc_security_context *ctx,
grpc_secure_transport_setup *s = grpc_secure_transport_setup *s =
gpr_malloc(sizeof(grpc_secure_transport_setup)); gpr_malloc(sizeof(grpc_secure_transport_setup));
memset(s, 0, 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) { if (result != GRPC_SECURITY_OK) {
secure_transport_setup_done(s, 0); secure_transport_setup_done(s, 0);
return; 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_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
s->handshake_buffer = gpr_malloc(s->handshake_buffer_size); s->handshake_buffer = gpr_malloc(s->handshake_buffer_size);
s->endpoint = nonsecure_endpoint; s->endpoint = nonsecure_endpoint;

@ -35,7 +35,7 @@
#define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H #define GRPC_INTERNAL_CORE_SECURITY_SECURE_TRANSPORT_SETUP_H
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/security/security_context.h" #include "src/core/security/security_connector.h"
/* --- Secure transport setup --- */ /* --- Secure transport setup --- */
@ -45,7 +45,7 @@ typedef void (*grpc_secure_transport_setup_done_cb)(
grpc_endpoint *secure_endpoint); grpc_endpoint *secure_endpoint);
/* Calls the callback upon completion. */ /* 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_endpoint *nonsecure_endpoint,
grpc_secure_transport_setup_done_cb cb, grpc_secure_transport_setup_done_cb cb,
void *user_data); void *user_data);

@ -31,12 +31,10 @@
* *
*/ */
#include "src/core/security/security_context.h" #include "src/core/security/security_connector.h"
#include <string.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/credentials.h"
#include "src/core/security/secure_endpoint.h" #include "src/core/security/secure_endpoint.h"
#include "src/core/support/env.h" #include "src/core/support/env.h"
@ -56,7 +54,8 @@
#ifndef INSTALL_PREFIX #ifndef INSTALL_PREFIX
static const char *installed_roots_path = "/usr/share/grpc/roots.pem"; static const char *installed_roots_path = "/usr/share/grpc/roots.pem";
#else #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 #endif
/* -- Cipher suites. -- */ /* -- Cipher suites. -- */
@ -82,75 +81,77 @@ static const char *ssl_cipher_suites(void) {
/* -- Common methods. -- */ /* -- Common methods. -- */
grpc_security_status grpc_security_context_create_handshaker( grpc_security_status grpc_security_connector_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) { grpc_security_connector *sc, tsi_handshaker **handshaker) {
if (ctx == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR; if (sc == NULL || handshaker == NULL) return GRPC_SECURITY_ERROR;
return ctx->vtable->create_handshaker(ctx, handshaker); return sc->vtable->create_handshaker(sc, handshaker);
} }
grpc_security_status grpc_security_context_check_peer( grpc_security_status grpc_security_connector_check_peer(
grpc_security_context *ctx, tsi_peer peer, grpc_security_check_cb cb, grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb,
void *user_data) { void *user_data) {
if (ctx == NULL) { if (sc == NULL) {
tsi_peer_destruct(&peer); tsi_peer_destruct(&peer);
return GRPC_SECURITY_ERROR; 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_security_status grpc_channel_security_connector_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_security_check_cb cb, void *user_data) {
if (ctx == NULL || ctx->check_call_host == NULL) return GRPC_SECURITY_ERROR; if (sc == NULL || sc->check_call_host == NULL) return GRPC_SECURITY_ERROR;
return ctx->check_call_host(ctx, host, cb, user_data); return sc->check_call_host(sc, host, cb, user_data);
} }
void grpc_security_context_unref(grpc_security_context *ctx) { void grpc_security_connector_unref(grpc_security_connector *sc) {
if (ctx == NULL) return; if (sc == NULL) return;
if (gpr_unref(&ctx->refcount)) ctx->vtable->destroy(ctx); if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
} }
grpc_security_context *grpc_security_context_ref(grpc_security_context *ctx) { grpc_security_connector *grpc_security_connector_ref(
if (ctx == NULL) return NULL; grpc_security_connector *sc) {
gpr_ref(&ctx->refcount); if (sc == NULL) return NULL;
return ctx; gpr_ref(&sc->refcount);
return sc;
} }
static void context_pointer_arg_destroy(void *p) { static void connector_pointer_arg_destroy(void *p) {
grpc_security_context_unref(p); grpc_security_connector_unref(p);
} }
static void *context_pointer_arg_copy(void *p) { static void *connector_pointer_arg_copy(void *p) {
return grpc_security_context_ref(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; grpc_arg result;
result.type = GRPC_ARG_POINTER; result.type = GRPC_ARG_POINTER;
result.key = GRPC_SECURITY_CONTEXT_ARG; result.key = GRPC_SECURITY_CONNECTOR_ARG;
result.value.pointer.destroy = context_pointer_arg_destroy; result.value.pointer.destroy = connector_pointer_arg_destroy;
result.value.pointer.copy = context_pointer_arg_copy; result.value.pointer.copy = connector_pointer_arg_copy;
result.value.pointer.p = ctx; result.value.pointer.p = sc;
return result; return result;
} }
grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) { grpc_security_connector *grpc_security_connector_from_arg(const grpc_arg *arg) {
if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL; if (strcmp(arg->key, GRPC_SECURITY_CONNECTOR_ARG)) return NULL;
if (arg->type != GRPC_ARG_POINTER) { if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
GRPC_SECURITY_CONTEXT_ARG); GRPC_SECURITY_CONNECTOR_ARG);
return NULL; return NULL;
} }
return arg->value.pointer.p; 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) { const grpc_channel_args *args) {
size_t i; size_t i;
if (args == NULL) return NULL; if (args == NULL) return NULL;
for (i = 0; i < args->num_args; i++) { for (i = 0; i < args->num_args; i++) {
grpc_security_context *ctx = grpc_security_context_from_arg(&args->args[i]); grpc_security_connector *sc =
if (ctx != NULL) return ctx; grpc_security_connector_from_arg(&args->args[i]);
if (sc != NULL) return sc;
} }
return NULL; return NULL;
} }
@ -158,51 +159,41 @@ grpc_security_context *grpc_find_security_context_in_args(
static int check_request_metadata_creds(grpc_credentials *creds) { static int check_request_metadata_creds(grpc_credentials *creds) {
if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) { if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
"Incompatible credentials for channel security context: needs to " "Incompatible credentials for channel security connector: needs to "
"set request metadata."); "set request metadata.");
return 0; return 0;
} }
return 1; return 1;
} }
static grpc_mdctx *get_or_create_mdctx(grpc_credentials *creds) {
grpc_mdctx *mdctx = grpc_credentials_get_metadata_context(creds);
if (mdctx == NULL) {
mdctx = grpc_mdctx_create();
} else {
grpc_mdctx_ref(mdctx);
}
return mdctx;
}
/* -- Fake implementation. -- */ /* -- Fake implementation. -- */
typedef struct { typedef struct {
grpc_channel_security_context base; grpc_channel_security_connector base;
int call_host_check_is_async; 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) { static void fake_channel_destroy(grpc_security_connector *sc) {
grpc_channel_security_context *c = (grpc_channel_security_context *)ctx; grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
grpc_credentials_unref(c->request_metadata_creds); 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( 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); *handshaker = tsi_create_fake_handshaker(1);
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }
static grpc_security_status fake_server_create_handshaker( 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); *handshaker = tsi_create_fake_handshaker(0);
return GRPC_SECURITY_OK; 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, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
void *user_data) { void *user_data) {
@ -238,10 +229,10 @@ end:
} }
static grpc_security_status fake_channel_check_call_host( 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_security_check_cb cb, void *user_data) {
grpc_fake_channel_security_context *c = grpc_fake_channel_security_connector *c =
(grpc_fake_channel_security_context *)ctx; (grpc_fake_channel_security_connector *)sc;
if (c->call_host_check_is_async) { if (c->call_host_check_is_async) {
cb(user_data, GRPC_SECURITY_OK); cb(user_data, GRPC_SECURITY_OK);
return GRPC_SECURITY_PENDING; return GRPC_SECURITY_PENDING;
@ -250,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}; 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}; 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_credentials *request_metadata_creds, int call_host_check_is_async) {
grpc_fake_channel_security_context *c = grpc_fake_channel_security_connector *c =
gpr_malloc(sizeof(grpc_fake_channel_security_context)); gpr_malloc(sizeof(grpc_fake_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1; c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@ -271,8 +262,8 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create(
return &c->base; return &c->base;
} }
grpc_security_context *grpc_fake_server_security_context_create(void) { grpc_security_connector *grpc_fake_server_security_connector_create(void) {
grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context)); grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector));
gpr_ref_init(&c->refcount, 1); gpr_ref_init(&c->refcount, 1);
c->vtable = &fake_server_vtable; c->vtable = &fake_server_vtable;
c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
@ -282,21 +273,21 @@ grpc_security_context *grpc_fake_server_security_context_create(void) {
/* --- Ssl implementation. --- */ /* --- Ssl implementation. --- */
typedef struct { typedef struct {
grpc_channel_security_context base; grpc_channel_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory; tsi_ssl_handshaker_factory *handshaker_factory;
char *target_name; char *target_name;
char *overridden_target_name; char *overridden_target_name;
tsi_peer peer; tsi_peer peer;
} grpc_ssl_channel_security_context; } grpc_ssl_channel_security_connector;
typedef struct { typedef struct {
grpc_security_context base; grpc_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory; 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) { static void ssl_channel_destroy(grpc_security_connector *sc) {
grpc_ssl_channel_security_context *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_context *)ctx; (grpc_ssl_channel_security_connector *)sc;
grpc_credentials_unref(c->base.request_metadata_creds); grpc_credentials_unref(c->base.request_metadata_creds);
if (c->handshaker_factory != NULL) { if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
@ -304,15 +295,16 @@ static void ssl_channel_destroy(grpc_security_context *ctx) {
if (c->target_name != NULL) gpr_free(c->target_name); if (c->target_name != NULL) gpr_free(c->target_name);
if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
tsi_peer_destruct(&c->peer); tsi_peer_destruct(&c->peer);
gpr_free(ctx); gpr_free(sc);
} }
static void ssl_server_destroy(grpc_security_context *ctx) { static void ssl_server_destroy(grpc_security_connector *sc) {
grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx; grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
if (c->handshaker_factory != NULL) { if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
} }
gpr_free(ctx); gpr_free(sc);
} }
static grpc_security_status ssl_create_handshaker( static grpc_security_status ssl_create_handshaker(
@ -331,9 +323,9 @@ static grpc_security_status ssl_create_handshaker(
} }
static grpc_security_status ssl_channel_create_handshaker( static grpc_security_status ssl_channel_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) { grpc_security_connector *sc, tsi_handshaker **handshaker) {
grpc_ssl_channel_security_context *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_context *)ctx; (grpc_ssl_channel_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 1, return ssl_create_handshaker(c->handshaker_factory, 1,
c->overridden_target_name != NULL c->overridden_target_name != NULL
? c->overridden_target_name ? c->overridden_target_name
@ -342,13 +334,13 @@ static grpc_security_status ssl_channel_create_handshaker(
} }
static grpc_security_status ssl_server_create_handshaker( static grpc_security_status ssl_server_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) { grpc_security_connector *sc, tsi_handshaker **handshaker) {
grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx; grpc_ssl_server_security_connector *c =
(grpc_ssl_server_security_connector *)sc;
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker); return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
} }
static int ssl_host_matches_name(const tsi_peer *peer, static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
const char *peer_name) {
char *allocated_name = NULL; char *allocated_name = NULL;
int r; int r;
@ -359,7 +351,6 @@ static int ssl_host_matches_name(const tsi_peer *peer,
peer_name = allocated_name; peer_name = allocated_name;
if (!peer_name) return 0; if (!peer_name) return 0;
} }
r = tsi_ssl_peer_matches_name(peer, peer_name); r = tsi_ssl_peer_matches_name(peer, peer_name);
gpr_free(allocated_name); gpr_free(allocated_name);
return r; return r;
@ -385,8 +376,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
} }
/* Check the peer name if specified. */ /* Check the peer name if specified. */
if (peer_name != NULL && if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) {
!ssl_host_matches_name(peer, peer_name)) {
gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name);
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
@ -394,12 +384,12 @@ static grpc_security_status ssl_check_peer(const char *peer_name,
return GRPC_SECURITY_OK; 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, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
void *user_data) { void *user_data) {
grpc_ssl_channel_security_context *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_context *)ctx; (grpc_ssl_channel_security_connector *)sc;
grpc_security_status status; grpc_security_status status;
tsi_peer_destruct(&c->peer); tsi_peer_destruct(&c->peer);
c->peer = peer; c->peer = peer;
@ -410,7 +400,7 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_context *ctx,
return status; 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, tsi_peer peer,
grpc_security_check_cb cb, grpc_security_check_cb cb,
void *user_data) { void *user_data) {
@ -421,10 +411,10 @@ static grpc_security_status ssl_server_check_peer(grpc_security_context *ctx,
} }
static grpc_security_status ssl_channel_check_call_host( 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_security_check_cb cb, void *user_data) {
grpc_ssl_channel_security_context *c = grpc_ssl_channel_security_connector *c =
(grpc_ssl_channel_security_context *)ctx; (grpc_ssl_channel_security_connector *)sc;
if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK; if (ssl_host_matches_name(&c->peer, host)) return GRPC_SECURITY_OK;
@ -438,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}; 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}; ssl_server_destroy, ssl_server_create_handshaker, ssl_server_check_peer};
static gpr_slice default_pem_root_certs; static gpr_slice default_pem_root_certs;
@ -453,13 +443,13 @@ static void init_default_pem_root_certs(void) {
if (default_root_certs_path == NULL) { if (default_root_certs_path == NULL) {
default_pem_root_certs = gpr_empty_slice(); default_pem_root_certs = gpr_empty_slice();
} else { } 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); gpr_free(default_root_certs_path);
} }
/* Fall back to installed certs if needed. */ /* Fall back to installed certs if needed. */
if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) { 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);
} }
} }
@ -472,17 +462,17 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
return GPR_SLICE_LENGTH(default_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, grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
const char *target_name, const char *overridden_target_name, 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(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings = const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols); gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths = unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
grpc_ssl_channel_security_context *c; grpc_ssl_channel_security_connector *c;
size_t i; size_t i;
const unsigned char *pem_root_certs; const unsigned char *pem_root_certs;
size_t pem_root_certs_size; size_t pem_root_certs_size;
@ -503,8 +493,8 @@ grpc_security_status grpc_ssl_channel_security_context_create(
goto error; goto error;
} }
c = gpr_malloc(sizeof(grpc_ssl_channel_security_context)); c = gpr_malloc(sizeof(grpc_ssl_channel_security_connector));
memset(c, 0, sizeof(grpc_ssl_channel_security_context)); memset(c, 0, sizeof(grpc_ssl_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable; c->base.base.vtable = &ssl_channel_vtable;
@ -536,10 +526,10 @@ grpc_security_status grpc_ssl_channel_security_context_create(
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
ssl_channel_destroy(&c->base.base); ssl_channel_destroy(&c->base.base);
*ctx = NULL; *sc = NULL;
goto error; goto error;
} }
*ctx = &c->base; *sc = &c->base;
gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths); gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
@ -550,15 +540,15 @@ error:
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
grpc_security_status grpc_ssl_server_security_context_create( grpc_security_status grpc_ssl_server_security_connector_create(
const grpc_ssl_server_config *config, grpc_security_context **ctx) { const grpc_ssl_server_config *config, grpc_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings = const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols); gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths = unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols); gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
grpc_ssl_server_security_context *c; grpc_ssl_server_security_connector *c;
size_t i; size_t i;
for (i = 0; i < num_alpn_protocols; i++) { for (i = 0; i < num_alpn_protocols; i++) {
@ -572,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."); gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
goto error; goto error;
} }
c = gpr_malloc(sizeof(grpc_ssl_server_security_context)); c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
memset(c, 0, sizeof(grpc_ssl_server_security_context)); memset(c, 0, sizeof(grpc_ssl_server_security_connector));
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.refcount, 1);
c->base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.url_scheme = GRPC_SSL_URL_SCHEME;
@ -583,17 +573,17 @@ grpc_security_status grpc_ssl_server_security_context_create(
config->pem_private_keys_sizes, config->pem_private_keys_sizes,
(const unsigned char **)config->pem_cert_chains, (const unsigned char **)config->pem_cert_chains,
config->pem_cert_chains_sizes, config->num_key_cert_pairs, config->pem_cert_chains_sizes, config->num_key_cert_pairs,
config->pem_root_certs, config->pem_root_certs_size, config->pem_root_certs, config->pem_root_certs_size, ssl_cipher_suites(),
ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols,
alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory); &c->handshaker_factory);
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
ssl_server_destroy(&c->base); ssl_server_destroy(&c->base);
*ctx = NULL; *sc = NULL;
goto error; goto error;
} }
*ctx = &c->base; *sc = &c->base;
gpr_free(alpn_protocol_strings); gpr_free(alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths); gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
@ -604,84 +594,3 @@ error:
return GRPC_SECURITY_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, get_or_create_mdctx(request_metadata_creds));
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, get_or_create_mdctx(request_metadata_creds));
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();
}

@ -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 */

@ -1,214 +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, grpc_mdctx *mdctx);
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 context creation. */
grpc_security_status grpc_server_security_context_create(
grpc_server_credentials *creds, grpc_security_context **ctx);
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */

@ -40,7 +40,8 @@
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_server.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/security/secure_transport_setup.h"
#include "src/core/surface/server.h" #include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h" #include "src/core/transport/chttp2_transport.h"
@ -52,7 +53,7 @@
typedef struct grpc_server_secure_state { typedef struct grpc_server_secure_state {
grpc_server *server; grpc_server *server;
grpc_tcp_server *tcp; grpc_tcp_server *tcp;
grpc_security_context *ctx; grpc_security_connector *sc;
int is_shutdown; int is_shutdown;
gpr_mu mu; gpr_mu mu;
gpr_refcount refcount; gpr_refcount refcount;
@ -64,7 +65,7 @@ static void state_ref(grpc_server_secure_state *state) {
static void state_unref(grpc_server_secure_state *state) { static void state_unref(grpc_server_secure_state *state) {
if (gpr_unref(&state->refcount)) { if (gpr_unref(&state->refcount)) {
grpc_security_context_unref(state->ctx); grpc_security_connector_unref(state->sc);
gpr_free(state); gpr_free(state);
} }
} }
@ -104,7 +105,7 @@ static void on_secure_transport_setup_done(void *statep,
static void on_accept(void *statep, grpc_endpoint *tcp) { static void on_accept(void *statep, grpc_endpoint *tcp) {
grpc_server_secure_state *state = statep; grpc_server_secure_state *state = statep;
state_ref(state); state_ref(state);
grpc_setup_secure_transport(state->ctx, tcp, on_secure_transport_setup_done, grpc_setup_secure_transport(state->sc, tcp, on_secure_transport_setup_done,
state); state);
} }
@ -137,11 +138,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
int port_num = -1; int port_num = -1;
int port_temp; int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_status status = GRPC_SECURITY_ERROR;
grpc_security_context *ctx = NULL; grpc_security_connector *sc = NULL;
/* create security context */ /* create security context */
if (creds == NULL) goto error; if (creds == NULL) goto error;
status = grpc_server_security_context_create(creds, &ctx); status = grpc_server_credentials_create_security_connector(creds, &sc);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
"Unable to create secure server with credentials of type %s.", "Unable to create secure server with credentials of type %s.",
@ -188,7 +189,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
state = gpr_malloc(sizeof(*state)); state = gpr_malloc(sizeof(*state));
state->server = server; state->server = server;
state->tcp = tcp; state->tcp = tcp;
state->ctx = ctx; state->sc = sc;
state->is_shutdown = 0; state->is_shutdown = 0;
gpr_mu_init(&state->mu); gpr_mu_init(&state->mu);
gpr_ref_init(&state->refcount, 1); gpr_ref_init(&state->refcount, 1);
@ -200,8 +201,8 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
/* Error path: cleanup and return */ /* Error path: cleanup and return */
error: error:
if (ctx) { if (sc) {
grpc_security_context_unref(ctx); grpc_security_connector_unref(sc);
} }
if (resolved) { if (resolved) {
grpc_resolved_addresses_destroy(resolved); grpc_resolved_addresses_destroy(resolved);

@ -41,13 +41,14 @@
#include "src/core/support/string.h" #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; unsigned char *contents = NULL;
size_t contents_size = 0; size_t contents_size = 0;
unsigned char buf[4096];
char *error_msg = NULL; char *error_msg = NULL;
gpr_slice result = gpr_empty_slice(); gpr_slice result = gpr_empty_slice();
FILE *file = fopen(filename, "rb"); FILE *file = fopen(filename, "rb");
size_t bytes_read = 0;
if (file == NULL) { if (file == NULL) {
gpr_asprintf(&error_msg, "Could not open file %s (error = %s).", filename, 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); GPR_ASSERT(error_msg != NULL);
goto end; goto end;
} }
fseek(file, 0, SEEK_END);
while (1) { contents_size = ftell(file);
size_t bytes_read = fread(buf, 1, sizeof(buf), file); fseek(file, 0, SEEK_SET);
if (bytes_read > 0) { contents = gpr_malloc(contents_size + (add_null_terminator ? 1 : 0));
contents = gpr_realloc(contents, contents_size + bytes_read); bytes_read = fread(contents, 1, contents_size, file);
memcpy(contents + contents_size, buf, bytes_read); if (bytes_read < contents_size) {
contents_size += bytes_read; GPR_ASSERT(ferror(file));
} gpr_asprintf(&error_msg, "Error %s occured while reading file %s.",
if (bytes_read < sizeof(buf)) { strerror(errno), filename);
if (ferror(file)) { GPR_ASSERT(error_msg != NULL);
gpr_asprintf(&error_msg, "Error %s occured while reading file %s.", goto end;
strerror(errno), filename);
GPR_ASSERT(error_msg != NULL);
goto end;
} else {
GPR_ASSERT(feof(file));
break;
}
}
} }
if (success != NULL) *success = 1; if (success != NULL) *success = 1;
if (add_null_terminator) {
contents[contents_size++] = 0;
}
result = gpr_slice_new(contents, contents_size, gpr_free); result = gpr_slice_new(contents, contents_size, gpr_free);
end: end:

@ -44,9 +44,11 @@ extern "C" {
/* File utility functions */ /* 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. */ 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. /* Creates a temporary file from a prefix.
If tmp_filename is not NULL, *tmp_filename is assigned the name of the If tmp_filename is not NULL, *tmp_filename is assigned the name of the

@ -43,6 +43,12 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.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 { struct grpc_channel {
int is_client; int is_client;
gpr_refcount refs; gpr_refcount refs;
@ -51,10 +57,14 @@ struct grpc_channel {
grpc_mdstr *grpc_message_string; grpc_mdstr *grpc_message_string;
grpc_mdstr *path_string; grpc_mdstr *path_string;
grpc_mdstr *authority_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_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
#define CHANNEL_FROM_CHANNEL_STACK(channel_stack) (((grpc_channel *)(channel_stack)) - 1) #define CHANNEL_FROM_CHANNEL_STACK(channel_stack) \
(((grpc_channel *)(channel_stack)) - 1)
#define CHANNEL_FROM_TOP_ELEM(top_elem) \ #define CHANNEL_FROM_TOP_ELEM(top_elem) \
CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem)) CHANNEL_FROM_CHANNEL_STACK(grpc_channel_stack_from_top_element(top_elem))
@ -66,7 +76,8 @@ grpc_channel *grpc_channel_create_from_filters(
grpc_channel *channel = gpr_malloc(size); grpc_channel *channel = gpr_malloc(size);
GPR_ASSERT(grpc_is_initialized() && "call grpc_init()"); GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
channel->is_client = is_client; 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); gpr_ref_init(&channel->refs, 1 + is_client);
channel->metadata_context = mdctx; channel->metadata_context = mdctx;
channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status"); channel->grpc_status_string = grpc_mdstr_from_string(mdctx, "grpc-status");
@ -75,18 +86,17 @@ grpc_channel *grpc_channel_create_from_filters(
channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority"); channel->authority_string = grpc_mdstr_from_string(mdctx, ":authority");
grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context, grpc_channel_stack_init(filters, num_filters, args, channel->metadata_context,
CHANNEL_STACK_FROM_CHANNEL(channel)); CHANNEL_STACK_FROM_CHANNEL(channel));
gpr_mu_init(&channel->registered_call_mu);
channel->registered_calls = NULL;
return channel; return channel;
} }
static void do_nothing(void *ignored, grpc_op_error error) {} static void do_nothing(void *ignored, grpc_op_error error) {}
grpc_call *grpc_channel_create_call(grpc_channel *channel, static grpc_call *grpc_channel_create_call_internal(
grpc_completion_queue *cq, grpc_channel *channel, grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
const char *method, const char *host, grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
gpr_timespec absolute_deadline) {
grpc_call *call; grpc_call *call;
grpc_mdelem *path_mdelem;
grpc_mdelem *authority_mdelem;
grpc_call_op op; grpc_call_op op;
if (!channel->is_client) { if (!channel->is_client) {
@ -97,11 +107,6 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
call = grpc_call_create(channel, cq, NULL); call = grpc_call_create(channel, cq, NULL);
/* Add :path and :authority headers. */ /* 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.type = GRPC_SEND_METADATA;
op.dir = GRPC_CALL_DOWN; op.dir = GRPC_CALL_DOWN;
op.flags = 0; op.flags = 0;
@ -110,18 +115,14 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
op.user_data = NULL; op.user_data = NULL;
grpc_call_execute_op(call, &op); 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; op.data.metadata = authority_mdelem;
grpc_call_execute_op(call, &op); grpc_call_execute_op(call, &op);
if (0 != gpr_time_cmp(absolute_deadline, gpr_inf_future)) { if (0 != gpr_time_cmp(deadline, gpr_inf_future)) {
op.type = GRPC_SEND_DEADLINE; op.type = GRPC_SEND_DEADLINE;
op.dir = GRPC_CALL_DOWN; op.dir = GRPC_CALL_DOWN;
op.flags = 0; op.flags = 0;
op.data.deadline = absolute_deadline; op.data.deadline = deadline;
op.done_cb = do_nothing; op.done_cb = do_nothing;
op.user_data = NULL; op.user_data = NULL;
grpc_call_execute_op(call, &op); grpc_call_execute_op(call, &op);
@ -130,6 +131,21 @@ grpc_call *grpc_channel_create_call(grpc_channel *channel,
return call; return call;
} }
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);
}
grpc_call *grpc_channel_create_call_old(grpc_channel *channel, grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
const char *method, const char *host, const char *method, const char *host,
gpr_timespec absolute_deadline) { gpr_timespec absolute_deadline) {
@ -137,6 +153,31 @@ grpc_call *grpc_channel_create_call_old(grpc_channel *channel,
absolute_deadline); absolute_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) { void grpc_channel_internal_ref(grpc_channel *channel) {
gpr_ref(&channel->refs); gpr_ref(&channel->refs);
} }
@ -148,7 +189,15 @@ static void destroy_channel(void *p, int ok) {
grpc_mdstr_unref(channel->grpc_message_string); grpc_mdstr_unref(channel->grpc_message_string);
grpc_mdstr_unref(channel->path_string); grpc_mdstr_unref(channel->path_string);
grpc_mdstr_unref(channel->authority_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); grpc_mdctx_unref(channel->metadata_context);
gpr_mu_destroy(&channel->registered_call_mu);
gpr_free(channel); gpr_free(channel);
} }

@ -61,8 +61,8 @@ void grpc_init(void) {
grpc_register_tracer("http", &grpc_http_trace); grpc_register_tracer("http", &grpc_http_trace);
grpc_register_tracer("batch", &grpc_trace_batch); grpc_register_tracer("batch", &grpc_trace_batch);
grpc_security_pre_init(); grpc_security_pre_init();
grpc_tracer_init("GRPC_TRACE");
grpc_iomgr_init(); grpc_iomgr_init();
grpc_tracer_init("GRPC_TRACE");
census_init(); census_init();
grpc_timers_log_global_init(); grpc_timers_log_global_init();
} }

@ -48,7 +48,7 @@
#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_client.h"
#include "src/core/security/auth.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/security/secure_transport_setup.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/surface/channel.h" #include "src/core/surface/channel.h"
@ -74,7 +74,7 @@ typedef struct {
} request; } request;
struct setup { struct setup {
grpc_channel_security_context *security_context; grpc_channel_security_connector *security_connector;
const char *target; const char *target;
grpc_transport_setup_callback setup_callback; grpc_transport_setup_callback setup_callback;
void *setup_user_data; void *setup_user_data;
@ -130,7 +130,7 @@ static void on_connect(void *rp, grpc_endpoint *tcp) {
return; return;
} }
} else { } 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); on_secure_transport_setup_done, r);
} }
} }
@ -185,7 +185,7 @@ static void initiate_setup(void *sp, grpc_client_setup_request *cs_request) {
static void done_setup(void *sp) { static void done_setup(void *sp) {
setup *s = sp; setup *s = sp;
gpr_free((void *)s->target); gpr_free((void *)s->target);
grpc_security_context_unref(&s->security_context->base); grpc_security_connector_unref(&s->security_connector->base);
gpr_free(s); gpr_free(s);
} }
@ -203,23 +203,37 @@ static grpc_transport_setup_result complete_setup(void *channel_stack,
Asynchronously: - resolve target Asynchronously: - resolve target
- connect to it (trying alternatives as presented) - connect to it (trying alternatives as presented)
- perform handshakes */ - perform handshakes */
grpc_channel *grpc_secure_channel_create_internal( grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
const char *target, const grpc_channel_args *args, const char *target,
grpc_channel_security_context *context, grpc_mdctx *mdctx) { const grpc_channel_args *args) {
setup *s; setup *s;
grpc_channel *channel; grpc_channel *channel;
grpc_arg context_arg; grpc_arg connector_arg;
grpc_channel_args *args_copy; grpc_channel_args *args_copy;
grpc_channel_args *new_args_from_connector;
grpc_channel_security_connector* connector;
grpc_mdctx *mdctx;
#define MAX_FILTERS 3 #define MAX_FILTERS 3
const grpc_channel_filter *filters[MAX_FILTERS]; const grpc_channel_filter *filters[MAX_FILTERS];
int n = 0; 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."); 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)); s = gpr_malloc(sizeof(setup));
context_arg = grpc_security_context_to_arg(&context->base); connector_arg = grpc_security_connector_to_arg(&connector->base);
args_copy = grpc_channel_args_copy_and_add(args, &context_arg); 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; filters[n++] = &grpc_client_surface_filter;
if (grpc_channel_args_is_census_enabled(args)) { if (grpc_channel_args_is_census_enabled(args)) {
filters[n++] = &grpc_client_census_filter; filters[n++] = &grpc_client_census_filter;
@ -228,13 +242,14 @@ grpc_channel *grpc_secure_channel_create_internal(
GPR_ASSERT(n <= MAX_FILTERS); GPR_ASSERT(n <= MAX_FILTERS);
channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1); channel = grpc_channel_create_from_filters(filters, n, args_copy, mdctx, 1);
grpc_channel_args_destroy(args_copy); 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->target = gpr_strdup(target);
s->setup_callback = complete_setup; s->setup_callback = complete_setup;
s->setup_user_data = grpc_channel_get_channel_stack(channel); s->setup_user_data = grpc_channel_get_channel_stack(channel);
s->security_context = s->security_connector = connector;
(grpc_channel_security_context *)grpc_security_context_ref(
&context->base);
grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel), grpc_client_setup_create_and_attach(grpc_channel_get_channel_stack(channel),
args, mdctx, initiate_setup, done_setup, args, mdctx, initiate_setup, done_setup,
s); s);

@ -54,6 +54,7 @@ typedef struct {
gpr_uint8 process_ping_reply; gpr_uint8 process_ping_reply;
gpr_uint8 goaway; gpr_uint8 goaway;
gpr_int64 initial_window_update;
gpr_uint32 window_update; gpr_uint32 window_update;
gpr_uint32 goaway_last_stream_index; gpr_uint32 goaway_last_stream_index;
gpr_uint32 goaway_error; gpr_uint32 goaway_error;

@ -218,6 +218,14 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
return GRPC_CHTTP2_CONNECTION_ERROR; 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; parser->incoming_settings[parser->id] = parser->value;
if (grpc_http_trace) { if (grpc_http_trace) {
gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id, gpr_log(GPR_DEBUG, "CHTTP2: got setting %d = %d", parser->id,

@ -276,8 +276,8 @@ struct transport {
struct stream { struct stream {
gpr_uint32 id; gpr_uint32 id;
gpr_uint32 outgoing_window;
gpr_uint32 incoming_window; gpr_uint32 incoming_window;
gpr_int64 outgoing_window;
/* when the application requests writes be closed, the write_closed is /* when the application requests writes be closed, the write_closed is
'queued'; when the close is flow controlled into the send path, we are 'queued'; when the close is flow controlled into the send path, we are
'sending' it; when the write has been performed it is 'sent' */ 'sending' it; when the write has been performed it is 'sent' */
@ -852,7 +852,8 @@ static int prepare_write(transport *t) {
/* for each stream that's become writable, frame it's data (according to /* for each stream that's become writable, frame it's data (according to
available window sizes) and add to the output buffer */ 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( 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); GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
@ -867,7 +868,7 @@ static int prepare_write(transport *t) {
/* if there are still writes to do and the stream still has window /* if there are still writes to do and the stream still has window
available, then schedule a further write */ available, then schedule a further write */
if (s->outgoing_sopb.nops && s->outgoing_window) { if (s->outgoing_sopb.nops > 0 && s->outgoing_window > 0) {
GPR_ASSERT(!t->outgoing_window); GPR_ASSERT(!t->outgoing_window);
stream_list_add_tail(t, s, WRITABLE); stream_list_add_tail(t, s, WRITABLE);
} }
@ -1430,8 +1431,8 @@ static int init_frame_parser(transport *t) {
} }
} }
static int is_window_update_legal(gpr_uint32 window_update, gpr_uint32 window) { static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
return window_update < MAX_WINDOW - window; return window + window_update < MAX_WINDOW;
} }
static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) { static int parse_frame_slice(transport *t, gpr_slice slice, int is_last) {
@ -1485,12 +1486,23 @@ 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.nops > 0) {
stream_list_join(t, s, WRITABLE);
}
}
}
if (st.window_update) { if (st.window_update) {
if (t->incoming_stream_id) { if (t->incoming_stream_id) {
/* if there was a stream id, this is for some stream */ /* if there was a stream id, this is for some stream */
stream *s = lookup_stream(t, t->incoming_stream_id); stream *s = lookup_stream(t, t->incoming_stream_id);
if (s) { 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)) { if (!is_window_update_legal(st.window_update, s->outgoing_window)) {
cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status( cancel_stream(t, s, grpc_chttp2_http2_error_to_grpc_status(
GRPC_CHTTP2_FLOW_CONTROL_ERROR), GRPC_CHTTP2_FLOW_CONTROL_ERROR),

@ -41,6 +41,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h" #include "src/cpp/proto/proto_utils.h"
#include <grpc++/channel_arguments.h> #include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
@ -60,11 +61,17 @@ Channel::~Channel() { grpc_channel_destroy(c_channel_); }
Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) { CompletionQueue* cq) {
auto c_call = grpc_channel_create_call(c_channel_, cq->cq(), method.name(), auto c_call =
context->authority().empty() method.channel_tag()
? target_.c_str() ? grpc_channel_create_registered_call(c_channel_, cq->cq(),
: context->authority().c_str(), method.channel_tag(),
context->RawDeadline()); context->RawDeadline())
: grpc_channel_create_call(c_channel_, cq->cq(), method.name(),
context->authority().empty()
? target_.c_str()
: context->authority().c_str(),
context->RawDeadline());
GRPC_TIMER_MARK(CALL_CREATED, c_call);
context->set_call(c_call); context->set_call(c_call);
return Call(c_call, this, cq); return Call(c_call, this, cq);
} }
@ -73,9 +80,15 @@ void Channel::PerformOpsOnCall(CallOpBuffer* buf, Call* call) {
static const size_t MAX_OPS = 8; static const size_t MAX_OPS = 8;
size_t nops = MAX_OPS; size_t nops = MAX_OPS;
grpc_op ops[MAX_OPS]; grpc_op ops[MAX_OPS];
GRPC_TIMER_MARK(PERFORM_OPS_BEGIN, call->call());
buf->FillOps(ops, &nops); buf->FillOps(ops, &nops);
GPR_ASSERT(GRPC_CALL_OK == GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_batch(call->call(), ops, nops, buf)); 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 } // namespace grpc

@ -54,6 +54,7 @@ class Channel GRPC_FINAL : public ChannelInterface {
Channel(const grpc::string& target, grpc_channel* c_channel); Channel(const grpc::string& target, grpc_channel* c_channel);
~Channel() GRPC_OVERRIDE; ~Channel() GRPC_OVERRIDE;
virtual void *RegisterMethod(const char *method) GRPC_OVERRIDE;
virtual Call CreateCall(const RpcMethod& method, ClientContext* context, virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) GRPC_OVERRIDE; CompletionQueue* cq) GRPC_OVERRIDE;
virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE; virtual void PerformOpsOnCall(CallOpBuffer* ops, Call* call) GRPC_OVERRIDE;

@ -39,13 +39,13 @@ namespace grpc {
// begin a call to a named method // begin a call to a named method
std::unique_ptr<GenericClientAsyncReaderWriter> GenericStub::Call( std::unique_ptr<GenericClientAsyncReaderWriter> GenericStub::Call(
ClientContext* context, const grpc::string& method, ClientContext* context, const grpc::string& method, CompletionQueue* cq,
CompletionQueue* cq, void* tag) { void* tag) {
return std::unique_ptr<GenericClientAsyncReaderWriter>( return std::unique_ptr<GenericClientAsyncReaderWriter>(
new GenericClientAsyncReaderWriter( new GenericClientAsyncReaderWriter(
channel_.get(), cq, RpcMethod(method.c_str()), context, tag)); channel_.get(), cq,
RpcMethod(method.c_str(), RpcMethod::BIDI_STREAMING, nullptr),
context, tag));
} }
} // namespace grpc
} // namespace grpc

@ -38,6 +38,7 @@
#include <grpc++/client_context.h> #include <grpc++/client_context.h>
#include <grpc++/channel_interface.h> #include <grpc++/channel_interface.h>
#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h" #include "src/cpp/proto/proto_utils.h"
namespace grpc { namespace grpc {
@ -231,11 +232,13 @@ void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) {
} }
if (send_message_ || send_message_buffer_) { if (send_message_ || send_message_buffer_) {
if (send_message_) { if (send_message_) {
GRPC_TIMER_MARK(SER_PROTO_BEGIN, 0);
bool success = SerializeProto(*send_message_, &send_buf_); bool success = SerializeProto(*send_message_, &send_buf_);
if (!success) { if (!success) {
abort(); abort();
// TODO handle parse failure // TODO handle parse failure
} }
GRPC_TIMER_MARK(SER_PROTO_END, 0);
} else { } else {
send_buf_ = send_message_buffer_->buffer(); send_buf_ = send_message_buffer_->buffer();
} }
@ -307,8 +310,10 @@ bool CallOpBuffer::FinalizeResult(void** tag, bool* status) {
if (recv_buf_) { if (recv_buf_) {
got_message = *status; got_message = *status;
if (recv_message_) { if (recv_message_) {
GRPC_TIMER_MARK(DESER_PROTO_BEGIN, 0);
*status = *status && DeserializeProto(recv_buf_, recv_message_); *status = *status && DeserializeProto(recv_buf_, recv_message_);
grpc_byte_buffer_destroy(recv_buf_); grpc_byte_buffer_destroy(recv_buf_);
GRPC_TIMER_MARK(DESER_PROTO_END, 0);
} else { } else {
recv_message_buffer_->set_buffer(recv_buf_); recv_message_buffer_->set_buffer(recv_buf_);
} }

@ -68,9 +68,11 @@ bool AsyncServerContext::StartRead(grpc::protobuf::Message* request) {
bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response, bool AsyncServerContext::StartWrite(const grpc::protobuf::Message& response,
int flags) { int flags) {
grpc_byte_buffer* buffer = nullptr; grpc_byte_buffer* buffer = nullptr;
GRPC_TIMER_MARK(SER_PROTO_BEGIN, call_->call());
if (!SerializeProto(response, &buffer)) { if (!SerializeProto(response, &buffer)) {
return false; return false;
} }
GRPC_TIMER_MARK(SER_PROTO_END, call_->call());
grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags); grpc_call_error err = grpc_call_start_write_old(call_, buffer, this, flags);
grpc_byte_buffer_destroy(buffer); grpc_byte_buffer_destroy(buffer);
return err == GRPC_CALL_OK; return err == GRPC_CALL_OK;
@ -87,7 +89,9 @@ bool AsyncServerContext::StartWriteStatus(const Status& status) {
bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) { bool AsyncServerContext::ParseRead(grpc_byte_buffer* read_buffer) {
GPR_ASSERT(request_); GPR_ASSERT(request_);
GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_->call());
bool success = DeserializeProto(read_buffer, request_); bool success = DeserializeProto(read_buffer, request_);
GRPC_TIMER_MARK(DESER_PROTO_END, call_->call());
request_ = nullptr; request_ = nullptr;
return success; return success;
} }

@ -46,6 +46,7 @@
#include <grpc++/server_credentials.h> #include <grpc++/server_credentials.h>
#include <grpc++/thread_pool_interface.h> #include <grpc++/thread_pool_interface.h>
#include "src/core/profiling/timers.h"
#include "src/cpp/proto/proto_utils.h" #include "src/cpp/proto/proto_utils.h"
#include "src/cpp/util/time.h" #include "src/cpp/util/time.h"
@ -123,10 +124,12 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
std::unique_ptr<grpc::protobuf::Message> req; std::unique_ptr<grpc::protobuf::Message> req;
std::unique_ptr<grpc::protobuf::Message> res; std::unique_ptr<grpc::protobuf::Message> res;
if (has_request_payload_) { if (has_request_payload_) {
GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_.call());
req.reset(method_->AllocateRequestProto()); req.reset(method_->AllocateRequestProto());
if (!DeserializeProto(request_payload_, req.get())) { if (!DeserializeProto(request_payload_, req.get())) {
abort(); // for now abort(); // for now
} }
GRPC_TIMER_MARK(DESER_PROTO_END, call_.call());
} }
if (has_response_payload_) { if (has_response_payload_) {
res.reset(method_->AllocateResponseProto()); res.reset(method_->AllocateResponseProto());
@ -340,7 +343,9 @@ class Server::AsyncRequest GRPC_FINAL : public CompletionQueueTag {
bool orig_status = *status; bool orig_status = *status;
if (*status && request_) { if (*status && request_) {
if (payload_) { if (payload_) {
GRPC_TIMER_MARK(DESER_PROTO_BEGIN, call_);
*status = DeserializeProto(payload_, request_); *status = DeserializeProto(payload_, request_);
GRPC_TIMER_MARK(DESER_PROTO_END, call_);
} else { } else {
*status = false; *status = false;
} }

@ -60,7 +60,6 @@ void ByteBuffer::Dump(std::vector<Slice>* slices) {
gpr_slice s; gpr_slice s;
while (grpc_byte_buffer_reader_next(reader, &s)) { while (grpc_byte_buffer_reader_next(reader, &s)) {
slices->push_back(Slice(s, Slice::STEAL_REF)); slices->push_back(Slice(s, Slice::STEAL_REF));
gpr_slice_unref(s);
} }
grpc_byte_buffer_reader_destroy(reader); grpc_byte_buffer_reader_destroy(reader);
} }

@ -1,2 +1,3 @@
bin bin
obj obj
*.nupkg

@ -1,5 +1,7 @@
<?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"> <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> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@ -10,6 +12,7 @@
<RootNamespace>Grpc.Core</RootNamespace> <RootNamespace>Grpc.Core</RootNamespace>
<AssemblyName>Grpc.Core</AssemblyName> <AssemblyName>Grpc.Core</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<NuGetPackageImportStamp>8bb563fb</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -31,8 +34,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Collections.Immutable"> <Reference Include="System.Collections.Immutable, Version=1.0.34.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -92,7 +96,7 @@
ignored, which gives us the desired effect. --> ignored, which gives us the desired effect. -->
<When Condition=" '$(OS)' != 'Unix' "> <When Condition=" '$(OS)' != 'Unix' ">
<ItemGroup> <ItemGroup>
<Content Include="..\..\..\vsprojects\vs2013\Debug\grpc_csharp_ext.dll"> <Content Include="..\..\..\vsprojects\Debug\grpc_csharp_ext.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
@ -100,7 +104,16 @@
<Otherwise /> <Otherwise />
</Choose> </Choose>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup />
<Folder Include="Stub\" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
</ItemGroup> <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> </Project>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<package > <package>
<metadata> <metadata>
<id>Grpc.Core</id> <id>Grpc.Core</id>
<title>gRPC Core</title> <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. <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. This is an experimental release, not ready to use.
</description> </description>
<version>0.2.0</version> <version>0.2.1</version>
<authors>Google Inc.</authors> <authors>Google Inc.</authors>
<owners>jtattermusch</owners> <owners>jtattermusch</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl> <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
@ -16,6 +16,10 @@
<releaseNotes>The first experimental release. Not ready to use.</releaseNotes> <releaseNotes>The first experimental release. Not ready to use.</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright> <copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags> <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> </metadata>
<files> <files>
<file src="bin/Release/Grpc.Core.dll" target="lib/net45" /> <file src="bin/Release/Grpc.Core.dll" target="lib/net45" />

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <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> </packages>

@ -46,7 +46,7 @@ namespace math
Server server = new Server(); Server server = new Server();
server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl()));
int port = server.AddListeningPort(host + ":0"); int port = server.AddListeningPort(host + ":23456");
server.Start(); server.Start();
Console.WriteLine("MathServer listening on port " + port); Console.WriteLine("MathServer listening on port " + port);

@ -39,8 +39,9 @@
<Reference Include="Google.ProtocolBuffers"> <Reference Include="Google.ProtocolBuffers">
<HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath> <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Collections.Immutable"> <Reference Include="System.Collections.Immutable, Version=1.0.34.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" /> <package id="Google.ProtocolBuffers" version="2.4.1.521" targetFramework="net45" />
<package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" /> <package id="NUnit" version="2.6.4" targetFramework="net45" />
<package id="System.Collections.Immutable" version="1.1.34-rc" targetFramework="net45" />
</packages> </packages>

@ -1,44 +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.
syntax = "proto2";
package proto2;
// 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) { };
// };
//
message Empty {}

@ -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;
}

@ -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);
}

@ -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;

@ -67,10 +67,25 @@ function loadObject(value) {
/** /**
* Load a gRPC object from a .proto file. * Load a gRPC object from a .proto file.
* @param {string} filename The file to load * @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 * @return {Object<string, *>} The resulting gRPC object
*/ */
function load(filename) { function load(filename, format) {
var builder = ProtoBuf.loadProtoFile(filename); 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); return loadObject(builder.ns);
} }

@ -47,6 +47,28 @@ var mathService = math_proto.lookup('math.Math');
var capitalize = require('underscore.string/capitalize'); 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() { describe('Surface server constructor', function() {
it('Should fail with conflicting method names', function() { it('Should fail with conflicting method names', function() {
assert.throws(function() { assert.throws(function() {

@ -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": {}
}
}
}
]
}

@ -32,7 +32,7 @@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <RxLibrary/GRXWriter.h> #import <gRPC/GRXWriter.h>
@class GRPCMethodName; @class GRPCMethodName;

@ -33,8 +33,8 @@
#import "GRPCCall.h" #import "GRPCCall.h"
#include <grpc.h> #include <grpc/grpc.h>
#include <support/time.h> #include <grpc/support/grpc_time.h>
#import "GRPCMethodName.h" #import "GRPCMethodName.h"
#import "private/GRPCChannel.h" #import "private/GRPCChannel.h"

@ -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

@ -45,6 +45,7 @@ struct grpc_channel;
// Convenience constructor to allow for reuse of connections. // Convenience constructor to allow for reuse of connections.
+ (instancetype)channelToHost:(NSString *)host; + (instancetype)channelToHost:(NSString *)host;
// Designated initializer - (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithHost:(NSString *)host;
- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
@end @end

@ -33,7 +33,10 @@
#import "GRPCChannel.h" #import "GRPCChannel.h"
#import <grpc.h> #include <grpc/grpc.h>
#import "GRPCSecureChannel.h"
#import "GRPCUnsecuredChannel.h"
@implementation GRPCChannel @implementation GRPCChannel
@ -46,20 +49,42 @@
return [self initWithHost:nil]; return [self initWithHost:nil];
} }
// Designated initializer
- (instancetype)initWithHost:(NSString *)host { - (instancetype)initWithHost:(NSString *)host {
if (!host) { if (![host containsString:@"://"]) {
[NSException raise:NSInvalidArgumentException format:@"Host can't be nil."]; // 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])) { if ((self = [super init])) {
_unmanagedChannel = grpc_channel_create(host.UTF8String, NULL); _unmanagedChannel = unmanagedChannel;
} }
return self; return self;
} }
- (void)dealloc { - (void)dealloc {
// TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely, // _unmanagedChannel is NULL when deallocating an object of the base class (because the
// as in the past that made this call to crash. // initializer returns a different object).
grpc_channel_destroy(_unmanagedChannel); 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 @end

@ -33,7 +33,7 @@
#import "GRPCCompletionQueue.h" #import "GRPCCompletionQueue.h"
#import <grpc.h> #import <grpc/grpc.h>
@implementation GRPCCompletionQueue @implementation GRPCCompletionQueue

@ -33,7 +33,7 @@
#import "GRPCDelegateWrapper.h" #import "GRPCDelegateWrapper.h"
#import <RxLibrary/GRXWriteable.h> #import <gRPC/GRXWriteable.h>
@interface GRPCDelegateWrapper () @interface GRPCDelegateWrapper ()
// These are atomic so that cancellation can nillify them from any thread. // These are atomic so that cancellation can nillify them from any thread.

@ -31,16 +31,8 @@
* *
*/ */
#ifndef MK1MF_BUILD #import "GRPCChannel.h"
/* auto-generated by Configure for crypto/cversion.c:
* for Unix builds, crypto/Makefile.ssl generates functional definitions; @interface GRPCSecureChannel : GRPCChannel
* Windows builds (and other mk1mf builds) compile cversion.c with
* -DMK1MF_BUILD and use definitions added to this file by util/mk1mf.pl. */ @end
#error "Windows builds (PLATFORM=VC-WIN32) use mk1mf.pl-created Makefiles"
#endif
#ifdef MK1MF_PLATFORM_VC_WIN32
/* auto-generated/updated by util/mk1mf.pl for crypto/cversion.c */
#define CFLAGS "cl /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS -DDSO_WIN32 -W3 -Gs0 -GF -Gy -nologo -DOPENSSL_SYSNAME_WIN32 -DWIN32_LEAN_AND_MEAN -DL_ENDIAN -D_CRT_SECURE_NO_DEPRECATE -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE "
#define PLATFORM "VC-WIN32"
#define DATE "Sat Dec 13 01:17:07 2014"
#endif

@ -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

@ -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

@ -31,38 +31,14 @@
* *
*/ */
#include <string.h> #import "GRPCUnsecuredChannel.h"
#include <grpc/grpc.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, @implementation GRPCUnsecuredChannel
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);
}
grpc_security_status grpc_server_security_context_create(
grpc_server_credentials *creds, grpc_security_context **ctx) {
grpc_security_status status = GRPC_SECURITY_ERROR;
*ctx = NULL; - (instancetype)initWithHost:(NSString *)host {
if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) { return (self = [super initWithChannel:grpc_channel_create(host.UTF8String, NULL)]);
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;
}
return status;
} }
@end

@ -33,7 +33,7 @@
#import "NSData+GRPC.h" #import "NSData+GRPC.h"
#include <byte_buffer.h> #include <grpc/byte_buffer.h>
#include <string.h> #include <string.h>
// TODO(jcanizales): Move these two incantations to the C library. // TODO(jcanizales): Move these two incantations to the C library.

@ -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

@ -1,13 +1,14 @@
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' platform :ios, '8.0'
pod 'RxLibrary', :path => "../../RxLibrary" pod 'gRPC', :path => "../../../.."
pod 'GRPCClient', :path => "../../GRPCClient" pod 'Route_guide', :path => "RouteGuideClient"
pod 'RemoteTest', :path => "RemoteTestClient"
target 'Sample' do link_with 'Sample', 'SampleTests'
target 'Sample' do
end end
target 'SampleTests' do target 'SampleTests' do
end end

File diff suppressed because it is too large Load Diff

@ -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)

@ -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)

@ -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)

@ -0,0 +1,17 @@
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'
end

@ -0,0 +1,81 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
#import <ProtocolBuffers/ProtocolBuffers.h>
#import "Empty.pb.h"
#import "Messages.pb.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
// @@protoc_insertion_point(global_scope)

@ -0,0 +1,27 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
#import "Test.pb.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
// @@protoc_insertion_point(global_scope)

@ -1,5 +1,3 @@
// This file will be moved to a new location.
// Copyright 2015, Google Inc. // Copyright 2015, Google Inc.
// All rights reserved. // All rights reserved.
// //
@ -31,14 +29,18 @@
syntax = "proto2"; syntax = "proto2";
package 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 // 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 // messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance: // return value of a service API. For instance:
// //
// service Foo { // service Foo {
// rpc Bar (proto2.Empty) returns (proto2.Empty) { }; // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
// }; // };
// //
message Empty {} message Empty {}

@ -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;
}

@ -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);
}

@ -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)

@ -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

@ -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;
}

@ -37,6 +37,5 @@
@property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UIWindow *window;
@end @end

@ -34,37 +34,12 @@
#import "AppDelegate.h" #import "AppDelegate.h"
@interface AppDelegate () @interface AppDelegate ()
@end @end
@implementation AppDelegate @implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES; 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 @end

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save