Merge github.com:grpc/grpc into kinetic-lopsided-poetry

pull/2788/head^2
Craig Tiller 10 years ago
commit 6b9477e8dc
  1. 2
      BUILD
  2. 1989
      Makefile
  3. 45
      build.json
  4. 131
      doc/interop-test-descriptions.md
  5. 62
      include/grpc++/client_context.h
  6. 2
      include/grpc++/server_context.h
  7. 43
      include/grpc++/stub_options.h
  8. 38
      include/grpc/grpc.h
  9. 8
      src/compiler/cpp_generator.cc
  10. 82
      src/compiler/csharp_generator.cc
  11. 23
      src/core/channel/client_channel.c
  12. 99
      src/core/surface/call.c
  13. 4
      src/core/surface/call.h
  14. 19
      src/core/surface/channel.c
  15. 5
      src/core/surface/completion_queue.c
  16. 4
      src/core/surface/server.c
  17. 22
      src/cpp/client/channel.cc
  18. 12
      src/cpp/client/client_context.cc
  19. 74
      src/csharp/Grpc.Core.Tests/ClientServerTest.cs
  20. 30
      src/csharp/Grpc.Core.Tests/TimeoutsTest.cs
  21. 56
      src/csharp/Grpc.Core/CallInvocationDetails.cs
  22. 89
      src/csharp/Grpc.Core/CallOptions.cs
  23. 48
      src/csharp/Grpc.Core/Calls.cs
  24. 16
      src/csharp/Grpc.Core/Channel.cs
  25. 10
      src/csharp/Grpc.Core/ClientBase.cs
  26. 3
      src/csharp/Grpc.Core/Grpc.Core.csproj
  27. 84
      src/csharp/Grpc.Core/Internal/AsyncCall.cs
  28. 28
      src/csharp/Grpc.Core/Method.cs
  29. 15
      src/csharp/Grpc.Core/ServerCallContext.cs
  30. 54
      src/csharp/Grpc.Examples/MathGrpc.cs
  31. 21
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  32. 86
      src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
  33. 3
      src/csharp/ext/grpc_csharp_ext.c
  34. 5
      src/node/ext/call.cc
  35. 45
      src/objective-c/GRPCClient/GRPCCall+Tests.h
  36. 47
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  37. 12
      src/objective-c/GRPCClient/GRPCCall.m
  38. 13
      src/objective-c/GRPCClient/private/GRPCChannel.h
  39. 56
      src/objective-c/GRPCClient/private/GRPCChannel.m
  40. 2
      src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
  41. 58
      src/objective-c/GRPCClient/private/GRPCHost.h
  42. 134
      src/objective-c/GRPCClient/private/GRPCHost.m
  43. 15
      src/objective-c/GRPCClient/private/GRPCSecureChannel.h
  44. 78
      src/objective-c/GRPCClient/private/GRPCSecureChannel.m
  45. 2
      src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
  46. 6
      src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
  47. 7
      src/objective-c/GRPCClient/private/GRPCWrappedCall.h
  48. 39
      src/objective-c/GRPCClient/private/GRPCWrappedCall.m
  49. 44
      src/objective-c/tests/InteropTests.h
  50. 16
      src/objective-c/tests/InteropTests.m
  51. 62
      src/objective-c/tests/InteropTestsLocalSSL.m
  52. 15
      src/objective-c/tests/TestCertificates.bundle/test-certificates.pem
  53. 10
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  54. 3
      src/objective-c/tests/run_tests.sh
  55. 4
      src/php/ext/grpc/call.c
  56. 1
      src/python/grpcio/.gitignore
  57. 26
      src/python/grpcio/commands.py
  58. 2
      src/python/grpcio/grpc/_adapter/_c/types/channel.c
  59. 2
      src/python/grpcio/setup.py
  60. 8
      src/ruby/ext/grpc/rb_channel.c
  61. 2
      templates/tools/run_tests/tests.json.template
  62. 4
      test/core/end2end/dualstack_socket_test.c
  63. 8
      test/core/end2end/fixtures/chttp2_fullstack_compression.c
  64. 132
      test/core/end2end/fixtures/chttp2_fullstack_with_proxy.c
  65. 193
      test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c
  66. 1
      test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
  67. 430
      test/core/end2end/fixtures/proxy.c
  68. 55
      test/core/end2end/fixtures/proxy.h
  69. 46
      test/core/end2end/gen_build_json.py
  70. 3
      test/core/end2end/no_server_test.c
  71. 4
      test/core/end2end/tests/bad_hostname.c
  72. 7
      test/core/end2end/tests/cancel_after_accept.c
  73. 7
      test/core/end2end/tests/cancel_after_accept_and_writes_closed.c
  74. 7
      test/core/end2end/tests/cancel_after_invoke.c
  75. 4
      test/core/end2end/tests/cancel_before_invoke.c
  76. 4
      test/core/end2end/tests/cancel_in_a_vacuum.c
  77. 4
      test/core/end2end/tests/census_simple_request.c
  78. 3
      test/core/end2end/tests/default_host.c
  79. 4
      test/core/end2end/tests/disappearing_server.c
  80. 4
      test/core/end2end/tests/early_server_shutdown_finishes_inflight_calls.c
  81. 4
      test/core/end2end/tests/empty_batch.c
  82. 4
      test/core/end2end/tests/graceful_server_shutdown.c
  83. 4
      test/core/end2end/tests/invoke_large_request.c
  84. 12
      test/core/end2end/tests/max_concurrent_streams.c
  85. 4
      test/core/end2end/tests/max_message_length.c
  86. 4
      test/core/end2end/tests/ping_pong_streaming.c
  87. 3
      test/core/end2end/tests/registered_call.c
  88. 4
      test/core/end2end/tests/request_response_with_binary_metadata_and_payload.c
  89. 4
      test/core/end2end/tests/request_response_with_metadata_and_payload.c
  90. 4
      test/core/end2end/tests/request_response_with_payload.c
  91. 8
      test/core/end2end/tests/request_response_with_payload_and_call_creds.c
  92. 4
      test/core/end2end/tests/request_response_with_trailing_metadata_and_payload.c
  93. 4
      test/core/end2end/tests/request_with_compressed_payload.c
  94. 4
      test/core/end2end/tests/request_with_flags.c
  95. 4
      test/core/end2end/tests/request_with_large_metadata.c
  96. 4
      test/core/end2end/tests/request_with_payload.c
  97. 4
      test/core/end2end/tests/server_finishes_request.c
  98. 4
      test/core/end2end/tests/simple_delayed_request.c
  99. 4
      test/core/end2end/tests/simple_request.c
  100. 4
      test/core/end2end/tests/simple_request_with_high_initial_sequence_number.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -726,6 +726,7 @@ cc_library(
"include/grpc++/status.h",
"include/grpc++/status_code_enum.h",
"include/grpc++/stream.h",
"include/grpc++/stub_options.h",
"include/grpc++/thread_pool_interface.h",
"include/grpc++/time.h",
],
@ -813,6 +814,7 @@ cc_library(
"include/grpc++/status.h",
"include/grpc++/status_code_enum.h",
"include/grpc++/stream.h",
"include/grpc++/stub_options.h",
"include/grpc++/thread_pool_interface.h",
"include/grpc++/time.h",
],

1989
Makefile

File diff suppressed because one or more lines are too long

@ -69,6 +69,7 @@
"include/grpc++/status.h",
"include/grpc++/status_code_enum.h",
"include/grpc++/stream.h",
"include/grpc++/stub_options.h",
"include/grpc++/thread_pool_interface.h",
"include/grpc++/time.h"
],
@ -335,6 +336,7 @@
"name": "grpc_test_util_base",
"headers": [
"test/core/end2end/cq_verifier.h",
"test/core/end2end/fixtures/proxy.h",
"test/core/iomgr/endpoint_tests.h",
"test/core/security/oauth2_utils.h",
"test/core/util/grpc_profiler.h",
@ -344,6 +346,7 @@
],
"src": [
"test/core/end2end/cq_verifier.c",
"test/core/end2end/fixtures/proxy.c",
"test/core/iomgr/endpoint_tests.c",
"test/core/security/oauth2_utils.c",
"test/core/util/grpc_profiler.c",
@ -981,6 +984,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -998,6 +1003,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1015,6 +1022,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1062,6 +1071,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1079,6 +1090,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1552,6 +1565,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1748,6 +1763,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1765,6 +1782,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1782,6 +1801,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1902,6 +1923,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1922,6 +1945,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -1983,6 +2008,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2224,6 +2251,8 @@
"grpc++_test_config"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2245,6 +2274,8 @@
"grpc++_test_config"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2262,6 +2293,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2369,6 +2402,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2390,6 +2425,8 @@
"grpc++_test_config"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2411,6 +2448,8 @@
"grpc++_test_config"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2508,6 +2547,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2560,6 +2601,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},
@ -2580,6 +2623,8 @@
"gpr"
],
"platforms": [
"mac",
"linux",
"posix"
]
},

@ -55,7 +55,7 @@ Server features:
Procedure:
1. Client calls EmptyCall with the default Empty message
Asserts:
Client asserts:
* call was successful
* response is non-null
@ -84,7 +84,7 @@ Procedure:
}
```
Asserts:
Client asserts:
* call was successful
* response payload type is COMPRESSABLE
* response payload body is 314159 bytes in size
@ -110,6 +110,7 @@ Procedure:
}
}
```
3. Client then sends:
```
@ -119,6 +120,7 @@ Procedure:
}
}
```
4. Client then sends:
```
@ -128,6 +130,7 @@ Procedure:
}
}
```
5. Client then sends:
```
@ -137,9 +140,10 @@ Procedure:
}
}
```
6. Client halfCloses
Asserts:
6. Client half-closes
Client asserts:
* call was successful
* response aggregated_payload_size is 74922
@ -172,7 +176,7 @@ Procedure:
}
```
Asserts:
Client asserts:
* call was successful
* exactly four responses
* response payloads are COMPRESSABLE
@ -202,6 +206,7 @@ Procedure:
}
}
```
2. After getting a reply, it sends:
```
@ -215,6 +220,7 @@ Procedure:
}
}
```
3. After getting a reply, it sends:
```
@ -228,6 +234,7 @@ Procedure:
}
}
```
4. After getting a reply, it sends:
```
@ -242,7 +249,9 @@ Procedure:
}
```
Asserts:
5. After getting a reply, client half-closes
Client asserts:
* call was successful
* exactly four responses
* response payloads are COMPRESSABLE
@ -261,7 +270,7 @@ Server features:
Procedure:
1. Client calls FullDuplexCall and then half-closes
Asserts:
Client asserts:
* call was successful
* exactly zero responses
@ -300,7 +309,7 @@ Procedure:
}
```
Asserts:
Client asserts:
* call was successful
* received SimpleResponse.username equals the value of `--default_service_account` flag
* received SimpleResponse.oauth_scope is in `--oauth_scope`
@ -328,7 +337,7 @@ Server features:
* [Echo OAuth Scope][]
Procedure:
1. Client configures the channel to use ServiceAccountCredentials.
1. Client configures the channel to use ServiceAccountCredentials
2. Client calls UnaryCall with:
```
@ -343,7 +352,7 @@ Procedure:
}
```
Asserts:
Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file read from
`--service_account_key_file`
@ -370,7 +379,7 @@ Server features:
* [Echo OAuth Scope][]
Procedure:
1. Client configures the channel to use JWTTokenCredentials.
1. Client configures the channel to use JWTTokenCredentials
2. Client calls UnaryCall with:
```
@ -384,7 +393,7 @@ Procedure:
}
```
Asserts:
Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file read from
`--service_account_key_file`
@ -422,7 +431,7 @@ Server features:
Procedure:
1. Client uses the auth library to obtain an authorization token
2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1.
2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1
3. Client calls UnaryCall with the following message
```
@ -431,8 +440,8 @@ Procedure:
fill_oauth_scope: true
}
```
Asserts:
Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token
@ -464,10 +473,10 @@ Server features:
Procedure:
1. Client uses the auth library to obtain an authorization token
2. Client configures the channel with just SSL credentials.
2. Client configures the channel with just SSL credentials
3. Client calls UnaryCall, setting per-call credentials to
AccessTokenCredentials with the access token obtained in step 1. The request is
the following message
AccessTokenCredentials with the access token obtained in step 1. The request
is the following message
```
{
@ -475,8 +484,8 @@ Procedure:
fill_oauth_scope: true
}
```
Asserts:
Client asserts:
* call was successful
* received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token
@ -496,8 +505,14 @@ Server features:
* [Echo Metadata][]
Procedure:
1. While sending custom metadata (ascii + binary) in the header, client calls
UnaryCall with:
1. The client attaches custom metadata with the following keys and values:
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
to a UnaryCall with request:
```
{
@ -508,23 +523,41 @@ Procedure:
}
}
```
The client attaches custom metadata with the following keys and values:
2. The client attaches custom metadata with the following keys and values:
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts:
to a FullDuplexCall with request:
```
{
response_type: COMPRESSABLE
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
and then half-closes
Client asserts:
* call was successful
* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata.
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata.
* metadata with key `"x-grpc-test-echo-initial"` and value
`"test_initial_metadata_value"`is received in the initial metadata for calls
in Procedure steps 1 and 2.
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is
received in the trailing metadata for calls in Procedure steps 1 and 2.
### status_code_and_message
This test verifies unary calls succeed in sending messages, and propagates back
This test verifies unary calls succeed in sending messages, and propagate back
status code and message sent along with the messages.
Server features:
@ -543,12 +576,26 @@ Procedure:
}
}
```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
2. Client calls FullDuplexCall with:
```
{
response_status:{
code: 2
message: "test status message"
}
}
```
and then half-closes
Asserts:
* received status code is the same with sent code
* received status message is the same with sent message
Client asserts:
* received status code is the same as the sent code for both Procedure steps 1
and 2
* received status message is the same as the sent message for both Procedure
steps 1 and 2
### unimplemented_method
@ -556,15 +603,19 @@ Status: Ready for implementation. Blocking beta.
This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code.
Server features:
N/A
Procedure:
* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`):
* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an
empty request (defined as `grpc.testing.Empty`):
```
{
}
```
Asserts:
Client asserts:
* received status code is 12 (UNIMPLEMENTED)
* received status message is empty or null/unset
@ -580,7 +631,7 @@ Procedure:
1. Client starts StreamingInputCall
2. Client immediately cancels request
Asserts:
Client asserts:
* Call completed with status CANCELLED
### cancel_after_first_response
@ -606,9 +657,10 @@ Procedure:
}
}
```
2. After receiving a response, client cancels request
Asserts:
Client asserts:
* Call completed with status CANCELLED
### timeout_on_sleeping_server
@ -620,7 +672,8 @@ Server features:
* [FullDuplexCall][]
Procedure:
1. Client calls FullDuplexCall with the following request and sets its timeout to 1ms.
1. Client calls FullDuplexCall with the following request and sets its timeout
to 1ms
```
{
@ -630,7 +683,9 @@ Procedure:
}
```
Asserts:
2. Client waits
Client asserts:
* Call completed with status DEADLINE_EXCEEDED.
### concurrent_large_unary

@ -39,6 +39,7 @@
#include <string>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpc++/auth_context.h>
@ -46,8 +47,6 @@
#include <grpc++/status.h>
#include <grpc++/time.h>
struct grpc_call;
struct grpc_completion_queue;
struct census_context;
namespace grpc {
@ -70,12 +69,68 @@ template <class R, class W>
class ClientAsyncReaderWriter;
template <class R>
class ClientAsyncResponseReader;
class ServerContext;
class PropagationOptions {
public:
PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
PropagationOptions& enable_deadline_propagation() {
propagate_ |= GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& disable_deadline_propagation() {
propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
return *this;
}
PropagationOptions& enable_census_stats_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& disable_census_stats_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
return *this;
}
PropagationOptions& enable_census_tracing_propagation() {
propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& disable_census_tracing_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
return *this;
}
PropagationOptions& enable_cancellation_propagation() {
propagate_ |= GRPC_PROPAGATE_CANCELLATION;
return *this;
}
PropagationOptions& disable_cancellation_propagation() {
propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
return *this;
}
gpr_uint32 c_bitmask() const { return propagate_; }
private:
gpr_uint32 propagate_;
};
class ClientContext {
public:
ClientContext();
~ClientContext();
/// Create a new ClientContext that propagates some or all of its attributes
static std::unique_ptr<ClientContext> FromServerContext(
const ServerContext& server_context,
PropagationOptions options = PropagationOptions());
void AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value);
@ -181,6 +236,9 @@ class ClientContext {
std::multimap<grpc::string, grpc::string> recv_initial_metadata_;
std::multimap<grpc::string, grpc::string> trailing_metadata_;
grpc_call* propagate_from_call_;
PropagationOptions propagation_options_;
grpc_compression_algorithm compression_algorithm_;
};

@ -50,6 +50,7 @@ struct census_context;
namespace grpc {
class ClientContext;
template <class W, class R>
class ServerAsyncReader;
template <class W>
@ -158,6 +159,7 @@ class ServerContext {
friend class ServerStreamingHandler;
template <class ServiceType, class RequestType, class ResponseType>
friend class BidiStreamingHandler;
friend class ::grpc::ClientContext;
// Prevent copying.
ServerContext(const ServerContext&);

@ -0,0 +1,43 @@
/*
*
* 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 GRPCXX_STUB_OPTIONS_H
#define GRPCXX_STUB_OPTIONS_H
namespace grpc {
class StubOptions {};
} // namespace grpc
#endif // GRPCXX_STUB_OPTIONS_H

@ -177,6 +177,8 @@ typedef enum grpc_call_error {
GRPC_CALL_ERROR_INVALID_FLAGS,
/** invalid metadata was passed to this call */
GRPC_CALL_ERROR_INVALID_METADATA,
/** invalid message was passed to this call */
GRPC_CALL_ERROR_INVALID_MESSAGE,
/** completion queue for notification has not been registered with the
server */
GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE
@ -308,8 +310,8 @@ typedef struct grpc_op {
value, or reuse it in a future op. */
grpc_metadata_array *recv_initial_metadata;
/** ownership of the byte buffer is moved to the caller; the caller must
call
grpc_byte_buffer_destroy on this value, or reuse it in a future op. */
call grpc_byte_buffer_destroy on this value, or reuse it in a future op.
*/
grpc_byte_buffer **recv_message;
struct {
/** ownership of the array is with the caller, but ownership of the
@ -351,6 +353,26 @@ typedef struct grpc_op {
} data;
} grpc_op;
/* Propagation bits: this can be bitwise or-ed to form propagation_mask for
* grpc_call */
/** Propagate deadline */
#define GRPC_PROPAGATE_DEADLINE ((gpr_uint32)1)
/** Propagate census context */
#define GRPC_PROPAGATE_CENSUS_STATS_CONTEXT ((gpr_uint32)2)
#define GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT ((gpr_uint32)4)
/** Propagate cancellation */
#define GRPC_PROPAGATE_CANCELLATION ((gpr_uint32)8)
/* Default propagation mask: clients of the core API are encouraged to encode
deltas from this in their implementations... ie write:
GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline
propagation. Doing so gives flexibility in the future to define new
propagation types that are default inherited or not. */
#define GRPC_PROPAGATE_DEFAULTS \
((gpr_uint32)(( \
0xffff | GRPC_PROPAGATE_DEADLINE | GRPC_PROPAGATE_CENSUS_STATS_CONTEXT | \
GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT | GRPC_PROPAGATE_CANCELLATION)))
/** Initialize the grpc library.
It is not safe to call any other grpc functions before calling this.
@ -430,8 +452,13 @@ void grpc_channel_watch_connectivity_state(
/** Create a call given a grpc_channel, in order to call 'method'. All
completions are sent to 'completion_queue'. 'method' and 'host' need only
live through the invocation of this function. */
live through the invocation of this function.
If parent_call is non-NULL, it must be a server-side call. It will be used
to propagate properties from the server call to this new client call.
*/
grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *parent_call,
gpr_uint32 propagation_mask,
grpc_completion_queue *completion_queue,
const char *method, const char *host,
gpr_timespec deadline);
@ -442,8 +469,9 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
/** 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);
grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
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
completion of type 'tag' to the completion queue bound to the call.

@ -119,6 +119,7 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
"#include <grpc++/async_unary_call.h>\n"
"#include <grpc++/status.h>\n"
"#include <grpc++/stream.h>\n"
"#include <grpc++/stub_options.h>\n"
"\n"
"namespace grpc {\n"
"class CompletionQueue;\n"
@ -574,8 +575,8 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
printer->Print("};\n");
printer->Print(
"static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
"::grpc::ChannelInterface>& "
"channel);\n");
"::grpc::ChannelInterface>& channel, "
"const ::grpc::StubOptions& options = ::grpc::StubOptions());\n");
printer->Print("\n");
@ -966,7 +967,8 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
printer->Print(
*vars,
"std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
"const std::shared_ptr< ::grpc::ChannelInterface>& channel) {\n"
"const std::shared_ptr< ::grpc::ChannelInterface>& channel, "
"const ::grpc::StubOptions& options) {\n"
" std::unique_ptr< $ns$$Service$::Stub> stub(new "
"$ns$$Service$::Stub(channel));\n"
" return stub;\n"

@ -246,6 +246,8 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
out->Indent();
out->Print("$methodtype$,\n", "methodtype",
GetCSharpMethodType(GetMethodType(method)));
out->Print("$servicenamefield$,\n", "servicenamefield",
GetServiceNameFieldName());
out->Print("\"$methodname$\",\n", "methodname", method->name());
out->Print("$requestmarshaller$,\n", "requestmarshaller",
GetMarshallerFieldName(method->input_type()));
@ -273,6 +275,13 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
// overload taking CallOptions as a param
out->Print(
"$response$ $methodname$($request$ request, CallOptions options);\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
}
std::string method_name = method->name();
@ -284,6 +293,13 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
// overload taking CallOptions as a param
out->Print(
"$returntype$ $methodname$($request_maybe$CallOptions options);\n",
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
}
out->Outdent();
out->Print("}\n");
@ -340,10 +356,23 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
GetClassName(method->output_type()));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n",
"servicenamefield", GetServiceNameFieldName(), "methodfield",
GetMethodFieldName(method));
out->Print("return Calls.BlockingUnaryCall(call, request, cancellationToken);\n");
out->Print("var call = CreateCall($methodfield$, new CallOptions(headers, deadline, cancellationToken));\n",
"methodfield", GetMethodFieldName(method));
out->Print("return Calls.BlockingUnaryCall(call, request);\n");
out->Outdent();
out->Print("}\n");
// overload taking CallOptions as a param
out->Print(
"public $response$ $methodname$($request$ request, CallOptions options)\n",
"methodname", method->name(), "request",
GetClassName(method->input_type()), "response",
GetClassName(method->output_type()));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($methodfield$, options);\n",
"methodfield", GetMethodFieldName(method));
out->Print("return Calls.BlockingUnaryCall(call, request);\n");
out->Outdent();
out->Print("}\n");
}
@ -359,26 +388,55 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
GetMethodReturnTypeClient(method));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n",
"servicenamefield", GetServiceNameFieldName(), "methodfield",
GetMethodFieldName(method));
out->Print("var call = CreateCall($methodfield$, new CallOptions(headers, deadline, cancellationToken));\n",
"methodfield", GetMethodFieldName(method));
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
out->Print("return Calls.AsyncUnaryCall(call, request, cancellationToken);\n");
out->Print("return Calls.AsyncUnaryCall(call, request);\n");
break;
case METHODTYPE_CLIENT_STREAMING:
out->Print("return Calls.AsyncClientStreamingCall(call, cancellationToken);\n");
out->Print("return Calls.AsyncClientStreamingCall(call);\n");
break;
case METHODTYPE_SERVER_STREAMING:
out->Print(
"return Calls.AsyncServerStreamingCall(call, request, cancellationToken);\n");
"return Calls.AsyncServerStreamingCall(call, request);\n");
break;
case METHODTYPE_BIDI_STREAMING:
out->Print("return Calls.AsyncDuplexStreamingCall(call, cancellationToken);\n");
out->Print("return Calls.AsyncDuplexStreamingCall(call);\n");
break;
default:
GOOGLE_LOG(FATAL)<< "Can't get here.";
}
}
out->Outdent();
out->Print("}\n");
// overload taking CallOptions as a param
out->Print(
"public $returntype$ $methodname$($request_maybe$CallOptions options)\n",
"methodname", method_name, "request_maybe",
GetMethodRequestParamMaybe(method), "returntype",
GetMethodReturnTypeClient(method));
out->Print("{\n");
out->Indent();
out->Print("var call = CreateCall($methodfield$, options);\n",
"methodfield", GetMethodFieldName(method));
switch (GetMethodType(method)) {
case METHODTYPE_NO_STREAMING:
out->Print("return Calls.AsyncUnaryCall(call, request);\n");
break;
case METHODTYPE_CLIENT_STREAMING:
out->Print("return Calls.AsyncClientStreamingCall(call);\n");
break;
case METHODTYPE_SERVER_STREAMING:
out->Print(
"return Calls.AsyncServerStreamingCall(call, request);\n");
break;
case METHODTYPE_BIDI_STREAMING:
out->Print("return Calls.AsyncDuplexStreamingCall(call);\n");
break;
default:
GOOGLE_LOG(FATAL)<< "Can't get here.";
}
out->Outdent();
out->Print("}\n");
}

@ -56,6 +56,8 @@ typedef struct {
grpc_mdctx *mdctx;
/** resolver for this channel */
grpc_resolver *resolver;
/** have we started resolving this channel */
int started_resolving;
/** master channel - the grpc_channel instance that ultimately owns
this channel_data via its channel stack.
We occasionally use this to bump the refcount on the master channel
@ -398,6 +400,12 @@ static void perform_transport_stream_op(grpc_call_element *elem,
} else if (chand->resolver != NULL) {
calld->state = CALL_WAITING_FOR_CONFIG;
add_to_lb_policy_wait_queue_locked_state_config(elem);
if (!chand->started_resolving && chand->resolver != NULL) {
chand->started_resolving = 1;
grpc_resolver_next(chand->resolver,
&chand->incoming_configuration,
&chand->on_config_changed);
}
gpr_mu_unlock(&chand->mu_config);
gpr_mu_unlock(&calld->mu_state);
} else {
@ -690,12 +698,18 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
/* post construction initialization: set the transport setup pointer */
grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
channel_data *chand = elem->channel_data;
gpr_mu_lock(&chand->mu_config);
GPR_ASSERT(!chand->resolver);
chand->resolver = resolver;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
GRPC_RESOLVER_REF(resolver, "channel");
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
if (chand->waiting_for_config_closures != NULL ||
chand->exit_idle_when_lb_policy_arrives) {
chand->started_resolving = 1;
grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}
gpr_mu_unlock(&chand->mu_config);
}
grpc_connectivity_state grpc_client_channel_check_connectivity_state(
@ -709,6 +723,11 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
grpc_lb_policy_exit_idle(chand->lb_policy);
} else {
chand->exit_idle_when_lb_policy_arrives = 1;
if (!chand->started_resolving && chand->resolver != NULL) {
chand->started_resolving = 1;
grpc_resolver_next(chand->resolver, &chand->incoming_configuration,
&chand->on_config_changed);
}
}
}
gpr_mu_unlock(&chand->mu_config);

@ -143,6 +143,8 @@ typedef enum {
struct grpc_call {
grpc_completion_queue *cq;
grpc_channel *channel;
grpc_call *parent;
grpc_call *first_child;
grpc_mdctx *metadata_context;
/* TODO(ctiller): share with cq if possible? */
gpr_mu mu;
@ -176,6 +178,8 @@ struct grpc_call {
gpr_uint8 cancel_alarm;
/** bitmask of allocated completion events in completions */
gpr_uint8 allocated_completions;
/** flag indicating that cancellation is inherited */
gpr_uint8 cancellation_is_inherited;
/* flags with bits corresponding to write states allowing us to determine
what was sent */
@ -267,6 +271,11 @@ struct grpc_call {
/** completion events - for completion queue use */
grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS];
/** siblings: children of the same parent form a list, and this list is protected under
parent->mu */
grpc_call *sibling_next;
grpc_call *sibling_prev;
};
#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@ -290,7 +299,9 @@ static void finished_loose_op(void *call, int success);
static void lock(grpc_call *call);
static void unlock(grpc_call *call);
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
gpr_uint32 propagation_mask,
grpc_completion_queue *cq,
const void *server_transport_data,
grpc_mdelem **add_initial_metadata,
size_t add_initial_metadata_count,
@ -306,9 +317,10 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
gpr_mu_init(&call->completion_mu);
call->channel = channel;
call->cq = cq;
if (cq) {
if (cq != NULL) {
GRPC_CQ_INTERNAL_REF(cq, "bind");
}
call->parent = parent_call;
call->is_client = server_transport_data == NULL;
for (i = 0; i < GRPC_IOREQ_OP_COUNT; i++) {
call->request_set[i] = REQSET_EMPTY;
@ -347,6 +359,46 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
}
grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr,
CALL_STACK_FROM_CALL(call));
if (parent_call != NULL) {
GRPC_CALL_INTERNAL_REF(parent_call, "child");
GPR_ASSERT(call->is_client);
GPR_ASSERT(!parent_call->is_client);
gpr_mu_lock(&parent_call->mu);
if (propagation_mask & GRPC_PROPAGATE_DEADLINE) {
send_deadline = gpr_time_min(
gpr_convert_clock_type(send_deadline,
parent_call->send_deadline.clock_type),
parent_call->send_deadline);
}
/* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
* GRPC_PROPAGATE_STATS_CONTEXT */
/* TODO(ctiller): This should change to use the appropriate census start_op
* call. */
if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
grpc_call_context_set(call, GRPC_CONTEXT_TRACING,
parent_call->context[GRPC_CONTEXT_TRACING].value,
NULL);
} else {
GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
}
if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
call->cancellation_is_inherited = 1;
}
if (parent_call->first_child == NULL) {
parent_call->first_child = call;
call->sibling_next = call->sibling_prev = call;
} else {
call->sibling_next = parent_call->first_child;
call->sibling_prev = parent_call->first_child->sibling_prev;
call->sibling_next->sibling_prev = call->sibling_prev->sibling_next = call;
}
gpr_mu_unlock(&parent_call->mu);
}
if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) !=
0) {
set_deadline_alarm(call, send_deadline);
@ -404,6 +456,20 @@ void grpc_call_internal_ref(grpc_call *c) {
static void destroy_call(void *call, int ignored_success) {
size_t i;
grpc_call *c = call;
grpc_call *parent = c->parent;
if (parent) {
gpr_mu_lock(&parent->mu);
if (call == parent->first_child) {
parent->first_child = c->sibling_next;
if (c == parent->first_child) {
parent->first_child = NULL;
}
c->sibling_prev->sibling_next = c->sibling_next;
c->sibling_next->sibling_prev = c->sibling_prev;
}
gpr_mu_unlock(&parent->mu);
GRPC_CALL_INTERNAL_UNREF(parent, "child", 1);
}
grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
gpr_mu_destroy(&c->mu);
@ -870,6 +936,8 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
static void call_on_done_recv(void *pc, int success) {
grpc_call *call = pc;
grpc_call *child_call;
grpc_call *next_child_call;
size_t i;
GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0);
lock(call);
@ -903,6 +971,19 @@ static void call_on_done_recv(void *pc, int success) {
GPR_ASSERT(call->read_state <= READ_STATE_STREAM_CLOSED);
call->read_state = READ_STATE_STREAM_CLOSED;
call->cancel_alarm |= call->have_alarm;
/* propagate cancellation to any interested children */
child_call = call->first_child;
if (child_call != NULL) {
do {
next_child_call = child_call->sibling_next;
if (child_call->cancellation_is_inherited) {
GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
grpc_call_cancel(child_call);
GRPC_CALL_INTERNAL_UNREF(child_call, "propagate_cancel", 0);
}
child_call = next_child_call;
} while (child_call != call->first_child);
}
GRPC_CALL_INTERNAL_UNREF(call, "closed", 0);
}
finish_read_ops(call);
@ -1283,9 +1364,9 @@ static void set_deadline_alarm(grpc_call *call, gpr_timespec deadline) {
}
GRPC_CALL_INTERNAL_REF(call, "alarm");
call->have_alarm = 1;
grpc_alarm_init(&call->alarm,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
call_alarm, call, gpr_now(GPR_CLOCK_MONOTONIC));
call->send_deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
grpc_alarm_init(&call->alarm, call->send_deadline, call_alarm, call,
gpr_now(GPR_CLOCK_MONOTONIC));
}
/* we offset status by a small amount when storing it into transport metadata
@ -1377,7 +1458,8 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) {
}
}
if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
0) {
0 &&
!call->is_client) {
set_deadline_alarm(call, md->deadline);
}
if (!is_trailing) {
@ -1465,6 +1547,9 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
if (!are_write_flags_valid(op->flags)) {
return GRPC_CALL_ERROR_INVALID_FLAGS;
}
if (op->data.send_message == NULL) {
return GRPC_CALL_ERROR_INVALID_MESSAGE;
}
req = &reqs[out++];
req->op = GRPC_IOREQ_SEND_MESSAGE;
req->data.send_message = op->data.send_message;
@ -1514,6 +1599,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_INITIAL_METADATA;
req->data.recv_metadata = op->data.recv_initial_metadata;
req->data.recv_metadata->count = 0;
req->flags = op->flags;
break;
case GRPC_OP_RECV_MESSAGE:
@ -1545,6 +1631,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
req->op = GRPC_IOREQ_RECV_TRAILING_METADATA;
req->data.recv_metadata =
op->data.recv_status_on_client.trailing_metadata;
req->data.recv_metadata->count = 0;
req = &reqs[out++];
req->op = GRPC_IOREQ_RECV_CLOSE;
finish_func = finish_batch_with_close;

@ -85,7 +85,9 @@ typedef struct {
typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success,
void *user_data);
grpc_call *grpc_call_create(grpc_channel *channel, grpc_completion_queue *cq,
grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
gpr_uint32 propagation_mask,
grpc_completion_queue *cq,
const void *server_transport_data,
grpc_mdelem **add_initial_metadata,
size_t add_initial_metadata_count,

@ -146,7 +146,8 @@ char *grpc_channel_get_target(grpc_channel *channel) {
}
static grpc_call *grpc_channel_create_call_internal(
grpc_channel *channel, grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
grpc_completion_queue *cq, grpc_mdelem *path_mdelem,
grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
grpc_mdelem *send_metadata[2];
int num_metadata = 0;
@ -158,16 +159,18 @@ static grpc_call *grpc_channel_create_call_internal(
send_metadata[num_metadata++] = authority_mdelem;
}
return grpc_call_create(channel, cq, NULL, send_metadata,
num_metadata, deadline);
return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL,
send_metadata, num_metadata, deadline);
}
grpc_call *grpc_channel_create_call(grpc_channel *channel,
grpc_call *parent_call,
gpr_uint32 propagation_mask,
grpc_completion_queue *cq,
const char *method, const char *host,
gpr_timespec deadline) {
return grpc_channel_create_call_internal(
channel, cq,
channel, parent_call, propagation_mask, cq,
grpc_mdelem_from_metadata_strings(
channel->metadata_context, GRPC_MDSTR_REF(channel->path_string),
grpc_mdstr_from_string(channel->metadata_context, method, 0)),
@ -195,11 +198,13 @@ void *grpc_channel_register_call(grpc_channel *channel, const char *method,
}
grpc_call *grpc_channel_create_registered_call(
grpc_channel *channel, grpc_completion_queue *completion_queue,
void *registered_call_handle, gpr_timespec deadline) {
grpc_channel *channel, grpc_call *parent_call, gpr_uint32 propagation_mask,
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),
channel, parent_call, propagation_mask, completion_queue,
GRPC_MDELEM_REF(rc->path),
rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
}

@ -114,6 +114,11 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
}
void grpc_cq_begin_op(grpc_completion_queue *cc) {
#ifndef NDEBUG
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
GPR_ASSERT(!cc->shutdown_called);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
#endif
gpr_ref(&cc->pending_events);
}

@ -644,8 +644,8 @@ static void accept_stream(void *cd, grpc_transport *transport,
const void *transport_server_data) {
channel_data *chand = cd;
/* create a call */
grpc_call_create(chand->channel, NULL, transport_server_data, NULL, 0,
gpr_inf_future(GPR_CLOCK_REALTIME));
grpc_call_create(chand->channel, NULL, 0, NULL, transport_server_data, NULL,
0, gpr_inf_future(GPR_CLOCK_MONOTONIC));
}
static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) {

@ -61,16 +61,18 @@ Channel::~Channel() { grpc_channel_destroy(c_channel_); }
Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) {
const char* host_str = host_.empty() ? NULL : host_.c_str();
auto c_call =
method.channel_tag() && context->authority().empty()
? grpc_channel_create_registered_call(c_channel_, cq->cq(),
method.channel_tag(),
context->raw_deadline())
: grpc_channel_create_call(c_channel_, cq->cq(), method.name(),
context->authority().empty()
? host_str
: context->authority().c_str(),
context->raw_deadline());
auto c_call = method.channel_tag() && context->authority().empty()
? grpc_channel_create_registered_call(
c_channel_, context->propagate_from_call_,
context->propagation_options_.c_bitmask(), cq->cq(),
method.channel_tag(), context->raw_deadline())
: grpc_channel_create_call(
c_channel_, context->propagate_from_call_,
context->propagation_options_.c_bitmask(), cq->cq(),
method.name(), context->authority().empty()
? host_str
: context->authority().c_str(),
context->raw_deadline());
grpc_census_call_set_context(c_call, context->census_context());
GRPC_TIMER_MARK(GRPC_PTAG_CPP_CALL_CREATED, c_call);
context->set_call(c_call, shared_from_this());

@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <grpc++/credentials.h>
#include <grpc++/server_context.h>
#include <grpc++/time.h>
#include "src/core/channel/compress_filter.h"
@ -48,7 +49,8 @@ ClientContext::ClientContext()
: initial_metadata_received_(false),
call_(nullptr),
cq_(nullptr),
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)) {}
deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
propagate_from_call_(nullptr) {}
ClientContext::~ClientContext() {
if (call_) {
@ -64,6 +66,14 @@ ClientContext::~ClientContext() {
}
}
std::unique_ptr<ClientContext> ClientContext::FromServerContext(
const ServerContext& context, PropagationOptions options) {
std::unique_ptr<ClientContext> ctx(new ClientContext);
ctx->propagate_from_call_ = context.call_;
ctx->propagation_options_ = options;
return ctx;
}
void ClientContext::AddMetadata(const grpc::string& meta_key,
const grpc::string& meta_value) {
send_initial_metadata_.insert(std::make_pair(meta_key, meta_value));

@ -46,23 +46,26 @@ namespace Grpc.Core.Tests
public class ClientServerTest
{
const string Host = "127.0.0.1";
const string ServiceName = "/tests.Test";
const string ServiceName = "tests.Test";
static readonly Method<string, string> EchoMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/Echo",
ServiceName,
"Echo",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
static readonly Method<string, string> ConcatAndEchoMethod = new Method<string, string>(
MethodType.ClientStreaming,
"/tests.Test/ConcatAndEcho",
ServiceName,
"ConcatAndEcho",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
static readonly Method<string, string> NonexistentMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/NonexistentMethod",
ServiceName,
"NonexistentMethod",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
@ -102,17 +105,17 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Assert.AreEqual("ABC", Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
Assert.AreEqual("ABC", Calls.BlockingUnaryCall(callDetails, "ABC"));
}
[Test]
public void UnaryCall_ServerHandlerThrows()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
Calls.BlockingUnaryCall(internalCall, "THROW", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "THROW");
Assert.Fail();
}
catch (RpcException e)
@ -124,10 +127,10 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall_ServerHandlerThrowsRpcException()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
Calls.BlockingUnaryCall(internalCall, "THROW_UNAUTHENTICATED", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "THROW_UNAUTHENTICATED");
Assert.Fail();
}
catch (RpcException e)
@ -139,10 +142,10 @@ namespace Grpc.Core.Tests
[Test]
public void UnaryCall_ServerHandlerSetsStatus()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
Calls.BlockingUnaryCall(internalCall, "SET_UNAUTHENTICATED", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "SET_UNAUTHENTICATED");
Assert.Fail();
}
catch (RpcException e)
@ -152,20 +155,20 @@ namespace Grpc.Core.Tests
}
[Test]
public void AsyncUnaryCall()
public async Task AsyncUnaryCall()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var result = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None).ResponseAsync.Result;
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
var result = await Calls.AsyncUnaryCall(callDetails, "ABC");
Assert.AreEqual("ABC", result);
}
[Test]
public async Task AsyncUnaryCall_ServerHandlerThrows()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
try
{
await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None);
await Calls.AsyncUnaryCall(callDetails, "THROW");
Assert.Fail();
}
catch (RpcException e)
@ -177,8 +180,8 @@ namespace Grpc.Core.Tests
[Test]
public async Task ClientStreamingCall()
{
var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None);
var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions());
var call = Calls.AsyncClientStreamingCall(callDetails);
await call.RequestStream.WriteAll(new string[] { "A", "B", "C" });
Assert.AreEqual("ABC", await call.ResponseAsync);
@ -187,10 +190,9 @@ namespace Grpc.Core.Tests
[Test]
public async Task ClientStreamingCall_CancelAfterBegin()
{
var internalCall = new Call<string, string>(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty);
var cts = new CancellationTokenSource();
var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token);
var callDetails = new CallInvocationDetails<string, string>(channel, ConcatAndEchoMethod, new CallOptions(cancellationToken: cts.Token));
var call = Calls.AsyncClientStreamingCall(callDetails);
// TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it.
await Task.Delay(1000);
@ -214,8 +216,8 @@ namespace Grpc.Core.Tests
new Metadata.Entry("ascii-header", "abcdefg"),
new Metadata.Entry("binary-header-bin", new byte[] { 1, 2, 3, 0, 0xff }),
};
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, headers);
var call = Calls.AsyncUnaryCall(internalCall, "ABC", CancellationToken.None);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions(headers: headers));
var call = Calls.AsyncUnaryCall(callDetails, "ABC");
Assert.AreEqual("ABC", call.ResponseAsync.Result);
@ -235,25 +237,25 @@ namespace Grpc.Core.Tests
{
channel.Dispose();
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(internalCall, "ABC", CancellationToken.None));
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
Assert.Throws(typeof(ObjectDisposedException), () => Calls.BlockingUnaryCall(callDetails, "ABC"));
}
[Test]
public void UnaryCallPerformance()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
BenchmarkUtil.RunBenchmark(100, 100,
() => { Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken)); });
() => { Calls.BlockingUnaryCall(callDetails, "ABC"); });
}
[Test]
public void UnknownMethodHandler()
{
var internalCall = new Call<string, string>(ServiceName, NonexistentMethod, channel, Metadata.Empty);
var callDetails = new CallInvocationDetails<string, string>(channel, NonexistentMethod, new CallOptions());
try
{
Calls.BlockingUnaryCall(internalCall, "ABC", default(CancellationToken));
Calls.BlockingUnaryCall(callDetails, "ABC");
Assert.Fail();
}
catch (RpcException e)
@ -265,16 +267,16 @@ namespace Grpc.Core.Tests
[Test]
public void UserAgentStringPresent()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
string userAgent = Calls.BlockingUnaryCall(internalCall, "RETURN-USER-AGENT", CancellationToken.None);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
string userAgent = Calls.BlockingUnaryCall(callDetails, "RETURN-USER-AGENT");
Assert.IsTrue(userAgent.StartsWith("grpc-csharp/"));
}
[Test]
public void PeerInfoPresent()
{
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
string peer = Calls.BlockingUnaryCall(callDetails, "RETURN-PEER");
Assert.IsTrue(peer.Contains(Host));
}
@ -286,8 +288,8 @@ namespace Grpc.Core.Tests
var stateChangedTask = channel.WaitForStateChangedAsync(channel.State);
var internalCall = new Call<string, string>(ServiceName, EchoMethod, channel, Metadata.Empty);
await Calls.AsyncUnaryCall(internalCall, "abc", CancellationToken.None);
var callDetails = new CallInvocationDetails<string, string>(channel, EchoMethod, new CallOptions());
await Calls.AsyncUnaryCall(callDetails, "abc");
await stateChangedTask;
Assert.AreEqual(ChannelState.Ready, channel.State);

@ -49,11 +49,12 @@ namespace Grpc.Core.Tests
public class TimeoutsTest
{
const string Host = "localhost";
const string ServiceName = "/tests.Test";
const string ServiceName = "tests.Test";
static readonly Method<string, string> TestMethod = new Method<string, string>(
MethodType.Unary,
"/tests.Test/Test",
ServiceName,
"Test",
Marshallers.StringMarshaller,
Marshallers.StringMarshaller);
@ -98,12 +99,12 @@ namespace Grpc.Core.Tests
public void InfiniteDeadline()
{
// no deadline specified, check server sees infinite deadline
var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty);
Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None));
var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions());
Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE"));
// DateTime.MaxValue deadline specified, check server sees infinite deadline
var internalCall2 = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, DateTime.MaxValue);
Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall2, "RETURN_DEADLINE", CancellationToken.None));
var callDetails2 = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions());
Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(callDetails2, "RETURN_DEADLINE"));
}
[Test]
@ -112,9 +113,9 @@ namespace Grpc.Core.Tests
var remainingTimeClient = TimeSpan.FromDays(7);
var deadline = DateTime.UtcNow + remainingTimeClient;
Thread.Sleep(1000);
var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
var serverDeadlineTicksString = Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None);
var serverDeadlineTicksString = Calls.BlockingUnaryCall(callDetails, "RETURN_DEADLINE");
var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc);
// A fairly relaxed check that the deadline set by client and deadline seen by server
@ -126,12 +127,11 @@ namespace Grpc.Core.Tests
[Test]
public void DeadlineInThePast()
{
var deadline = DateTime.MinValue;
var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: DateTime.MinValue));
try
{
Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "TIMEOUT");
Assert.Fail();
}
catch (RpcException e)
@ -145,11 +145,11 @@ namespace Grpc.Core.Tests
public void DeadlineExceededStatusOnTimeout()
{
var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
try
{
Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "TIMEOUT");
Assert.Fail();
}
catch (RpcException e)
@ -163,11 +163,11 @@ namespace Grpc.Core.Tests
public void ServerReceivesCancellationOnTimeout()
{
var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5));
var internalCall = new Call<string, string>(ServiceName, TestMethod, channel, Metadata.Empty, deadline);
var callDetails = new CallInvocationDetails<string, string>(channel, TestMethod, new CallOptions(deadline: deadline));
try
{
Calls.BlockingUnaryCall(internalCall, "CHECK_CANCELLATION_RECEIVED", CancellationToken.None);
Calls.BlockingUnaryCall(callDetails, "CHECK_CANCELLATION_RECEIVED");
Assert.Fail();
}
catch (RpcException e)

@ -38,30 +38,30 @@ using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Abstraction of a call to be invoked on a client.
/// Details about a client-side call to be invoked.
/// </summary>
public class Call<TRequest, TResponse>
public class CallInvocationDetails<TRequest, TResponse>
{
readonly string name;
readonly Channel channel;
readonly string method;
readonly string host;
readonly Marshaller<TRequest> requestMarshaller;
readonly Marshaller<TResponse> responseMarshaller;
readonly Channel channel;
readonly Metadata headers;
readonly DateTime deadline;
readonly CallOptions options;
public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers)
: this(serviceName, method, channel, headers, DateTime.MaxValue)
public CallInvocationDetails(Channel channel, Method<TRequest, TResponse> method, CallOptions options) :
this(channel, method.FullName, null, method.RequestMarshaller, method.ResponseMarshaller, options)
{
}
public Call(string serviceName, Method<TRequest, TResponse> method, Channel channel, Metadata headers, DateTime deadline)
public CallInvocationDetails(Channel channel, string method, string host, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller, CallOptions options)
{
this.name = method.GetFullName(serviceName);
this.requestMarshaller = method.RequestMarshaller;
this.responseMarshaller = method.ResponseMarshaller;
this.channel = Preconditions.CheckNotNull(channel);
this.headers = Preconditions.CheckNotNull(headers);
this.deadline = deadline;
this.method = Preconditions.CheckNotNull(method);
this.host = host;
this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
this.options = Preconditions.CheckNotNull(options);
}
public Channel Channel
@ -72,49 +72,43 @@ namespace Grpc.Core
}
}
/// <summary>
/// Full methods name including the service name.
/// </summary>
public string Name
public string Method
{
get
{
return name;
return this.method;
}
}
/// <summary>
/// Headers to send at the beginning of the call.
/// </summary>
public Metadata Headers
public string Host
{
get
{
return headers;
return this.host;
}
}
public DateTime Deadline
public Marshaller<TRequest> RequestMarshaller
{
get
{
return this.deadline;
return this.requestMarshaller;
}
}
public Marshaller<TRequest> RequestMarshaller
public Marshaller<TResponse> ResponseMarshaller
{
get
{
return requestMarshaller;
return this.responseMarshaller;
}
}
public Marshaller<TResponse> ResponseMarshaller
public CallOptions Options
{
get
{
return responseMarshaller;
return options;
}
}
}

@ -0,0 +1,89 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Threading;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Options for calls made by client.
/// </summary>
public class CallOptions
{
readonly Metadata headers;
readonly DateTime deadline;
readonly CancellationToken cancellationToken;
/// <summary>
/// Creates a new instance of <c>CallOptions</c>.
/// </summary>
/// <param name="headers">Headers to be sent with the call.</param>
/// <param name="deadline">Deadline for the call to finish. null means no deadline.</param>
/// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
// TODO(jtattermusch): consider only creating metadata object once it's really needed.
this.headers = headers != null ? headers : new Metadata();
this.deadline = deadline.HasValue ? deadline.Value : DateTime.MaxValue;
this.cancellationToken = cancellationToken;
}
/// <summary>
/// Headers to send at the beginning of the call.
/// </summary>
public Metadata Headers
{
get { return headers; }
}
/// <summary>
/// Call deadline.
/// </summary>
public DateTime Deadline
{
get { return deadline; }
}
/// <summary>
/// Token that can be used for cancelling the call.
/// </summary>
public CancellationToken CancellationToken
{
get { return cancellationToken; }
}
}
}

@ -43,70 +43,52 @@ namespace Grpc.Core
/// </summary>
public static class Calls
{
public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
public static TResponse BlockingUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
// TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts.
RegisterCancellationCallback(asyncCall, token);
return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers, call.Deadline);
var asyncCall = new AsyncCall<TRequest, TResponse>(call);
return asyncCall.UnaryCall(req);
}
public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
public static AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var asyncCall = new AsyncCall<TRequest, TResponse>(call);
var asyncResult = asyncCall.UnaryCallAsync(req);
return new AsyncUnaryCall<TResponse>(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token)
public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call, TRequest req)
where TRequest : class
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
asyncCall.StartServerStreamingCall(req, call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var asyncCall = new AsyncCall<TRequest, TResponse>(call);
asyncCall.StartServerStreamingCall(req);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
return new AsyncServerStreamingCall<TResponse>(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var asyncCall = new AsyncCall<TRequest, TResponse>(call);
var resultTask = asyncCall.ClientStreamingCallAsync();
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
return new AsyncClientStreamingCall<TRequest, TResponse>(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token)
public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(CallInvocationDetails<TRequest, TResponse> call)
where TRequest : class
where TResponse : class
{
var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline));
asyncCall.StartDuplexStreamingCall(call.Headers, call.Deadline);
RegisterCancellationCallback(asyncCall, token);
var asyncCall = new AsyncCall<TRequest, TResponse>(call);
asyncCall.StartDuplexStreamingCall();
var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
return new AsyncDuplexStreamingCall<TRequest, TResponse>(requestStream, responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel);
}
private static void RegisterCancellationCallback<TRequest, TResponse>(AsyncCall<TRequest, TResponse> asyncCall, CancellationToken token)
{
if (token.CanBeCanceled)
{
token.Register(() => asyncCall.Cancel());
}
}
}
}

@ -178,22 +178,6 @@ namespace Grpc.Core
}
}
internal CompletionQueueSafeHandle CompletionQueue
{
get
{
return this.environment.CompletionQueue;
}
}
internal CompletionRegistry CompletionRegistry
{
get
{
return this.environment.CompletionRegistry;
}
}
internal GrpcEnvironment Environment
{
get

@ -76,19 +76,17 @@ namespace Grpc.Core
/// <summary>
/// Creates a new call to given method.
/// </summary>
protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method, Metadata metadata, DateTime? deadline)
protected CallInvocationDetails<TRequest, TResponse> CreateCall<TRequest, TResponse>(Method<TRequest, TResponse> method, CallOptions options)
where TRequest : class
where TResponse : class
{
var interceptor = HeaderInterceptor;
if (interceptor != null)
{
metadata = metadata ?? new Metadata();
interceptor(metadata);
metadata.Freeze();
interceptor(options.Headers);
options.Headers.Freeze();
}
return new Call<TRequest, TResponse>(serviceName, method, channel,
metadata ?? Metadata.Empty, deadline ?? DateTime.MaxValue);
return new CallInvocationDetails<TRequest, TResponse>(channel, method, options);
}
}
}

@ -57,7 +57,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RpcException.cs" />
<Compile Include="Calls.cs" />
<Compile Include="Call.cs" />
<Compile Include="AsyncClientStreamingCall.cs" />
<Compile Include="GrpcEnvironment.cs" />
<Compile Include="Status.cs" />
@ -114,6 +113,8 @@
<Compile Include="Logging\ConsoleLogger.cs" />
<Compile Include="Internal\NativeLogRedirector.cs" />
<Compile Include="ChannelState.cs" />
<Compile Include="CallInvocationDetails.cs" />
<Compile Include="CallOptions.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Grpc.Core.nuspec" />

@ -50,7 +50,7 @@ namespace Grpc.Core.Internal
{
static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
Channel channel;
readonly CallInvocationDetails<TRequest, TResponse> callDetails;
// Completion of a pending unary response if not null.
TaskCompletionSource<TResponse> unaryResponseTcs;
@ -60,26 +60,18 @@ namespace Grpc.Core.Internal
bool readObserverCompleted; // True if readObserver has already been completed.
public AsyncCall(Func<TRequest, byte[]> serializer, Func<byte[], TResponse> deserializer) : base(serializer, deserializer)
public AsyncCall(CallInvocationDetails<TRequest, TResponse> callDetails)
: base(callDetails.RequestMarshaller.Serializer, callDetails.ResponseMarshaller.Deserializer)
{
}
public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName, Timespec deadline)
{
this.channel = channel;
var call = channel.Handle.CreateCall(channel.CompletionRegistry, cq, methodName, null, deadline);
channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call);
this.callDetails = callDetails;
}
// TODO: this method is not Async, so it shouldn't be in AsyncCall class, but
// it is reusing fair amount of code in this class, so we are leaving it here.
// TODO: for other calls, you need to call Initialize, this methods calls initialize
// on its own, so there's a usage inconsistency.
/// <summary>
/// Blocking unary request - unary response call.
/// </summary>
public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers, DateTime deadline)
public TResponse UnaryCall(TRequest msg)
{
using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create())
{
@ -89,13 +81,15 @@ namespace Grpc.Core.Internal
lock (myLock)
{
Initialize(channel, cq, methodName, Timespec.FromDateTime(deadline));
Preconditions.CheckState(!started);
started = true;
Initialize(cq);
halfcloseRequested = true;
readingDone = true;
}
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
using (var ctx = BatchContextSafeHandle.Create())
{
@ -129,20 +123,22 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - unary response call.
/// </summary>
public Task<TResponse> UnaryCallAsync(TRequest msg, Metadata headers, DateTime deadline)
public Task<TResponse> UnaryCallAsync(TRequest msg)
{
lock (myLock)
{
Preconditions.CheckNotNull(call);
Preconditions.CheckState(!started);
started = true;
Initialize(callDetails.Channel.Environment.CompletionQueue);
halfcloseRequested = true;
readingDone = true;
byte[] payload = UnsafeSerialize(msg);
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartUnary(payload, HandleUnaryResponse, metadataArray);
}
@ -154,17 +150,19 @@ namespace Grpc.Core.Internal
/// Starts a streamed request - unary response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
public Task<TResponse> ClientStreamingCallAsync(Metadata headers, DateTime deadline)
public Task<TResponse> ClientStreamingCallAsync()
{
lock (myLock)
{
Preconditions.CheckNotNull(call);
Preconditions.CheckState(!started);
started = true;
Initialize(callDetails.Channel.Environment.CompletionQueue);
readingDone = true;
unaryResponseTcs = new TaskCompletionSource<TResponse>();
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartClientStreaming(HandleUnaryResponse, metadataArray);
}
@ -176,19 +174,21 @@ namespace Grpc.Core.Internal
/// <summary>
/// Starts a unary request - streamed response call.
/// </summary>
public void StartServerStreamingCall(TRequest msg, Metadata headers, DateTime deadline)
public void StartServerStreamingCall(TRequest msg)
{
lock (myLock)
{
Preconditions.CheckNotNull(call);
Preconditions.CheckState(!started);
started = true;
Initialize(callDetails.Channel.Environment.CompletionQueue);
halfcloseRequested = true;
halfclosed = true; // halfclose not confirmed yet, but it will be once finishedHandler is called.
byte[] payload = UnsafeSerialize(msg);
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartServerStreaming(payload, HandleFinished, metadataArray);
}
@ -199,15 +199,16 @@ namespace Grpc.Core.Internal
/// Starts a streaming request - streaming response call.
/// Use StartSendMessage and StartSendCloseFromClient to stream requests.
/// </summary>
public void StartDuplexStreamingCall(Metadata headers, DateTime deadline)
public void StartDuplexStreamingCall()
{
lock (myLock)
{
Preconditions.CheckNotNull(call);
Preconditions.CheckState(!started);
started = true;
using (var metadataArray = MetadataArraySafeHandle.Create(headers))
Initialize(callDetails.Channel.Environment.CompletionQueue);
using (var metadataArray = MetadataArraySafeHandle.Create(callDetails.Options.Headers))
{
call.StartDuplexStreaming(HandleFinished, metadataArray);
}
@ -309,7 +310,26 @@ namespace Grpc.Core.Internal
protected override void OnReleaseResources()
{
channel.Environment.DebugStats.ActiveClientCalls.Decrement();
callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Decrement();
}
private void Initialize(CompletionQueueSafeHandle cq)
{
var call = callDetails.Channel.Handle.CreateCall(callDetails.Channel.Environment.CompletionRegistry, cq,
callDetails.Method, callDetails.Host, Timespec.FromDateTime(callDetails.Options.Deadline));
callDetails.Channel.Environment.DebugStats.ActiveClientCalls.Increment();
InitializeInternal(call);
RegisterCancellationCallback();
}
// Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.
private void RegisterCancellationCallback()
{
var token = callDetails.Options.CancellationToken;
if (token.CanBeCanceled)
{
token.Register(() => this.Cancel());
}
}
/// <summary>

@ -53,16 +53,20 @@ namespace Grpc.Core
public class Method<TRequest, TResponse>
{
readonly MethodType type;
readonly string serviceName;
readonly string name;
readonly Marshaller<TRequest> requestMarshaller;
readonly Marshaller<TResponse> responseMarshaller;
readonly string fullName;
public Method(MethodType type, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
public Method(MethodType type, string serviceName, string name, Marshaller<TRequest> requestMarshaller, Marshaller<TResponse> responseMarshaller)
{
this.type = type;
this.name = name;
this.requestMarshaller = requestMarshaller;
this.responseMarshaller = responseMarshaller;
this.serviceName = Preconditions.CheckNotNull(serviceName);
this.name = Preconditions.CheckNotNull(name);
this.requestMarshaller = Preconditions.CheckNotNull(requestMarshaller);
this.responseMarshaller = Preconditions.CheckNotNull(responseMarshaller);
this.fullName = GetFullName(serviceName);
}
public MethodType Type
@ -72,6 +76,14 @@ namespace Grpc.Core
return this.type;
}
}
public string ServiceName
{
get
{
return this.serviceName;
}
}
public string Name
{
@ -97,6 +109,14 @@ namespace Grpc.Core
}
}
public string FullName
{
get
{
return this.fullName;
}
}
/// <summary>
/// Gets full name of the method including the service name.
/// </summary>

@ -65,7 +65,7 @@ namespace Grpc.Core
this.cancellationToken = cancellationToken;
}
/// <summary> Name of method called in this RPC. </summary>
/// <summary>Name of method called in this RPC.</summary>
public string Method
{
get
@ -74,7 +74,7 @@ namespace Grpc.Core
}
}
/// <summary> Name of host called in this RPC. </summary>
/// <summary>Name of host called in this RPC.</summary>
public string Host
{
get
@ -83,7 +83,7 @@ namespace Grpc.Core
}
}
/// <summary> Address of the remote endpoint in URI format. </summary>
/// <summary>Address of the remote endpoint in URI format.</summary>
public string Peer
{
get
@ -92,7 +92,7 @@ namespace Grpc.Core
}
}
/// <summary> Deadline for this RPC. </summary>
/// <summary>Deadline for this RPC.</summary>
public DateTime Deadline
{
get
@ -101,7 +101,7 @@ namespace Grpc.Core
}
}
/// <summary> Initial metadata sent by client. </summary>
/// <summary>Initial metadata sent by client.</summary>
public Metadata RequestHeaders
{
get
@ -110,8 +110,7 @@ namespace Grpc.Core
}
}
// TODO(jtattermusch): support signalling cancellation.
/// <summary> Cancellation token signals when call is cancelled. </summary>
///<summary>Cancellation token signals when call is cancelled.</summary>
public CancellationToken CancellationToken
{
get
@ -120,7 +119,7 @@ namespace Grpc.Core
}
}
/// <summary> Trailers to send back to client after RPC finishes.</summary>
/// <summary>Trailers to send back to client after RPC finishes.</summary>
public Metadata ResponseTrailers
{
get

@ -19,24 +19,28 @@ namespace math {
static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_Div = new Method<global::math.DivArgs, global::math.DivReply>(
MethodType.Unary,
__ServiceName,
"Div",
__Marshaller_DivArgs,
__Marshaller_DivReply);
static readonly Method<global::math.DivArgs, global::math.DivReply> __Method_DivMany = new Method<global::math.DivArgs, global::math.DivReply>(
MethodType.DuplexStreaming,
__ServiceName,
"DivMany",
__Marshaller_DivArgs,
__Marshaller_DivReply);
static readonly Method<global::math.FibArgs, global::math.Num> __Method_Fib = new Method<global::math.FibArgs, global::math.Num>(
MethodType.ServerStreaming,
__ServiceName,
"Fib",
__Marshaller_FibArgs,
__Marshaller_Num);
static readonly Method<global::math.Num, global::math.Num> __Method_Sum = new Method<global::math.Num, global::math.Num>(
MethodType.ClientStreaming,
__ServiceName,
"Sum",
__Marshaller_Num,
__Marshaller_Num);
@ -45,10 +49,15 @@ namespace math {
public interface IMathClient
{
global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::math.DivReply Div(global::math.DivArgs request, CallOptions options);
AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options);
AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options);
AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options);
AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options);
}
// server-side interface
@ -68,28 +77,53 @@ namespace math {
}
public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Div, headers, deadline);
return Calls.BlockingUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::math.DivReply Div(global::math.DivArgs request, CallOptions options)
{
var call = CreateCall(__Method_Div, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Div, headers, deadline);
return Calls.AsyncUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::math.DivReply> DivAsync(global::math.DivArgs request, CallOptions options)
{
var call = CreateCall(__Method_Div, options);
return Calls.AsyncUnaryCall(call, request);
}
public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_DivMany, headers, deadline);
return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
public AsyncDuplexStreamingCall<global::math.DivArgs, global::math.DivReply> DivMany(CallOptions options)
{
var call = CreateCall(__Method_DivMany, options);
return Calls.AsyncDuplexStreamingCall(call);
}
public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Fib, headers, deadline);
return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncServerStreamingCall(call, request);
}
public AsyncServerStreamingCall<global::math.Num> Fib(global::math.FibArgs request, CallOptions options)
{
var call = CreateCall(__Method_Fib, options);
return Calls.AsyncServerStreamingCall(call, request);
}
public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Sum, headers, deadline);
return Calls.AsyncClientStreamingCall(call, cancellationToken);
var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncClientStreamingCall(call);
}
public AsyncClientStreamingCall<global::math.Num, global::math.Num> Sum(CallOptions options)
{
var call = CreateCall(__Method_Sum, options);
return Calls.AsyncClientStreamingCall(call);
}
}

@ -17,6 +17,7 @@ namespace Grpc.Health.V1Alpha {
static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
MethodType.Unary,
__ServiceName,
"Check",
__Marshaller_HealthCheckRequest,
__Marshaller_HealthCheckResponse);
@ -25,7 +26,9 @@ namespace Grpc.Health.V1Alpha {
public interface IHealthClient
{
global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options);
AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options);
}
// server-side interface
@ -42,13 +45,23 @@ namespace Grpc.Health.V1Alpha {
}
public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Check, headers, deadline);
return Calls.BlockingUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options)
{
var call = CreateCall(__Method_Check, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_Check, headers, deadline);
return Calls.AsyncUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options)
{
var call = CreateCall(__Method_Check, options);
return Calls.AsyncUnaryCall(call, request);
}
}

@ -22,36 +22,42 @@ namespace grpc.testing {
static readonly Method<global::grpc.testing.Empty, global::grpc.testing.Empty> __Method_EmptyCall = new Method<global::grpc.testing.Empty, global::grpc.testing.Empty>(
MethodType.Unary,
__ServiceName,
"EmptyCall",
__Marshaller_Empty,
__Marshaller_Empty);
static readonly Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse> __Method_UnaryCall = new Method<global::grpc.testing.SimpleRequest, global::grpc.testing.SimpleResponse>(
MethodType.Unary,
__ServiceName,
"UnaryCall",
__Marshaller_SimpleRequest,
__Marshaller_SimpleResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_StreamingOutputCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.ServerStreaming,
__ServiceName,
"StreamingOutputCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
static readonly Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> __Method_StreamingInputCall = new Method<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse>(
MethodType.ClientStreaming,
__ServiceName,
"StreamingInputCall",
__Marshaller_StreamingInputCallRequest,
__Marshaller_StreamingInputCallResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_FullDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
__ServiceName,
"FullDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
static readonly Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> __Method_HalfDuplexCall = new Method<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse>(
MethodType.DuplexStreaming,
__ServiceName,
"HalfDuplexCall",
__Marshaller_StreamingOutputCallRequest,
__Marshaller_StreamingOutputCallResponse);
@ -60,13 +66,21 @@ namespace grpc.testing {
public interface ITestServiceClient
{
global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options);
AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options);
global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options);
AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options);
AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options);
AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
}
// server-side interface
@ -88,43 +102,83 @@ namespace grpc.testing {
}
public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline);
return Calls.BlockingUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_EmptyCall, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline);
return Calls.AsyncUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::grpc.testing.Empty> EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options)
{
var call = CreateCall(__Method_EmptyCall, options);
return Calls.AsyncUnaryCall(call, request);
}
public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline);
return Calls.BlockingUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request);
}
public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options)
{
var call = CreateCall(__Method_UnaryCall, options);
return Calls.BlockingUnaryCall(call, request);
}
public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline);
return Calls.AsyncUnaryCall(call, request, cancellationToken);
var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request);
}
public AsyncUnaryCall<global::grpc.testing.SimpleResponse> UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options)
{
var call = CreateCall(__Method_UnaryCall, options);
return Calls.AsyncUnaryCall(call, request);
}
public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers, deadline);
return Calls.AsyncServerStreamingCall(call, request, cancellationToken);
var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncServerStreamingCall(call, request);
}
public AsyncServerStreamingCall<global::grpc.testing.StreamingOutputCallResponse> StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options)
{
var call = CreateCall(__Method_StreamingOutputCall, options);
return Calls.AsyncServerStreamingCall(call, request);
}
public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers, deadline);
return Calls.AsyncClientStreamingCall(call, cancellationToken);
var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncClientStreamingCall(call);
}
public AsyncClientStreamingCall<global::grpc.testing.StreamingInputCallRequest, global::grpc.testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
{
var call = CreateCall(__Method_StreamingInputCall, options);
return Calls.AsyncClientStreamingCall(call);
}
public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers, deadline);
return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
{
var call = CreateCall(__Method_FullDuplexCall, options);
return Calls.AsyncDuplexStreamingCall(call);
}
public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{
var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers, deadline);
return Calls.AsyncDuplexStreamingCall(call, cancellationToken);
var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncDuplexStreamingCall(call);
}
public AsyncDuplexStreamingCall<global::grpc.testing.StreamingOutputCallRequest, global::grpc.testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
{
var call = CreateCall(__Method_HalfDuplexCall, options);
return Calls.AsyncDuplexStreamingCall(call);
}
}

@ -379,7 +379,8 @@ GPR_EXPORT grpc_call *GPR_CALLTYPE
grpcsharp_channel_create_call(grpc_channel *channel, grpc_completion_queue *cq,
const char *method, const char *host,
gpr_timespec deadline) {
return grpc_channel_create_call(channel, cq, method, host, deadline);
return grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
method, host, deadline);
}
GPR_EXPORT grpc_connectivity_state GPR_CALLTYPE

@ -511,8 +511,9 @@ NAN_METHOD(Call::New) {
double deadline = args[2]->NumberValue();
grpc_channel *wrapped_channel = channel->GetWrappedChannel();
grpc_call *wrapped_call = grpc_channel_create_call(
wrapped_channel, CompletionQueueAsyncWorker::GetQueue(), *method,
channel->GetHost(), MillisecondsToTimespec(deadline));
wrapped_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
CompletionQueueAsyncWorker::GetQueue(), *method, channel->GetHost(),
MillisecondsToTimespec(deadline));
call = new Call(wrapped_call);
args.This()->SetHiddenValue(NanNew("channel_"), channel_object);
}

@ -0,0 +1,45 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import "GRPCCall.h"
@interface GRPCCall (Tests)
// Establish all SSL connections to the provided host using the passed SSL target name and the root
// certificates found in the file at |certsPath|.
// Must be called before any gRPC call to that host is made.
+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host;
@end

@ -0,0 +1,47 @@
/*
*
* 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 "GRPCCall+Tests.h"
#import "private/GRPCHost.h"
@implementation GRPCCall (Tests)
+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = YES;
hostConfig.pathToCertificates = certsPath;
hostConfig.hostNameOverride = testName;
}
@end

@ -37,7 +37,6 @@
#include <grpc/support/time.h>
#import <RxLibrary/GRXConcurrentWriteable.h>
#import "private/GRPCChannel.h"
#import "private/GRPCWrappedCall.h"
#import "private/NSData+GRPC.h"
#import "private/NSDictionary+GRPC.h"
@ -70,8 +69,6 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
GRPCWrappedCall *_wrappedCall;
dispatch_once_t _callAlreadyInvoked;
GRPCChannel *_channel;
// The C gRPC library has less guarantees on the ordering of events than we
// do. Particularly, in the face of errors, there's no ordering guarantee at
// all. This wrapper over our actual writeable ensures thread-safety and
@ -105,11 +102,10 @@ NSString * const kGRPCStatusMetadataKey = @"io.grpc.StatusMetadataKey";
format:@"The requests writer can't be already started."];
}
if ((self = [super init])) {
_channel = [GRPCChannel channelToHost:host];
_wrappedCall = [[GRPCWrappedCall alloc] initWithChannel:_channel
path:path
host:host];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:host path:path];
if (!_wrappedCall) {
return nil;
}
// Serial queue to invoke the non-reentrant methods of the grpc_call object.
_callQueue = dispatch_queue_create("org.grpc.call", NULL);

@ -35,17 +35,12 @@
struct grpc_channel;
// Each separate instance of this class represents at least one TCP
// connection to the provided host. To create a grpc_call, pass the
// value of the unmanagedChannel property to grpc_channel_create_call.
// Release this object when the call is finished.
// Each separate instance of this class represents at least one TCP connection to the provided host.
// Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
@interface GRPCChannel : NSObject
@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
// Convenience constructor to allow for reuse of connections.
+ (instancetype)channelToHost:(NSString *)host;
- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
// This initializer takes ownership of the passed channel, and will destroy it when this object is
// deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects.
- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
@end

@ -35,53 +35,17 @@
#include <grpc/grpc.h>
#import "GRPCSecureChannel.h"
#import "GRPCUnsecuredChannel.h"
@implementation GRPCChannel
+ (instancetype)channelToHost:(NSString *)host {
// TODO(mlumish): Investigate whether a cache with strong links is a good idea
static NSMutableDictionary *channelCache;
static dispatch_once_t cacheInitialization;
dispatch_once(&cacheInitialization, ^{
channelCache = [NSMutableDictionary dictionary];
});
GRPCChannel *channel = channelCache[host];
if (!channel) {
channel = [[self alloc] initWithHost:host];
channelCache[host] = channel;
}
return channel;
}
- (instancetype)init {
return [self initWithHost:nil];
return [self initWithChannel:NULL];
}
- (instancetype)initWithHost:(NSString *)host {
if (![host rangeOfString:@"://"].length) {
// No scheme provided; assume https.
host = [@"https://" stringByAppendingString:host];
}
NSURL *hostURL = [NSURL URLWithString:host];
if (!hostURL) {
[NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", host];
// Designated initializer
- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
if (!unmanagedChannel) {
return nil;
}
if ([hostURL.scheme isEqualToString:@"https"]) {
host = [@[hostURL.host, hostURL.port ?: @443] componentsJoinedByString:@":"];
return [[GRPCSecureChannel alloc] initWithHost:host];
}
if ([hostURL.scheme isEqualToString:@"http"]) {
host = [@[hostURL.host, hostURL.port ?: @80] componentsJoinedByString:@":"];
return [[GRPCUnsecuredChannel alloc] initWithHost:host];
}
[NSException raise:NSInvalidArgumentException
format:@"URL scheme %@ isn't supported.", hostURL.scheme];
return nil; // silence warning.
}
- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel {
if ((self = [super init])) {
_unmanagedChannel = unmanagedChannel;
}
@ -89,12 +53,8 @@
}
- (void)dealloc {
// _unmanagedChannel is NULL when deallocating an object of the base class (because the
// initializer returns a different object).
if (_unmanagedChannel) {
// TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
// as in the past that made this call to crash.
grpc_channel_destroy(_unmanagedChannel);
}
// 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

@ -38,8 +38,6 @@
@implementation GRPCCompletionQueue
+ (instancetype)completionQueue {
// TODO(jcanizales): Reuse completion queues to consume only one thread,
// instead of one per call.
return [[self alloc] init];
}

@ -0,0 +1,58 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import <Foundation/Foundation.h>
@class GRPCCompletionQueue;
struct grpc_call;
@interface GRPCHost : NSObject
@property(nonatomic, readonly) NSString *address;
// The following properties should only be modified for testing:
@property(nonatomic, getter=isSecure) BOOL secure;
@property(nonatomic, copy) NSString *pathToCertificates;
@property(nonatomic, copy) NSString *hostNameOverride;
// Host objects initialized with the same address are the same.
+ (instancetype)hostWithAddress:(NSString *)address;
- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
// Create a grpc_call object to the provided path on this host.
- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
completionQueue:(GRPCCompletionQueue *)queue;
@end

@ -0,0 +1,134 @@
/*
*
* 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 "GRPCHost.h"
#include <grpc/grpc.h>
#import "GRPCChannel.h"
#import "GRPCCompletionQueue.h"
#import "GRPCSecureChannel.h"
#import "GRPCUnsecuredChannel.h"
@interface GRPCHost ()
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@property(nonatomic, strong) GRPCChannel *channel;
@end
@implementation GRPCHost
+ (instancetype)hostWithAddress:(NSString *)address {
return [[self alloc] initWithAddress:address];
}
- (instancetype)init {
return [self initWithAddress:nil];
}
// Default initializer.
- (instancetype)initWithAddress:(NSString *)address {
// Verify and normalize the address, and decide whether to use SSL.
if (![address rangeOfString:@"://"].length) {
// No scheme provided; assume https.
address = [@"https://" stringByAppendingString:address];
}
NSURL *hostURL = [NSURL URLWithString:address];
if (!hostURL) {
[NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", address];
}
NSString *scheme = hostURL.scheme;
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
[NSException raise:NSInvalidArgumentException format:@"URL scheme %@ isn't supported.", scheme];
}
// If the user didn't specify a port (hostURL.port is nil), provide a default one.
NSNumber *port = hostURL.port ?: [scheme isEqualToString:@"https"] ? @443 : @80;
address = [@[hostURL.host, port] componentsJoinedByString:@":"];
// Look up the GRPCHost in the cache.
static NSMutableDictionary *hostCache;
static dispatch_once_t cacheInitialization;
dispatch_once(&cacheInitialization, ^{
hostCache = [NSMutableDictionary dictionary];
});
@synchronized(hostCache) {
GRPCHost *cachedHost = hostCache[address];
if (cachedHost) {
// We could verify here that the cached host uses the same protocol that we're expecting. But
// creating non-SSL channels by adding "http://" to the address is going away (to make the use
// of insecure channels less subtle), so it's not worth it now.
return cachedHost;
}
if ((self = [super init])) {
_address = address;
_secure = [scheme isEqualToString:@"https"];
hostCache[address] = self;
}
return self;
}
}
- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
if (!queue || !path || !self.channel) {
return NULL;
}
return grpc_channel_create_call(self.channel.unmanagedChannel,
NULL, GRPC_PROPAGATE_DEFAULTS,
queue.unmanagedQueue,
path.UTF8String,
self.hostName.UTF8String,
gpr_inf_future(GPR_CLOCK_REALTIME));
}
- (GRPCChannel *)channel {
// Create it lazily, because we don't want to open a connection just because someone is
// configuring a host.
if (!_channel) {
if (_secure) {
_channel = [[GRPCSecureChannel alloc] initWithHost:_address
pathToCertificates:_pathToCertificates
hostNameOverride:_hostNameOverride];
} else {
_channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address];
}
}
return _channel;
}
- (NSString *)hostName {
// TODO(jcanizales): Default to nil instead of _address when Issue #2635 is clarified.
return _hostNameOverride ?: _address;
}
@end

@ -31,8 +31,23 @@
*
*/
#include <grpc/grpc.h>
#import "GRPCChannel.h"
struct grpc_credentials;
@interface GRPCSecureChannel : GRPCChannel
- (instancetype)initWithHost:(NSString *)host;
// Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for
// pathToCertificates results in using the default root certificates distributed with the library.
- (instancetype)initWithHost:(NSString *)host
pathToCertificates:(NSString *)path
hostNameOverride:(NSString *)hostNameOverride;
// The passed arguments aren't required to be valid beyond the invocation of this initializer.
- (instancetype)initWithHost:(NSString *)host
credentials:(struct grpc_credentials *)credentials
args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
@end

@ -33,28 +33,80 @@
#import "GRPCSecureChannel.h"
#import <grpc/grpc_security.h>
#include <grpc/grpc_security.h>
// Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL,
// *errorPtr will be an object describing what went wrong.
static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
NSString *certsContent = [NSString stringWithContentsOfFile:path
encoding:NSASCIIStringEncoding
error:errorPtr];
if (!certsContent) {
// Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
return NULL;
}
const char * asCString = [certsContent cStringUsingEncoding:NSASCIIStringEncoding];
return grpc_ssl_credentials_create(asCString, NULL);
}
@implementation GRPCSecureChannel
- (instancetype)initWithHost:(NSString *)host {
static grpc_credentials *kCredentials;
return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil];
}
- (instancetype)initWithHost:(NSString *)host
pathToCertificates:(NSString *)path
hostNameOverride:(NSString *)hostNameOverride {
// Load default SSL certificates once.
static grpc_credentials *kDefaultCertificates;
static dispatch_once_t loading;
dispatch_once(&loading, ^{
NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
// Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *certsPath = [bundle pathForResource:@"gRPCCertificates.bundle/roots" ofType:@"pem"];
NSAssert(certsPath.length,
@"gRPCCertificates.bundle/roots.pem not found under %@. This file, with the root "
"certificates, is needed to establish TLS (HTTPS) connections.", bundle.bundlePath);
NSData *certsData = [NSData dataWithContentsOfFile:certsPath];
NSAssert(certsData.length, @"No data read from %@", certsPath);
NSString *certsString = [[NSString alloc] initWithData:certsData encoding:NSUTF8StringEncoding];
kCredentials = grpc_ssl_credentials_create(certsString.UTF8String, NULL);
NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
NSError *error;
kDefaultCertificates = CertificatesAtPath(path, &error);
NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
"certificates, is needed to establish secure (TLS) connections. Because the file is "
"distributed with the gRPC library, this error is usually a sign that the library "
"wasn't configured correctly for your project. Error: %@",
bundle.bundlePath, defaultPath, error);
});
return (self = [super initWithChannel:grpc_secure_channel_create(kCredentials,
host.UTF8String,
NULL)]);
//TODO(jcanizales): Add NSError** parameter to the initializer.
grpc_credentials *certificates = path ? CertificatesAtPath(path, NULL) : kDefaultCertificates;
if (!certificates) {
return nil;
}
// Ritual to pass the SSL host name override to the C library.
grpc_channel_args channelArgs;
grpc_arg nameOverrideArg;
channelArgs.num_args = 1;
channelArgs.args = &nameOverrideArg;
nameOverrideArg.type = GRPC_ARG_STRING;
nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
// Cast const away. Hope C gRPC doesn't modify it!
nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String;
grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL;
return [self initWithHost:host credentials:certificates args:args];
}
- (instancetype)initWithHost:(NSString *)host
credentials:(grpc_credentials *)credentials
args:(grpc_channel_args *)args {
return (self =
[super initWithChannel:grpc_secure_channel_create(credentials, host.UTF8String, args)]);
}
// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
[NSException raise:NSInternalInconsistencyException format:@"use another initializer"];
return [self initWithHost:nil]; // silence warnings
}
@end

@ -34,5 +34,5 @@
#import "GRPCChannel.h"
@interface GRPCUnsecuredChannel : GRPCChannel
- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
@end

@ -41,4 +41,10 @@
return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL)]);
}
// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
[NSException raise:NSInternalInconsistencyException format:@"use the other initializer"];
return [self initWithHost:nil]; // silence warnings
}
@end

@ -81,11 +81,12 @@
@end
#pragma mark GRPCWrappedCall
@interface GRPCWrappedCall : NSObject
- (instancetype)initWithChannel:(GRPCChannel *)channel
path:(NSString *)path
host:(NSString *)host NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path NS_DESIGNATED_INITIALIZER;
- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)())errorHandler;

@ -32,11 +32,14 @@
*/
#import "GRPCWrappedCall.h"
#import <Foundation/Foundation.h>
#include <grpc/grpc.h>
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#import "GRPCCompletionQueue.h"
#import "GRPCHost.h"
#import "NSDictionary+GRPC.h"
#import "NSData+GRPC.h"
#import "NSError+GRPC.h"
@ -219,38 +222,36 @@
@end
@implementation GRPCWrappedCall{
grpc_call *_call;
#pragma mark GRPCWrappedCall
@implementation GRPCWrappedCall {
GRPCCompletionQueue *_queue;
grpc_call *_call;
}
- (instancetype)init {
return [self initWithChannel:nil path:nil host:nil];
return [self initWithHost:nil path:nil];
}
- (instancetype)initWithChannel:(GRPCChannel *)channel
path:(NSString *)path
host:(NSString *)host {
if (!channel || !path || !host) {
- (instancetype)initWithHost:(NSString *)host
path:(NSString *)path {
if (!path || !host) {
[NSException raise:NSInvalidArgumentException
format:@"channel, method, and host cannot be nil."];
format:@"path and host cannot be nil."];
}
if (self = [super init]) {
static dispatch_once_t initialization;
dispatch_once(&initialization, ^{
grpc_init();
});
// Each completion queue consumes one thread. There's a trade to be made between creating and
// consuming too many threads and having contention of multiple calls in a single completion
// queue. Currently we favor latency and use one per call.
_queue = [GRPCCompletionQueue completionQueue];
if (!_queue) {
return nil;
}
_call = grpc_channel_create_call(channel.unmanagedChannel,
_queue.unmanagedQueue,
path.UTF8String,
host.UTF8String,
gpr_inf_future(GPR_CLOCK_REALTIME));
_call = [[GRPCHost hostWithAddress:host] unmanagedCallWithPath:path completionQueue:_queue];
if (_call == NULL) {
return nil;
}
@ -299,4 +300,4 @@
grpc_call_destroy(_call);
}
@end
@end

@ -0,0 +1,44 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#import <XCTest/XCTest.h>
// Implements tests as described here:
// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
@interface InteropTests : XCTestCase
// Returns @"http://localhost:5050".
// Override in a subclass to perform the same tests against a different address.
// For interop tests, use @"grpc-test.sandbox.google.com".
+ (NSString *)host;
@end

@ -31,10 +31,9 @@
*
*/
#include <grpc/status.h>
#import "InteropTests.h"
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#include <grpc/status.h>
#import <ProtoRPC/ProtoRPC.h>
#import <RemoteTest/Empty.pbobjc.h>
@ -76,21 +75,18 @@
}
@end
@interface InteropTests : XCTestCase
@end
@implementation InteropTests {
RMTTestService *_service;
}
// grpc-test.sandbox.google.com
+ (NSString *)host {
return @"http://localhost:5050";
}
- (void)setUp {
_service = [[RMTTestService alloc] initWithHost:@"http://localhost:5050"];
_service = [[RMTTestService alloc] initWithHost:self.class.host];
}
// Tests as described here: https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
- (void)testEmptyUnaryRPC {
__weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyUnary"];

@ -0,0 +1,62 @@
/*
*
* 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.
*
*/
// Repeat of the tests in InteropTests.m, but using SSL to communicate with the local server instead
// of cleartext.
#import <GRPCClient/GRPCCall+Tests.h>
#import "InteropTests.h"
static NSString * const kLocalSSLHost = @"localhost:5051";
@interface InteropTestsLocalSSL : InteropTests
@end
@implementation InteropTestsLocalSSL
+ (NSString *)host {
return kLocalSSLHost;
}
- (void)setUp {
// Register test server certificates and name.
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates"
ofType:@"pem"];
[GRPCCall useTestCertsPath:certsPath testName:@"foo.test.google.fr" forHost:kLocalSSLHost];
[super setUp];
}
@end

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
Dfcog5wrJytaQ6UA0wE=
-----END CERTIFICATE-----

@ -13,6 +13,8 @@
63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 63423F501B151B77006CF63C /* RxLibraryUnitTests.m */; };
635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; };
635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
7D8A186224D39101F90230F6 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */; };
/* End PBXBuildFile section */
@ -49,6 +51,9 @@
635697CC1B14FC11007A7283 /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
635697D81B14FC11007A7283 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTests.m; sourceTree = "<group>"; };
63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = "<group>"; };
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = "<group>"; };
FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -93,6 +98,7 @@
isa = PBXGroup;
children = (
635697C91B14FC11007A7283 /* Tests */,
63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */,
635697C81B14FC11007A7283 /* Products */,
51E4650F34F854F41FF053B3 /* Pods */,
136D535E19727099B941D7B1 /* Frameworks */,
@ -111,12 +117,14 @@
635697C91B14FC11007A7283 /* Tests */ = {
isa = PBXGroup;
children = (
63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */,
6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */,
63175DFE1B1B9FAF00027841 /* LocalClearTextTests.m */,
635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */,
63423F501B151B77006CF63C /* RxLibraryUnitTests.m */,
635697CC1B14FC11007A7283 /* Tests.m */,
635697D71B14FC11007A7283 /* Supporting Files */,
63E240CC1B6C4D3A005F3B0E /* InteropTests.h */,
);
name = Tests;
sourceTree = SOURCE_ROOT;
@ -209,6 +217,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
63E240D01B6C63DC005F3B0E /* TestCertificates.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -254,6 +263,7 @@
files = (
63175DFF1B1B9FAF00027841 /* LocalClearTextTests.m in Sources */,
63423F511B151B77006CF63C /* RxLibraryUnitTests.m in Sources */,
63E240CE1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m in Sources */,
6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */,
635ED2EC1B1A3BC400FDE5C3 /* InteropTests.m in Sources */,
);

@ -37,7 +37,8 @@ cd $(dirname $0)
# Run the tests server.
../../../bins/$CONFIG/interop_server --port=5050 &
# Kill it when this script exits.
../../../bins/$CONFIG/interop_server --port=5051 --enable_ssl &
# Kill them when this script exits.
trap 'kill -9 `jobs -p`' EXIT
# xcodebuild is very verbose. We filter its output and tell Bash to fail if any

@ -240,8 +240,8 @@ PHP_METHOD(Call, __construct) {
(wrapped_grpc_timeval *)zend_object_store_get_object(
deadline_obj TSRMLS_CC);
call->wrapped = grpc_channel_create_call(
channel->wrapped, completion_queue, method, channel->target,
deadline->wrapped);
channel->wrapped, NULL, GRPC_PROPAGATE_DEFAULTS, completion_queue, method,
channel->target, deadline->wrapped);
}
/**

@ -6,3 +6,4 @@ dist/
*.egg/
*.eggs/
doc/
_grpcio_metadata.py

@ -34,6 +34,7 @@ import os.path
import sys
import setuptools
from setuptools.command import build_py
_CONF_PY_ADDENDUM = """
extensions.append('sphinx.ext.napoleon')
@ -74,3 +75,28 @@ class SphinxDocumentation(setuptools.Command):
conf_file.write(_CONF_PY_ADDENDUM)
sphinx.main(['', os.path.join('doc', 'src'), os.path.join('doc', 'build')])
class BuildProjectMetadata(setuptools.Command):
"""Command to generate project metadata in a module."""
description = ''
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
with open('grpc/_grpcio_metadata.py', 'w') as module_file:
module_file.write('__version__ = """{}"""'.format(
self.distribution.get_version()))
class BuildPy(build_py.build_py):
"""Custom project build command."""
def run(self):
self.run_command('build_project_metadata')
build_py.build_py.run(self)

@ -128,7 +128,7 @@ Call *pygrpc_Channel_create_call(
}
call = pygrpc_Call_new_empty(cq);
call->c_call = grpc_channel_create_call(
self->c_chan, cq->c_cq, method, host,
self->c_chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq->c_cq, method, host,
pygrpc_cast_double_to_gpr_timespec(deadline));
return call;
}

@ -98,6 +98,8 @@ _SETUP_REQUIRES = (
_COMMAND_CLASS = {
'doc': commands.SphinxDocumentation,
'build_project_metadata': commands.BuildProjectMetadata,
'build_py': commands.BuildPy,
}
setuptools.setup(

@ -212,10 +212,10 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method,
return Qnil;
}
call =
grpc_channel_create_call(ch, cq, method_chars, host_chars,
grpc_rb_time_timeval(deadline,
/* absolute time */ 0));
call = grpc_channel_create_call(ch, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
method_chars, host_chars,
grpc_rb_time_timeval(deadline,
/* absolute time */ 0));
if (call == NULL) {
rb_raise(rb_eRuntimeError, "cannot create call with method %s",
method_chars);

@ -4,7 +4,7 @@ import json
${json.dumps([{"name": tgt.name,
"language": tgt.language,
"platforms": tgt.platforms,
"platforms": tgt.platforms,
"flaky": tgt.flaky}
for tgt in targets
if tgt.get('run', True) and tgt.build == 'test'],

@ -131,8 +131,8 @@ void test_connect(const char *server_host, const char *client_host, int port,
}
/* Send a trivial request. */
c = grpc_channel_create_call(client, cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
op = ops;

@ -53,8 +53,8 @@
typedef struct fullstack_compression_fixture_data {
char *localaddr;
grpc_channel_args* client_args_compression;
grpc_channel_args* server_args_compression;
grpc_channel_args *client_args_compression;
grpc_channel_args *server_args_compression;
} fullstack_compression_fixture_data;
static grpc_end2end_test_fixture chttp2_create_fixture_fullstack_compression(
@ -75,7 +75,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_fullstack_compression(
}
void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
grpc_channel_args *client_args) {
fullstack_compression_fixture_data *ffd = f->fixture_data;
if (ffd->client_args_compression != NULL) {
grpc_channel_args_destroy(ffd->client_args_compression);
@ -87,7 +87,7 @@ void chttp2_init_client_fullstack_compression(grpc_end2end_test_fixture *f,
}
void chttp2_init_server_fullstack_compression(grpc_end2end_test_fixture *f,
grpc_channel_args *server_args) {
grpc_channel_args *server_args) {
fullstack_compression_fixture_data *ffd = f->fixture_data;
if (ffd->server_args_compression != NULL) {
grpc_channel_args_destroy(ffd->server_args_compression);

@ -0,0 +1,132 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <string.h>
#include "src/core/channel/client_channel.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/http_server_filter.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/server.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "test/core/end2end/fixtures/proxy.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
typedef struct fullstack_fixture_data {
grpc_end2end_proxy *proxy;
} fullstack_fixture_data;
static grpc_server *create_proxy_server(const char *port) {
grpc_server *s = grpc_server_create(NULL);
GPR_ASSERT(grpc_server_add_insecure_http2_port(s, port));
return s;
}
static grpc_channel *create_proxy_client(const char *target) {
return grpc_insecure_channel_create(target, NULL);
}
static const grpc_end2end_proxy_def proxy_def = {create_proxy_server,
create_proxy_client};
static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
grpc_channel_args *client_args, grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
memset(&f, 0, sizeof(f));
ffd->proxy = grpc_end2end_proxy_create(&proxy_def);
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create();
return f;
}
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args) {
fullstack_fixture_data *ffd = f->fixture_data;
f->client = grpc_insecure_channel_create(
grpc_end2end_proxy_get_client_target(ffd->proxy), client_args);
GPR_ASSERT(f->client);
}
void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *server_args) {
fullstack_fixture_data *ffd = f->fixture_data;
if (f->server) {
grpc_server_destroy(f->server);
}
f->server = grpc_server_create(server_args);
grpc_server_register_completion_queue(f->server, f->cq);
GPR_ASSERT(grpc_server_add_insecure_http2_port(
f->server, grpc_end2end_proxy_get_server_port(ffd->proxy)));
grpc_server_start(f->server);
}
void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
fullstack_fixture_data *ffd = f->fixture_data;
grpc_end2end_proxy_destroy(ffd->proxy);
gpr_free(ffd);
}
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/fullstack+proxy", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
};
int main(int argc, char **argv) {
size_t i;
grpc_test_init(argc, argv);
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
grpc_end2end_tests(configs[i]);
}
grpc_shutdown();
return 0;
}

@ -0,0 +1,193 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/end2end/end2end_tests.h"
#include <stdio.h>
#include <string.h>
#include "src/core/channel/channel_args.h"
#include "src/core/security/credentials.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include "test/core/end2end/data/ssl_test_data.h"
#include "test/core/end2end/fixtures/proxy.h"
#include "test/core/util/test_config.h"
#include "test/core/util/port.h"
typedef struct fullstack_secure_fixture_data {
grpc_end2end_proxy *proxy;
} fullstack_secure_fixture_data;
static grpc_server *create_proxy_server(const char *port) {
grpc_server *s = grpc_server_create(NULL);
grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0);
GPR_ASSERT(grpc_server_add_secure_http2_port(s, port, ssl_creds));
grpc_server_credentials_release(ssl_creds);
return s;
}
static grpc_channel *create_proxy_client(const char *target) {
grpc_channel *channel;
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.fr"}};
grpc_channel_args client_args;
client_args.num_args = 1;
client_args.args = &ssl_name_override;
channel = grpc_secure_channel_create(ssl_creds, target, &client_args);
grpc_credentials_release(ssl_creds);
return channel;
}
static const grpc_end2end_proxy_def proxy_def = {create_proxy_server,
create_proxy_client};
static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
grpc_channel_args *client_args, grpc_channel_args *server_args) {
grpc_end2end_test_fixture f;
fullstack_secure_fixture_data *ffd =
gpr_malloc(sizeof(fullstack_secure_fixture_data));
memset(&f, 0, sizeof(f));
ffd->proxy = grpc_end2end_proxy_create(&proxy_def);
f.fixture_data = ffd;
f.cq = grpc_completion_queue_create();
return f;
}
static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args,
grpc_credentials *creds) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
f->client = grpc_secure_channel_create(
creds, grpc_end2end_proxy_get_client_target(ffd->proxy), client_args);
GPR_ASSERT(f->client != NULL);
grpc_credentials_release(creds);
}
static void chttp2_init_server_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
grpc_server_credentials *server_creds) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
if (f->server) {
grpc_server_destroy(f->server);
}
f->server = grpc_server_create(server_args);
grpc_server_register_completion_queue(f->server, f->cq);
GPR_ASSERT(grpc_server_add_secure_http2_port(
f->server, grpc_end2end_proxy_get_server_port(ffd->proxy), server_creds));
grpc_server_credentials_release(server_creds);
grpc_server_start(f->server);
}
void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
fullstack_secure_fixture_data *ffd = f->fixture_data;
grpc_end2end_proxy_destroy(ffd->proxy);
gpr_free(ffd);
}
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.fr"}};
grpc_channel_args *new_client_args =
grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
grpc_channel_args_destroy(new_client_args);
}
static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0);
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
}
/* All test configurations */
static grpc_end2end_test_config configs[] = {
{"chttp2/simple_ssl_fullstack",
FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
FEATURE_MASK_SUPPORTS_HOSTNAME_VERIFICATION |
FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS,
chttp2_create_fixture_secure_fullstack,
chttp2_init_client_simple_ssl_secure_fullstack,
chttp2_init_server_simple_ssl_secure_fullstack,
chttp2_tear_down_secure_fullstack},
};
int main(int argc, char **argv) {
size_t i;
FILE *roots_file;
size_t roots_size = strlen(test_root_cert);
char *roots_filename;
grpc_test_init(argc, argv);
/* Set the SSL roots env var. */
roots_file = gpr_tmpfile("chttp2_simple_ssl_fullstack_test", &roots_filename);
GPR_ASSERT(roots_filename != NULL);
GPR_ASSERT(roots_file != NULL);
GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size);
fclose(roots_file);
gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename);
grpc_init();
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
grpc_end2end_tests(configs[i]);
}
grpc_shutdown();
/* Cleanup. */
remove(roots_filename);
gpr_free(roots_filename);
return 0;
}

@ -148,6 +148,7 @@ int main(int argc, char **argv) {
/* force tracing on, with a value to force many
code paths in trace.c to be taken */
gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all");
g_fixture_slowdown_factor = 10.0;
grpc_test_init(argc, argv);
grpc_init();

@ -0,0 +1,430 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "test/core/end2end/fixtures/proxy.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/host_port.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "test/core/util/port.h"
struct grpc_end2end_proxy {
gpr_thd_id thd;
char *proxy_port;
char *server_port;
grpc_completion_queue *cq;
grpc_server *server;
grpc_channel *client;
int shutdown;
/* requested call */
grpc_call *new_call;
grpc_call_details new_call_details;
grpc_metadata_array new_call_metadata;
};
typedef struct {
void (*func)(void *arg, int success);
void *arg;
} closure;
typedef struct {
gpr_refcount refs;
grpc_end2end_proxy *proxy;
grpc_call *c2p;
grpc_call *p2s;
grpc_metadata_array c2p_initial_metadata;
grpc_metadata_array p2s_initial_metadata;
grpc_byte_buffer *c2p_msg;
grpc_byte_buffer *p2s_msg;
grpc_metadata_array p2s_trailing_metadata;
grpc_status_code p2s_status;
char *p2s_status_details;
size_t p2s_status_details_capacity;
int c2p_server_cancelled;
} proxy_call;
static void thread_main(void *arg);
static void request_call(grpc_end2end_proxy *proxy);
grpc_end2end_proxy *grpc_end2end_proxy_create(
const grpc_end2end_proxy_def *def) {
gpr_thd_options opt = gpr_thd_options_default();
int proxy_port = grpc_pick_unused_port_or_die();
int server_port = grpc_pick_unused_port_or_die();
grpc_end2end_proxy *proxy = gpr_malloc(sizeof(*proxy));
memset(proxy, 0, sizeof(*proxy));
gpr_join_host_port(&proxy->proxy_port, "localhost", proxy_port);
gpr_join_host_port(&proxy->server_port, "localhost", server_port);
proxy->cq = grpc_completion_queue_create();
proxy->server = def->create_server(proxy->proxy_port);
proxy->client = def->create_client(proxy->server_port);
grpc_server_register_completion_queue(proxy->server, proxy->cq);
grpc_server_start(proxy->server);
gpr_thd_options_set_joinable(&opt);
GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt));
request_call(proxy);
return proxy;
}
static closure *new_closure(void (*func)(void *arg, int success), void *arg) {
closure *cl = gpr_malloc(sizeof(*cl));
cl->func = func;
cl->arg = arg;
return cl;
}
static void shutdown_complete(void *arg, int success) {
grpc_end2end_proxy *proxy = arg;
proxy->shutdown = 1;
grpc_completion_queue_shutdown(proxy->cq);
}
void grpc_end2end_proxy_destroy(grpc_end2end_proxy *proxy) {
grpc_server_shutdown_and_notify(proxy->server, proxy->cq,
new_closure(shutdown_complete, proxy));
gpr_thd_join(proxy->thd);
gpr_free(proxy->proxy_port);
gpr_free(proxy->server_port);
grpc_server_destroy(proxy->server);
grpc_channel_destroy(proxy->client);
grpc_completion_queue_destroy(proxy->cq);
grpc_call_details_destroy(&proxy->new_call_details);
gpr_free(proxy);
}
static void unrefpc(proxy_call *pc, const char *reason) {
gpr_log(GPR_DEBUG, "unref %p: %s %d -> %d", pc, reason, pc->refs.count,
pc->refs.count - 1);
if (gpr_unref(&pc->refs)) {
grpc_call_destroy(pc->c2p);
grpc_call_destroy(pc->p2s);
grpc_metadata_array_destroy(&pc->c2p_initial_metadata);
grpc_metadata_array_destroy(&pc->p2s_initial_metadata);
grpc_metadata_array_destroy(&pc->p2s_trailing_metadata);
gpr_free(pc->p2s_status_details);
gpr_free(pc);
}
}
static void refpc(proxy_call *pc, const char *reason) {
gpr_log(GPR_DEBUG, "ref %p: %s %d -> %d", pc, reason, pc->refs.count,
pc->refs.count + 1);
gpr_ref(&pc->refs);
}
static void on_c2p_sent_initial_metadata(void *arg, int success) {
proxy_call *pc = arg;
unrefpc(pc, "on_c2p_sent_initial_metadata");
}
static void on_p2s_recv_initial_metadata(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
if (!pc->proxy->shutdown) {
op.op = GRPC_OP_SEND_INITIAL_METADATA;
op.flags = 0;
op.data.send_initial_metadata.count = pc->p2s_initial_metadata.count;
op.data.send_initial_metadata.metadata = pc->p2s_initial_metadata.metadata;
refpc(pc, "on_c2p_sent_initial_metadata");
err = grpc_call_start_batch(pc->c2p, &op, 1,
new_closure(on_c2p_sent_initial_metadata, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
unrefpc(pc, "on_p2s_recv_initial_metadata");
}
static void on_p2s_sent_initial_metadata(void *arg, int success) {
proxy_call *pc = arg;
unrefpc(pc, "on_p2s_sent_initial_metadata");
}
static void on_c2p_recv_msg(void *arg, int success);
static void on_p2s_sent_message(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
grpc_byte_buffer_destroy(pc->c2p_msg);
if (!pc->proxy->shutdown && success) {
op.op = GRPC_OP_RECV_MESSAGE;
op.flags = 0;
op.data.recv_message = &pc->c2p_msg;
refpc(pc, "on_c2p_recv_msg");
err = grpc_call_start_batch(pc->c2p, &op, 1,
new_closure(on_c2p_recv_msg, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
unrefpc(pc, "on_p2s_sent_message");
}
static void on_p2s_sent_close(void *arg, int success) {
proxy_call *pc = arg;
unrefpc(pc, "on_p2s_sent_close");
}
static void on_c2p_recv_msg(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
if (!pc->proxy->shutdown && success) {
if (pc->c2p_msg != NULL) {
op.op = GRPC_OP_SEND_MESSAGE;
op.flags = 0;
op.data.send_message = pc->c2p_msg;
refpc(pc, "on_p2s_sent_message");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_sent_message, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
} else {
op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op.flags = 0;
refpc(pc, "on_p2s_sent_close");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_sent_close, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
}
unrefpc(pc, "on_c2p_recv_msg");
}
static void on_p2s_recv_msg(void *arg, int success);
static void on_c2p_sent_message(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
grpc_byte_buffer_destroy(pc->p2s_msg);
if (!pc->proxy->shutdown && success) {
op.op = GRPC_OP_RECV_MESSAGE;
op.flags = 0;
op.data.recv_message = &pc->p2s_msg;
refpc(pc, "on_p2s_recv_msg");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_recv_msg, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
unrefpc(pc, "on_c2p_sent_message");
}
static void on_p2s_recv_msg(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
if (!pc->proxy->shutdown && success && pc->p2s_msg) {
op.op = GRPC_OP_SEND_MESSAGE;
op.flags = 0;
op.data.send_message = pc->p2s_msg;
refpc(pc, "on_c2p_sent_message");
err = grpc_call_start_batch(pc->c2p, &op, 1,
new_closure(on_c2p_sent_message, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
unrefpc(pc, "on_p2s_recv_msg");
}
static void on_c2p_sent_status(void *arg, int success) {
proxy_call *pc = arg;
unrefpc(pc, "on_c2p_sent_status");
}
static void on_p2s_status(void *arg, int success) {
proxy_call *pc = arg;
grpc_op op;
grpc_call_error err;
if (!pc->proxy->shutdown) {
GPR_ASSERT(success);
op.op = GRPC_OP_SEND_STATUS_FROM_SERVER;
op.flags = 0;
op.data.send_status_from_server.trailing_metadata_count =
pc->p2s_trailing_metadata.count;
op.data.send_status_from_server.trailing_metadata =
pc->p2s_trailing_metadata.metadata;
op.data.send_status_from_server.status = pc->p2s_status;
op.data.send_status_from_server.status_details = pc->p2s_status_details;
refpc(pc, "on_c2p_sent_status");
err = grpc_call_start_batch(pc->c2p, &op, 1,
new_closure(on_c2p_sent_status, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
}
unrefpc(pc, "on_p2s_status");
}
static void on_c2p_closed(void *arg, int success) {
proxy_call *pc = arg;
unrefpc(pc, "on_c2p_closed");
}
static void on_new_call(void *arg, int success) {
grpc_end2end_proxy *proxy = arg;
grpc_call_error err;
if (success) {
grpc_op op;
proxy_call *pc = gpr_malloc(sizeof(*pc));
memset(pc, 0, sizeof(*pc));
pc->proxy = proxy;
GPR_SWAP(grpc_metadata_array, pc->c2p_initial_metadata,
proxy->new_call_metadata);
pc->c2p = proxy->new_call;
pc->p2s = grpc_channel_create_call(
proxy->client, pc->c2p, GRPC_PROPAGATE_DEFAULTS, proxy->cq,
proxy->new_call_details.method, proxy->new_call_details.host,
proxy->new_call_details.deadline);
gpr_ref_init(&pc->refs, 1);
op.flags = 0;
op.op = GRPC_OP_RECV_INITIAL_METADATA;
op.data.recv_initial_metadata = &pc->p2s_initial_metadata;
refpc(pc, "on_p2s_recv_initial_metadata");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_recv_initial_metadata, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
op.op = GRPC_OP_SEND_INITIAL_METADATA;
op.data.send_initial_metadata.count = pc->c2p_initial_metadata.count;
op.data.send_initial_metadata.metadata = pc->c2p_initial_metadata.metadata;
refpc(pc, "on_p2s_sent_initial_metadata");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_sent_initial_metadata, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
op.op = GRPC_OP_RECV_MESSAGE;
op.data.recv_message = &pc->c2p_msg;
refpc(pc, "on_c2p_recv_msg");
err = grpc_call_start_batch(pc->c2p, &op, 1,
new_closure(on_c2p_recv_msg, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
op.op = GRPC_OP_RECV_MESSAGE;
op.data.recv_message = &pc->p2s_msg;
refpc(pc, "on_p2s_recv_msg");
err = grpc_call_start_batch(pc->p2s, &op, 1,
new_closure(on_p2s_recv_msg, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
op.op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op.data.recv_status_on_client.trailing_metadata =
&pc->p2s_trailing_metadata;
op.data.recv_status_on_client.status = &pc->p2s_status;
op.data.recv_status_on_client.status_details = &pc->p2s_status_details;
op.data.recv_status_on_client.status_details_capacity =
&pc->p2s_status_details_capacity;
refpc(pc, "on_p2s_status");
err =
grpc_call_start_batch(pc->p2s, &op, 1, new_closure(on_p2s_status, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
op.op = GRPC_OP_RECV_CLOSE_ON_SERVER;
op.data.recv_close_on_server.cancelled = &pc->c2p_server_cancelled;
refpc(pc, "on_c2p_closed");
err =
grpc_call_start_batch(pc->c2p, &op, 1, new_closure(on_c2p_closed, pc));
GPR_ASSERT(err == GRPC_CALL_OK);
request_call(proxy);
unrefpc(pc, "init");
} else {
GPR_ASSERT(proxy->new_call == NULL);
}
}
static void request_call(grpc_end2end_proxy *proxy) {
proxy->new_call = NULL;
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
proxy->server, &proxy->new_call,
&proxy->new_call_details,
&proxy->new_call_metadata, proxy->cq,
proxy->cq, new_closure(on_new_call, proxy)));
}
static void thread_main(void *arg) {
grpc_end2end_proxy *proxy = arg;
closure *cl;
for (;;) {
grpc_event ev = grpc_completion_queue_next(
proxy->cq, gpr_inf_future(GPR_CLOCK_MONOTONIC));
switch (ev.type) {
case GRPC_QUEUE_TIMEOUT:
gpr_log(GPR_ERROR, "Should never reach here");
abort();
case GRPC_QUEUE_SHUTDOWN:
return;
case GRPC_OP_COMPLETE:
cl = ev.tag;
cl->func(cl->arg, ev.success);
gpr_free(cl);
break;
}
}
}
const char *grpc_end2end_proxy_get_client_target(grpc_end2end_proxy *proxy) {
return proxy->proxy_port;
}
const char *grpc_end2end_proxy_get_server_port(grpc_end2end_proxy *proxy) {
return proxy->server_port;
}

@ -0,0 +1,55 @@
/*
*
* 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_TEST_CORE_END2END_FIXTURES_PROXY_H
#define GRPC_TEST_CORE_END2END_FIXTURES_PROXY_H
#include <grpc/grpc.h>
/* proxy service for _with_proxy fixtures */
typedef struct grpc_end2end_proxy grpc_end2end_proxy;
typedef struct grpc_end2end_proxy_def {
grpc_server *(*create_server)(const char *port);
grpc_channel *(*create_client)(const char *target);
} grpc_end2end_proxy_def;
grpc_end2end_proxy *grpc_end2end_proxy_create(
const grpc_end2end_proxy_def *def);
void grpc_end2end_proxy_destroy(grpc_end2end_proxy *proxy);
const char *grpc_end2end_proxy_get_client_target(grpc_end2end_proxy *proxy);
const char *grpc_end2end_proxy_get_server_port(grpc_end2end_proxy *proxy);
#endif /* GRPC_TEST_CORE_END2END_FIXTURES_PROXY_H */

@ -36,30 +36,33 @@ import simplejson
import collections
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack dns_resolver secure platforms')
default_unsecure_fixture_options = FixtureOptions(True, True, False, ['windows', 'posix'])
socketpair_unsecure_fixture_options = FixtureOptions(False, False, False, ['windows', 'posix'])
default_secure_fixture_options = FixtureOptions(True, True, True, ['windows', 'posix'])
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms')
default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix'])
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'])
# maps fixture name to whether it requires the security library
END2END_FIXTURES = {
'chttp2_fake_security': default_secure_fixture_options,
'chttp2_fullstack_compression': default_unsecure_fixture_options,
'chttp2_fullstack': default_unsecure_fixture_options,
'chttp2_fullstack_uds_posix': FixtureOptions(True, False, False, ['posix']),
'chttp2_fullstack_uds_posix_with_poll': FixtureOptions(True, False, False, ['posix']),
'chttp2_fullstack_with_poll': FixtureOptions(True, True, False, ['posix']),
'chttp2_fullstack_compression': default_unsecure_fixture_options,
'chttp2_fullstack_uds_posix': uds_fixture_options,
'chttp2_fullstack_uds_posix_with_poll': uds_fixture_options._replace(platforms=['linux']),
'chttp2_fullstack_with_poll': default_unsecure_fixture_options._replace(platforms=['linux']),
'chttp2_fullstack_with_proxy': default_unsecure_fixture_options._replace(includes_proxy=True),
'chttp2_simple_ssl_fullstack': default_secure_fixture_options,
'chttp2_simple_ssl_fullstack_with_poll': FixtureOptions(True, True, True, ['posix']),
'chttp2_simple_ssl_fullstack_with_poll': default_secure_fixture_options._replace(platforms=['linux']),
'chttp2_simple_ssl_fullstack_with_proxy': default_secure_fixture_options._replace(includes_proxy=True),
'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options,
'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options,
'chttp2_socket_pair': socketpair_unsecure_fixture_options,
'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options,
'chttp2_socket_pair_with_grpc_trace': socketpair_unsecure_fixture_options,
}
TestOptions = collections.namedtuple('TestOptions', 'needs_fullstack needs_dns flaky secure')
default_test_options = TestOptions(False, False, False, False)
connectivity_test_options = TestOptions(True, False, False, False)
TestOptions = collections.namedtuple('TestOptions', 'needs_fullstack needs_dns proxyable flaky secure')
default_test_options = TestOptions(False, False, True, False, False)
connectivity_test_options = default_test_options._replace(needs_fullstack=True)
# maps test names to options
END2END_TESTS = {
@ -70,26 +73,26 @@ END2END_TESTS = {
'cancel_before_invoke': default_test_options,
'cancel_in_a_vacuum': default_test_options,
'census_simple_request': default_test_options,
'channel_connectivity': connectivity_test_options,
'default_host': TestOptions(True, True, False, False),
'channel_connectivity': connectivity_test_options._replace(proxyable=False),
'default_host': default_test_options._replace(needs_fullstack=True, needs_dns=True),
'disappearing_server': connectivity_test_options,
'early_server_shutdown_finishes_inflight_calls': default_test_options,
'early_server_shutdown_finishes_tags': default_test_options,
'empty_batch': default_test_options,
'graceful_server_shutdown': default_test_options,
'invoke_large_request': default_test_options,
'max_concurrent_streams': default_test_options,
'max_concurrent_streams': default_test_options._replace(proxyable=False),
'max_message_length': default_test_options,
'no_op': default_test_options,
'ping_pong_streaming': default_test_options,
'registered_call': default_test_options,
'request_response_with_binary_metadata_and_payload': default_test_options,
'request_response_with_metadata_and_payload': default_test_options,
'request_response_with_payload_and_call_creds': TestOptions(needs_fullstack=False, needs_dns=False, flaky=False, secure=True),
'request_response_with_payload_and_call_creds': default_test_options._replace(secure=True),
'request_response_with_payload': default_test_options,
'request_response_with_trailing_metadata_and_payload': default_test_options,
'request_with_compressed_payload': default_test_options,
'request_with_flags': default_test_options,
'request_with_compressed_payload': default_test_options._replace(proxyable=False),
'request_with_flags': default_test_options._replace(proxyable=False),
'request_with_large_metadata': default_test_options,
'request_with_payload': default_test_options,
'server_finishes_request': default_test_options,
@ -106,6 +109,9 @@ def compatible(f, t):
if END2END_TESTS[t].needs_dns:
if not END2END_FIXTURES[f].dns_resolver:
return False
if not END2END_TESTS[t].proxyable:
if END2END_FIXTURES[f].includes_proxy:
return False
return True
@ -132,7 +138,7 @@ def main():
'language': 'c',
'secure': 'check' if END2END_FIXTURES[f].secure else 'no',
'src': ['test/core/end2end/fixtures/%s.c' % f],
'platforms': [ 'posix' ] if f.endswith('_posix') else END2END_FIXTURES[f].platforms,
'platforms': [ 'linux', 'mac', 'posix' ] if f.endswith('_posix') else END2END_FIXTURES[f].platforms,
'deps': sec_deps if END2END_FIXTURES[f].secure else unsec_deps,
'headers': ['test/core/end2end/end2end_tests.h'],
}

@ -62,7 +62,8 @@ int main(int argc, char **argv) {
/* create a call, channel to a non existant server */
chan = grpc_insecure_channel_create("nonexistant:54321", NULL);
call = grpc_channel_create_call(chan, cq, "/Foo", "nonexistant", deadline);
call = grpc_channel_create_call(chan, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
"/Foo", "nonexistant", deadline);
op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;

@ -113,8 +113,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
char *details = NULL;
size_t details_capacity = 0;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "slartibartfast.local",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "slartibartfast.local", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -126,8 +126,8 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
@ -192,8 +192,7 @@ static void test_cancel_after_accept(grpc_end2end_test_config config,
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(status == mode.expect_status);
GPR_ASSERT(0 == strcmp(details, mode.expect_details));
GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
GPR_ASSERT(was_cancelled == 1);
grpc_metadata_array_destroy(&initial_metadata_recv);

@ -126,8 +126,8 @@ static void test_cancel_after_accept_and_writes_closed(
grpc_raw_byte_buffer_create(&response_payload_slice, 1);
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
@ -195,8 +195,7 @@ static void test_cancel_after_accept_and_writes_closed(
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(status == mode.expect_status);
GPR_ASSERT(0 == strcmp(details, mode.expect_details));
GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
GPR_ASSERT(was_cancelled == 1);
grpc_metadata_array_destroy(&initial_metadata_recv);

@ -121,8 +121,8 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
grpc_byte_buffer *request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
@ -164,8 +164,7 @@ static void test_cancel_after_invoke(grpc_end2end_test_config config,
cq_expect_completion(cqv, tag(1), 1);
cq_verify(cqv);
GPR_ASSERT(status == mode.expect_status);
GPR_ASSERT(0 == strcmp(details, mode.expect_details));
GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);

@ -119,8 +119,8 @@ static void test_cancel_before_invoke(grpc_end2end_test_config config,
grpc_byte_buffer *request_payload =
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
GPR_ASSERT(GRPC_CALL_OK == grpc_call_cancel(c));

@ -107,8 +107,8 @@ static void test_cancel_in_a_vacuum(grpc_end2end_test_config config,
gpr_timespec deadline = five_seconds_time();
cq_verifier *v_client = cq_verifier_create(f.cq);
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c));

@ -111,8 +111,8 @@ static void test_body(grpc_end2end_test_fixture f) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -116,7 +116,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
int was_cancelled = 2;
char *peer;
c = grpc_channel_create_call(f.client, f.cq, "/foo", NULL, deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", NULL, deadline);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);

@ -97,8 +97,8 @@ static void do_request_and_shutdown_server(grpc_end2end_test_fixture *f,
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f->client, f->cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -105,8 +105,8 @@ static void test_early_server_shutdown_finishes_inflight_calls(
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -105,8 +105,8 @@ static void empty_batch_body(grpc_end2end_test_fixture f) {
cq_verifier *cqv = cq_verifier_create(f.cq);
grpc_op *op = NULL;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(c, op, 0, tag(1)));

@ -112,8 +112,8 @@ static void test_early_server_shutdown_finishes_inflight_calls(
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -128,8 +128,8 @@ static void test_invoke_large_request(grpc_end2end_test_config config) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -113,8 +113,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);
@ -244,11 +244,11 @@ static void test_max_concurrent_streams(grpc_end2end_test_config config) {
/* start two requests - ensuring that the second is not accepted until
the first completes */
deadline = n_seconds_time(1000);
c1 = grpc_channel_create_call(f.client, f.cq, "/alpha",
"foo.test.google.fr:1234", deadline);
c1 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/alpha", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c1);
c2 = grpc_channel_create_call(f.client, f.cq, "/beta",
"foo.test.google.fr:1234", deadline);
c2 = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/beta", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c2);
GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(

@ -128,8 +128,8 @@ static void test_max_message_length(grpc_end2end_test_config config) {
f = begin_test(config, "test_max_message_length", NULL, &server_args);
cqv = cq_verifier_create(f.cq);
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234",
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234",
gpr_inf_future(GPR_CLOCK_REALTIME));
GPR_ASSERT(c);

@ -124,8 +124,8 @@ static void test_pingpong_streaming(grpc_end2end_test_config config,
gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
gpr_slice response_payload_slice = gpr_slice_from_copied_string("hello you");
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -115,7 +115,8 @@ static void simple_request_body(grpc_end2end_test_fixture f, void *rc) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_registered_call(f.client, f.cq, rc, deadline);
c = grpc_channel_create_registered_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, rc, deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -143,8 +143,8 @@ static void test_request_response_with_metadata_and_payload(
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -129,8 +129,8 @@ static void test_request_response_with_metadata_and_payload(
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -121,8 +121,8 @@ static void request_response_with_payload(grpc_end2end_test_fixture f) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -130,8 +130,8 @@ static void test_call_creds_failure(grpc_end2end_test_config config) {
grpc_end2end_test_fixture f =
begin_test(config, "test_call_creds_failure", NULL, NULL);
gpr_timespec deadline = five_seconds_time();
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
/* Try with credentials unfit to be set on a call (channel creds). */
@ -175,8 +175,8 @@ static void request_response_with_payload_and_call_creds(
grpc_credentials *creds = NULL;
grpc_auth_context *s_auth_context = NULL;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
creds = grpc_iam_credentials_create(iam_token, iam_selector);
GPR_ASSERT(creds != NULL);

@ -131,8 +131,8 @@ static void test_request_response_with_metadata_and_payload(
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -141,8 +141,8 @@ static void request_with_payload_template(
f = begin_test(config, test_name, client_args, server_args);
cqv = cq_verifier_create(f.cq);
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -121,8 +121,8 @@ static void test_invoke_request_with_flags(
size_t details_capacity = 0;
grpc_call_error expectation;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -122,8 +122,8 @@ static void test_request_with_large_metadata(grpc_end2end_test_config config) {
int was_cancelled = 2;
const int large_size = 64 * 1024;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
meta.key = "key";

@ -120,8 +120,8 @@ static void test_invoke_request_with_payload(grpc_end2end_test_config config) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -115,8 +115,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -107,8 +107,8 @@ static void simple_delayed_request_body(grpc_end2end_test_config config,
config.init_client(f, client_args);
c = grpc_channel_create_call(f->client, f->cq, "/foo", "foo.test.google.fr",
deadline);
c = grpc_channel_create_call(f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
"/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

@ -116,8 +116,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
int was_cancelled = 2;
char *peer;
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
peer = grpc_call_get_peer(c);

@ -115,8 +115,8 @@ static void simple_request_body(grpc_end2end_test_fixture f) {
size_t details_capacity = 0;
int was_cancelled = 2;
c = grpc_channel_create_call(f.client, f.cq, "/foo",
"foo.test.google.fr:1234", deadline);
c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
"/foo", "foo.test.google.fr:1234", deadline);
GPR_ASSERT(c);
grpc_metadata_array_init(&initial_metadata_recv);

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

Loading…
Cancel
Save