aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/cpp_generator.cc16
-rw-r--r--src/core/channel/client_channel.c50
-rw-r--r--src/core/channel/compress_filter.c7
-rw-r--r--src/core/channel/connected_channel.c1
-rw-r--r--src/core/channel/http_client_filter.c3
-rw-r--r--src/core/channel/http_server_filter.c3
-rw-r--r--src/core/client_config/lb_policies/pick_first.c48
-rw-r--r--src/core/client_config/subchannel.c17
-rw-r--r--src/core/client_config/subchannel.h22
-rw-r--r--src/core/client_config/uri_parser.c4
-rw-r--r--src/core/compression/algorithm.c2
-rw-r--r--src/core/httpcli/parser.c11
-rw-r--r--src/core/iomgr/closure.c24
-rw-r--r--src/core/iomgr/closure.h3
-rw-r--r--src/core/iomgr/exec_ctx.c8
-rw-r--r--src/core/iomgr/fd_posix.c224
-rw-r--r--src/core/iomgr/fd_posix.h19
-rw-r--r--src/core/iomgr/pollset_multipoller_with_epoll.c9
-rw-r--r--src/core/iomgr/pollset_multipoller_with_poll_posix.c34
-rw-r--r--src/core/iomgr/pollset_posix.c165
-rw-r--r--src/core/iomgr/pollset_posix.h11
-rw-r--r--src/core/iomgr/tcp_client_posix.c2
-rw-r--r--src/core/iomgr/tcp_posix.c22
-rw-r--r--src/core/iomgr/tcp_server_posix.c2
-rw-r--r--src/core/iomgr/tcp_server_windows.c2
-rw-r--r--src/core/iomgr/udp_server.c2
-rw-r--r--src/core/iomgr/udp_server.h3
-rw-r--r--src/core/iomgr/wakeup_fd_eventfd.c6
-rw-r--r--src/core/profiling/basic_timers.c103
-rw-r--r--src/core/profiling/stap_timers.c16
-rw-r--r--src/core/profiling/timers.h115
-rw-r--r--src/core/security/credentials.c42
-rw-r--r--src/core/security/credentials.h8
-rw-r--r--src/core/security/security_context.c26
-rw-r--r--src/core/security/security_context.h11
-rw-r--r--src/core/security/server_auth_filter.c36
-rw-r--r--src/core/security/server_secure_chttp2.c4
-rw-r--r--src/core/support/alloc.c14
-rw-r--r--src/core/support/sync_posix.c13
-rw-r--r--src/core/support/time_posix.c3
-rw-r--r--src/core/support/time_precise.c89
-rw-r--r--src/core/support/time_precise.h55
-rw-r--r--src/core/surface/byte_buffer.c7
-rw-r--r--src/core/surface/call.c91
-rw-r--r--src/core/surface/call.h11
-rw-r--r--src/core/surface/call_test_only.h (renamed from src/node/examples/stock_client.js)46
-rw-r--r--src/core/surface/channel_connectivity.c8
-rw-r--r--src/core/surface/completion_queue.c18
-rw-r--r--src/core/surface/init.c4
-rw-r--r--src/core/transport/chttp2/bin_encoder.c16
-rw-r--r--src/core/transport/chttp2/frame_data.c4
-rw-r--r--src/core/transport/chttp2/frame_goaway.c4
-rw-r--r--src/core/transport/chttp2/hpack_parser.c8
-rw-r--r--src/core/transport/chttp2/parsing.c21
-rw-r--r--src/core/transport/chttp2/stream_encoder.c6
-rw-r--r--src/core/transport/chttp2/writing.c5
-rw-r--r--src/core/transport/chttp2_transport.c16
-rw-r--r--src/core/transport/stream_op.c6
-rw-r--r--src/core/tsi/fake_transport_security.c8
-rw-r--r--src/core/tsi/ssl_transport_security.c13
-rw-r--r--src/cpp/client/channel.cc3
-rw-r--r--src/cpp/proto/proto_utils.cc4
-rw-r--r--src/cpp/server/server.cc5
-rw-r--r--src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs (renamed from src/csharp/Grpc.Auth/AuthInterceptors.cs)26
-rw-r--r--src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs96
-rw-r--r--src/csharp/Grpc.Auth/Grpc.Auth.csproj3
-rw-r--r--src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs (renamed from src/csharp/Grpc.Core.Tests/ClientBaseTest.cs)25
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs (renamed from src/node/interop/empty.proto)46
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelTest.cs10
-rw-r--r--src/csharp/Grpc.Core.Tests/FakeCredentials.cs (renamed from src/node/examples/stock.proto)63
-rw-r--r--src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj4
-rw-r--r--src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs4
-rw-r--r--src/csharp/Grpc.Core.Tests/MockServiceHelper.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/PInvokeTest.cs2
-rw-r--r--src/csharp/Grpc.Core/CallCredentials.cs152
-rw-r--r--src/csharp/Grpc.Core/CallOptions.cs16
-rw-r--r--src/csharp/Grpc.Core/Channel.cs4
-rw-r--r--src/csharp/Grpc.Core/ChannelCredentials.cs (renamed from src/csharp/Grpc.Core/Credentials.cs)81
-rw-r--r--src/csharp/Grpc.Core/ClientBase.cs31
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj4
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.nuspec2
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs6
-rw-r--r--src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs8
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs113
-rw-r--r--src/csharp/Grpc.Examples.MathClient/MathClient.cs2
-rw-r--r--src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs2
-rw-r--r--src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs2
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj49
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Client/packages.config11
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj49
-rw-r--r--src/csharp/Grpc.IntegrationTesting.Server/packages.config11
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Empty.cs5
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj4
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs97
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs7
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Messages.cs446
-rw-r--r--src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs97
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Test.cs37
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestGrpc.cs188
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/empty.proto43
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/messages.proto132
-rw-r--r--src/csharp/Grpc.IntegrationTesting/proto/test.proto71
-rw-r--r--src/csharp/build_packages.bat4
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c66
-rwxr-xr-xsrc/csharp/generate_proto_csharp.sh2
-rw-r--r--src/node/.istanbul.yml6
-rw-r--r--src/node/LICENSE28
-rw-r--r--src/node/README.md36
-rw-r--r--src/node/bin/README.md16
-rwxr-xr-xsrc/node/bin/service_packager2
-rw-r--r--src/node/binding.gyp100
-rw-r--r--src/node/cli/service_packager.js142
-rw-r--r--src/node/cli/service_packager/index.js36
-rw-r--r--src/node/cli/service_packager/package.json.template17
-rw-r--r--src/node/examples/stock_server.js87
-rw-r--r--src/node/ext/call.cc29
-rw-r--r--src/node/ext/call.h5
-rw-r--r--src/node/ext/call_credentials.cc259
-rw-r--r--src/node/ext/call_credentials.h100
-rw-r--r--src/node/ext/channel.cc8
-rw-r--r--src/node/ext/channel_credentials.cc (renamed from src/node/ext/credentials.cc)106
-rw-r--r--src/node/ext/channel_credentials.h (renamed from src/node/ext/credentials.h)23
-rw-r--r--src/node/ext/node_grpc.cc8
-rw-r--r--src/node/index.js31
-rw-r--r--src/node/interop/interop_client.js336
-rw-r--r--src/node/interop/interop_server.js113
-rw-r--r--src/node/interop/messages.proto132
-rw-r--r--src/node/interop/test.proto72
-rw-r--r--src/node/package.json64
-rw-r--r--src/node/performance/perf_test.js (renamed from src/node/examples/perf_test.js)2
-rw-r--r--src/node/performance/qps_test.js (renamed from src/node/examples/qps_test.js)2
-rw-r--r--src/node/src/client.js352
-rw-r--r--src/node/src/credentials.js163
-rw-r--r--src/node/src/metadata.js5
-rw-r--r--src/node/src/server.js4
-rw-r--r--src/node/test/async_test.js6
-rw-r--r--src/node/test/call_test.js4
-rw-r--r--src/node/test/channel_test.js5
-rw-r--r--src/node/test/constant_test.js2
-rw-r--r--src/node/test/credentials_test.js243
-rw-r--r--src/node/test/end_to_end_test.js4
-rw-r--r--src/node/test/health_test.js2
-rw-r--r--src/node/test/interop_sanity_test.js14
-rw-r--r--src/node/test/math/math.proto (renamed from src/node/examples/math.proto)0
-rw-r--r--src/node/test/math/math_server.js (renamed from src/node/examples/math_server.js)2
-rw-r--r--src/node/test/math_client_test.js6
-rw-r--r--src/node/test/server_test.js2
-rw-r--r--src/node/test/surface_test.js320
-rw-r--r--src/objective-c/README.md5
-rw-r--r--src/objective-c/RxLibrary/GRXWriter.m10
-rw-r--r--src/php/ext/grpc/package.xml30
-rw-r--r--src/php/ext/grpc/php_grpc.c118
-rwxr-xr-xsrc/php/lib/Grpc/BaseStub.php25
-rw-r--r--src/php/tests/generated_code/AbstractGeneratedCodeTest.php8
-rwxr-xr-xsrc/php/tests/interop/interop_client.php20
-rw-r--r--src/ruby/lib/grpc/generic/client_stub.rb22
-rw-r--r--src/ruby/spec/generic/client_stub_spec.rb14
160 files changed, 4306 insertions, 2442 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 1bf2b16ed6..3c8ca8ab45 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -585,7 +585,7 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
"class Service : public ::grpc::SynchronousService {\n"
" public:\n");
printer->Indent();
- printer->Print("Service() : service_(nullptr) {}\n");
+ printer->Print("Service();\n");
printer->Print("virtual ~Service();\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderServerMethodSync(printer, service->method(i), vars);
@@ -594,7 +594,7 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer,
printer->Outdent();
printer->Print(
" private:\n"
- " ::grpc::RpcService* service_;\n");
+ " std::unique_ptr< ::grpc::RpcService> service_;\n");
printer->Print("};\n");
// Server side - Asynchronous
@@ -1014,8 +1014,10 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
"{}\n\n");
printer->Print(*vars,
+ "$ns$$Service$::Service::Service() {\n"
+ "}\n\n");
+ printer->Print(*vars,
"$ns$$Service$::Service::~Service() {\n"
- " delete service_;\n"
"}\n\n");
for (int i = 0; i < service->method_count(); ++i) {
(*vars)["Idx"] = as_string(i);
@@ -1026,10 +1028,10 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
"::grpc::RpcService* $ns$$Service$::Service::service() {\n");
printer->Indent();
printer->Print(
- "if (service_ != nullptr) {\n"
- " return service_;\n"
+ "if (service_) {\n"
+ " return service_.get();\n"
"}\n");
- printer->Print("service_ = new ::grpc::RpcService();\n");
+ printer->Print("service_ = std::unique_ptr< ::grpc::RpcService>(new ::grpc::RpcService());\n");
for (int i = 0; i < service->method_count(); ++i) {
const grpc::protobuf::MethodDescriptor *method = service->method(i);
(*vars)["Idx"] = as_string(i);
@@ -1077,7 +1079,7 @@ void PrintSourceService(grpc::protobuf::io::Printer *printer,
" std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
}
}
- printer->Print("return service_;\n");
+ printer->Print("return service_.get();\n");
printer->Outdent();
printer->Print("}\n\n");
}
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index b59b62a6aa..9f85557ea1 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -36,22 +36,24 @@
#include <stdio.h>
#include <string.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/useful.h>
+
#include "src/core/channel/channel_args.h"
#include "src/core/channel/connected_channel.h"
-#include "src/core/surface/channel.h"
#include "src/core/iomgr/iomgr.h"
+#include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
+#include "src/core/surface/channel.h"
#include "src/core/transport/connectivity_state.h"
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/useful.h>
/* Client channel implementation */
typedef struct call_data call_data;
-typedef struct {
+typedef struct client_channel_channel_data {
/** metadata context for this channel */
grpc_mdctx *mdctx;
/** resolver for this channel */
@@ -196,13 +198,12 @@ static int is_empty(void *p, int len) {
return 1;
}
-static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
- int iomgr_success) {
+static void started_call_locked(grpc_exec_ctx *exec_ctx, void *arg,
+ int iomgr_success) {
call_data *calld = arg;
grpc_transport_stream_op op;
int have_waiting;
- gpr_mu_lock(&calld->mu_state);
if (calld->state == CALL_CANCELLED && calld->subchannel_call != NULL) {
memset(&op, 0, sizeof(op));
op.cancel_with_status = GRPC_STATUS_CANCELLED;
@@ -230,10 +231,20 @@ static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
}
}
+static void started_call(grpc_exec_ctx *exec_ctx, void *arg,
+ int iomgr_success) {
+ call_data *calld = arg;
+ gpr_mu_lock(&calld->mu_state);
+ started_call_locked(exec_ctx, arg, iomgr_success);
+}
+
static void picked_target(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
call_data *calld = arg;
grpc_pollset *pollset;
+ grpc_subchannel_call_create_status call_creation_status;
+
+ GPR_TIMER_BEGIN("picked_target", 0);
if (calld->picked_channel == NULL) {
/* treat this like a cancellation */
@@ -248,13 +259,19 @@ static void picked_target(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(calld->state == CALL_WAITING_FOR_PICK);
calld->state = CALL_WAITING_FOR_CALL;
pollset = calld->waiting_op.bind_pollset;
- gpr_mu_unlock(&calld->mu_state);
grpc_closure_init(&calld->async_setup_task, started_call, calld);
- grpc_subchannel_create_call(exec_ctx, calld->picked_channel, pollset,
- &calld->subchannel_call,
- &calld->async_setup_task);
+ call_creation_status = grpc_subchannel_create_call(
+ exec_ctx, calld->picked_channel, pollset, &calld->subchannel_call,
+ &calld->async_setup_task);
+ if (call_creation_status == GRPC_SUBCHANNEL_CALL_CREATE_READY) {
+ started_call_locked(exec_ctx, calld, iomgr_success);
+ } else {
+ gpr_mu_unlock(&calld->mu_state);
+ }
}
}
+
+ GPR_TIMER_END("picked_target", 0);
}
static grpc_closure *merge_into_waiting_op(grpc_call_element *elem,
@@ -315,6 +332,7 @@ static void perform_transport_stream_op(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *subchannel_call;
grpc_lb_policy *lb_policy;
grpc_transport_stream_op op2;
+ GPR_TIMER_BEGIN("perform_transport_stream_op", 0);
GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
@@ -426,6 +444,8 @@ static void perform_transport_stream_op(grpc_exec_ctx *exec_ctx,
}
break;
}
+
+ GPR_TIMER_END("perform_transport_stream_op", 0);
}
static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@@ -645,9 +665,7 @@ static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
case CALL_WAITING_FOR_CONFIG:
case CALL_WAITING_FOR_CALL:
case CALL_WAITING_FOR_SEND:
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- break;
+ GPR_UNREACHABLE_CODE(return );
}
}
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 182fbf18bf..20b5084044 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -41,6 +41,7 @@
#include "src/core/channel/compress_filter.h"
#include "src/core/channel/channel_args.h"
+#include "src/core/profiling/timers.h"
#include "src/core/compression/message_compress.h"
#include "src/core/support/string.h"
@@ -242,7 +243,7 @@ static void process_send_ops(grpc_call_element *elem,
GPR_ASSERT(calld->remaining_slice_bytes > 0);
/* Increase input ref count, gpr_slice_buffer_add takes ownership. */
gpr_slice_buffer_add(&calld->slices, gpr_slice_ref(sop->data.slice));
- GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) >=
+ GPR_ASSERT(GPR_SLICE_LENGTH(sop->data.slice) <=
calld->remaining_slice_bytes);
calld->remaining_slice_bytes -=
(gpr_uint32)GPR_SLICE_LENGTH(sop->data.slice);
@@ -271,10 +272,14 @@ static void process_send_ops(grpc_call_element *elem,
static void compress_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
+ GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
+
if (op->send_ops && op->send_ops->nops > 0) {
process_send_ops(elem, op->send_ops);
}
+ GPR_TIMER_END("compress_start_transport_stream_op", 0);
+
/* pass control down the stack */
grpc_call_next_op(exec_ctx, elem, op);
}
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index f9fc280259..6d4d7be632 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -39,6 +39,7 @@
#include "src/core/support/string.h"
#include "src/core/transport/transport.h"
+#include "src/core/profiling/timers.h"
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index d67dc37ad2..f78a5cc315 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -36,6 +36,7 @@
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/support/string.h"
+#include "src/core/profiling/timers.h"
typedef struct call_data {
grpc_linked_mdelem method;
@@ -162,8 +163,10 @@ static void hc_mutate_op(grpc_call_element *elem,
static void hc_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
+ GPR_TIMER_BEGIN("hc_start_transport_op", 0);
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
hc_mutate_op(elem, op);
+ GPR_TIMER_END("hc_start_transport_op", 0);
grpc_call_next_op(exec_ctx, elem, op);
}
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 5e6d684a52..99e5066a4e 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -36,6 +36,7 @@
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/profiling/timers.h"
typedef struct call_data {
gpr_uint8 got_initial_metadata;
@@ -230,8 +231,10 @@ static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
grpc_call_element *elem,
grpc_transport_stream_op *op) {
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+ GPR_TIMER_BEGIN("hs_start_transport_op", 0);
hs_mutate_op(elem, op);
grpc_call_next_op(exec_ctx, elem, op);
+ GPR_TIMER_END("hs_start_transport_op", 0);
}
/* Constructor for call_data */
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 28155d0fbc..e5bf0680ff 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -101,6 +101,9 @@ void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
for (i = 0; i < p->num_subchannels; i++) {
GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
}
+ if (p->selected) {
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
+ }
grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
gpr_free(p->subchannels);
gpr_mu_destroy(&p->mu);
@@ -172,6 +175,35 @@ void pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
}
}
+static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
+ int iomgr_success) {
+ pick_first_lb_policy *p = arg;
+ size_t i;
+ grpc_transport_op op;
+ size_t num_subchannels = p->num_subchannels;
+ grpc_subchannel **subchannels;
+ grpc_subchannel *exclude_subchannel;
+
+ gpr_mu_lock(&p->mu);
+ subchannels = p->subchannels;
+ p->num_subchannels = 0;
+ p->subchannels = NULL;
+ exclude_subchannel = p->selected;
+ gpr_mu_unlock(&p->mu);
+ GRPC_LB_POLICY_UNREF(exec_ctx, &p->base, "destroy_subchannels");
+
+ for (i = 0; i < num_subchannels; i++) {
+ if (subchannels[i] != exclude_subchannel) {
+ memset(&op, 0, sizeof(op));
+ op.disconnect = 1;
+ grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], &op);
+ }
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
+ }
+
+ gpr_free(subchannels);
+}
+
static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
pick_first_lb_policy *p = arg;
@@ -200,6 +232,12 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
GRPC_CHANNEL_READY, "connecting_ready");
p->selected = p->subchannels[p->checking_subchannel];
+ GRPC_SUBCHANNEL_REF(p->selected, "picked_first");
+ /* drop the pick list: we are connected now */
+ GRPC_LB_POLICY_REF(&p->base, "destroy_subchannels");
+ grpc_exec_ctx_enqueue(exec_ctx,
+ grpc_closure_create(destroy_subchannels, p), 1);
+ /* update any calls that were waiting for a pick */
while ((pp = p->pending_picks)) {
p->pending_picks = pp->next;
*pp->target = p->selected;
@@ -279,10 +317,15 @@ static void pf_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
size_t i;
size_t n;
grpc_subchannel **subchannels;
+ grpc_subchannel *selected;
gpr_mu_lock(&p->mu);
n = p->num_subchannels;
subchannels = gpr_malloc(n * sizeof(*subchannels));
+ selected = p->selected;
+ if (selected) {
+ GRPC_SUBCHANNEL_REF(selected, "pf_broadcast_to_selected");
+ }
for (i = 0; i < n; i++) {
subchannels[i] = p->subchannels[i];
GRPC_SUBCHANNEL_REF(subchannels[i], "pf_broadcast");
@@ -290,9 +333,14 @@ static void pf_broadcast(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
gpr_mu_unlock(&p->mu);
for (i = 0; i < n; i++) {
+ if (selected == subchannels[i]) continue;
grpc_subchannel_process_transport_op(exec_ctx, subchannels[i], op);
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pf_broadcast");
}
+ if (p->selected) {
+ grpc_subchannel_process_transport_op(exec_ctx, selected, op);
+ GRPC_SUBCHANNEL_UNREF(exec_ctx, selected, "pf_broadcast_to_selected");
+ }
gpr_free(subchannels);
}
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index a378f06543..8494ebdc1d 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -358,18 +358,20 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
static void continue_creating_call(grpc_exec_ctx *exec_ctx, void *arg,
int iomgr_success) {
+ grpc_subchannel_call_create_status call_creation_status;
waiting_for_connect *w4c = arg;
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, w4c->pollset);
- grpc_subchannel_create_call(exec_ctx, w4c->subchannel, w4c->pollset,
- w4c->target, w4c->notify);
+ call_creation_status = grpc_subchannel_create_call(
+ exec_ctx, w4c->subchannel, w4c->pollset, w4c->target, w4c->notify);
+ GPR_ASSERT(call_creation_status == GRPC_SUBCHANNEL_CALL_CREATE_READY);
+ w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success);
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect");
gpr_free(w4c);
}
-void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
- grpc_pollset *pollset,
- grpc_subchannel_call **target,
- grpc_closure *notify) {
+grpc_subchannel_call_create_status grpc_subchannel_create_call(
+ grpc_exec_ctx *exec_ctx, grpc_subchannel *c, grpc_pollset *pollset,
+ grpc_subchannel_call **target, grpc_closure *notify) {
connection *con;
gpr_mu_lock(&c->mu);
if (c->active != NULL) {
@@ -378,7 +380,7 @@ void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
gpr_mu_unlock(&c->mu);
*target = create_call(exec_ctx, con);
- notify->cb(exec_ctx, notify->cb_arg, 1);
+ return GRPC_SUBCHANNEL_CALL_CREATE_READY;
} else {
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
w4c->next = c->waiting;
@@ -403,6 +405,7 @@ void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
} else {
gpr_mu_unlock(&c->mu);
}
+ return GRPC_SUBCHANNEL_CALL_CREATE_PENDING;
}
}
diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h
index f9bc0c2d2f..ec1cc7cc69 100644
--- a/src/core/client_config/subchannel.h
+++ b/src/core/client_config/subchannel.h
@@ -75,12 +75,22 @@ void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx,
grpc_subchannel_call *call
GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
-/** construct a call (possibly asynchronously) */
-void grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx,
- grpc_subchannel *subchannel,
- grpc_pollset *pollset,
- grpc_subchannel_call **target,
- grpc_closure *notify);
+typedef enum {
+ GRPC_SUBCHANNEL_CALL_CREATE_READY,
+ GRPC_SUBCHANNEL_CALL_CREATE_PENDING
+} grpc_subchannel_call_create_status;
+
+/** construct a subchannel call (possibly asynchronously).
+ *
+ * If the returned status is \a GRPC_SUBCHANNEL_CALL_CREATE_READY, the call will
+ * return immediately and \a target will point to a connected \a subchannel_call
+ * instance. Note that \a notify will \em not be invoked in this case.
+ * Otherwise, if the returned status is GRPC_SUBCHANNEL_CALL_CREATE_PENDING, the
+ * subchannel call will be created asynchronously, invoking the \a notify
+ * callback upon completion. */
+grpc_subchannel_call_create_status grpc_subchannel_create_call(
+ grpc_exec_ctx *exec_ctx, grpc_subchannel *subchannel, grpc_pollset *pollset,
+ grpc_subchannel_call **target, grpc_closure *notify);
/** cancel \a call in the waiting state. */
void grpc_subchannel_cancel_waiting_call(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/client_config/uri_parser.c b/src/core/client_config/uri_parser.c
index df9f32d403..cbdfffcf8e 100644
--- a/src/core/client_config/uri_parser.c
+++ b/src/core/client_config/uri_parser.c
@@ -37,6 +37,7 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
#include <grpc/support/string_util.h>
/** a size_t default value... maps to all 1's */
@@ -120,8 +121,7 @@ static int parse_fragment_or_query(const char *uri_text, size_t *i) {
} else {
return 1;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return 0);
default:
(*i) += advance;
break;
diff --git a/src/core/compression/algorithm.c b/src/core/compression/algorithm.c
index d55e499f5e..fd95a3c891 100644
--- a/src/core/compression/algorithm.c
+++ b/src/core/compression/algorithm.c
@@ -101,6 +101,7 @@ grpc_compression_algorithm grpc_compression_algorithm_for_level(
default:
/* we shouldn't be making it here */
abort();
+ return GRPC_COMPRESS_NONE;
}
}
@@ -116,6 +117,7 @@ grpc_compression_level grpc_compression_level_for_algorithm(
}
}
abort();
+ return GRPC_COMPRESS_LEVEL_NONE;
}
void grpc_compression_options_init(grpc_compression_options *opts) {
diff --git a/src/core/httpcli/parser.c b/src/core/httpcli/parser.c
index 404906d5ae..046770c094 100644
--- a/src/core/httpcli/parser.c
+++ b/src/core/httpcli/parser.c
@@ -139,8 +139,7 @@ static int finish_line(grpc_httpcli_parser *parser) {
}
break;
case GRPC_HTTPCLI_BODY:
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return 0);
}
parser->cur_line_length = 0;
@@ -165,8 +164,7 @@ static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
} else {
return 1;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return 0);
case GRPC_HTTPCLI_BODY:
if (parser->r.body_length == parser->body_capacity) {
parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
@@ -177,10 +175,7 @@ static int addbyte(grpc_httpcli_parser *parser, gpr_uint8 byte) {
parser->r.body_length++;
return 1;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
-
- return 0;
+ GPR_UNREACHABLE_CODE(return 0);
}
void grpc_httpcli_parser_init(grpc_httpcli_parser *parser) {
diff --git a/src/core/iomgr/closure.c b/src/core/iomgr/closure.c
index 3265425789..d91681990f 100644
--- a/src/core/iomgr/closure.c
+++ b/src/core/iomgr/closure.c
@@ -33,6 +33,8 @@
#include "src/core/iomgr/closure.h"
+#include <grpc/support/alloc.h>
+
void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg) {
closure->cb = cb;
@@ -69,3 +71,25 @@ void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst) {
}
src->head = src->tail = NULL;
}
+
+typedef struct {
+ grpc_iomgr_cb_func cb;
+ void *cb_arg;
+ grpc_closure wrapper;
+} wrapped_closure;
+
+static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+ wrapped_closure *wc = arg;
+ grpc_iomgr_cb_func cb = wc->cb;
+ void *cb_arg = wc->cb_arg;
+ gpr_free(wc);
+ cb(exec_ctx, cb_arg, success);
+}
+
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
+ wrapped_closure *wc = gpr_malloc(sizeof(*wc));
+ wc->cb = cb;
+ wc->cb_arg = cb_arg;
+ grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
+ return &wc->wrapper;
+}
diff --git a/src/core/iomgr/closure.h b/src/core/iomgr/closure.h
index 982ffa4e1b..d812659af0 100644
--- a/src/core/iomgr/closure.h
+++ b/src/core/iomgr/closure.h
@@ -77,6 +77,9 @@ struct grpc_closure {
void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
void *cb_arg);
+/* Create a heap allocated closure: try to avoid except for very rare events */
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
+
#define GRPC_CLOSURE_LIST_INIT \
{ NULL, NULL }
diff --git a/src/core/iomgr/exec_ctx.c b/src/core/iomgr/exec_ctx.c
index f2914d376e..410b34c521 100644
--- a/src/core/iomgr/exec_ctx.c
+++ b/src/core/iomgr/exec_ctx.c
@@ -35,18 +35,24 @@
#include <grpc/support/log.h>
+#include "src/core/profiling/timers.h"
+
int grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
int did_something = 0;
+ GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
while (!grpc_closure_list_empty(exec_ctx->closure_list)) {
grpc_closure *c = exec_ctx->closure_list.head;
exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
while (c != NULL) {
grpc_closure *next = c->next;
- did_something = 1;
+ did_something++;
+ GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
c->cb(exec_ctx, c->cb_arg, c->success);
+ GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
c = next;
}
}
+ GPR_TIMER_END("grpc_exec_ctx_flush", 0);
return did_something;
}
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index b48b7f050a..7ff80e6cf8 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -45,10 +45,8 @@
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
-enum descriptor_state {
- NOT_READY = 0,
- READY = 1
-}; /* or a pointer to a closure to call */
+#define CLOSURE_NOT_READY ((grpc_closure *)0)
+#define CLOSURE_READY ((grpc_closure *)1)
/* We need to keep a freelist not because of any concerns of malloc performance
* but instead so that implementations with multiple threads in (for example)
@@ -88,14 +86,13 @@ static grpc_fd *alloc_fd(int fd) {
gpr_mu_unlock(&fd_freelist_mu);
if (r == NULL) {
r = gpr_malloc(sizeof(grpc_fd));
- gpr_mu_init(&r->set_state_mu);
- gpr_mu_init(&r->watcher_mu);
+ gpr_mu_init(&r->mu);
}
gpr_atm_rel_store(&r->refst, 1);
- gpr_atm_rel_store(&r->readst, NOT_READY);
- gpr_atm_rel_store(&r->writest, NOT_READY);
- gpr_atm_rel_store(&r->shutdown, 0);
+ r->shutdown = 0;
+ r->read_closure = CLOSURE_NOT_READY;
+ r->write_closure = CLOSURE_NOT_READY;
r->fd = fd;
r->inactive_watcher_root.next = r->inactive_watcher_root.prev =
&r->inactive_watcher_root;
@@ -107,8 +104,7 @@ static grpc_fd *alloc_fd(int fd) {
}
static void destroy(grpc_fd *fd) {
- gpr_mu_destroy(&fd->set_state_mu);
- gpr_mu_destroy(&fd->watcher_mu);
+ gpr_mu_destroy(&fd->mu);
gpr_free(fd);
}
@@ -173,39 +169,35 @@ int grpc_fd_is_orphaned(grpc_fd *fd) {
return (gpr_atm_acq_load(&fd->refst) & 1) == 0;
}
-static void pollset_kick_locked(grpc_pollset *pollset) {
- gpr_mu_lock(GRPC_POLLSET_MU(pollset));
- grpc_pollset_kick(pollset, NULL);
- gpr_mu_unlock(GRPC_POLLSET_MU(pollset));
+static void pollset_kick_locked(grpc_fd_watcher *watcher) {
+ gpr_mu_lock(GRPC_POLLSET_MU(watcher->pollset));
+ GPR_ASSERT(watcher->worker);
+ grpc_pollset_kick_ext(watcher->pollset, watcher->worker,
+ GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
+ gpr_mu_unlock(GRPC_POLLSET_MU(watcher->pollset));
}
static void maybe_wake_one_watcher_locked(grpc_fd *fd) {
if (fd->inactive_watcher_root.next != &fd->inactive_watcher_root) {
- pollset_kick_locked(fd->inactive_watcher_root.next->pollset);
+ pollset_kick_locked(fd->inactive_watcher_root.next);
} else if (fd->read_watcher) {
- pollset_kick_locked(fd->read_watcher->pollset);
+ pollset_kick_locked(fd->read_watcher);
} else if (fd->write_watcher) {
- pollset_kick_locked(fd->write_watcher->pollset);
+ pollset_kick_locked(fd->write_watcher);
}
}
-static void maybe_wake_one_watcher(grpc_fd *fd) {
- gpr_mu_lock(&fd->watcher_mu);
- maybe_wake_one_watcher_locked(fd);
- gpr_mu_unlock(&fd->watcher_mu);
-}
-
static void wake_all_watchers_locked(grpc_fd *fd) {
grpc_fd_watcher *watcher;
for (watcher = fd->inactive_watcher_root.next;
watcher != &fd->inactive_watcher_root; watcher = watcher->next) {
- pollset_kick_locked(watcher->pollset);
+ pollset_kick_locked(watcher);
}
if (fd->read_watcher) {
- pollset_kick_locked(fd->read_watcher->pollset);
+ pollset_kick_locked(fd->read_watcher);
}
if (fd->write_watcher && fd->write_watcher != fd->read_watcher) {
- pollset_kick_locked(fd->write_watcher->pollset);
+ pollset_kick_locked(fd->write_watcher);
}
}
@@ -218,7 +210,7 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
const char *reason) {
fd->on_done_closure = on_done;
shutdown(fd->fd, SHUT_RDWR);
- gpr_mu_lock(&fd->watcher_mu);
+ gpr_mu_lock(&fd->mu);
REF_BY(fd, 1, reason); /* remove active status, but keep referenced */
if (!has_watchers(fd)) {
fd->closed = 1;
@@ -227,7 +219,7 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
} else {
wake_all_watchers_locked(fd);
}
- gpr_mu_unlock(&fd->watcher_mu);
+ gpr_mu_unlock(&fd->mu);
UNREF_BY(fd, 2, reason); /* drop the reference */
}
@@ -247,136 +239,121 @@ void grpc_fd_ref(grpc_fd *fd) { ref_by(fd, 2); }
void grpc_fd_unref(grpc_fd *fd) { unref_by(fd, 2); }
#endif
-static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *st,
- grpc_closure *closure) {
- switch (gpr_atm_acq_load(st)) {
- case NOT_READY:
- /* There is no race if the descriptor is already ready, so we skip
- the interlocked op in that case. As long as the app doesn't
- try to set the same upcall twice (which it shouldn't) then
- oldval should never be anything other than READY or NOT_READY. We
- don't
- check for user error on the fast path. */
- if (gpr_atm_rel_cas(st, NOT_READY, (gpr_intptr)closure)) {
- /* swap was successful -- the closure will run after the next
- set_ready call. NOTE: we don't have an ABA problem here,
- since we should never have concurrent calls to the same
- notify_on function. */
- maybe_wake_one_watcher(fd);
- return;
- }
- /* swap was unsuccessful due to an intervening set_ready call.
- Fall through to the READY code below */
- case READY:
- GPR_ASSERT(gpr_atm_no_barrier_load(st) == READY);
- gpr_atm_rel_store(st, NOT_READY);
- grpc_exec_ctx_enqueue(exec_ctx, closure,
- !gpr_atm_acq_load(&fd->shutdown));
- return;
- default: /* WAITING */
- /* upcallptr was set to a different closure. This is an error! */
- gpr_log(GPR_ERROR,
- "User called a notify_on function with a previous callback still "
- "pending");
- abort();
+static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+ grpc_closure **st, grpc_closure *closure) {
+ if (*st == CLOSURE_NOT_READY) {
+ /* not ready ==> switch to a waiting state by setting the closure */
+ *st = closure;
+ } else if (*st == CLOSURE_READY) {
+ /* already ready ==> queue the closure to run immediately */
+ *st = CLOSURE_NOT_READY;
+ grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown);
+ maybe_wake_one_watcher_locked(fd);
+ } else {
+ /* upcallptr was set to a different closure. This is an error! */
+ gpr_log(GPR_ERROR,
+ "User called a notify_on function with a previous callback still "
+ "pending");
+ abort();
}
- gpr_log(GPR_ERROR, "Corrupt memory in &st->state");
- abort();
}
-static void set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
- gpr_atm *st) {
- gpr_intptr state = gpr_atm_acq_load(st);
-
- switch (state) {
- case READY:
- /* duplicate ready, ignore */
- return;
- case NOT_READY:
- if (gpr_atm_rel_cas(st, NOT_READY, READY)) {
- /* swap was successful -- the closure will run after the next
- notify_on call. */
- return;
- }
- /* swap was unsuccessful due to an intervening set_ready call.
- Fall through to the WAITING code below */
- state = gpr_atm_acq_load(st);
- default: /* waiting */
- GPR_ASSERT(gpr_atm_no_barrier_load(st) != READY &&
- gpr_atm_no_barrier_load(st) != NOT_READY);
- grpc_exec_ctx_enqueue(exec_ctx, (grpc_closure *)state,
- !gpr_atm_acq_load(&fd->shutdown));
- gpr_atm_rel_store(st, NOT_READY);
- return;
+/* returns 1 if state becomes not ready */
+static int set_ready_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+ grpc_closure **st) {
+ if (*st == CLOSURE_READY) {
+ /* duplicate ready ==> ignore */
+ return 0;
+ } else if (*st == CLOSURE_NOT_READY) {
+ /* not ready, and not waiting ==> flag ready */
+ *st = CLOSURE_READY;
+ return 0;
+ } else {
+ /* waiting ==> queue closure */
+ grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown);
+ *st = CLOSURE_NOT_READY;
+ return 1;
}
}
-static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *st) {
+static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure **st) {
/* only one set_ready can be active at once (but there may be a racing
notify_on) */
- gpr_mu_lock(&fd->set_state_mu);
+ gpr_mu_lock(&fd->mu);
set_ready_locked(exec_ctx, fd, st);
- gpr_mu_unlock(&fd->set_state_mu);
+ gpr_mu_unlock(&fd->mu);
}
void grpc_fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- gpr_mu_lock(&fd->set_state_mu);
- GPR_ASSERT(!gpr_atm_no_barrier_load(&fd->shutdown));
- gpr_atm_rel_store(&fd->shutdown, 1);
- set_ready_locked(exec_ctx, fd, &fd->readst);
- set_ready_locked(exec_ctx, fd, &fd->writest);
- gpr_mu_unlock(&fd->set_state_mu);
+ gpr_mu_lock(&fd->mu);
+ GPR_ASSERT(!fd->shutdown);
+ fd->shutdown = 1;
+ set_ready_locked(exec_ctx, fd, &fd->read_closure);
+ set_ready_locked(exec_ctx, fd, &fd->write_closure);
+ gpr_mu_unlock(&fd->mu);
}
void grpc_fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) {
- notify_on(exec_ctx, fd, &fd->readst, closure);
+ gpr_mu_lock(&fd->mu);
+ notify_on_locked(exec_ctx, fd, &fd->read_closure, closure);
+ gpr_mu_unlock(&fd->mu);
}
void grpc_fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
grpc_closure *closure) {
- notify_on(exec_ctx, fd, &fd->writest, closure);
+ gpr_mu_lock(&fd->mu);
+ notify_on_locked(exec_ctx, fd, &fd->write_closure, closure);
+ gpr_mu_unlock(&fd->mu);
}
gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
- gpr_uint32 read_mask, gpr_uint32 write_mask,
- grpc_fd_watcher *watcher) {
+ grpc_pollset_worker *worker, gpr_uint32 read_mask,
+ gpr_uint32 write_mask, grpc_fd_watcher *watcher) {
gpr_uint32 mask = 0;
+ grpc_closure *cur;
+ int requested;
/* keep track of pollers that have requested our events, in case they change
*/
GRPC_FD_REF(fd, "poll");
- gpr_mu_lock(&fd->watcher_mu);
+ gpr_mu_lock(&fd->mu);
+
/* if we are shutdown, then don't add to the watcher set */
- if (gpr_atm_no_barrier_load(&fd->shutdown)) {
+ if (fd->shutdown) {
watcher->fd = NULL;
watcher->pollset = NULL;
- gpr_mu_unlock(&fd->watcher_mu);
+ watcher->worker = NULL;
+ gpr_mu_unlock(&fd->mu);
GRPC_FD_UNREF(fd, "poll");
return 0;
}
+
/* if there is nobody polling for read, but we need to, then start doing so */
- if (read_mask && !fd->read_watcher &&
- (gpr_uintptr)gpr_atm_acq_load(&fd->readst) > READY) {
+ cur = fd->read_closure;
+ requested = cur != CLOSURE_READY;
+ if (read_mask && fd->read_watcher == NULL && requested) {
fd->read_watcher = watcher;
mask |= read_mask;
}
/* if there is nobody polling for write, but we need to, then start doing so
*/
- if (write_mask && !fd->write_watcher &&
- (gpr_uintptr)gpr_atm_acq_load(&fd->writest) > READY) {
+ cur = fd->write_closure;
+ requested = cur != CLOSURE_READY;
+ if (write_mask && fd->write_watcher == NULL && requested) {
fd->write_watcher = watcher;
mask |= write_mask;
}
/* if not polling, remember this watcher in case we need someone to later */
- if (mask == 0) {
+ if (mask == 0 && worker != NULL) {
watcher->next = &fd->inactive_watcher_root;
watcher->prev = watcher->next->prev;
watcher->next->prev = watcher->prev->next = watcher;
}
watcher->pollset = pollset;
+ watcher->worker = worker;
watcher->fd = fd;
- gpr_mu_unlock(&fd->watcher_mu);
+ gpr_mu_unlock(&fd->mu);
return mask;
}
@@ -391,24 +368,39 @@ void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
return;
}
- gpr_mu_lock(&fd->watcher_mu);
+ gpr_mu_lock(&fd->mu);
+
if (watcher == fd->read_watcher) {
/* remove read watcher, kick if we still need a read */
was_polling = 1;
- kick = kick || !got_read;
+ if (!got_read) {
+ kick = 1;
+ }
fd->read_watcher = NULL;
}
if (watcher == fd->write_watcher) {
/* remove write watcher, kick if we still need a write */
was_polling = 1;
- kick = kick || !got_write;
+ if (!got_write) {
+ kick = 1;
+ }
fd->write_watcher = NULL;
}
- if (!was_polling) {
+ if (!was_polling && watcher->worker != NULL) {
/* remove from inactive list */
watcher->next->prev = watcher->prev;
watcher->prev->next = watcher->next;
}
+ if (got_read) {
+ if (set_ready_locked(exec_ctx, fd, &fd->read_closure)) {
+ kick = 1;
+ }
+ }
+ if (got_write) {
+ if (set_ready_locked(exec_ctx, fd, &fd->write_closure)) {
+ kick = 1;
+ }
+ }
if (kick) {
maybe_wake_one_watcher_locked(fd);
}
@@ -417,17 +409,17 @@ void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *watcher,
close(fd->fd);
grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
}
- gpr_mu_unlock(&fd->watcher_mu);
+ gpr_mu_unlock(&fd->mu);
GRPC_FD_UNREF(fd, "poll");
}
void grpc_fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- set_ready(exec_ctx, fd, &fd->readst);
+ set_ready(exec_ctx, fd, &fd->read_closure);
}
void grpc_fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
- set_ready(exec_ctx, fd, &fd->writest);
+ set_ready(exec_ctx, fd, &fd->write_closure);
}
#endif
diff --git a/src/core/iomgr/fd_posix.h b/src/core/iomgr/fd_posix.h
index 089aa4d717..dc917ebbc0 100644
--- a/src/core/iomgr/fd_posix.h
+++ b/src/core/iomgr/fd_posix.h
@@ -46,6 +46,7 @@ typedef struct grpc_fd_watcher {
struct grpc_fd_watcher *next;
struct grpc_fd_watcher *prev;
grpc_pollset *pollset;
+ grpc_pollset_worker *worker;
grpc_fd *fd;
} grpc_fd_watcher;
@@ -58,8 +59,8 @@ struct grpc_fd {
and just unref by 1 when we're ready to flag the object as orphaned */
gpr_atm refst;
- gpr_mu set_state_mu;
- gpr_atm shutdown;
+ gpr_mu mu;
+ int shutdown;
int closed;
/* The watcher list.
@@ -84,18 +85,16 @@ struct grpc_fd {
If at a later time there becomes need of a poller to poll, one of
the inactive pollers may be kicked out of their poll loops to take
that responsibility. */
- gpr_mu watcher_mu;
grpc_fd_watcher inactive_watcher_root;
grpc_fd_watcher *read_watcher;
grpc_fd_watcher *write_watcher;
- gpr_atm readst;
- gpr_atm writest;
+ grpc_closure *read_closure;
+ grpc_closure *write_closure;
struct grpc_fd *freelist_next;
grpc_closure *on_done_closure;
- grpc_closure *shutdown_closures[2];
grpc_iomgr_object iomgr_object;
};
@@ -126,10 +125,12 @@ void grpc_fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_closure *on_done,
fd's current interest (such as epoll) do not need to call this function.
MUST NOT be called with a pollset lock taken */
gpr_uint32 grpc_fd_begin_poll(grpc_fd *fd, grpc_pollset *pollset,
- gpr_uint32 read_mask, gpr_uint32 write_mask,
- grpc_fd_watcher *rec);
+ grpc_pollset_worker *worker, gpr_uint32 read_mask,
+ gpr_uint32 write_mask, grpc_fd_watcher *rec);
/* Complete polling previously started with grpc_fd_begin_poll
- MUST NOT be called with a pollset lock taken */
+ MUST NOT be called with a pollset lock taken
+ if got_read or got_write are 1, also does the become_{readable,writable} as
+ appropriate. */
void grpc_fd_end_poll(grpc_exec_ctx *exec_ctx, grpc_fd_watcher *rec,
int got_read, int got_write);
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index faf0a6362b..2aafd21dfb 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -41,10 +41,11 @@
#include <sys/epoll.h>
#include <unistd.h>
-#include "src/core/iomgr/fd_posix.h"
-#include "src/core/support/block_annotate.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/iomgr/fd_posix.h"
+#include "src/core/support/block_annotate.h"
+#include "src/core/profiling/timers.h"
typedef struct wakeup_fd_hdl {
grpc_wakeup_fd wakeup_fd;
@@ -72,7 +73,7 @@ static void finally_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
/* We pretend to be polling whilst adding an fd to keep the fd from being
closed during the add. This may result in a spurious wakeup being assigned
to this pollset whilst adding, but that should be benign. */
- GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, 0, 0, &watcher) == 0);
+ GPR_ASSERT(grpc_fd_begin_poll(fd, pollset, NULL, 0, 0, &watcher) == 0);
if (watcher.fd != NULL) {
ev.events = (uint32_t)(EPOLLIN | EPOLLOUT | EPOLLET);
ev.data.ptr = fd;
@@ -182,9 +183,11 @@ static void multipoll_with_epoll_pollset_maybe_work_and_unlock(
/* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
even going into the blocking annotation if possible */
+ GPR_TIMER_BEGIN("poll", 0);
GRPC_SCHEDULING_START_BLOCKING_REGION;
poll_rv = grpc_poll_function(pfds, 2, timeout_ms);
GRPC_SCHEDULING_END_BLOCKING_REGION;
+ GPR_TIMER_END("poll", 0);
if (poll_rv < 0) {
if (errno != EINTR) {
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index 1356ebe7a0..faa6c14491 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -102,6 +102,9 @@ static void multipoll_with_poll_pollset_del_fd(grpc_exec_ctx *exec_ctx,
static void multipoll_with_poll_pollset_maybe_work_and_unlock(
grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, grpc_pollset_worker *worker,
gpr_timespec deadline, gpr_timespec now) {
+#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
+#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
+
int timeout;
int r;
size_t i, j, fd_count;
@@ -147,8 +150,8 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
gpr_mu_unlock(&pollset->mu);
for (i = 2; i < pfd_count; i++) {
- pfds[i].events = (short)grpc_fd_begin_poll(watchers[i].fd, pollset, POLLIN,
- POLLOUT, &watchers[i]);
+ pfds[i].events = (short)grpc_fd_begin_poll(watchers[i].fd, pollset, worker,
+ POLLIN, POLLOUT, &watchers[i]);
}
/* TODO(vpai): Consider first doing a 0 timeout poll here to avoid
@@ -157,34 +160,29 @@ static void multipoll_with_poll_pollset_maybe_work_and_unlock(
r = grpc_poll_function(pfds, pfd_count, timeout);
GRPC_SCHEDULING_END_BLOCKING_REGION;
- for (i = 2; i < pfd_count; i++) {
- grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN,
- pfds[i].revents & POLLOUT);
- }
-
if (r < 0) {
- if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ for (i = 2; i < pfd_count; i++) {
+ grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
}
} else if (r == 0) {
- /* do nothing */
+ for (i = 2; i < pfd_count; i++) {
+ grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
+ }
} else {
- if (pfds[0].revents & POLLIN) {
+ if (pfds[0].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
}
- if (pfds[1].revents & POLLIN) {
+ if (pfds[1].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd);
}
for (i = 2; i < pfd_count; i++) {
if (watchers[i].fd == NULL) {
+ grpc_fd_end_poll(exec_ctx, &watchers[i], 0, 0);
continue;
}
- if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
- grpc_fd_become_readable(exec_ctx, watchers[i].fd);
- }
- if (pfds[i].revents & (POLLOUT | POLLHUP | POLLERR)) {
- grpc_fd_become_writable(exec_ctx, watchers[i].fd);
- }
+ grpc_fd_end_poll(exec_ctx, &watchers[i], pfds[i].revents & POLLIN_CHECK,
+ pfds[i].revents & POLLOUT_CHECK);
}
}
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index b663780a02..4d8bc5374f 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -98,29 +98,70 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker;
}
-void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
+void grpc_pollset_kick_ext(grpc_pollset *p,
+ grpc_pollset_worker *specific_worker,
+ gpr_uint32 flags) {
+ GPR_TIMER_BEGIN("grpc_pollset_kick_ext", 0);
+
/* pollset->mu already held */
if (specific_worker != NULL) {
if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
+ GPR_TIMER_BEGIN("grpc_pollset_kick_ext.broadcast", 0);
+ GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
for (specific_worker = p->root_worker.next;
specific_worker != &p->root_worker;
specific_worker = specific_worker->next) {
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd);
}
p->kicked_without_pollers = 1;
+ GPR_TIMER_END("grpc_pollset_kick_ext.broadcast", 0);
} else if (gpr_tls_get(&g_current_thread_worker) !=
(gpr_intptr)specific_worker) {
+ GPR_TIMER_MARK("different_thread_worker", 0);
+ if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
+ specific_worker->reevaluate_polling_on_wakeup = 1;
+ }
+ grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd);
+ } else if ((flags & GRPC_POLLSET_CAN_KICK_SELF) != 0) {
+ GPR_TIMER_MARK("kick_yoself", 0);
+ if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
+ specific_worker->reevaluate_polling_on_wakeup = 1;
+ }
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd);
}
} else if (gpr_tls_get(&g_current_thread_poller) != (gpr_intptr)p) {
+ GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
+ GPR_TIMER_MARK("kick_anonymous", 0);
specific_worker = pop_front_worker(p);
if (specific_worker != NULL) {
- push_back_worker(p, specific_worker);
- grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd);
+ if (gpr_tls_get(&g_current_thread_worker) ==
+ (gpr_intptr)specific_worker) {
+ GPR_TIMER_MARK("kick_anonymous_not_self", 0);
+ push_back_worker(p, specific_worker);
+ specific_worker = pop_front_worker(p);
+ if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
+ gpr_tls_get(&g_current_thread_worker) ==
+ (gpr_intptr)specific_worker) {
+ push_back_worker(p, specific_worker);
+ specific_worker = NULL;
+ }
+ }
+ if (specific_worker != NULL) {
+ GPR_TIMER_MARK("finally_kick", 0);
+ push_back_worker(p, specific_worker);
+ grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd);
+ }
} else {
+ GPR_TIMER_MARK("kicked_no_pollers", 0);
p->kicked_without_pollers = 1;
}
}
+
+ GPR_TIMER_END("grpc_pollset_kick_ext", 0);
+}
+
+void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
+ grpc_pollset_kick_ext(p, specific_worker, 0);
}
/* global state management */
@@ -195,52 +236,91 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
/* pollset->mu already held */
int added_worker = 0;
int locked = 1;
+ int queued_work = 0;
+ int keep_polling = 0;
+ GPR_TIMER_BEGIN("grpc_pollset_work", 0);
/* this must happen before we (potentially) drop pollset->mu */
worker->next = worker->prev = NULL;
+ worker->reevaluate_polling_on_wakeup = 0;
/* TODO(ctiller): pool these */
grpc_wakeup_fd_init(&worker->wakeup_fd);
+ /* If there's work waiting for the pollset to be idle, and the
+ pollset is idle, then do that work */
if (!grpc_pollset_has_workers(pollset) &&
!grpc_closure_list_empty(pollset->idle_jobs)) {
grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs);
goto done;
}
+ /* Check alarms - these are a global resource so we just ping
+ each time through on every pollset.
+ May update deadline to ensure timely wakeups.
+ TODO(ctiller): can this work be localized? */
if (grpc_alarm_check(exec_ctx, now, &deadline)) {
gpr_mu_unlock(&pollset->mu);
locked = 0;
goto done;
}
+ /* If we're shutting down then we don't execute any extended work */
if (pollset->shutting_down) {
goto done;
}
+ /* Give do_promote priority so we don't starve it out */
if (pollset->in_flight_cbs) {
- /* Give do_promote priority so we don't starve it out */
gpr_mu_unlock(&pollset->mu);
locked = 0;
goto done;
}
- if (!pollset->kicked_without_pollers) {
- push_front_worker(pollset, worker);
- added_worker = 1;
- gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
- gpr_tls_set(&g_current_thread_worker, (gpr_intptr)worker);
- pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, worker, deadline,
- now);
- locked = 0;
- gpr_tls_set(&g_current_thread_poller, 0);
- gpr_tls_set(&g_current_thread_worker, 0);
- } else {
- pollset->kicked_without_pollers = 0;
- }
-done:
- if (!locked) {
- grpc_exec_ctx_flush(exec_ctx);
- gpr_mu_lock(&pollset->mu);
- locked = 1;
+ /* Start polling, and keep doing so while we're being asked to
+ re-evaluate our pollers (this allows poll() based pollers to
+ ensure they don't miss wakeups) */
+ keep_polling = 1;
+ while (keep_polling) {
+ keep_polling = 0;
+ if (!pollset->kicked_without_pollers) {
+ if (!added_worker) {
+ push_front_worker(pollset, worker);
+ added_worker = 1;
+ }
+ gpr_tls_set(&g_current_thread_poller, (gpr_intptr)pollset);
+ gpr_tls_set(&g_current_thread_worker, (gpr_intptr)worker);
+ GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
+ pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, worker,
+ deadline, now);
+ GPR_TIMER_END("maybe_work_and_unlock", 0);
+ locked = 0;
+ gpr_tls_set(&g_current_thread_poller, 0);
+ gpr_tls_set(&g_current_thread_worker, 0);
+ } else {
+ pollset->kicked_without_pollers = 0;
+ }
+ /* Finished execution - start cleaning up.
+ Note that we may arrive here from outside the enclosing while() loop.
+ In that case we won't loop though as we haven't added worker to the
+ worker list, which means nobody could ask us to re-evaluate polling). */
+ done:
+ if (!locked) {
+ queued_work |= grpc_exec_ctx_flush(exec_ctx);
+ gpr_mu_lock(&pollset->mu);
+ locked = 1;
+ }
+ /* If we're forced to re-evaluate polling (via grpc_pollset_kick with
+ GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
+ a loop */
+ if (worker->reevaluate_polling_on_wakeup) {
+ worker->reevaluate_polling_on_wakeup = 0;
+ pollset->kicked_without_pollers = 0;
+ if (queued_work) {
+ /* If there's queued work on the list, then set the deadline to be
+ immediate so we get back out of the polling loop quickly */
+ deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
+ }
+ keep_polling = 1;
+ }
}
- grpc_wakeup_fd_destroy(&worker->wakeup_fd);
if (added_worker) {
remove_worker(pollset, worker);
}
+ grpc_wakeup_fd_destroy(&worker->wakeup_fd);
if (pollset->shutting_down) {
if (grpc_pollset_has_workers(pollset)) {
grpc_pollset_kick(pollset, NULL);
@@ -261,6 +341,7 @@ done:
gpr_mu_lock(&pollset->mu);
}
}
+ GPR_TIMER_END("grpc_pollset_work", 0);
}
void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@@ -454,6 +535,9 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
grpc_pollset_worker *worker,
gpr_timespec deadline,
gpr_timespec now) {
+#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
+#define POLLIN_CHECK (POLLIN | POLLHUP | POLLERR)
+
struct pollfd pfd[3];
grpc_fd *fd;
grpc_fd_watcher fd_watcher;
@@ -479,8 +563,8 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
pfd[2].revents = 0;
GRPC_FD_REF(fd, "basicpoll_begin");
gpr_mu_unlock(&pollset->mu);
- pfd[2].events =
- (short)grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
+ pfd[2].events = (short)grpc_fd_begin_poll(fd, pollset, worker, POLLIN,
+ POLLOUT, &fd_watcher);
if (pfd[2].events != 0) {
nfds++;
}
@@ -492,36 +576,33 @@ static void basic_pollset_maybe_work_and_unlock(grpc_exec_ctx *exec_ctx,
even going into the blocking annotation if possible */
/* poll fd count (argument 2) is shortened by one if we have no events
to poll on - such that it only includes the kicker */
+ GPR_TIMER_BEGIN("poll", 0);
GRPC_SCHEDULING_START_BLOCKING_REGION;
r = grpc_poll_function(pfd, nfds, timeout);
GRPC_SCHEDULING_END_BLOCKING_REGION;
- GRPC_TIMER_MARK(GRPC_PTAG_POLL_FINISHED, r);
-
- if (fd) {
- grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN,
- pfd[2].revents & POLLOUT);
- }
+ GPR_TIMER_END("poll", 0);
if (r < 0) {
- if (errno != EINTR) {
- gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
+ if (fd) {
+ grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
}
} else if (r == 0) {
- /* do nothing */
+ if (fd) {
+ grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
+ }
} else {
- if (pfd[0].revents & POLLIN) {
+ if (pfd[0].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&grpc_global_wakeup_fd);
}
- if (pfd[1].revents & POLLIN) {
+ if (pfd[1].revents & POLLIN_CHECK) {
grpc_wakeup_fd_consume_wakeup(&worker->wakeup_fd);
}
if (nfds > 2) {
- if (pfd[2].revents & (POLLIN | POLLHUP | POLLERR)) {
- grpc_fd_become_readable(exec_ctx, fd);
- }
- if (pfd[2].revents & (POLLOUT | POLLHUP | POLLERR)) {
- grpc_fd_become_writable(exec_ctx, fd);
- }
+ grpc_fd_end_poll(exec_ctx, &fd_watcher, pfd[2].revents & POLLIN_CHECK,
+ pfd[2].revents & POLLOUT_CHECK);
+ } else if (fd) {
+ grpc_fd_end_poll(exec_ctx, &fd_watcher, 0, 0);
}
}
diff --git a/src/core/iomgr/pollset_posix.h b/src/core/iomgr/pollset_posix.h
index 83c5258539..34f76db2af 100644
--- a/src/core/iomgr/pollset_posix.h
+++ b/src/core/iomgr/pollset_posix.h
@@ -50,6 +50,7 @@ struct grpc_fd;
typedef struct grpc_pollset_worker {
grpc_wakeup_fd wakeup_fd;
+ int reevaluate_polling_on_wakeup;
struct grpc_pollset_worker *next;
struct grpc_pollset_worker *prev;
} grpc_pollset_worker;
@@ -111,6 +112,16 @@ void grpc_kick_drain(grpc_pollset *p);
int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
gpr_timespec now);
+/* Allow kick to wakeup the currently polling worker */
+#define GRPC_POLLSET_CAN_KICK_SELF 1
+/* Force the wakee to repoll when awoken */
+#define GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP 2
+/* As per grpc_pollset_kick, with an extended set of flags (defined above)
+ -- mostly for fd_posix's use. */
+void grpc_pollset_kick_ext(grpc_pollset *p,
+ grpc_pollset_worker *specific_worker,
+ gpr_uint32 flags);
+
/* turn a pollset into a multipoller: platform specific */
typedef void (*grpc_platform_become_multipoller_type)(grpc_exec_ctx *exec_ctx,
grpc_pollset *pollset,
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index aca2691c41..fe20039264 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -191,7 +191,7 @@ static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) {
goto finish;
}
- abort();
+ GPR_UNREACHABLE_CODE(return );
finish:
if (fd != NULL) {
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 4a57037a72..915553d509 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -180,7 +180,7 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
GPR_ASSERT(!tcp->finished_edge);
GPR_ASSERT(tcp->iov_size <= MAX_READ_IOVEC);
GPR_ASSERT(tcp->incoming_buffer->count <= MAX_READ_IOVEC);
- GRPC_TIMER_BEGIN(GRPC_PTAG_HANDLE_READ, 0);
+ GPR_TIMER_BEGIN("tcp_continue_read", 0);
while (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
gpr_slice_buffer_add_indexed(tcp->incoming_buffer,
@@ -199,11 +199,11 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
msg.msg_controllen = 0;
msg.msg_flags = 0;
- GRPC_TIMER_BEGIN(GRPC_PTAG_RECVMSG, 0);
+ GPR_TIMER_BEGIN("recvmsg", 1);
do {
read_bytes = recvmsg(tcp->fd, &msg, 0);
} while (read_bytes < 0 && errno == EINTR);
- GRPC_TIMER_END(GRPC_PTAG_RECVMSG, 0);
+ GPR_TIMER_END("recvmsg", 0);
if (read_bytes < 0) {
/* NB: After calling call_read_cb a parallel call of the read handler may
@@ -240,7 +240,7 @@ static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
TCP_UNREF(exec_ctx, tcp, "read");
}
- GRPC_TIMER_END(GRPC_PTAG_HANDLE_READ, 0);
+ GPR_TIMER_END("tcp_continue_read", 0);
}
static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
@@ -316,12 +316,12 @@ static flush_result tcp_flush(grpc_tcp *tcp) {
msg.msg_controllen = 0;
msg.msg_flags = 0;
- GRPC_TIMER_BEGIN(GRPC_PTAG_SENDMSG, 0);
+ GPR_TIMER_BEGIN("sendmsg", 1);
do {
/* TODO(klempner): Cork if this is a partial write */
sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS);
} while (sent_length < 0 && errno == EINTR);
- GRPC_TIMER_END(GRPC_PTAG_SENDMSG, 0);
+ GPR_TIMER_END("sendmsg", 0);
if (sent_length < 0) {
if (errno == EAGAIN) {
@@ -370,17 +370,17 @@ static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
return;
}
- GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_CB_WRITE, 0);
status = tcp_flush(tcp);
if (status == FLUSH_PENDING) {
grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
} else {
cb = tcp->write_cb;
tcp->write_cb = NULL;
+ GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
cb->cb(exec_ctx, cb->cb_arg, status == FLUSH_DONE);
+ GPR_TIMER_END("tcp_handle_write.cb", 0);
TCP_UNREF(exec_ctx, tcp, "write");
}
- GRPC_TIMER_END(GRPC_PTAG_TCP_CB_WRITE, 0);
}
static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -399,11 +399,11 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
}
}
- GRPC_TIMER_BEGIN(GRPC_PTAG_TCP_WRITE, 0);
+ GPR_TIMER_BEGIN("tcp_write", 0);
GPR_ASSERT(tcp->write_cb == NULL);
if (buf->length == 0) {
- GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
+ GPR_TIMER_END("tcp_write", 0);
grpc_exec_ctx_enqueue(exec_ctx, cb, 1);
return;
}
@@ -420,7 +420,7 @@ static void tcp_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE);
}
- GRPC_TIMER_END(GRPC_PTAG_TCP_WRITE, 0);
+ GPR_TIMER_END("tcp_write", 0);
}
static void tcp_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 13bd67576f..99c76dcbe9 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -352,7 +352,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
gpr_free(addr_str);
}
- abort();
+ GPR_UNREACHABLE_CODE(return );
error:
gpr_mu_lock(&sp->server->mu);
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index db3319b3c6..3fea8b5b35 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -336,6 +336,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
peer_name_string);
gpr_free(fd_name);
gpr_free(peer_name_string);
+ } else {
+ closesocket(sock);
}
}
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
index 1304f2067e..9903e970e6 100644
--- a/src/core/iomgr/udp_server.c
+++ b/src/core/iomgr/udp_server.c
@@ -278,7 +278,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
/* Tell the registered callback that data is available to read. */
GPR_ASSERT(sp->read_cb);
- sp->read_cb(sp->emfd, sp->server->grpc_server);
+ sp->read_cb(exec_ctx, sp->emfd, sp->server->grpc_server);
/* Re-arm the notification event so we get another chance to read. */
grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
index dbbe097109..de5736c426 100644
--- a/src/core/iomgr/udp_server.h
+++ b/src/core/iomgr/udp_server.h
@@ -43,7 +43,8 @@ typedef struct grpc_server grpc_server;
typedef struct grpc_udp_server grpc_udp_server;
/* Called when data is available to read from the socket. */
-typedef void (*grpc_udp_server_read_cb)(grpc_fd *emfd, grpc_server *server);
+typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd,
+ grpc_server *server);
/* Create a server, initially not bound to any ports */
grpc_udp_server *grpc_udp_server_create(void);
diff --git a/src/core/iomgr/wakeup_fd_eventfd.c b/src/core/iomgr/wakeup_fd_eventfd.c
index 48eb1afb3d..f67379e4fc 100644
--- a/src/core/iomgr/wakeup_fd_eventfd.c
+++ b/src/core/iomgr/wakeup_fd_eventfd.c
@@ -39,9 +39,11 @@
#include <sys/eventfd.h>
#include <unistd.h>
-#include "src/core/iomgr/wakeup_fd_posix.h"
#include <grpc/support/log.h>
+#include "src/core/iomgr/wakeup_fd_posix.h"
+#include "src/core/profiling/timers.h"
+
static void eventfd_create(grpc_wakeup_fd* fd_info) {
int efd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
/* TODO(klempner): Handle failure more gracefully */
@@ -60,9 +62,11 @@ static void eventfd_consume(grpc_wakeup_fd* fd_info) {
static void eventfd_wakeup(grpc_wakeup_fd* fd_info) {
int err;
+ GPR_TIMER_BEGIN("eventfd_wakeup", 0);
do {
err = eventfd_write(fd_info->read_fd, 1);
} while (err < 0 && errno == EINTR);
+ GPR_TIMER_END("eventfd_wakeup", 0);
}
static void eventfd_destroy(grpc_wakeup_fd* fd_info) {
diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c
index 2f6c88daac..b49cdd07b3 100644
--- a/src/core/profiling/basic_timers.c
+++ b/src/core/profiling/basic_timers.c
@@ -44,98 +44,91 @@
#include <grpc/support/thd.h>
#include <stdio.h>
-typedef enum {
- BEGIN = '{',
- END = '}',
- MARK = '.',
- IMPORTANT = '!'
-} marker_type;
-
-typedef struct grpc_timer_entry {
+typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type;
+
+typedef struct gpr_timer_entry {
gpr_timespec tm;
- int tag;
const char *tagstr;
- marker_type type;
- void *id;
const char *file;
int line;
-} grpc_timer_entry;
+ char type;
+ gpr_uint8 important;
+} gpr_timer_entry;
+
+#define MAX_COUNT (1024 * 1024 / sizeof(gpr_timer_entry))
-#define MAX_COUNT (1024 * 1024 / sizeof(grpc_timer_entry))
+static __thread gpr_timer_entry g_log[MAX_COUNT];
+static __thread int g_count;
+static gpr_once g_once_init = GPR_ONCE_INIT;
+static FILE *output_file;
-static __thread grpc_timer_entry log[MAX_COUNT];
-static __thread int count;
+static void close_output() { fclose(output_file); }
+
+static void init_output() {
+ output_file = fopen("latency_trace.txt", "w");
+ GPR_ASSERT(output_file);
+ atexit(close_output);
+}
static void log_report() {
int i;
- for (i = 0; i < count; i++) {
- grpc_timer_entry *entry = &(log[i]);
- printf("GRPC_LAT_PROF %ld.%09d %p %c %d(%s) %p %s %d\n", entry->tm.tv_sec,
- entry->tm.tv_nsec, (void *)(gpr_intptr)gpr_thd_currentid(),
- entry->type, entry->tag, entry->tagstr, entry->id, entry->file,
- entry->line);
+ gpr_once_init(&g_once_init, init_output);
+ for (i = 0; i < g_count; i++) {
+ gpr_timer_entry *entry = &(g_log[i]);
+ fprintf(output_file,
+ "{\"t\": %ld.%09d, \"thd\": \"%p\", \"type\": \"%c\", \"tag\": "
+ "\"%s\", \"file\": \"%s\", \"line\": %d, \"imp\": %d}\n",
+ entry->tm.tv_sec, entry->tm.tv_nsec,
+ (void *)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tagstr,
+ entry->file, entry->line, entry->important);
}
/* Now clear out the log */
- count = 0;
+ g_count = 0;
}
-static void grpc_timers_log_add(int tag, const char *tagstr, marker_type type,
- void *id, const char *file, int line) {
- grpc_timer_entry *entry;
+static void gpr_timers_log_add(const char *tagstr, marker_type type,
+ int important, const char *file, int line) {
+ gpr_timer_entry *entry;
/* TODO (vpai) : Improve concurrency */
- if (count == MAX_COUNT) {
+ if (g_count == MAX_COUNT) {
log_report();
}
- entry = &log[count++];
+ entry = &g_log[g_count++];
entry->tm = gpr_now(GPR_CLOCK_PRECISE);
- entry->tag = tag;
entry->tagstr = tagstr;
entry->type = type;
- entry->id = id;
entry->file = file;
entry->line = line;
+ entry->important = important != 0;
}
/* Latency profiler API implementation. */
-void grpc_timer_add_mark(int tag, const char *tagstr, void *id,
- const char *file, int line) {
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) {
- grpc_timers_log_add(tag, tagstr, MARK, id, file, line);
- }
+void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
+ int line) {
+ gpr_timers_log_add(tagstr, MARK, important, file, line);
}
-void grpc_timer_add_important_mark(int tag, const char *tagstr, void *id,
- const char *file, int line) {
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) {
- grpc_timers_log_add(tag, tagstr, IMPORTANT, id, file, line);
- }
+void gpr_timer_begin(const char *tagstr, int important, const char *file,
+ int line) {
+ gpr_timers_log_add(tagstr, BEGIN, important, file, line);
}
-void grpc_timer_begin(int tag, const char *tagstr, void *id, const char *file,
- int line) {
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) {
- grpc_timers_log_add(tag, tagstr, BEGIN, id, file, line);
- }
-}
-
-void grpc_timer_end(int tag, const char *tagstr, void *id, const char *file,
- int line) {
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) {
- grpc_timers_log_add(tag, tagstr, END, id, file, line);
- }
+void gpr_timer_end(const char *tagstr, int important, const char *file,
+ int line) {
+ gpr_timers_log_add(tagstr, END, important, file, line);
}
/* Basic profiler specific API functions. */
-void grpc_timers_global_init(void) {}
+void gpr_timers_global_init(void) {}
-void grpc_timers_global_destroy(void) {}
+void gpr_timers_global_destroy(void) {}
#else /* !GRPC_BASIC_PROFILER */
-void grpc_timers_global_init(void) {}
+void gpr_timers_global_init(void) {}
-void grpc_timers_global_destroy(void) {}
+void gpr_timers_global_destroy(void) {}
#endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/profiling/stap_timers.c b/src/core/profiling/stap_timers.c
index 6868a674a9..efcd1af4a1 100644
--- a/src/core/profiling/stap_timers.c
+++ b/src/core/profiling/stap_timers.c
@@ -42,23 +42,23 @@
#include "src/core/profiling/stap_probes.h"
/* Latency profiler API implementation. */
-void grpc_timer_add_mark(int tag, const char *tagstr, void *id,
- const char *file, int line) {
+void gpr_timer_add_mark(int tag, const char *tagstr, void *id, const char *file,
+ int line) {
_STAP_ADD_MARK(tag);
}
-void grpc_timer_add_important_mark(int tag, const char *tagstr, void *id,
- const char *file, int line) {
+void gpr_timer_add_important_mark(int tag, const char *tagstr, void *id,
+ const char *file, int line) {
_STAP_ADD_IMPORTANT_MARK(tag);
}
-void grpc_timer_begin(int tag, const char *tagstr, void *id, const char *file,
- int line) {
+void gpr_timer_begin(int tag, const char *tagstr, void *id, const char *file,
+ int line) {
_STAP_TIMING_NS_BEGIN(tag);
}
-void grpc_timer_end(int tag, const char *tagstr, void *id, const char *file,
- int line) {
+void gpr_timer_end(int tag, const char *tagstr, void *id, const char *file,
+ int line) {
_STAP_TIMING_NS_END(tag);
}
diff --git a/src/core/profiling/timers.h b/src/core/profiling/timers.h
index a70520408c..0d112e7248 100644
--- a/src/core/profiling/timers.h
+++ b/src/core/profiling/timers.h
@@ -38,65 +38,28 @@
extern "C" {
#endif
-void grpc_timers_global_init(void);
-void grpc_timers_global_destroy(void);
-
-void grpc_timer_add_mark(int tag, const char *tagstr, void *id,
- const char *file, int line);
-void grpc_timer_add_important_mark(int tag, const char *tagstr, void *id,
- const char *file, int line);
-void grpc_timer_begin(int tag, const char *tagstr, void *id, const char *file,
- int line);
-void grpc_timer_end(int tag, const char *tagstr, void *id, const char *file,
- int line);
-
-enum grpc_profiling_tags {
- /* Any GRPC_PTAG_* >= than the threshold won't generate any profiling mark. */
- GRPC_PTAG_IGNORE_THRESHOLD = 1000000,
-
- /* Re. Protos. */
- GRPC_PTAG_PROTO_SERIALIZE = 100 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_PROTO_DESERIALIZE = 101 + GRPC_PTAG_IGNORE_THRESHOLD,
-
- /* Re. sockets. */
- GRPC_PTAG_HANDLE_READ = 200 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_SENDMSG = 201 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_RECVMSG = 202 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_POLL_FINISHED = 203 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_TCP_CB_WRITE = 204 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_TCP_WRITE = 205 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_CALL_ON_DONE_RECV = 206 + GRPC_PTAG_IGNORE_THRESHOLD,
-
- /* C++ */
- GRPC_PTAG_CPP_CALL_CREATED = 300 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_CPP_PERFORM_OPS = 301 + GRPC_PTAG_IGNORE_THRESHOLD,
-
- /* Transports */
- GRPC_PTAG_HTTP2_UNLOCK = 401 + GRPC_PTAG_IGNORE_THRESHOLD,
- GRPC_PTAG_HTTP2_UNLOCK_CLEANUP = 402 + GRPC_PTAG_IGNORE_THRESHOLD,
-
- /* > 1024 Unassigned reserved. For any miscellaneous use.
- * Use addition to generate tags from this base or take advantage of the 10
- * zero'd bits for OR-ing. */
- GRPC_PTAG_OTHER_BASE = 1024
-};
+void gpr_timers_global_init(void);
+void gpr_timers_global_destroy(void);
+
+void gpr_timer_add_mark(const char *tagstr, int important, const char *file,
+ int line);
+void gpr_timer_begin(const char *tagstr, int important, const char *file,
+ int line);
+void gpr_timer_end(const char *tagstr, int important, const char *file,
+ int line);
#if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
/* No profiling. No-op all the things. */
-#define GRPC_TIMER_MARK(tag, id) \
- do { \
- } while (0)
-
-#define GRPC_TIMER_IMPORTANT_MARK(tag, id) \
- do { \
+#define GPR_TIMER_MARK(tag, important) \
+ do { \
} while (0)
-#define GRPC_TIMER_BEGIN(tag, id) \
- do { \
+#define GPR_TIMER_BEGIN(tag, important) \
+ do { \
} while (0)
-#define GRPC_TIMER_END(tag, id) \
- do { \
+#define GPR_TIMER_END(tag, important) \
+ do { \
} while (0)
#else /* at least one profiler requested... */
@@ -106,28 +69,14 @@ enum grpc_profiling_tags {
#endif
/* Generic profiling interface. */
-#define GRPC_TIMER_MARK(tag, id) \
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
- grpc_timer_add_mark(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, \
- __LINE__); \
- }
-
-#define GRPC_TIMER_IMPORTANT_MARK(tag, id) \
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
- grpc_timer_add_important_mark(tag, #tag, ((void *)(gpr_intptr)(id)), \
- __FILE__, __LINE__); \
- }
+#define GPR_TIMER_MARK(tag, important) \
+ gpr_timer_add_mark(tag, important, __FILE__, __LINE__);
-#define GRPC_TIMER_BEGIN(tag, id) \
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
- grpc_timer_begin(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, \
- __LINE__); \
- }
+#define GPR_TIMER_BEGIN(tag, important) \
+ gpr_timer_begin(tag, important, __FILE__, __LINE__);
-#define GRPC_TIMER_END(tag, id) \
- if (tag < GRPC_PTAG_IGNORE_THRESHOLD) { \
- grpc_timer_end(tag, #tag, ((void *)(gpr_intptr)(id)), __FILE__, __LINE__); \
- }
+#define GPR_TIMER_END(tag, important) \
+ gpr_timer_end(tag, important, __FILE__, __LINE__);
#ifdef GRPC_STAP_PROFILER
/* Empty placeholder for now. */
@@ -141,6 +90,28 @@ enum grpc_profiling_tags {
#ifdef __cplusplus
}
+
+#if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
+namespace grpc {
+class ProfileScope {
+ public:
+ ProfileScope(const char *desc, bool important) : desc_(desc) {
+ GPR_TIMER_BEGIN(desc_, important ? 1 : 0);
+ }
+ ~ProfileScope() { GPR_TIMER_END(desc_, 0); }
+
+ private:
+ const char *const desc_;
+};
+}
+
+#define GPR_TIMER_SCOPE(tag, important) \
+ ::grpc::ProfileScope _profile_scope_##__LINE__((tag), (important))
+#else
+#define GPR_TIMER_SCOPE(tag, important) \
+ do { \
+ } while (false)
+#endif
#endif
#endif /* GRPC_CORE_PROFILING_TIMERS_H */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 398db20e8c..5e155d83b9 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -181,6 +181,48 @@ void grpc_server_credentials_set_auth_metadata_processor(
creds->processor = processor;
}
+static void server_credentials_pointer_arg_destroy(void *p) {
+ grpc_server_credentials_unref(p);
+}
+
+static void *server_credentials_pointer_arg_copy(void *p) {
+ return grpc_server_credentials_ref(p);
+}
+
+grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) {
+ grpc_arg arg;
+ memset(&arg, 0, sizeof(grpc_arg));
+ arg.type = GRPC_ARG_POINTER;
+ arg.key = GRPC_SERVER_CREDENTIALS_ARG;
+ arg.value.pointer.p = p;
+ arg.value.pointer.copy = server_credentials_pointer_arg_copy;
+ arg.value.pointer.destroy = server_credentials_pointer_arg_destroy;
+ return arg;
+}
+
+grpc_server_credentials *grpc_server_credentials_from_arg(
+ const grpc_arg *arg) {
+ if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL;
+ if (arg->type != GRPC_ARG_POINTER) {
+ gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
+ GRPC_SERVER_CREDENTIALS_ARG);
+ return NULL;
+ }
+ return arg->value.pointer.p;
+}
+
+grpc_server_credentials *grpc_find_server_credentials_in_args(
+ const grpc_channel_args *args) {
+ size_t i;
+ if (args == NULL) return NULL;
+ for (i = 0; i < args->num_args; i++) {
+ grpc_server_credentials *p =
+ grpc_server_credentials_from_arg(&args->args[i]);
+ if (p != NULL) return p;
+ }
+ return NULL;
+}
+
/* -- Ssl credentials. -- */
static void ssl_destruct(grpc_credentials *creds) {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index b213e052d3..01203b08f1 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -215,7 +215,6 @@ typedef struct {
grpc_server_credentials *c, grpc_security_connector **sc);
} grpc_server_credentials_vtable;
-/* TODO(jboeuf): Add a refcount. */
struct grpc_server_credentials {
const grpc_server_credentials_vtable *vtable;
const char *type;
@@ -231,6 +230,13 @@ grpc_server_credentials *grpc_server_credentials_ref(
void grpc_server_credentials_unref(grpc_server_credentials *creds);
+#define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
+
+grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *c);
+grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg);
+grpc_server_credentials *grpc_find_server_credentials_in_args(
+ const grpc_channel_args *args);
+
/* -- Ssl credentials. -- */
typedef struct {
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index fb905e0b22..f544c1d943 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -305,33 +305,43 @@ void grpc_auth_property_reset(grpc_auth_property *property) {
memset(property, 0, sizeof(grpc_auth_property));
}
-grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p) {
+static void auth_context_pointer_arg_destroy(void *p) {
+ GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
+}
+
+static void *auth_context_pointer_arg_copy(void *p) {
+ return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
+}
+
+grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) {
grpc_arg arg;
memset(&arg, 0, sizeof(grpc_arg));
arg.type = GRPC_ARG_POINTER;
- arg.key = GRPC_AUTH_METADATA_PROCESSOR_ARG;
+ arg.key = GRPC_AUTH_CONTEXT_ARG;
arg.value.pointer.p = p;
+ arg.value.pointer.copy = auth_context_pointer_arg_copy;
+ arg.value.pointer.destroy = auth_context_pointer_arg_destroy;
return arg;
}
-grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg(
+grpc_auth_context *grpc_auth_context_from_arg(
const grpc_arg *arg) {
- if (strcmp(arg->key, GRPC_AUTH_METADATA_PROCESSOR_ARG) != 0) return NULL;
+ if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
- GRPC_AUTH_METADATA_PROCESSOR_ARG);
+ GRPC_AUTH_CONTEXT_ARG);
return NULL;
}
return arg->value.pointer.p;
}
-grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
+grpc_auth_context *grpc_find_auth_context_in_args(
const grpc_channel_args *args) {
size_t i;
if (args == NULL) return NULL;
for (i = 0; i < args->num_args; i++) {
- grpc_auth_metadata_processor *p =
- grpc_auth_metadata_processor_from_arg(&args->args[i]);
+ grpc_auth_context *p =
+ grpc_auth_context_from_arg(&args->args[i]);
if (p != NULL) return p;
}
return NULL;
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index a9a0306410..2bbdc4be97 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -103,13 +103,12 @@ typedef struct {
grpc_server_security_context *grpc_server_security_context_create(void);
void grpc_server_security_context_destroy(void *ctx);
-/* --- Auth metadata processing. --- */
-#define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor"
+/* --- Channel args for auth context --- */
+#define GRPC_AUTH_CONTEXT_ARG "grpc.auth_context"
-grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p);
-grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg(
- const grpc_arg *arg);
-grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args(
+grpc_arg grpc_auth_context_to_arg(grpc_auth_context *c);
+grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg);
+grpc_auth_context *grpc_find_auth_context_in_args(
const grpc_channel_args *args);
#endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index 30ca9f57a2..2e18369fe8 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -34,7 +34,7 @@
#include <string.h>
#include "src/core/security/auth_filters.h"
-#include "src/core/security/security_connector.h"
+#include "src/core/security/credentials.h"
#include "src/core/security/security_context.h"
#include <grpc/support/alloc.h>
@@ -58,8 +58,8 @@ typedef struct call_data {
} call_data;
typedef struct channel_data {
- grpc_security_connector *security_connector;
- grpc_auth_metadata_processor processor;
+ grpc_auth_context *auth_context;
+ grpc_server_credentials *creds;
grpc_mdctx *mdctx;
} channel_data;
@@ -160,12 +160,12 @@ static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
grpc_stream_op *op = &ops[i];
if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue;
calld->got_client_metadata = 1;
- if (chand->processor.process == NULL) continue;
+ if (chand->creds->processor.process == NULL) continue;
calld->md_op = op;
calld->md = metadata_batch_to_md_array(&op->data.metadata);
- chand->processor.process(chand->processor.state, calld->auth_context,
- calld->md.metadata, calld->md.count,
- on_md_processing_done, elem);
+ chand->creds->processor.process(
+ chand->creds->processor.state, calld->auth_context,
+ calld->md.metadata, calld->md.count, on_md_processing_done, elem);
return;
}
}
@@ -221,7 +221,7 @@ static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
}
server_ctx = grpc_server_security_context_create();
server_ctx->auth_context =
- grpc_auth_context_create(chand->security_connector->auth_context);
+ grpc_auth_context_create(chand->auth_context);
server_ctx->auth_context->pollset = initial_op->bind_pollset;
initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
initial_op->context[GRPC_CONTEXT_SECURITY].destroy =
@@ -241,9 +241,8 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem, grpc_channel *master,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
- grpc_security_connector *sc = grpc_find_security_connector_in_args(args);
- grpc_auth_metadata_processor *processor =
- grpc_find_auth_metadata_processor_in_args(args);
+ grpc_auth_context *auth_context = grpc_find_auth_context_in_args(args);
+ grpc_server_credentials *creds = grpc_find_server_credentials_in_args(args);
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
@@ -252,15 +251,14 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
path */
GPR_ASSERT(!is_first);
GPR_ASSERT(!is_last);
- GPR_ASSERT(sc != NULL);
- GPR_ASSERT(processor != NULL);
+ GPR_ASSERT(auth_context != NULL);
+ GPR_ASSERT(creds != NULL);
/* initialize members */
- GPR_ASSERT(!sc->is_client_side);
- chand->security_connector =
- GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter");
+ chand->auth_context =
+ GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
+ chand->creds = grpc_server_credentials_ref(creds);
chand->mdctx = mdctx;
- chand->processor = *processor;
}
/* Destructor for channel data */
@@ -268,8 +266,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_channel_element *elem) {
/* grab pointers to our data from the channel element */
channel_data *chand = elem->channel_data;
- GRPC_SECURITY_CONNECTOR_UNREF(chand->security_connector,
- "server_auth_filter");
+ GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
+ grpc_server_credentials_unref(chand->creds);
}
const grpc_channel_filter grpc_server_auth_filter = {
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 881e44a3fe..82c639e830 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -93,9 +93,9 @@ static void setup_transport(grpc_exec_ctx *exec_ctx, void *statep,
grpc_server_secure_state *state = statep;
grpc_channel_args *args_copy;
grpc_arg args_to_add[2];
- args_to_add[0] = grpc_security_connector_to_arg(state->sc);
+ args_to_add[0] = grpc_server_credentials_to_arg(state->creds);
args_to_add[1] =
- grpc_auth_metadata_processor_to_arg(&state->creds->processor);
+ grpc_auth_context_to_arg(state->sc->auth_context);
args_copy = grpc_channel_args_copy_and_add(
grpc_server_get_channel_args(state->server), args_to_add,
GPR_ARRAY_SIZE(args_to_add));
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
index d2ed82e771..bfcb77956b 100644
--- a/src/core/support/alloc.c
+++ b/src/core/support/alloc.c
@@ -35,22 +35,32 @@
#include <stdlib.h>
#include <grpc/support/port_platform.h>
+#include "src/core/profiling/timers.h"
void *gpr_malloc(size_t size) {
- void *p = malloc(size);
+ void *p;
+ GPR_TIMER_BEGIN("gpr_malloc", 0);
+ p = malloc(size);
if (!p) {
abort();
}
+ GPR_TIMER_END("gpr_malloc", 0);
return p;
}
-void gpr_free(void *p) { free(p); }
+void gpr_free(void *p) {
+ GPR_TIMER_BEGIN("gpr_free", 0);
+ free(p);
+ GPR_TIMER_END("gpr_free", 0);
+}
void *gpr_realloc(void *p, size_t size) {
+ GPR_TIMER_BEGIN("gpr_realloc", 0);
p = realloc(p, size);
if (!p) {
abort();
}
+ GPR_TIMER_END("gpr_realloc", 0);
return p;
}
diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c
index 91c30989ce..39c96feb13 100644
--- a/src/core/support/sync_posix.c
+++ b/src/core/support/sync_posix.c
@@ -40,14 +40,23 @@
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
+#include "src/core/profiling/timers.h"
void gpr_mu_init(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); }
void gpr_mu_destroy(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); }
-void gpr_mu_lock(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_lock(mu) == 0); }
+void gpr_mu_lock(gpr_mu* mu) {
+ GPR_TIMER_BEGIN("gpr_mu_lock", 0);
+ GPR_ASSERT(pthread_mutex_lock(mu) == 0);
+ GPR_TIMER_END("gpr_mu_lock", 0);
+}
-void gpr_mu_unlock(gpr_mu* mu) { GPR_ASSERT(pthread_mutex_unlock(mu) == 0); }
+void gpr_mu_unlock(gpr_mu* mu) {
+ GPR_TIMER_BEGIN("gpr_mu_unlock", 0);
+ GPR_ASSERT(pthread_mutex_unlock(mu) == 0);
+ GPR_TIMER_END("gpr_mu_unlock", 0);
+}
int gpr_mu_trylock(gpr_mu* mu) {
int err = pthread_mutex_trylock(mu);
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 78f2c2bb77..02cfca8555 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -63,7 +63,7 @@ static gpr_timespec gpr_from_timespec(struct timespec ts,
/** maps gpr_clock_type --> clockid_t for clock_gettime */
static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME};
-void gpr_time_init(void) {}
+void gpr_time_init(void) { gpr_precise_clock_init(); }
gpr_timespec gpr_now(gpr_clock_type clock_type) {
struct timespec now;
@@ -89,6 +89,7 @@ static uint64_t g_time_start;
void gpr_time_init(void) {
mach_timebase_info_data_t tb = {0, 1};
+ gpr_precise_clock_init();
mach_timebase_info(&tb);
g_time_scale = tb.numer;
g_time_scale /= tb.denom;
diff --git a/src/core/support/time_precise.c b/src/core/support/time_precise.c
new file mode 100644
index 0000000000..b37517e639
--- /dev/null
+++ b/src/core/support/time_precise.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdio.h>
+
+#ifdef GRPC_TIMERS_RDTSC
+#if defined(__i386__)
+static void gpr_get_cycle_counter(long long int *clk) {
+ long long int ret;
+ __asm__ volatile("rdtsc" : "=A"(ret));
+ *clk = ret;
+}
+
+// ----------------------------------------------------------------
+#elif defined(__x86_64__) || defined(__amd64__)
+static void gpr_get_cycle_counter(long long int *clk) {
+ unsigned long long low, high;
+ __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
+ *clk = (long long)(high << 32) | (long long)low;
+}
+#endif
+
+static double cycles_per_second = 0;
+static long long int start_cycle;
+void gpr_precise_clock_init(void) {
+ time_t start;
+ long long end_cycle;
+ gpr_log(GPR_DEBUG, "Calibrating timers");
+ start = time(NULL);
+ while (time(NULL) == start)
+ ;
+ gpr_get_cycle_counter(&start_cycle);
+ while (time(NULL) <= start + 10)
+ ;
+ gpr_get_cycle_counter(&end_cycle);
+ cycles_per_second = (double)(end_cycle - start_cycle) / 10.0;
+ gpr_log(GPR_DEBUG, "... cycles_per_second = %f\n", cycles_per_second);
+}
+
+void gpr_precise_clock_now(gpr_timespec *clk) {
+ long long int counter;
+ double secs;
+ gpr_get_cycle_counter(&counter);
+ secs = (double)(counter - start_cycle) / cycles_per_second;
+ clk->clock_type = GPR_CLOCK_PRECISE;
+ clk->tv_sec = (time_t)secs;
+ clk->tv_nsec = (int)(1e9 * (secs - (double)clk->tv_sec));
+}
+
+#else /* GRPC_TIMERS_RDTSC */
+void gpr_precise_clock_init(void) {}
+
+void gpr_precise_clock_now(gpr_timespec *clk) {
+ *clk = gpr_now(GPR_CLOCK_REALTIME);
+ clk->clock_type = GPR_CLOCK_PRECISE;
+}
+#endif /* GRPC_TIMERS_RDTSC */
diff --git a/src/core/support/time_precise.h b/src/core/support/time_precise.h
index cd201faab9..80c5000123 100644
--- a/src/core/support/time_precise.h
+++ b/src/core/support/time_precise.h
@@ -34,60 +34,9 @@
#ifndef GRPC_CORE_SUPPORT_TIME_PRECISE_H_
#define GRPC_CORE_SUPPORT_TIME_PRECISE_H_
-#include <grpc/support/sync.h>
#include <grpc/support/time.h>
-#include <stdio.h>
-#ifdef GRPC_TIMERS_RDTSC
-#if defined(__i386__)
-static void gpr_get_cycle_counter(long long int *clk) {
- long long int ret;
- __asm__ volatile("rdtsc" : "=A"(ret));
- *clk = ret;
-}
-
-// ----------------------------------------------------------------
-#elif defined(__x86_64__) || defined(__amd64__)
-static void gpr_get_cycle_counter(long long int *clk) {
- unsigned long long low, high;
- __asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
- *clk = (high << 32) | low;
-}
-#endif
-
-static gpr_once precise_clock_init = GPR_ONCE_INIT;
-static long long cycles_per_second = 0;
-static void gpr_precise_clock_init() {
- time_t start = time(NULL);
- gpr_precise_clock start_cycle;
- gpr_precise_clock end_cycle;
- while (time(NULL) == start)
- ;
- gpr_get_cycle_counter(&start_cycle);
- while (time(NULL) == start + 1)
- ;
- gpr_get_cycle_counter(&end_cycle);
- cycles_per_second = end_cycle - start_cycle;
-}
-
-static double grpc_precise_clock_scaling_factor() {
- gpr_once_init(&precise_clock_init, grpc_precise_clock_init);
- return 1e6 / cycles_per_second;
-}
-
-static void gpr_precise_clock_now(gpr_timespec *clk) {
- long long int counter;
- gpr_get_cycle_counter(&counter);
- clk->clock = GPR_CLOCK_REALTIME;
- clk->tv_sec = counter / cycles_per_second;
- clk->tv_nsec = counter % cycles_per_second;
-}
-
-#else /* GRPC_TIMERS_RDTSC */
-static void gpr_precise_clock_now(gpr_timespec *clk) {
- *clk = gpr_now(GPR_CLOCK_REALTIME);
- clk->clock_type = GPR_CLOCK_PRECISE;
-}
-#endif /* GRPC_TIMERS_RDTSC */
+void gpr_precise_clock_init(void);
+void gpr_precise_clock_now(gpr_timespec *clk);
#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_ */
diff --git a/src/core/surface/byte_buffer.c b/src/core/surface/byte_buffer.c
index a930949f2d..fb39c4531d 100644
--- a/src/core/surface/byte_buffer.c
+++ b/src/core/surface/byte_buffer.c
@@ -75,9 +75,7 @@ grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
return grpc_raw_byte_buffer_create(bb->data.raw.slice_buffer.slices,
bb->data.raw.slice_buffer.count);
}
- gpr_log(GPR_INFO, "should never get here");
- abort();
- return NULL;
+ GPR_UNREACHABLE_CODE(return NULL);
}
void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
@@ -95,6 +93,5 @@ size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
case GRPC_BB_RAW:
return bb->data.raw.slice_buffer.length;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return 0);
}
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index d15a3bcbad..b40e74d61b 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -306,8 +306,9 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
grpc_transport_stream_op *initial_op_ptr = NULL;
grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
- grpc_call *call =
- gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
+ grpc_call *call;
+ GPR_TIMER_BEGIN("grpc_call_create", 0);
+ call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
memset(call, 0, sizeof(grpc_call));
gpr_mu_init(&call->mu);
gpr_mu_init(&call->completion_mu);
@@ -401,6 +402,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
set_deadline_alarm(&exec_ctx, call, send_deadline);
}
grpc_exec_ctx_finish(&exec_ctx);
+ GPR_TIMER_END("grpc_call_create", 0);
return call;
}
@@ -425,12 +427,17 @@ static grpc_cq_completion *allocate_completion(grpc_call *call) {
if (call->allocated_completions & (1u << i)) {
continue;
}
- call->allocated_completions |= (gpr_uint8)(1u << i);
+ /* NB: the following integer arithmetic operation needs to be in its
+ * expanded form due to the "integral promotion" performed (see section
+ * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+ * is then required to avoid the compiler warning */
+ call->allocated_completions =
+ (gpr_uint8)(call->allocated_completions | (1u << i));
gpr_mu_unlock(&call->completion_mu);
return &call->completions[i];
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return NULL);
+ return NULL;
}
static void done_completion(grpc_exec_ctx *exec_ctx, void *call,
@@ -456,6 +463,7 @@ void grpc_call_internal_ref(grpc_call *c) {
static void destroy_call(grpc_exec_ctx *exec_ctx, grpc_call *call) {
size_t i;
grpc_call *c = call;
+ GPR_TIMER_BEGIN("destroy_call", 0);
grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
gpr_mu_destroy(&c->mu);
@@ -488,6 +496,7 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, grpc_call *call) {
GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
}
gpr_free(c);
+ GPR_TIMER_END("destroy_call", 0);
}
#ifdef GRPC_CALL_REF_COUNT_DEBUG
@@ -521,9 +530,13 @@ static void set_compression_algorithm(grpc_call *call,
call->compression_algorithm = algo;
}
-grpc_compression_algorithm grpc_call_get_compression_algorithm(
- const grpc_call *call) {
- return call->compression_algorithm;
+grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
+ grpc_call *call) {
+ grpc_compression_algorithm algorithm;
+ gpr_mu_lock(&call->mu);
+ algorithm = call->compression_algorithm;
+ gpr_mu_unlock(&call->mu);
+ return algorithm;
}
static void set_encodings_accepted_by_peer(
@@ -557,12 +570,20 @@ static void set_encodings_accepted_by_peer(
}
}
-gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call) {
- return call->encodings_accepted_by_peer;
+gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call) {
+ gpr_uint32 encodings_accepted_by_peer;
+ gpr_mu_lock(&call->mu);
+ encodings_accepted_by_peer = call->encodings_accepted_by_peer;
+ gpr_mu_unlock(&call->mu);
+ return encodings_accepted_by_peer;
}
-gpr_uint32 grpc_call_get_message_flags(const grpc_call *call) {
- return call->incoming_message_flags;
+gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call) {
+ gpr_uint32 flags;
+ gpr_mu_lock(&call->mu);
+ flags = call->incoming_message_flags;
+ gpr_mu_unlock(&call->mu);
+ return flags;
}
static void set_status_details(grpc_call *call, status_source source,
@@ -607,6 +628,8 @@ static void unlock(grpc_exec_ctx *exec_ctx, grpc_call *call) {
const size_t MAX_RECV_PEEK_AHEAD = 65536;
size_t buffered_bytes;
+ GPR_TIMER_BEGIN("unlock", 0);
+
memset(&op, 0, sizeof(op));
op.cancel_with_status = call->cancel_with_status;
@@ -677,6 +700,8 @@ static void unlock(grpc_exec_ctx *exec_ctx, grpc_call *call) {
unlock(exec_ctx, call);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completing");
}
+
+ GPR_TIMER_END("unlock", 0);
}
static void get_final_status(grpc_call *call, grpc_ioreq_data out) {
@@ -736,7 +761,11 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op,
size_t i;
/* ioreq is live: we need to do something */
master = &call->masters[master_set];
- master->complete_mask |= (gpr_uint16)(1u << op);
+ /* NB: the following integer arithmetic operation needs to be in its
+ * expanded form due to the "integral promotion" performed (see section
+ * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+ * is then required to avoid the compiler warning */
+ master->complete_mask = (gpr_uint16)(master->complete_mask | (1u << op));
if (!success) {
master->success = 0;
}
@@ -822,6 +851,7 @@ static void early_out_write_ops(grpc_call *call) {
static void call_on_done_send(grpc_exec_ctx *exec_ctx, void *pc, int success) {
grpc_call *call = pc;
+ GPR_TIMER_BEGIN("call_on_done_send", 0);
lock(call);
if (call->last_send_contains & (1 << GRPC_IOREQ_SEND_INITIAL_METADATA)) {
finish_ioreq_op(call, GRPC_IOREQ_SEND_INITIAL_METADATA, success);
@@ -845,9 +875,11 @@ static void call_on_done_send(grpc_exec_ctx *exec_ctx, void *pc, int success) {
call->sending = 0;
unlock(exec_ctx, call);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "sending");
+ GPR_TIMER_END("call_on_done_send", 0);
}
static void finish_message(grpc_call *call) {
+ GPR_TIMER_BEGIN("finish_message", 0);
if (call->error_status_set == 0) {
/* TODO(ctiller): this could be a lot faster if coded directly */
grpc_byte_buffer *byte_buffer;
@@ -867,6 +899,7 @@ static void finish_message(grpc_call *call) {
gpr_slice_buffer_reset_and_unref(&call->incoming_message);
GPR_ASSERT(call->incoming_message.count == 0);
call->reading_message = 0;
+ GPR_TIMER_END("finish_message", 0);
}
static int begin_message(grpc_call *call, grpc_begin_message msg) {
@@ -927,6 +960,7 @@ static int add_slice_to_message(grpc_call *call, gpr_slice slice) {
}
/* we have to be reading a message to know what to do here */
if (!call->reading_message) {
+ gpr_slice_unref(slice);
cancel_with_status(call, GRPC_STATUS_INVALID_ARGUMENT,
"Received payload data while not reading a message");
return 0;
@@ -955,7 +989,7 @@ static void call_on_done_recv(grpc_exec_ctx *exec_ctx, void *pc, int success) {
grpc_call *child_call;
grpc_call *next_child_call;
size_t i;
- GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0);
+ GPR_TIMER_BEGIN("call_on_done_recv", 0);
lock(call);
call->receiving = 0;
if (success) {
@@ -965,13 +999,19 @@ static void call_on_done_recv(grpc_exec_ctx *exec_ctx, void *pc, int success) {
case GRPC_NO_OP:
break;
case GRPC_OP_METADATA:
+ GPR_TIMER_BEGIN("recv_metadata", 0);
recv_metadata(exec_ctx, call, &op->data.metadata);
+ GPR_TIMER_END("recv_metadata", 0);
break;
case GRPC_OP_BEGIN_MESSAGE:
+ GPR_TIMER_BEGIN("begin_message", 0);
success = begin_message(call, op->data.begin_message);
+ GPR_TIMER_END("begin_message", 0);
break;
case GRPC_OP_SLICE:
+ GPR_TIMER_BEGIN("add_slice_to_message", 0);
success = add_slice_to_message(call, op->data.slice);
+ GPR_TIMER_END("add_slice_to_message", 0);
break;
}
}
@@ -1017,7 +1057,7 @@ static void call_on_done_recv(grpc_exec_ctx *exec_ctx, void *pc, int success) {
unlock(exec_ctx, call);
GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "receiving");
- GRPC_TIMER_END(GRPC_PTAG_CALL_ON_DONE_RECV, 0);
+ GPR_TIMER_END("call_on_done_recv", 0);
}
static int prepare_application_metadata(grpc_call *call, size_t count,
@@ -1246,7 +1286,11 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs,
GRPC_MDSTR_REF(reqs[i].data.send_status.details));
}
}
- have_ops |= (gpr_uint16)(1u << op);
+ /* NB: the following integer arithmetic operation needs to be in its
+ * expanded form due to the "integral promotion" performed (see section
+ * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+ * is then required to avoid the compiler warning */
+ have_ops = (gpr_uint16)(have_ops | (1u << op));
call->request_data[op] = data;
call->request_flags[op] = reqs[i].flags;
@@ -1491,16 +1535,25 @@ static void recv_metadata(grpc_exec_ctx *exec_ctx, grpc_call *call,
grpc_mdelem *mdel = l->md;
grpc_mdstr *key = mdel->key;
if (key == grpc_channel_get_status_string(call->channel)) {
+ GPR_TIMER_BEGIN("status", 0);
set_status_code(call, STATUS_FROM_WIRE, decode_status(mdel));
+ GPR_TIMER_END("status", 0);
} else if (key == grpc_channel_get_message_string(call->channel)) {
+ GPR_TIMER_BEGIN("status-details", 0);
set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(mdel->value));
+ GPR_TIMER_END("status-details", 0);
} else if (key ==
grpc_channel_get_compression_algorithm_string(call->channel)) {
+ GPR_TIMER_BEGIN("compression_algorithm", 0);
set_compression_algorithm(call, decode_compression(mdel));
+ GPR_TIMER_END("compression_algorithm", 0);
} else if (key == grpc_channel_get_encodings_accepted_by_peer_string(
call->channel)) {
+ GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
set_encodings_accepted_by_peer(call, mdel->value->slice);
+ GPR_TIMER_END("encodings_accepted_by_peer", 0);
} else {
+ GPR_TIMER_BEGIN("report_up", 0);
dest = &call->buffered_metadata[is_trailing];
if (dest->count == dest->capacity) {
dest->capacity = GPR_MAX(dest->capacity + 8, dest->capacity * 2);
@@ -1521,12 +1574,15 @@ static void recv_metadata(grpc_exec_ctx *exec_ctx, grpc_call *call,
}
call->owned_metadata[call->owned_metadata_count++] = mdel;
l->md = NULL;
+ GPR_TIMER_END("report_up", 0);
}
}
if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
0 &&
!call->is_client) {
+ GPR_TIMER_BEGIN("set_deadline_alarm", 0);
set_deadline_alarm(exec_ctx, call, md->deadline);
+ GPR_TIMER_END("set_deadline_alarm", 0);
}
if (!is_trailing) {
call->read_state = READ_STATE_GOT_INITIAL_METADATA;
@@ -1589,6 +1645,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
grpc_call_error error;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
+
GRPC_API_TRACE(
"grpc_call_start_batch(call=%p, ops=%p, nops=%lu, tag=%p, reserved=%p)",
5, (call, ops, (unsigned long)nops, tag, reserved));
@@ -1826,6 +1884,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
finish_func, tag);
done:
grpc_exec_ctx_finish(&exec_ctx);
+ GPR_TIMER_END("grpc_call_start_batch", 0);
return error;
}
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index f421a81619..9b7c6f9bfb 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -169,17 +169,6 @@ void *grpc_call_context_get(grpc_call *call, grpc_context_index elem);
gpr_uint8 grpc_call_is_client(grpc_call *call);
-grpc_compression_algorithm grpc_call_get_compression_algorithm(
- const grpc_call *call);
-
-gpr_uint32 grpc_call_get_message_flags(const grpc_call *call);
-
-/** Returns a bitset for the encodings (compression algorithms) supported by \a
- * call's peer.
- *
- * To be indexed by grpc_compression_algorithm enum values. */
-gpr_uint32 grpc_call_get_encodings_accepted_by_peer(grpc_call *call);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/node/examples/stock_client.js b/src/core/surface/call_test_only.h
index ab9b050e9b..df4be3248b 100644
--- a/src/node/examples/stock_client.js
+++ b/src/core/surface/call_test_only.h
@@ -31,17 +31,35 @@
*
*/
-var grpc = require('..');
-var examples = grpc.load(__dirname + '/stock.proto').examples;
-
-/**
- * This exports a client constructor for the Stock service. The usage looks like
- *
- * var StockClient = require('stock_client.js');
- * var stockClient = new StockClient(server_address,
- * grpc.Credentials.createInsecure());
- * stockClient.getLastTradePrice({symbol: 'GOOG'}, function(error, response) {
- * console.log(error || response);
- * });
- */
-module.exports = examples.Stock;
+#ifndef GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
+#define GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H
+
+#include <grpc/grpc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Return the compression algorithm from \a call.
+ *
+ * \warning This function should \b only be used in test code. */
+grpc_compression_algorithm grpc_call_test_only_get_compression_algorithm(
+ grpc_call *call);
+
+/** Return the message flags from \a call.
+ *
+ * \warning This function should \b only be used in test code. */
+gpr_uint32 grpc_call_test_only_get_message_flags(grpc_call *call);
+
+/** Returns a bitset for the encodings (compression algorithms) supported by \a
+ * call's peer.
+ *
+ * To be indexed by grpc_compression_algorithm enum values. */
+gpr_uint32 grpc_call_test_only_get_encodings_accepted_by_peer(grpc_call *call);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_INTERNAL_CORE_SURFACE_CALL_TEST_ONLY_H */
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index 01430785dc..52a64fb2cd 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -117,9 +117,7 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
switch (w->phase) {
case WAITING:
case CALLED_BACK:
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- break;
+ GPR_UNREACHABLE_CODE(return );
case CALLING_BACK:
w->phase = CALLED_BACK;
break;
@@ -171,9 +169,7 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
w->phase = CALLING_BACK_AND_FINISHED;
break;
case CALLING_BACK_AND_FINISHED:
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- break;
+ GPR_UNREACHABLE_CODE(return );
case CALLED_BACK:
delete = 1;
break;
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index e818ccba48..bcdb363873 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -42,6 +42,7 @@
#include "src/core/surface/call.h"
#include "src/core/surface/event_string.h"
#include "src/core/surface/surface_trace.h"
+#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
@@ -143,6 +144,8 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
int i;
grpc_pollset_worker *pluck_worker;
+ GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
+
storage->tag = tag;
storage->done = done;
storage->done_arg = done_arg;
@@ -174,6 +177,8 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
grpc_pollset_shutdown(exec_ctx, &cc->pollset, &cc->pollset_destroy_done);
}
+
+ GPR_TIMER_END("grpc_cq_end_op", 0);
}
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
@@ -184,6 +189,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_timespec now;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
+
GRPC_API_TRACE(
"grpc_completion_queue_next("
"cc=%p, "
@@ -230,6 +237,9 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "next");
grpc_exec_ctx_finish(&exec_ctx);
+
+ GPR_TIMER_END("grpc_completion_queue_next", 0);
+
return ret;
}
@@ -254,8 +264,7 @@ static void del_plucker(grpc_completion_queue *cc, void *tag,
return;
}
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return );
}
grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
@@ -268,6 +277,8 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
int first_loop = 1;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
+
GRPC_API_TRACE(
"grpc_completion_queue_pluck("
"cc=%p, tag=%p, "
@@ -333,6 +344,9 @@ done:
GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
grpc_exec_ctx_finish(&exec_ctx);
+
+ GPR_TIMER_END("grpc_completion_queue_pluck", 0);
+
return ret;
}
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index 95011cab17..715c90a5e1 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -115,7 +115,7 @@ void grpc_init(void) {
gpr_log(GPR_ERROR, "Could not initialize census.");
}
}
- grpc_timers_global_init();
+ gpr_timers_global_init();
for (i = 0; i < g_number_of_plugins; i++) {
if (g_all_of_the_plugins[i].init != NULL) {
g_all_of_the_plugins[i].init();
@@ -133,7 +133,7 @@ void grpc_shutdown(void) {
if (--g_initializations == 0) {
grpc_iomgr_shutdown();
census_shutdown();
- grpc_timers_global_destroy();
+ gpr_timers_global_destroy();
grpc_tracer_shutdown();
grpc_resolver_registry_shutdown();
for (i = 0; i < g_number_of_plugins; i++) {
diff --git a/src/core/transport/chttp2/bin_encoder.c b/src/core/transport/chttp2/bin_encoder.c
index f1bbf9aa91..9c9070ede4 100644
--- a/src/core/transport/chttp2/bin_encoder.c
+++ b/src/core/transport/chttp2/bin_encoder.c
@@ -185,8 +185,12 @@ gpr_slice grpc_chttp2_huffman_compress(gpr_slice input) {
}
if (temp_length) {
- *out++ = (gpr_uint8)(temp << (8u - temp_length)) |
- (gpr_uint8)(0xffu >> temp_length);
+ /* NB: the following integer arithmetic operation needs to be in its
+ * expanded form due to the "integral promotion" performed (see section
+ * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+ * is then required to avoid the compiler warning */
+ *out++ = (gpr_uint8)((gpr_uint8)(temp << (8u - temp_length)) |
+ (gpr_uint8)(0xffu >> temp_length));
}
GPR_ASSERT(out == GPR_SLICE_END_PTR(output));
@@ -265,8 +269,12 @@ gpr_slice grpc_chttp2_base64_encode_and_huffman_compress(gpr_slice input) {
}
if (out.temp_length) {
- *out.out++ = (gpr_uint8)(out.temp << (8u - out.temp_length)) |
- (gpr_uint8)(0xffu >> out.temp_length);
+ /* NB: the following integer arithmetic operation needs to be in its
+ * expanded form due to the "integral promotion" performed (see section
+ * 3.2.1.1 of the C89 draft standard). A cast to the smaller container type
+ * is then required to avoid the compiler warning */
+ *out.out++ = (gpr_uint8)((gpr_uint8)(out.temp << (8u - out.temp_length)) |
+ (gpr_uint8)(0xffu >> out.temp_length));
}
GPR_ASSERT(out.out <= GPR_SLICE_END_PTR(output));
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index acfa7c002e..07179a4571 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -168,7 +168,5 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
}
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}
diff --git a/src/core/transport/chttp2/frame_goaway.c b/src/core/transport/chttp2/frame_goaway.c
index 2ff1eda89b..c5758bcb71 100644
--- a/src/core/transport/chttp2/frame_goaway.c
+++ b/src/core/transport/chttp2/frame_goaway.c
@@ -152,9 +152,7 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
}
return GRPC_CHTTP2_PARSE_OK;
}
- gpr_log(GPR_ERROR, "Should never end up here");
- abort();
- return GRPC_CHTTP2_CONNECTION_ERROR;
+ GPR_UNREACHABLE_CODE(return GRPC_CHTTP2_CONNECTION_ERROR);
}
void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code,
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index 20ea513375..20d8312d54 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -1166,9 +1166,7 @@ static int append_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
append_bytes(str, decoded, 3);
goto b64_byte0;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- return 1;
+ GPR_UNREACHABLE_CODE(return 1);
}
/* append a null terminator to a string */
@@ -1313,9 +1311,7 @@ static int parse_value_string(grpc_chttp2_hpack_parser *p, const gpr_uint8 *cur,
return 0;
}
/* Add code to prevent return without value error */
- gpr_log(GPR_ERROR, "Should never reach beyond switch in parse_value_string");
- abort();
- return 0;
+ GPR_UNREACHABLE_CODE(return 0);
}
static int parse_value_string_with_indexed_key(grpc_chttp2_hpack_parser *p,
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index f7a0a10581..5d4d8e70c4 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -35,6 +35,7 @@
#include <string.h>
+#include "src/core/profiling/timers.h"
#include "src/core/transport/chttp2/http2_errors.h"
#include "src/core/transport/chttp2/status_conversion.h"
#include "src/core/transport/chttp2/timeout_encoding.h"
@@ -68,6 +69,8 @@ void grpc_chttp2_prepare_to_read(
grpc_chttp2_stream_global *stream_global;
grpc_chttp2_stream_parsing *stream_parsing;
+ GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
+
transport_parsing->next_stream_id = transport_global->next_stream_id;
/* update the parsing view of incoming window */
@@ -89,6 +92,8 @@ void grpc_chttp2_prepare_to_read(
stream_parsing->incoming_window = stream_global->incoming_window;
}
}
+
+ GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0);
}
void grpc_chttp2_publish_reads(
@@ -417,14 +422,10 @@ int grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
transport_parsing->incoming_frame_size -= (gpr_uint32)(end - cur);
return 1;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return 0);
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
-
- return 0;
+ GPR_UNREACHABLE_CODE(return 0);
}
static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) {
@@ -580,9 +581,7 @@ static int init_data_frame_parser(
case GRPC_CHTTP2_CONNECTION_ERROR:
return 0;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- return 0;
+ GPR_UNREACHABLE_CODE(return 0);
}
static void free_timeout(void *p) { gpr_free(p); }
@@ -820,7 +819,5 @@ static int parse_frame_slice(grpc_exec_ctx *exec_ctx,
case GRPC_CHTTP2_CONNECTION_ERROR:
return 0;
}
- gpr_log(GPR_ERROR, "should never reach here");
- abort();
- return 0;
+ GPR_UNREACHABLE_CODE(return 0);
}
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 83227e677d..6c7f7a9ea7 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -428,7 +428,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
return elem;
}
- abort();
+ GPR_UNREACHABLE_CODE(return NULL);
}
indices_key = c->indices_keys[HASH_FRAGMENT_3(key_hash)];
@@ -442,7 +442,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
return elem;
}
- abort();
+ GPR_UNREACHABLE_CODE(return NULL);
}
/* no elem, key in the table... fall back to literal emission */
@@ -454,7 +454,7 @@ static grpc_mdelem *hpack_enc(grpc_chttp2_hpack_compressor *c,
emit_lithdr_noidx_v(c, elem, st);
return elem;
}
- abort();
+ GPR_UNREACHABLE_CODE(return NULL);
}
#define STRLEN_LIT(x) (sizeof(x) - 1)
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index d1c9da6df0..69ad8854ba 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -37,6 +37,7 @@
#include <grpc/support/log.h>
+#include "src/core/profiling/timers.h"
#include "src/core/transport/chttp2/http2_errors.h"
static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing);
@@ -180,6 +181,8 @@ void grpc_chttp2_perform_writes(
static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
grpc_chttp2_stream_writing *stream_writing;
+ GPR_TIMER_BEGIN("finalize_outbuf", 0);
+
while (
grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
if (stream_writing->sopb.nops > 0 ||
@@ -208,6 +211,8 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
}
grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
}
+
+ GPR_TIMER_END("finalize_outbuf", 0);
}
void grpc_chttp2_cleanup_writing(
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index de74379546..effc3c4b3b 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -510,6 +510,7 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
+ GPR_TIMER_BEGIN("unlock", 0);
unlock_check_read_write_state(exec_ctx, t);
if (!t->writing_active && !t->closed &&
grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
@@ -520,6 +521,7 @@ static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
}
gpr_mu_unlock(&t->mu);
+ GPR_TIMER_END("unlock", 0);
}
/*
@@ -546,6 +548,8 @@ void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
+ GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
+
lock(t);
allow_endpoint_shutdown_locked(exec_ctx, t);
@@ -567,12 +571,16 @@ void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
unlock(exec_ctx, t);
UNREF_TRANSPORT(exec_ctx, t, "writing");
+
+ GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
}
static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
int iomgr_success_ignored) {
grpc_chttp2_transport *t = gt;
+ GPR_TIMER_BEGIN("writing_action", 0);
grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
+ GPR_TIMER_END("writing_action", 0);
}
void grpc_chttp2_add_incoming_goaway(
@@ -642,6 +650,7 @@ static void maybe_start_some_streams(
static void perform_stream_op_locked(
grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
+ GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
if (op->cancel_with_status != GRPC_STATUS_OK) {
cancel_from_api(transport_global, stream_global, op->cancel_with_status);
}
@@ -713,6 +722,7 @@ static void perform_stream_op_locked(
}
grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
+ GPR_TIMER_END("perform_stream_op_locked", 0);
}
static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
@@ -1103,6 +1113,8 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
int keep_reading = 0;
grpc_chttp2_transport *t = tp;
+ GPR_TIMER_BEGIN("recv_data", 0);
+
lock(t);
i = 0;
GPR_ASSERT(!t->parsing_active);
@@ -1113,11 +1125,13 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
&t->parsing_stream_map);
grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
gpr_mu_unlock(&t->mu);
+ GPR_TIMER_BEGIN("recv_data.parse", 0);
for (; i < t->read_buffer.count &&
grpc_chttp2_perform_read(exec_ctx, &t->parsing,
t->read_buffer.slices[i]);
i++)
;
+ GPR_TIMER_END("recv_data.parse", 0);
gpr_mu_lock(&t->mu);
if (i != t->read_buffer.count) {
drop_connection(exec_ctx, t);
@@ -1154,6 +1168,8 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
} else {
UNREF_TRANSPORT(exec_ctx, t, "recv_data");
}
+
+ GPR_TIMER_END("recv_data", 0);
}
/*
diff --git a/src/core/transport/stream_op.c b/src/core/transport/stream_op.c
index 1cb2bd7c59..6493e77bc5 100644
--- a/src/core/transport/stream_op.c
+++ b/src/core/transport/stream_op.c
@@ -38,6 +38,8 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/profiling/timers.h"
+
/* Exponential growth function: Given x, return a larger x.
Currently we grow by 1.5 times upon reallocation. */
#define GROW(x) (3 * (x) / 2)
@@ -300,6 +302,8 @@ void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
grpc_linked_mdelem *l;
grpc_linked_mdelem *next;
+ GPR_TIMER_BEGIN("grpc_metadata_batch_filter", 0);
+
assert_valid_list(&batch->list);
assert_valid_list(&batch->garbage);
for (l = batch->list.head; l; l = next) {
@@ -328,4 +332,6 @@ void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
}
assert_valid_list(&batch->list);
assert_valid_list(&batch->garbage);
+
+ GPR_TIMER_END("grpc_metadata_batch_filter", 0);
}
diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
index cbb6f17ae1..99e28ab63b 100644
--- a/src/core/tsi/fake_transport_security.c
+++ b/src/core/tsi/fake_transport_security.c
@@ -118,10 +118,10 @@ static gpr_uint32 load32_little_endian(const unsigned char *buf) {
}
static void store32_little_endian(gpr_uint32 value, unsigned char *buf) {
- buf[3] = (unsigned char)(value >> 24) & 0xFF;
- buf[2] = (unsigned char)(value >> 16) & 0xFF;
- buf[1] = (unsigned char)(value >> 8) & 0xFF;
- buf[0] = (unsigned char)(value)&0xFF;
+ buf[3] = (unsigned char)((value >> 24) & 0xFF);
+ buf[2] = (unsigned char)((value >> 16) & 0xFF);
+ buf[1] = (unsigned char)((value >> 8) & 0xFF);
+ buf[0] = (unsigned char)((value)&0xFF);
}
static void tsi_fake_frame_reset(tsi_fake_frame *frame, int needs_draining) {
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 05789f07d4..22b57964cc 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -319,8 +319,9 @@ static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
/* TODO(jboeuf): Maybe add more properties. */
GENERAL_NAMES *subject_alt_names =
X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
- int subject_alt_name_count =
- (subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0;
+ int subject_alt_name_count = (subject_alt_names != NULL)
+ ? (int)sk_GENERAL_NAME_num(subject_alt_names)
+ : 0;
size_t property_count;
tsi_result result;
GPR_ASSERT(subject_alt_name_count >= 0);
@@ -358,7 +359,7 @@ static void log_ssl_error_stack(void) {
unsigned long err;
while ((err = ERR_get_error()) != 0) {
char details[256];
- ERR_error_string_n(err, details, sizeof(details));
+ ERR_error_string_n((uint32_t)err, details, sizeof(details));
gpr_log(GPR_ERROR, "%s", details);
}
}
@@ -668,7 +669,7 @@ static tsi_result ssl_protector_protect(tsi_frame_protector *self,
tsi_result result = TSI_OK;
/* First see if we have some pending data in the SSL BIO. */
- int pending_in_ssl = BIO_pending(impl->from_ssl);
+ int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
if (pending_in_ssl > 0) {
*unprotected_bytes_size = 0;
GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
@@ -726,7 +727,7 @@ static tsi_result ssl_protector_protect_flush(
impl->buffer_offset = 0;
}
- pending = BIO_pending(impl->from_ssl);
+ pending = (int)BIO_pending(impl->from_ssl);
GPR_ASSERT(pending >= 0);
*still_pending_size = (size_t)pending;
if (*still_pending_size == 0) return TSI_OK;
@@ -739,7 +740,7 @@ static tsi_result ssl_protector_protect_flush(
return TSI_INTERNAL_ERROR;
}
*protected_output_frames_size = (size_t)read_from_ssl;
- pending = BIO_pending(impl->from_ssl);
+ pending = (int)BIO_pending(impl->from_ssl);
GPR_ASSERT(pending >= 0);
*still_pending_size = (size_t)pending;
return TSI_OK;
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index dc8e304664..c7974d655b 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -78,7 +78,6 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context,
context->raw_deadline(), nullptr);
}
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());
return Call(c_call, this, cq);
}
@@ -87,11 +86,9 @@ void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) {
static const size_t MAX_OPS = 8;
size_t nops = 0;
grpc_op cops[MAX_OPS];
- GRPC_TIMER_BEGIN(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
ops->FillOps(cops, &nops);
GPR_ASSERT(GRPC_CALL_OK ==
grpc_call_start_batch(call->call(), cops, nops, ops, nullptr));
- GRPC_TIMER_END(GRPC_PTAG_CPP_PERFORM_OPS, call->call());
}
void* Channel::RegisterMethod(const char* method) {
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index 4131fbe5e5..b1330fde7f 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -42,6 +42,8 @@
#include <grpc/support/port_platform.h>
#include <grpc++/support/config.h>
+#include "src/core/profiling/timers.h"
+
const int kMaxBufferLength = 8192;
class GrpcBufferWriter GRPC_FINAL
@@ -158,6 +160,7 @@ namespace grpc {
Status SerializeProto(const grpc::protobuf::Message& msg,
grpc_byte_buffer** bp) {
+ GPR_TIMER_SCOPE("SerializeProto", 0);
int byte_size = msg.ByteSize();
if (byte_size <= kMaxBufferLength) {
gpr_slice slice = gpr_slice_malloc(byte_size);
@@ -176,6 +179,7 @@ Status SerializeProto(const grpc::protobuf::Message& msg,
Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
int max_message_size) {
+ GPR_TIMER_SCOPE("DeserializeProto", 0);
if (!buffer) {
return Status(StatusCode::INTERNAL, "No payload");
}
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index a44e1d2025..f5063a079e 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -153,8 +153,7 @@ class Server::SyncRequest GRPC_FINAL : public CompletionQueueTag {
GPR_ASSERT((*req)->in_flight_);
return true;
}
- gpr_log(GPR_ERROR, "Should never reach here");
- abort();
+ GPR_UNREACHABLE_CODE(return false);
}
void SetupRequest() { cq_ = grpc_completion_queue_create(nullptr); }
@@ -541,6 +540,7 @@ void Server::ScheduleCallback() {
void Server::RunRpc() {
// Wait for one more incoming rpc.
bool ok;
+ GPR_TIMER_SCOPE("Server::RunRpc", 0);
auto* mrd = SyncRequest::Wait(&cq_, &ok);
if (mrd) {
ScheduleCallback();
@@ -556,6 +556,7 @@ void Server::RunRpc() {
mrd->TeardownRequest();
}
}
+ GPR_TIMER_SCOPE("cd.Run()", 0);
cd.Run();
}
}
diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
index c8ab4d9af6..1c14c5bb5b 100644
--- a/src/csharp/Grpc.Auth/AuthInterceptors.cs
+++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
@@ -41,40 +41,38 @@ using Grpc.Core.Utils;
namespace Grpc.Auth
{
/// <summary>
- /// Factory methods to create authorization interceptors. Interceptors created can be registered with gRPC client classes (autogenerated client stubs that
- /// inherit from <see cref="Grpc.Core.ClientBase"/>).
+ /// Factory methods to create authorization interceptors for Google credentials.
+ /// <seealso cref="GoogleGrpcCredentials"/>
/// </summary>
- public static class AuthInterceptors
+ public static class GoogleAuthInterceptors
{
private const string AuthorizationHeader = "Authorization";
private const string Schema = "Bearer";
/// <summary>
- /// Creates interceptor that will obtain access token from any credential type that implements
+ /// Creates an <see cref="AsyncAuthInterceptor"/> that will obtain access token from any credential type that implements
/// <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
- /// <returns>The header interceptor.</returns>
- public static HeaderInterceptor FromCredential(ITokenAccess credential)
+ /// <returns>The interceptor.</returns>
+ public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
{
- return new HeaderInterceptor((method, authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
- // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
- var accessToken = credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None)
- .ConfigureAwait(false).GetAwaiter().GetResult();
+ var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false);
metadata.Add(CreateBearerTokenHeader(accessToken));
});
}
/// <summary>
- /// Creates OAuth2 interceptor that will use given access token as authorization.
+ /// Creates an <see cref="AsyncAuthInterceptor"/> that will use given access token as authorization.
/// </summary>
/// <param name="accessToken">OAuth2 access token.</param>
- /// <returns>The header interceptor.</returns>
- public static HeaderInterceptor FromAccessToken(string accessToken)
+ /// <returns>The interceptor.</returns>
+ public static AsyncAuthInterceptor FromAccessToken(string accessToken)
{
Preconditions.CheckNotNull(accessToken);
- return new HeaderInterceptor((method, authUri, metadata) =>
+ return new AsyncAuthInterceptor(async (authUri, metadata) =>
{
metadata.Add(CreateBearerTokenHeader(accessToken));
});
diff --git a/src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs b/src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs
new file mode 100644
index 0000000000..a1e7db13bd
--- /dev/null
+++ b/src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs
@@ -0,0 +1,96 @@
+#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 System.Threading.Tasks;
+
+using Google.Apis.Auth.OAuth2;
+using Grpc.Core;
+using Grpc.Core.Utils;
+
+namespace Grpc.Auth
+{
+ /// <summary>
+ /// Factory/extension methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes
+ /// based on credential objects originating from Google auth library.
+ /// </summary>
+ public static class GoogleGrpcCredentials
+ {
+ /// <summary>
+ /// Retrieves an instance of Google's Application Default Credentials using
+ /// <c>GoogleCredential.GetApplicationDefaultAsync()</c> and converts them
+ /// into a gRPC <see cref="ChannelCredentials"/> that use the default SSL credentials.
+ /// </summary>
+ /// <returns>The <c>ChannelCredentials</c> instance.</returns>
+ public static async Task<ChannelCredentials> GetApplicationDefaultAsync()
+ {
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync().ConfigureAwait(false);
+ return googleCredential.ToChannelCredentials();
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="CallCredentials"/> that will use given access token to authenticate
+ /// with a gRPC service.
+ /// </summary>
+ /// <param name="accessToken">OAuth2 access token.</param>
+ /// /// <returns>The <c>MetadataCredentials</c> instance.</returns>
+ public static CallCredentials FromAccessToken(string accessToken)
+ {
+ return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromAccessToken(accessToken));
+ }
+
+ /// <summary>
+ /// Converts a <c>ITokenAccess</c> (e.g. <c>GoogleCredential</c>) object
+ /// into a gRPC <see cref="CallCredentials"/> object.
+ /// </summary>
+ /// <param name="credential">The credential to use to obtain access tokens.</param>
+ /// <returns>The <c>CallCredentials</c> instance.</returns>
+ public static CallCredentials ToCallCredentials(this ITokenAccess credential)
+ {
+ return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromCredential(credential));
+ }
+
+ /// <summary>
+ /// Converts a <c>ITokenAccess</c> (e.g. <c>GoogleCredential</c>) object
+ /// into a gRPC <see cref="ChannelCredentials"/> object.
+ /// Default SSL credentials are used.
+ /// </summary>
+ /// <param name="googleCredential">The credential to use to obtain access tokens.</param>
+ /// <returns>>The <c>ChannelCredentials</c> instance.</returns>
+ public static ChannelCredentials ToChannelCredentials(this ITokenAccess googleCredential)
+ {
+ return ChannelCredentials.Create(new SslCredentials(), googleCredential.ToCallCredentials());
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index 4fb087d4a3..55bde6e194 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -78,8 +78,9 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
+ <Compile Include="GoogleGrpcCredentials.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="AuthInterceptors.cs" />
+ <Compile Include="GoogleAuthInterceptors.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
index 2dc10ebe97..82f881969e 100644
--- a/src/csharp/Grpc.Core.Tests/ClientBaseTest.cs
+++ b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
@@ -32,6 +32,10 @@
#endregion
using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
@@ -39,24 +43,23 @@ using NUnit.Framework;
namespace Grpc.Core.Tests
{
- public class ClientBaseTest
+ public class CallCredentialsTest
{
[Test]
- public void GetAuthUriBase_Valid()
+ public void CallCredentials_ComposeAtLeastTwo()
{
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com/"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("dns:///some.googleapi.com:443/"));
- Assert.AreEqual("https://some.googleapi.com/", ClientBase.GetAuthUriBase("some.googleapi.com:443/"));
+ Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials()));
}
[Test]
- public void GetAuthUriBase_Invalid()
+ public void CallCredentials_ToNativeCredentials()
{
- Assert.IsNull(ClientBase.GetAuthUriBase("some.googleapi.com:"));
- Assert.IsNull(ClientBase.GetAuthUriBase("https://some.googleapi.com/"));
- Assert.IsNull(ClientBase.GetAuthUriBase("dns://some.googleapi.com:443")); // just two slashes
- Assert.IsNull(ClientBase.GetAuthUriBase(""));
+ var composite = CallCredentials.Compose(
+ CallCredentials.FromInterceptor(async (uri, m) => { await Task.Delay(1); }),
+ CallCredentials.FromInterceptor(async (uri, m) => { await Task.Delay(2); }));
+ using (var nativeComposite = composite.ToNativeCredentials())
+ {
+ }
}
}
}
diff --git a/src/node/interop/empty.proto b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
index 6d0eb937d6..d5315ed39b 100644
--- a/src/node/interop/empty.proto
+++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
@@ -1,3 +1,4 @@
+#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
@@ -28,16 +29,39 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-syntax = "proto3";
+#endregion
-package grpc.testing;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
-// An empty message that you can re-use to avoid defining duplicated empty
-// messages in your project. A typical example is to use it as argument or the
-// return value of a service API. For instance:
-//
-// service Foo {
-// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
-// };
-//
-message Empty {}
+namespace Grpc.Core.Tests
+{
+ public class ChannelCredentialsTest
+ {
+ [Test]
+ public void InsecureCredentials_IsNonComposable()
+ {
+ Assert.IsFalse(ChannelCredentials.Insecure.IsComposable);
+ }
+
+ [Test]
+ public void ChannelCredentials_CreateComposite()
+ {
+ var composite = ChannelCredentials.Create(new FakeChannelCredentials(true), new FakeCallCredentials());
+ Assert.IsFalse(composite.IsComposable);
+
+ Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
+ Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
+
+ // forbid composing non-composable
+ Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
index dfbd92879e..f4ae9abefd 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs
@@ -44,13 +44,13 @@ namespace Grpc.Core.Tests
[Test]
public void Constructor_RejectsInvalidParams()
{
- Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
+ Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, ChannelCredentials.Insecure));
}
[Test]
public void State_IdleAfterCreation()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.AreEqual(ChannelState.Idle, channel.State);
channel.ShutdownAsync().Wait();
}
@@ -58,7 +58,7 @@ namespace Grpc.Core.Tests
[Test]
public void WaitForStateChangedAsync_InvalidArgument()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
channel.ShutdownAsync().Wait();
}
@@ -66,7 +66,7 @@ namespace Grpc.Core.Tests
[Test]
public void ResolvedTarget()
{
- var channel = new Channel("127.0.0.1", Credentials.Insecure);
+ var channel = new Channel("127.0.0.1", ChannelCredentials.Insecure);
Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1"));
channel.ShutdownAsync().Wait();
}
@@ -74,7 +74,7 @@ namespace Grpc.Core.Tests
[Test]
public void Shutdown_AllowedOnlyOnce()
{
- var channel = new Channel("localhost", Credentials.Insecure);
+ var channel = new Channel("localhost", ChannelCredentials.Insecure);
channel.ShutdownAsync().Wait();
Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult());
}
diff --git a/src/node/examples/stock.proto b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
index 5ee2bcbce6..87d55cd276 100644
--- a/src/node/examples/stock.proto
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -1,3 +1,5 @@
+#region Copyright notice and license
+
// Copyright 2015, Google Inc.
// All rights reserved.
//
@@ -27,36 +29,45 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-syntax = "proto3";
+#endregion
-package examples;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
-// Protocol type definitions
-message StockRequest {
- string symbol = 1;
- int32 num_trades_to_watch = 2;
-}
+namespace Grpc.Core.Tests
+{
+ internal class FakeChannelCredentials : ChannelCredentials
+ {
+ readonly bool composable;
-message StockReply {
- float price = 1;
- string symbol = 2;
-}
+ public FakeChannelCredentials(bool composable)
+ {
+ this.composable = composable;
+ }
+ internal override bool IsComposable
+ {
+ get { return composable; }
+ }
-// Interface exported by the server
-service Stock {
- // Simple blocking RPC
- rpc GetLastTradePrice(StockRequest) returns (StockReply) {
- }
- // Bidirectional streaming RPC
- rpc GetLastTradePriceMultiple(stream StockRequest) returns
- (stream StockReply) {
- }
- // Unidirectional server-to-client streaming RPC
- rpc WatchFutureTrades(StockRequest) returns (stream StockReply) {
- }
- // Unidirectional client-to-server streaming RPC
- rpc GetHighestTradePrice(stream StockRequest) returns (StockReply) {
- }
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
+ internal class FakeCallCredentials : CallCredentials
+ {
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return null;
+ }
+ }
}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index f730936062..91d072abab 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -63,8 +63,10 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
- <Compile Include="ClientBaseTest.cs" />
+ <Compile Include="CallCredentialsTest.cs" />
+ <Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
+ <Compile Include="ChannelCredentialsTest.cs" />
<Compile Include="ShutdownTest.cs" />
<Compile Include="Internal\AsyncCallTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index 685c5f7d6c..246072bff1 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests
[SetUp]
public void Init()
{
- channel = new Channel("localhost", Credentials.Insecure);
+ channel = new Channel("localhost", ChannelCredentials.Insecure);
fakeCall = new FakeNativeCall();
diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
index 83707e0c6d..37fb36946a 100644
--- a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs
@@ -119,7 +119,7 @@ namespace Grpc.Core.Tests
[Test]
public void RequestParsingError_UnaryRequest()
{
- helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
+ helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
{
return Task.FromResult("RESPONSE");
});
@@ -161,7 +161,7 @@ namespace Grpc.Core.Tests
{
helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
{
- CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync());
+ CollectionAssert.AreEqual(new[] { "A", "B" }, await requestStream.ToListAsync());
return "RESPONSE";
});
var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
index 765732c768..567e04eddc 100644
--- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
+++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
@@ -154,7 +154,7 @@ namespace Grpc.Core.Tests
{
if (channel == null)
{
- channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure);
}
return channel;
}
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 714c2f7494..073c502daf 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -60,7 +60,7 @@ namespace Grpc.Core.Tests
public void CompletionQueueCreateDestroyBenchmark()
{
BenchmarkUtil.RunBenchmark(
- 100000, 1000000,
+ 10, 10,
() =>
{
CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create();
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
new file mode 100644
index 0000000000..400a9825de
--- /dev/null
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -0,0 +1,152 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+ /// <summary>
+ /// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
+ /// </summary>
+ /// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
+ /// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
+ /// <returns></returns>
+ public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
+
+ /// <summary>
+ /// Client-side call credentials. Provide authorization with per-call granularity.
+ /// </summary>
+ public abstract class CallCredentials
+ {
+ /// <summary>
+ /// Composes multiple multiple <c>CallCredentials</c> objects into
+ /// a single <c>CallCredentials</c> object.
+ /// </summary>
+ /// <param name="credentials">credentials to compose</param>
+ /// <returns>The new <c>CompositeCallCredentials</c></returns>
+ public static CallCredentials Compose(params CallCredentials[] credentials)
+ {
+ return new CompositeCallCredentials(credentials);
+ }
+
+ /// <summary>
+ /// Creates a new instance of <c>CallCredentials</c> class from an
+ /// interceptor that can attach metadata to outgoing calls.
+ /// </summary>
+ /// <param name="interceptor">authentication interceptor</param>
+ public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor)
+ {
+ return new MetadataCredentials(interceptor);
+ }
+
+ /// <summary>
+ /// Creates native object for the credentials.
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal abstract CredentialsSafeHandle ToNativeCredentials();
+ }
+
+ /// <summary>
+ /// Client-side credentials that delegate metadata based auth to an interceptor.
+ /// The interceptor is automatically invoked for each remote call that uses <c>MetadataCredentials.</c>
+ /// </summary>
+ internal sealed class MetadataCredentials : CallCredentials
+ {
+ readonly AsyncAuthInterceptor interceptor;
+
+ /// <summary>
+ /// Initializes a new instance of <c>MetadataCredentials</c> class.
+ /// </summary>
+ /// <param name="interceptor">authentication interceptor</param>
+ public MetadataCredentials(AsyncAuthInterceptor interceptor)
+ {
+ this.interceptor = Preconditions.CheckNotNull(interceptor);
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
+ return plugin.Credentials;
+ }
+ }
+
+ /// <summary>
+ /// Credentials that allow composing multiple credentials objects into one <see cref="CallCredentials"/> object.
+ /// </summary>
+ internal sealed class CompositeCallCredentials : CallCredentials
+ {
+ readonly List<CallCredentials> credentials;
+
+ /// <summary>
+ /// Initializes a new instance of <c>CompositeCallCredentials</c> class.
+ /// The resulting credentials object will be composite of all the credentials specified as parameters.
+ /// </summary>
+ /// <param name="credentials">credentials to compose</param>
+ public CompositeCallCredentials(params CallCredentials[] credentials)
+ {
+ Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
+ this.credentials = new List<CallCredentials>(credentials);
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ return ToNativeRecursive(0);
+ }
+
+ // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier.
+ // In practice, we won't usually see composites from more than two credentials anyway.
+ private CredentialsSafeHandle ToNativeRecursive(int startIndex)
+ {
+ if (startIndex == credentials.Count - 1)
+ {
+ return credentials[startIndex].ToNativeCredentials();
+ }
+
+ using (var cred1 = credentials[startIndex].ToNativeCredentials())
+ using (var cred2 = ToNativeRecursive(startIndex + 1))
+ {
+ var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+ if (nativeComposite.IsInvalid)
+ {
+ throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
+ }
+ return nativeComposite;
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs
index c3bc9c3156..c0f94c63c2 100644
--- a/src/csharp/Grpc.Core/CallOptions.cs
+++ b/src/csharp/Grpc.Core/CallOptions.cs
@@ -49,6 +49,7 @@ namespace Grpc.Core
CancellationToken cancellationToken;
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
+ CallCredentials credentials;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@@ -58,14 +59,16 @@ namespace Grpc.Core
/// <param name="cancellationToken">Can be used to request cancellation of the call.</param>
/// <param name="writeOptions">Write options that will be used for this call.</param>
/// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
+ /// <param name="credentials">Credentials to use for this call.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
- WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null)
+ WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null)
{
this.headers = headers;
this.deadline = deadline;
this.cancellationToken = cancellationToken;
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
+ this.credentials = credentials;
}
/// <summary>
@@ -115,6 +118,17 @@ namespace Grpc.Core
}
/// <summary>
+ /// Credentials to use for this call.
+ /// </summary>
+ public CallCredentials Credentials
+ {
+ get
+ {
+ return this.credentials;
+ }
+ }
+
+ /// <summary>
/// Returns new instance of <see cref="CallOptions"/> with
/// <c>Headers</c> set to the value provided. Values of all other fields are preserved.
/// </summary>
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index f1942727cd..6b99055d4c 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -68,7 +68,7 @@ namespace Grpc.Core
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null)
+ public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
{
this.target = Preconditions.CheckNotNull(target, "target");
this.environment = GrpcEnvironment.AddRef();
@@ -96,7 +96,7 @@ namespace Grpc.Core
/// <param name="port">The port.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
- public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
+ public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}
diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
index 4fcac0c4c0..9d2bcdabe8 100644
--- a/src/csharp/Grpc.Core/Credentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -32,22 +32,26 @@
#endregion
using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
using Grpc.Core.Internal;
+using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
- /// Client-side credentials. Used for creation of a secure channel.
+ /// Client-side channel credentials. Used for creation of a secure channel.
/// </summary>
- public abstract class Credentials
+ public abstract class ChannelCredentials
{
- static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
+ static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
/// <summary>
- /// Returns instance of credential that provides no security and
+ /// Returns instance of credentials that provides no security and
/// will result in creating an unsecure channel with no encryption whatsoever.
/// </summary>
- public static Credentials Insecure
+ public static ChannelCredentials Insecure
{
get
{
@@ -56,13 +60,33 @@ namespace Grpc.Core
}
/// <summary>
+ /// Creates a new instance of <c>ChannelCredentials</c> class by composing
+ /// given channel credentials with call credentials.
+ /// </summary>
+ /// <param name="channelCredentials">Channel credentials.</param>
+ /// <param name="callCredentials">Call credentials.</param>
+ /// <returns>The new composite <c>ChannelCredentials</c></returns>
+ public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials)
+ {
+ return new CompositeChannelCredentials(channelCredentials, callCredentials);
+ }
+
+ /// <summary>
/// Creates native object for the credentials. May return null if insecure channel
/// should be created.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
- private sealed class InsecureCredentialsImpl : Credentials
+ /// <summary>
+ /// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
+ /// </summary>
+ internal virtual bool IsComposable
+ {
+ get { return false; }
+ }
+
+ private sealed class InsecureCredentialsImpl : ChannelCredentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
@@ -74,7 +98,7 @@ namespace Grpc.Core
/// <summary>
/// Client-side SSL credentials.
/// </summary>
- public sealed class SslCredentials : Credentials
+ public sealed class SslCredentials : ChannelCredentials
{
readonly string rootCertificates;
readonly KeyCertificatePair keyCertificatePair;
@@ -130,9 +154,52 @@ namespace Grpc.Core
}
}
+ // Composing composite makes no sense.
+ internal override bool IsComposable
+ {
+ get { return true; }
+ }
+
internal override CredentialsSafeHandle ToNativeCredentials()
{
return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
}
+
+ /// <summary>
+ /// Credentials that allow composing one <see cref="ChannelCredentials"/> object and
+ /// one or more <see cref="CallCredentials"/> objects into a single <see cref="ChannelCredentials"/>.
+ /// </summary>
+ internal sealed class CompositeChannelCredentials : ChannelCredentials
+ {
+ readonly ChannelCredentials channelCredentials;
+ readonly CallCredentials callCredentials;
+
+ /// <summary>
+ /// Initializes a new instance of <c>CompositeChannelCredentials</c> class.
+ /// The resulting credentials object will be composite of all the credentials specified as parameters.
+ /// </summary>
+ /// <param name="channelCredentials">channelCredentials to compose</param>
+ /// <param name="callCredentials">channelCredentials to compose</param>
+ public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials)
+ {
+ this.channelCredentials = Preconditions.CheckNotNull(channelCredentials);
+ this.callCredentials = Preconditions.CheckNotNull(callCredentials);
+ Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
+ }
+
+ internal override CredentialsSafeHandle ToNativeCredentials()
+ {
+ using (var cred1 = channelCredentials.ToNativeCredentials())
+ using (var cred2 = callCredentials.ToNativeCredentials())
+ {
+ var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+ if (nativeComposite.IsInvalid)
+ {
+ throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
+ }
+ return nativeComposite;
+ }
+ }
+ }
}
diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs
index f4533e735c..e5b398062b 100644
--- a/src/csharp/Grpc.Core/ClientBase.cs
+++ b/src/csharp/Grpc.Core/ClientBase.cs
@@ -40,18 +40,17 @@ namespace Grpc.Core
/// <summary>
/// Interceptor for call headers.
/// </summary>
- public delegate void HeaderInterceptor(IMethod method, string authUri, Metadata metadata);
+ /// <remarks>Header interceptor is no longer to recommented way to perform authentication.
+ /// For header (initial metadata) based auth such as OAuth2 or JWT access token, use <see cref="MetadataCredentials"/>.
+ /// </remarks>
+ public delegate void HeaderInterceptor(IMethod method, Metadata metadata);
/// <summary>
/// Base class for client-side stubs.
/// </summary>
public abstract class ClientBase
{
- // Regex for removal of the optional DNS scheme, trailing port, and trailing backslash
- static readonly Regex ChannelTargetPattern = new Regex(@"^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$");
-
readonly Channel channel;
- readonly string authUriBase;
/// <summary>
/// Initializes a new instance of <c>ClientBase</c> class.
@@ -60,13 +59,14 @@ namespace Grpc.Core
public ClientBase(Channel channel)
{
this.channel = channel;
- this.authUriBase = GetAuthUriBase(channel.Target);
}
/// <summary>
- /// Can be used to register a custom header (request metadata) interceptor.
+ /// Can be used to register a custom header interceptor.
/// The interceptor is invoked each time a new call on this client is started.
+ /// It is not recommented to use header interceptor to add auth headers to RPC calls.
/// </summary>
+ /// <seealso cref="HeaderInterceptor"/>
public HeaderInterceptor HeaderInterceptor
{
get;
@@ -115,24 +115,9 @@ namespace Grpc.Core
{
options = options.WithHeaders(new Metadata());
}
- var authUri = authUriBase != null ? authUriBase + method.ServiceName : null;
- interceptor(method, authUri, options.Headers);
+ interceptor(method, options.Headers);
}
return new CallInvocationDetails<TRequest, TResponse>(channel, method, Host, options);
}
-
- /// <summary>
- /// Creates Auth URI base from channel's target (the one passed at channel creation).
- /// Fully-qualified service name is to be appended to this.
- /// </summary>
- internal static string GetAuthUriBase(string target)
- {
- var match = ChannelTargetPattern.Match(target);
- if (!match.Success)
- {
- return null;
- }
- return "https://" + match.Groups[2].Value + "/";
- }
}
}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index ad2af17bc7..92d4e19eac 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -48,7 +48,9 @@
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" />
+ <Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" />
+ <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
<Compile Include="Internal\INativeCall.cs" />
<Compile Include="IServerStreamWriter.cs" />
<Compile Include="IAsyncStreamWriter.cs" />
@@ -79,7 +81,7 @@
<Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" />
- <Compile Include="Credentials.cs" />
+ <Compile Include="ChannelCredentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
<Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 06de55c8c3..67a04afc22 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -16,7 +16,7 @@
<tags>gRPC RPC Protocol HTTP/2</tags>
<dependencies>
<dependency id="Ix-Async" version="1.2.3" />
- <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
+ <dependency id="grpc.native.csharp" version="$GrpcNativeCsharpVersion$" />
</dependencies>
</metadata>
<files>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index e3b00781c6..800462c854 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -344,9 +344,13 @@ namespace Grpc.Core.Internal
var parentCall = details.Options.PropagationToken != null ? details.Options.PropagationToken.ParentCall : CallSafeHandle.NullInstance;
- return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
- parentCall, ContextPropagationToken.DefaultMask, cq,
- details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value));
+ var credentials = details.Options.Credentials;
+ using (var nativeCredentials = credentials != null ? credentials.ToNativeCredentials() : null)
+ {
+ return details.Channel.Handle.CreateCall(environment.CompletionRegistry,
+ parentCall, ContextPropagationToken.DefaultMask, cq,
+ details.Method, details.Host, Timespec.FromDateTime(details.Options.Deadline.Value), nativeCredentials);
+ }
}
// Make sure that once cancellationToken for this call is cancelled, Cancel() will be called.
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index c3611a7761..0be7a4dd3a 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -99,6 +99,9 @@ namespace Grpc.Core.Internal
BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
[DllImport("grpc_csharp_ext.dll")]
+ static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
[DllImport("grpc_csharp_ext.dll")]
@@ -113,6 +116,11 @@ namespace Grpc.Core.Internal
this.completionRegistry = completionRegistry;
}
+ public void SetCredentials(CredentialsSafeHandle credentials)
+ {
+ grpcsharp_call_set_credentials(this, credentials).CheckOk();
+ }
+
public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, MetadataArraySafeHandle metadataArray, WriteFlags writeFlags)
{
var ctx = BatchContextSafeHandle.Create();
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 7a1c6e3dac..d270d77526 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -82,9 +82,13 @@ namespace Grpc.Core.Internal
return grpcsharp_secure_channel_create(credentials, target, channelArgs);
}
- public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+ public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials)
{
var result = grpcsharp_channel_create_call(this, parentCall, propagationMask, cq, method, host, deadline);
+ if (credentials != null)
+ {
+ result.SetCredentials(credentials);
+ }
result.SetCompletionRegistry(registry);
return result;
}
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
index feed335362..bab45108e0 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
@@ -44,6 +44,9 @@ namespace Grpc.Core.Internal
static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
[DllImport("grpc_csharp_ext.dll")]
+ static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_credentials_release(IntPtr credentials);
private CredentialsSafeHandle()
@@ -69,6 +72,11 @@ namespace Grpc.Core.Internal
}
}
+ public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2)
+ {
+ return grpcsharp_composite_credentials_create(creds1, creds2);
+ }
+
protected override bool ReleaseHandle()
{
grpcsharp_credentials_release(handle);
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
new file mode 100644
index 0000000000..f76492cba4
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -0,0 +1,113 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
+
+ internal class NativeMetadataCredentialsPlugin
+ {
+ const string GetMetadataExceptionMsg = "Exception occured in metadata credentials plugin.";
+ static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
+
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
+
+ AsyncAuthInterceptor interceptor;
+ GCHandle gcHandle;
+ NativeMetadataInterceptor nativeInterceptor;
+ CredentialsSafeHandle credentials;
+
+ public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
+ {
+ this.interceptor = Preconditions.CheckNotNull(interceptor, "interceptor");
+ this.nativeInterceptor = NativeMetadataInterceptorHandler;
+
+ // Make sure the callback doesn't get garbage collected until it is destroyed.
+ this.gcHandle = GCHandle.Alloc(this.nativeInterceptor, GCHandleType.Normal);
+ this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
+ }
+
+ public CredentialsSafeHandle Credentials
+ {
+ get { return credentials; }
+ }
+
+ private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
+ {
+ if (isDestroy)
+ {
+ gcHandle.Free();
+ return;
+ }
+
+ try
+ {
+ string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr);
+ StartGetMetadata(serviceUrl, callbackPtr, userDataPtr);
+ }
+ catch (Exception e)
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
+ Logger.Error(e, GetMetadataExceptionMsg);
+ }
+ }
+
+ private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr)
+ {
+ try
+ {
+ var metadata = new Metadata();
+ await interceptor(serviceUrl, metadata);
+
+ using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null);
+ }
+ }
+ catch (Exception e)
+ {
+ grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
+ Logger.Error(e, GetMetadataExceptionMsg);
+ }
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index 01e4a80bab..64e429ed5a 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,7 +39,7 @@ namespace Math
{
public static void Main(string[] args)
{
- var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure);
+ var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure);
Math.IMathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index e2975b5da9..290d42808e 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -61,7 +61,7 @@ namespace Math.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
- channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Math.NewClient(channel);
}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
index 6c3a53bec0..d90f21c2e1 100644
--- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -63,7 +63,7 @@ namespace Grpc.HealthCheck.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
- channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
+ channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index 2c38c9645c..8bc2082a1d 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>6d22e68f</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+ <None Include="packages.config" />
</ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/packages.config b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
new file mode 100644
index 0000000000..7a02c95db9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Client/packages.config
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 949ad61375..1eadbeb920 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -9,6 +9,7 @@
<AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
<StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <NuGetPackageImportStamp>d9ee8e52</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -38,7 +39,47 @@
<AssemblyOriginatorKeyFile>C:\keys\Grpc.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="BouncyCastle.Crypto, Version=1.7.4137.9688, Culture=neutral, PublicKeyToken=a4292a325f69b123, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Auth.PlatformServices, Version=1.9.3.19383, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+ </Reference>
+ <Reference Include="Google.Apis.Core, Version=1.9.3.19379, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks, Version=1.0.12.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions">
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop, Version=1.0.168.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+ </Reference>
+ <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Net.Http.Extensions">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.Primitives">
+ <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+ </Reference>
+ <Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Grpc.Core\Version.cs">
@@ -60,5 +101,13 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
+ <None Include="packages.config" />
</ItemGroup>
+ <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
+ </Target>
</Project> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/packages.config b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
new file mode 100644
index 0000000000..7a02c95db9
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting.Server/packages.config
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+ <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+ <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+ <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+ <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+ <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+ <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages> \ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs
index 28c28c9afd..9bf2b8f7cf 100644
--- a/src/csharp/Grpc.IntegrationTesting/Empty.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: empty.proto
+// source: test/proto/empty.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -23,7 +23,8 @@ namespace Grpc.Testing {
static Empty() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM="));
+ "ChZ0ZXN0L3Byb3RvL2VtcHR5LnByb3RvEgxncnBjLnRlc3RpbmciBwoFRW1w",
+ "dHliBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index a0bcf431f7..2b75305731 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -96,6 +96,7 @@
<Compile Include="Empty.cs" />
<Compile Include="Messages.cs" />
<Compile Include="InteropClientServerTest.cs" />
+ <Compile Include="MetadataCredentialsTest.cs" />
<Compile Include="TestServiceImpl.cs" />
<Compile Include="InteropServer.cs" />
<Compile Include="InteropClient.cs" />
@@ -118,9 +119,6 @@
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
- <None Include="proto\test.proto" />
- <None Include="proto\empty.proto" />
- <None Include="proto\messages.proto" />
<None Include="data\README">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 504d798b89..030a098cad 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -33,20 +33,21 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using CommandLine;
+using CommandLine.Text;
using Google.Apis.Auth.OAuth2;
using Google.Protobuf;
using Grpc.Auth;
using Grpc.Core;
using Grpc.Core.Utils;
using Grpc.Testing;
+using Newtonsoft.Json.Linq;
using NUnit.Framework;
-using CommandLine.Text;
-using System.IO;
namespace Grpc.IntegrationTesting
{
@@ -66,11 +67,13 @@ namespace Grpc.IntegrationTesting
[Option("test_case", DefaultValue = "large_unary")]
public string TestCase { get; set; }
- [Option("use_tls")]
- public bool UseTls { get; set; }
+ // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
+ [Option("use_tls", DefaultValue = false)]
+ public bool? UseTls { get; set; }
- [Option("use_test_ca")]
- public bool UseTestCa { get; set; }
+ // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca)
+ [Option("use_test_ca", DefaultValue = false)]
+ public bool? UseTestCa { get; set; }
[Option("default_service_account", Required = false)]
public string DefaultServiceAccount { get; set; }
@@ -116,7 +119,7 @@ namespace Grpc.IntegrationTesting
private async Task Run()
{
- var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure;
+ var credentials = await CreateCredentialsAsync();
List<ChannelOption> channelOptions = null;
if (!string.IsNullOrEmpty(options.ServerHostOverride))
@@ -132,6 +135,26 @@ namespace Grpc.IntegrationTesting
await channel.ShutdownAsync();
}
+ private async Task<ChannelCredentials> CreateCredentialsAsync()
+ {
+ var credentials = options.UseTls.Value ? TestCredentials.CreateTestClientCredentials(options.UseTestCa.Value) : ChannelCredentials.Insecure;
+
+ if (options.TestCase == "jwt_token_creds")
+ {
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ Assert.IsTrue(googleCredential.IsCreateScopedRequired);
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+ }
+
+ if (options.TestCase == "compute_engine_creds")
+ {
+ var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ Assert.IsFalse(googleCredential.IsCreateScopedRequired);
+ credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials());
+ }
+ return credentials;
+ }
+
private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options)
{
switch (options.TestCase)
@@ -155,16 +178,16 @@ namespace Grpc.IntegrationTesting
await RunEmptyStreamAsync(client);
break;
case "compute_engine_creds":
- await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope);
break;
case "jwt_token_creds":
- await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount);
+ RunJwtTokenCreds(client);
break;
case "oauth2_auth_token":
- await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ await RunOAuth2AuthTokenAsync(client, options.OAuthScope);
break;
case "per_rpc_creds":
- await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope);
+ await RunPerRpcCredsAsync(client, options.OAuthScope);
break;
case "cancel_after_begin":
await RunCancelAfterBeginAsync(client);
@@ -318,13 +341,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
{
Console.WriteLine("running compute_engine_creds");
- var credential = await GoogleCredential.GetApplicationDefaultAsync();
- Assert.IsFalse(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
-
+
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@@ -334,6 +354,7 @@ namespace Grpc.IntegrationTesting
FillOauthScope = true
};
+ // not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
@@ -344,13 +365,10 @@ namespace Grpc.IntegrationTesting
Console.WriteLine("Passed!");
}
- public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount)
+ public static void RunJwtTokenCreds(TestService.TestServiceClient client)
{
Console.WriteLine("running jwt_token_creds");
- var credential = await GoogleCredential.GetApplicationDefaultAsync();
- Assert.IsTrue(credential.IsCreateScopedRequired);
- client.HeaderInterceptor = AuthInterceptors.FromCredential(credential);
-
+
var request = new SimpleRequest
{
ResponseType = PayloadType.COMPRESSABLE,
@@ -359,53 +377,50 @@ namespace Grpc.IntegrationTesting
FillUsername = true,
};
+ // not setting credentials here because they were set on channel already
var response = client.UnaryCall(request);
Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
Assert.AreEqual(314159, response.Payload.Body.Length);
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running oauth2_auth_token");
ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
string oauth2Token = await credential.GetAccessTokenForRequestAsync();
- client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token);
-
+ var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token);
var request = new SimpleRequest
{
FillUsername = true,
FillOauthScope = true
};
- var response = client.UnaryCall(request);
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
Assert.False(string.IsNullOrEmpty(response.OauthScope));
Assert.True(oauthScope.Contains(response.OauthScope));
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
- public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope)
+ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope)
{
Console.WriteLine("running per_rpc_creds");
- ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope });
- string accessToken = await credential.GetAccessTokenForRequestAsync();
- var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken);
+ ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
+ var credentials = googleCredential.ToCallCredentials();
var request = new SimpleRequest
{
FillUsername = true,
};
- var headers = new Metadata();
- headerInterceptor(null, "", headers);
- var response = client.UnaryCall(request, headers: headers);
+ var response = client.UnaryCall(request, new CallOptions(credentials: credentials));
- Assert.AreEqual(defaultServiceAccount, response.Username);
+ Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username);
Console.WriteLine("Passed!");
}
@@ -485,5 +500,17 @@ namespace Grpc.IntegrationTesting
{
return new Payload { Body = ByteString.CopyFrom(new byte[size]) };
}
+
+ // extracts the client_email field from service account file used for auth test cases
+ private static string GetEmailFromServiceAccountFile()
+ {
+ string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
+ Assert.IsNotNull(keyFile);
+
+ var jobject = JObject.Parse(File.ReadAllText(keyFile));
+ string email = jobject.GetValue("client_email").Value<string>();
+ Assert.IsTrue(email.Length > 0); // spec requires nonempty client email.
+ return email;
+ }
}
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 513f8722d6..29f842be2e 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -54,8 +54,9 @@ namespace Grpc.IntegrationTesting
[Option("port", DefaultValue = 8070)]
public int Port { get; set; }
- [Option("use_tls")]
- public bool UseTls { get; set; }
+ // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls)
+ [Option("use_tls", DefaultValue = false)]
+ public bool? UseTls { get; set; }
[HelpOption]
public string GetUsage()
@@ -99,7 +100,7 @@ namespace Grpc.IntegrationTesting
string host = "0.0.0.0";
int port = options.Port;
- if (options.UseTls)
+ if (options.UseTls.Value)
{
server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials());
}
diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs
index a3cbb7d76e..51a56f067b 100644
--- a/src/csharp/Grpc.IntegrationTesting/Messages.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: messages.proto
+// source: test/proto/messages.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -21,37 +21,48 @@ namespace Grpc.Testing {
static Messages() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE",
- "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5",
- "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB",
- "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6",
- "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv",
- "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl",
- "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n",
- "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0",
- "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK",
- "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl",
- "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf",
- "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo",
- "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs",
- "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu",
- "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu",
- "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg",
- "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0",
- "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
- "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V",
- "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM="));
+ "Chl0ZXN0L3Byb3RvL21lc3NhZ2VzLnByb3RvEgxncnBjLnRlc3RpbmciQAoH",
+ "UGF5bG9hZBInCgR0eXBlGAEgASgOMhkuZ3JwYy50ZXN0aW5nLlBheWxvYWRU",
+ "eXBlEgwKBGJvZHkYAiABKAwiKwoKRWNob1N0YXR1cxIMCgRjb2RlGAEgASgF",
+ "Eg8KB21lc3NhZ2UYAiABKAkioQIKDVNpbXBsZVJlcXVlc3QSMAoNcmVzcG9u",
+ "c2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIVCg1y",
+ "ZXNwb25zZV9zaXplGAIgASgFEiYKB3BheWxvYWQYAyABKAsyFS5ncnBjLnRl",
+ "c3RpbmcuUGF5bG9hZBIVCg1maWxsX3VzZXJuYW1lGAQgASgIEhgKEGZpbGxf",
+ "b2F1dGhfc2NvcGUYBSABKAgSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiAB",
+ "KA4yHS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNl",
+ "X3N0YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIl8KDlNp",
+ "bXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu",
+ "UGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0aF9zY29wZRgDIAEo",
+ "CSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYKB3BheWxvYWQYASAB",
+ "KAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJlYW1pbmdJbnB1dENh",
+ "bGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRfc2l6ZRgBIAEoBSI3",
+ "ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEoBRITCgtpbnRlcnZh",
+ "bF91cxgCIAEoBSKlAgoaU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QSMAoN",
+ "cmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlw",
+ "ZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAuZ3JwYy50ZXN0aW5n",
+ "LlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50",
+ "ZXN0aW5nLlBheWxvYWQSOwoUcmVzcG9uc2VfY29tcHJlc3Npb24YBiABKA4y",
+ "HS5ncnBjLnRlc3RpbmcuQ29tcHJlc3Npb25UeXBlEjEKD3Jlc3BvbnNlX3N0",
+ "YXR1cxgHIAEoCzIYLmdycGMudGVzdGluZy5FY2hvU3RhdHVzIkUKG1N0cmVh",
+ "bWluZ091dHB1dENhbGxSZXNwb25zZRImCgdwYXlsb2FkGAEgASgLMhUuZ3Jw",
+ "Yy50ZXN0aW5nLlBheWxvYWQiMwoNUmVjb25uZWN0SW5mbxIOCgZwYXNzZWQY",
+ "ASABKAgSEgoKYmFja29mZl9tcxgCIAMoBSo/CgtQYXlsb2FkVHlwZRIQCgxD",
+ "T01QUkVTU0FCTEUQABISCg5VTkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC",
+ "KjIKD0NvbXByZXNzaW9uVHlwZRIICgROT05FEAASCAoER1pJUBABEgsKB0RF",
+ "RkxBVEUQAmIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { },
- new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] {
+ new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), typeof(global::Grpc.Testing.CompressionType), }, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.EchoStatus), new[]{ "Code", "Message" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", "ResponseCompression", "ResponseStatus" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null),
- new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null)
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload", "ResponseCompression", "ResponseStatus" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null),
+ new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ReconnectInfo), new[]{ "Passed", "BackoffMs" }, null, null, null)
}));
}
#endregion
@@ -64,6 +75,12 @@ namespace Grpc.Testing {
RANDOM = 2,
}
+ public enum CompressionType {
+ NONE = 0,
+ GZIP = 1,
+ DEFLATE = 2,
+ }
+
#endregion
#region Messages
@@ -196,12 +213,140 @@ namespace Grpc.Testing {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class EchoStatus : pb::IMessage<EchoStatus> {
+ private static readonly pb::MessageParser<EchoStatus> _parser = new pb::MessageParser<EchoStatus>(() => new EchoStatus());
+ public static pb::MessageParser<EchoStatus> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public EchoStatus() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public EchoStatus(EchoStatus other) : this() {
+ code_ = other.code_;
+ message_ = other.message_;
+ }
+
+ public EchoStatus Clone() {
+ return new EchoStatus(this);
+ }
+
+ public const int CodeFieldNumber = 1;
+ private int code_;
+ public int Code {
+ get { return code_; }
+ set {
+ code_ = value;
+ }
+ }
+
+ public const int MessageFieldNumber = 2;
+ private string message_ = "";
+ public string Message {
+ get { return message_; }
+ set {
+ message_ = pb::Preconditions.CheckNotNull(value, "value");
+ }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as EchoStatus);
+ }
+
+ public bool Equals(EchoStatus other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Code != other.Code) return false;
+ if (Message != other.Message) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Code != 0) hash ^= Code.GetHashCode();
+ if (Message.Length != 0) hash ^= Message.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Code != 0) {
+ output.WriteRawTag(8);
+ output.WriteInt32(Code);
+ }
+ if (Message.Length != 0) {
+ output.WriteRawTag(18);
+ output.WriteString(Message);
+ }
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Code != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(Code);
+ }
+ if (Message.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Message);
+ }
+ return size;
+ }
+
+ public void MergeFrom(EchoStatus other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Code != 0) {
+ Code = other.Code;
+ }
+ if (other.Message.Length != 0) {
+ Message = other.Message;
+ }
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Code = input.ReadInt32();
+ break;
+ }
+ case 18: {
+ Message = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class SimpleRequest : pb::IMessage<SimpleRequest> {
private static readonly pb::MessageParser<SimpleRequest> _parser = new pb::MessageParser<SimpleRequest>(() => new SimpleRequest());
public static pb::MessageParser<SimpleRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -220,6 +365,8 @@ namespace Grpc.Testing {
Payload = other.payload_ != null ? other.Payload.Clone() : null;
fillUsername_ = other.fillUsername_;
fillOauthScope_ = other.fillOauthScope_;
+ responseCompression_ = other.responseCompression_;
+ ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public SimpleRequest Clone() {
@@ -271,6 +418,24 @@ namespace Grpc.Testing {
}
}
+ public const int ResponseCompressionFieldNumber = 6;
+ private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ public global::Grpc.Testing.CompressionType ResponseCompression {
+ get { return responseCompression_; }
+ set {
+ responseCompression_ = value;
+ }
+ }
+
+ public const int ResponseStatusFieldNumber = 7;
+ private global::Grpc.Testing.EchoStatus responseStatus_;
+ public global::Grpc.Testing.EchoStatus ResponseStatus {
+ get { return responseStatus_; }
+ set {
+ responseStatus_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as SimpleRequest);
}
@@ -287,6 +452,8 @@ namespace Grpc.Testing {
if (!object.Equals(Payload, other.Payload)) return false;
if (FillUsername != other.FillUsername) return false;
if (FillOauthScope != other.FillOauthScope) return false;
+ if (ResponseCompression != other.ResponseCompression) return false;
+ if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@@ -297,6 +464,8 @@ namespace Grpc.Testing {
if (payload_ != null) hash ^= Payload.GetHashCode();
if (FillUsername != false) hash ^= FillUsername.GetHashCode();
if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode();
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -325,6 +494,14 @@ namespace Grpc.Testing {
output.WriteRawTag(40);
output.WriteBool(FillOauthScope);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ output.WriteRawTag(48);
+ output.WriteEnum((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ output.WriteRawTag(58);
+ output.WriteMessage(ResponseStatus);
+ }
}
public int CalculateSize() {
@@ -344,6 +521,12 @@ namespace Grpc.Testing {
if (FillOauthScope != false) {
size += 1 + 1;
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
+ }
return size;
}
@@ -369,6 +552,15 @@ namespace Grpc.Testing {
if (other.FillOauthScope != false) {
FillOauthScope = other.FillOauthScope;
}
+ if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ ResponseCompression = other.ResponseCompression;
+ }
+ if (other.responseStatus_ != null) {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ ResponseStatus.MergeFrom(other.ResponseStatus);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -401,6 +593,17 @@ namespace Grpc.Testing {
FillOauthScope = input.ReadBool();
break;
}
+ case 48: {
+ responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+ break;
+ }
+ case 58: {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ input.ReadMessage(responseStatus_);
+ break;
+ }
}
}
}
@@ -413,7 +616,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<SimpleResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -573,7 +776,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -681,7 +884,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingInputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -783,7 +986,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<ResponseParameters> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -911,7 +1114,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -928,6 +1131,8 @@ namespace Grpc.Testing {
responseType_ = other.responseType_;
responseParameters_ = other.responseParameters_.Clone();
Payload = other.payload_ != null ? other.Payload.Clone() : null;
+ responseCompression_ = other.responseCompression_;
+ ResponseStatus = other.responseStatus_ != null ? other.ResponseStatus.Clone() : null;
}
public StreamingOutputCallRequest Clone() {
@@ -960,6 +1165,24 @@ namespace Grpc.Testing {
}
}
+ public const int ResponseCompressionFieldNumber = 6;
+ private global::Grpc.Testing.CompressionType responseCompression_ = global::Grpc.Testing.CompressionType.NONE;
+ public global::Grpc.Testing.CompressionType ResponseCompression {
+ get { return responseCompression_; }
+ set {
+ responseCompression_ = value;
+ }
+ }
+
+ public const int ResponseStatusFieldNumber = 7;
+ private global::Grpc.Testing.EchoStatus responseStatus_;
+ public global::Grpc.Testing.EchoStatus ResponseStatus {
+ get { return responseStatus_; }
+ set {
+ responseStatus_ = value;
+ }
+ }
+
public override bool Equals(object other) {
return Equals(other as StreamingOutputCallRequest);
}
@@ -974,6 +1197,8 @@ namespace Grpc.Testing {
if (ResponseType != other.ResponseType) return false;
if(!responseParameters_.Equals(other.responseParameters_)) return false;
if (!object.Equals(Payload, other.Payload)) return false;
+ if (ResponseCompression != other.ResponseCompression) return false;
+ if (!object.Equals(ResponseStatus, other.ResponseStatus)) return false;
return true;
}
@@ -982,6 +1207,8 @@ namespace Grpc.Testing {
if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode();
hash ^= responseParameters_.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) hash ^= ResponseCompression.GetHashCode();
+ if (responseStatus_ != null) hash ^= ResponseStatus.GetHashCode();
return hash;
}
@@ -999,6 +1226,14 @@ namespace Grpc.Testing {
output.WriteRawTag(26);
output.WriteMessage(Payload);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ output.WriteRawTag(48);
+ output.WriteEnum((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ output.WriteRawTag(58);
+ output.WriteMessage(ResponseStatus);
+ }
}
public int CalculateSize() {
@@ -1010,6 +1245,12 @@ namespace Grpc.Testing {
if (payload_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload);
}
+ if (ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseCompression);
+ }
+ if (responseStatus_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(ResponseStatus);
+ }
return size;
}
@@ -1027,6 +1268,15 @@ namespace Grpc.Testing {
}
Payload.MergeFrom(other.Payload);
}
+ if (other.ResponseCompression != global::Grpc.Testing.CompressionType.NONE) {
+ ResponseCompression = other.ResponseCompression;
+ }
+ if (other.responseStatus_ != null) {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ ResponseStatus.MergeFrom(other.ResponseStatus);
+ }
}
public void MergeFrom(pb::CodedInputStream input) {
@@ -1051,6 +1301,17 @@ namespace Grpc.Testing {
input.ReadMessage(payload_);
break;
}
+ case 48: {
+ responseCompression_ = (global::Grpc.Testing.CompressionType) input.ReadEnum();
+ break;
+ }
+ case 58: {
+ if (responseStatus_ == null) {
+ responseStatus_ = new global::Grpc.Testing.EchoStatus();
+ }
+ input.ReadMessage(responseStatus_);
+ break;
+ }
}
}
}
@@ -1063,7 +1324,7 @@ namespace Grpc.Testing {
public static pb::MessageParser<StreamingOutputCallResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
- get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; }
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[8]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
@@ -1165,6 +1426,127 @@ namespace Grpc.Testing {
}
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class ReconnectInfo : pb::IMessage<ReconnectInfo> {
+ private static readonly pb::MessageParser<ReconnectInfo> _parser = new pb::MessageParser<ReconnectInfo>(() => new ReconnectInfo());
+ public static pb::MessageParser<ReconnectInfo> Parser { get { return _parser; } }
+
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[9]; }
+ }
+
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ public ReconnectInfo() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ public ReconnectInfo(ReconnectInfo other) : this() {
+ passed_ = other.passed_;
+ backoffMs_ = other.backoffMs_.Clone();
+ }
+
+ public ReconnectInfo Clone() {
+ return new ReconnectInfo(this);
+ }
+
+ public const int PassedFieldNumber = 1;
+ private bool passed_;
+ public bool Passed {
+ get { return passed_; }
+ set {
+ passed_ = value;
+ }
+ }
+
+ public const int BackoffMsFieldNumber = 2;
+ private static readonly pb::FieldCodec<int> _repeated_backoffMs_codec
+ = pb::FieldCodec.ForInt32(18);
+ private readonly pbc::RepeatedField<int> backoffMs_ = new pbc::RepeatedField<int>();
+ public pbc::RepeatedField<int> BackoffMs {
+ get { return backoffMs_; }
+ }
+
+ public override bool Equals(object other) {
+ return Equals(other as ReconnectInfo);
+ }
+
+ public bool Equals(ReconnectInfo other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Passed != other.Passed) return false;
+ if(!backoffMs_.Equals(other.backoffMs_)) return false;
+ return true;
+ }
+
+ public override int GetHashCode() {
+ int hash = 1;
+ if (Passed != false) hash ^= Passed.GetHashCode();
+ hash ^= backoffMs_.GetHashCode();
+ return hash;
+ }
+
+ public override string ToString() {
+ return pb::JsonFormatter.Default.Format(this);
+ }
+
+ public void WriteTo(pb::CodedOutputStream output) {
+ if (Passed != false) {
+ output.WriteRawTag(8);
+ output.WriteBool(Passed);
+ }
+ backoffMs_.WriteTo(output, _repeated_backoffMs_codec);
+ }
+
+ public int CalculateSize() {
+ int size = 0;
+ if (Passed != false) {
+ size += 1 + 1;
+ }
+ size += backoffMs_.CalculateSize(_repeated_backoffMs_codec);
+ return size;
+ }
+
+ public void MergeFrom(ReconnectInfo other) {
+ if (other == null) {
+ return;
+ }
+ if (other.Passed != false) {
+ Passed = other.Passed;
+ }
+ backoffMs_.Add(other.backoffMs_);
+ }
+
+ public void MergeFrom(pb::CodedInputStream input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ input.SkipLastField();
+ break;
+ case 8: {
+ Passed = input.ReadBool();
+ break;
+ }
+ case 18:
+ case 16: {
+ backoffMs_.AddEntriesFrom(input, _repeated_backoffMs_codec);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
#endregion
}
diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
new file mode 100644
index 0000000000..3d56678b99
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Testing;
+using NUnit.Framework;
+
+namespace Grpc.IntegrationTesting
+{
+ public class MetadataCredentialsTest
+ {
+ const string Host = "localhost";
+ Server server;
+ Channel channel;
+ TestService.ITestServiceClient client;
+
+ [TestFixtureSetUp]
+ public void Init()
+ {
+ var serverCredentials = new SslServerCredentials(new[] { new KeyCertificatePair(File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)) });
+ server = new Server
+ {
+ Services = { TestService.BindService(new TestServiceImpl()) },
+ Ports = { { Host, ServerPort.PickUnused, serverCredentials } }
+ };
+ server.Start();
+
+ var options = new List<ChannelOption>
+ {
+ new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
+ };
+
+ var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) =>
+ {
+ await Task.Delay(100); // make sure the operation is asynchronous.
+ metadata.Add("authorization", "SECRET_TOKEN");
+ });
+
+ var clientCredentials = ChannelCredentials.Create(
+ new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)),
+ CallCredentials.FromInterceptor(asyncAuthInterceptor));
+ channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);
+ client = TestService.NewClient(channel);
+ }
+
+ [TestFixtureTearDown]
+ public void Cleanup()
+ {
+ channel.ShutdownAsync().Wait();
+ server.ShutdownAsync().Wait();
+ }
+
+ [Test]
+ public void MetadataCredentials()
+ {
+ var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 });
+ Assert.AreEqual(10, response.Payload.Body.Length);
+ }
+ }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs
index 466ec57d3d..cf47707058 100644
--- a/src/csharp/Grpc.IntegrationTesting/Test.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Test.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: test.proto
+// source: test/proto/test.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
@@ -21,21 +21,26 @@ namespace Grpc.Testing {
static Test() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz",
- "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw",
- "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5",
- "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0",
- "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n",
- "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj",
- "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry",
- "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0",
- "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs",
- "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T",
- "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl",
- "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs",
- "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku",
- "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi",
- "BnByb3RvMw=="));
+ "ChV0ZXN0L3Byb3RvL3Rlc3QucHJvdG8SDGdycGMudGVzdGluZxoWdGVzdC9w",
+ "cm90by9lbXB0eS5wcm90bxoZdGVzdC9wcm90by9tZXNzYWdlcy5wcm90bzK7",
+ "BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3JwYy50ZXN0aW5nLkVt",
+ "cHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5Q2FsbBIbLmdycGMu",
+ "dGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0aW5nLlNpbXBsZVJl",
+ "c3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5ncnBjLnRlc3Rpbmcu",
+ "U3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBjLnRlc3RpbmcuU3Ry",
+ "ZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3RyZWFtaW5nSW5wdXRD",
+ "YWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0Q2FsbFJlcXVlc3Qa",
+ "KC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxsUmVzcG9uc2UoARJp",
+ "Cg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRw",
+ "dXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJlYW1pbmdPdXRwdXRD",
+ "YWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxsEiguZ3JwYy50ZXN0",
+ "aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0GikuZ3JwYy50ZXN0aW5n",
+ "LlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAEyVQoUVW5pbXBsZW1l",
+ "bnRlZFNlcnZpY2USPQoRVW5pbXBsZW1lbnRlZENhbGwSEy5ncnBjLnRlc3Rp",
+ "bmcuRW1wdHkaEy5ncnBjLnRlc3RpbmcuRW1wdHkyfwoQUmVjb25uZWN0U2Vy",
+ "dmljZRIxCgVTdGFydBITLmdycGMudGVzdGluZy5FbXB0eRoTLmdycGMudGVz",
+ "dGluZy5FbXB0eRI4CgRTdG9wEhMuZ3JwYy50ZXN0aW5nLkVtcHR5GhsuZ3Jw",
+ "Yy50ZXN0aW5nLlJlY29ubmVjdEluZm9iBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, },
new pbr::GeneratedCodeInfo(null, null));
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index f63e148475..8c884b7408 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -1,5 +1,5 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: test.proto
+// source: test/proto/test.proto
#region Designer generated code
using System;
@@ -207,5 +207,191 @@ namespace Grpc.Testing {
}
}
+ public static class UnimplementedService
+ {
+ static readonly string __ServiceName = "grpc.testing.UnimplementedService";
+
+ static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_UnimplementedCall = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+ MethodType.Unary,
+ __ServiceName,
+ "UnimplementedCall",
+ __Marshaller_Empty,
+ __Marshaller_Empty);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Test.Descriptor.Services[1]; }
+ }
+
+ // client interface
+ public interface IUnimplementedServiceClient
+ {
+ global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ }
+
+ // server-side interface
+ public interface IUnimplementedService
+ {
+ Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+ }
+
+ // client stub
+ public class UnimplementedServiceClient : ClientBase, IUnimplementedServiceClient
+ {
+ public UnimplementedServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnimplementedCall, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_UnimplementedCall, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_UnimplementedCall, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
+ }
+
+ // creates a new client
+ public static UnimplementedServiceClient NewClient(Channel channel)
+ {
+ return new UnimplementedServiceClient(channel);
+ }
+
+ }
+ public static class ReconnectService
+ {
+ static readonly string __ServiceName = "grpc.testing.ReconnectService";
+
+ static readonly Marshaller<global::Grpc.Testing.Empty> __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom);
+ static readonly Marshaller<global::Grpc.Testing.ReconnectInfo> __Marshaller_ReconnectInfo = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.ReconnectInfo.Parser.ParseFrom);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty> __Method_Start = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.Empty>(
+ MethodType.Unary,
+ __ServiceName,
+ "Start",
+ __Marshaller_Empty,
+ __Marshaller_Empty);
+
+ static readonly Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo> __Method_Stop = new Method<global::Grpc.Testing.Empty, global::Grpc.Testing.ReconnectInfo>(
+ MethodType.Unary,
+ __ServiceName,
+ "Stop",
+ __Marshaller_Empty,
+ __Marshaller_ReconnectInfo);
+
+ // service descriptor
+ public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
+ {
+ get { return global::Grpc.Testing.Test.Descriptor.Services[2]; }
+ }
+
+ // client interface
+ public interface IReconnectServiceClient
+ {
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options);
+ AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+ AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
+ }
+
+ // server-side interface
+ public interface IReconnectService
+ {
+ Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.Empty request, ServerCallContext context);
+ Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
+ }
+
+ // client stub
+ public class ReconnectServiceClient : ClientBase, IReconnectServiceClient
+ {
+ public ReconnectServiceClient(Channel channel) : base(channel)
+ {
+ }
+ public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.Empty Start(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Start, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Start, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.Empty> StartAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Start, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public global::Grpc.Testing.ReconnectInfo Stop(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Stop, options);
+ return Calls.BlockingUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var call = CreateCall(__Method_Stop, new CallOptions(headers, deadline, cancellationToken));
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ public AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options)
+ {
+ var call = CreateCall(__Method_Stop, options);
+ return Calls.AsyncUnaryCall(call, request);
+ }
+ }
+
+ // creates service definition that can be registered with a server
+ public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
+ {
+ return ServerServiceDefinition.CreateBuilder(__ServiceName)
+ .AddMethod(__Method_Start, serviceImpl.Start)
+ .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
+ }
+
+ // creates a new client
+ public static ReconnectServiceClient NewClient(Channel channel)
+ {
+ return new ReconnectServiceClient(channel);
+ }
+
+ }
}
#endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
deleted file mode 100644
index 6d0eb937d6..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto
+++ /dev/null
@@ -1,43 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// An empty message that you can re-use to avoid defining duplicated empty
-// messages in your project. A typical example is to use it as argument or the
-// return value of a service API. For instance:
-//
-// service Foo {
-// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
-// };
-//
-message Empty {}
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
deleted file mode 100644
index 7df85e3c13..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto
+++ /dev/null
@@ -1,132 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Message definitions to be used by integration test service definitions.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// The type of payload that should be returned.
-enum PayloadType {
- // Compressable text format.
- COMPRESSABLE = 0;
-
- // Uncompressable binary format.
- UNCOMPRESSABLE = 1;
-
- // Randomly chosen from all other formats defined in this enum.
- RANDOM = 2;
-}
-
-// A block of data, to simply increase gRPC message size.
-message Payload {
- // The type of data in body.
- PayloadType type = 1;
- // Primary contents of payload.
- bytes body = 2;
-}
-
-// Unary request.
-message SimpleRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, server randomly chooses one from other formats.
- PayloadType response_type = 1;
-
- // Desired payload size in the response from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 response_size = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-
- // Whether SimpleResponse should include username.
- bool fill_username = 4;
-
- // Whether SimpleResponse should include OAuth scope.
- bool fill_oauth_scope = 5;
-}
-
-// Unary response, as configured by the request.
-message SimpleResponse {
- // Payload to increase message size.
- Payload payload = 1;
- // The user the request came from, for verifying authentication was
- // successful when the client expected it.
- string username = 2;
- // OAuth scope.
- string oauth_scope = 3;
-}
-
-// Client-streaming request.
-message StreamingInputCallRequest {
- // Optional input payload sent along with the request.
- Payload payload = 1;
-
- // Not expecting any payload from the response.
-}
-
-// Client-streaming response.
-message StreamingInputCallResponse {
- // Aggregated size of payloads received from the client.
- int32 aggregated_payload_size = 1;
-}
-
-// Configuration for a particular response.
-message ResponseParameters {
- // Desired payload sizes in responses from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 size = 1;
-
- // Desired interval between consecutive responses in the response stream in
- // microseconds.
- int32 interval_us = 2;
-}
-
-// Server-streaming request.
-message StreamingOutputCallRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, the payload from each response in the stream
- // might be of different types. This is to simulate a mixed type of payload
- // stream.
- PayloadType response_type = 1;
-
- // Configuration for each expected response message.
- repeated ResponseParameters response_parameters = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-}
-
-// Server-streaming response, as configured by the request and parameters.
-message StreamingOutputCallResponse {
- // Payload to increase response size.
- Payload payload = 1;
-}
diff --git a/src/csharp/Grpc.IntegrationTesting/proto/test.proto b/src/csharp/Grpc.IntegrationTesting/proto/test.proto
deleted file mode 100644
index 5496f72af0..0000000000
--- a/src/csharp/Grpc.IntegrationTesting/proto/test.proto
+++ /dev/null
@@ -1,71 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// An integration test service that covers all the method signature permutations
-// of unary/streaming requests/responses.
-syntax = "proto3";
-
-import "empty.proto";
-import "messages.proto";
-
-package grpc.testing;
-
-// A simple service to test the various types of RPCs and experiment with
-// performance with various types of payload.
-service TestService {
- // One empty request followed by one empty response.
- rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
-
- // One request followed by one response.
- rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
-
- // One request followed by a sequence of responses (streamed download).
- // The server returns the payload with client desired type and sizes.
- rpc StreamingOutputCall(StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by one response (streamed upload).
- // The server returns the aggregated size of client payload as the result.
- rpc StreamingInputCall(stream StreamingInputCallRequest)
- returns (StreamingInputCallResponse);
-
- // A sequence of requests with each request served by the server immediately.
- // As one request could lead to multiple responses, this interface
- // demonstrates the idea of full duplexing.
- rpc FullDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by a sequence of responses.
- // The server buffers all the client requests and then serves them in order. A
- // stream of responses are returned to the client when the server starts with
- // first request.
- rpc HalfDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-}
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index a3505b1e01..b864a955a8 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -20,9 +20,9 @@ endlocal
@call ..\..\vsprojects\build_plugins.bat || goto :error
-%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
+%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp.nuspec -Version %CORE_VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
+%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpVersion=%CORE_VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 51e0728fb9..679ca43d74 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -68,7 +68,7 @@ grpc_byte_buffer *string_to_byte_buffer(const char *buffer, size_t len) {
/*
* Helper to maintain lifetime of batch op inputs and store batch op outputs.
*/
-typedef struct gprcsharp_batch_context {
+typedef struct grpcsharp_batch_context {
grpc_metadata_array send_initial_metadata;
grpc_byte_buffer *send_message;
struct {
@@ -665,16 +665,16 @@ grpcsharp_call_start_duplex_streaming(grpc_call *call,
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
- grpc_call *call, grpcsharp_batch_context *ctx) {
- /* TODO: don't use magic number */
- grpc_op ops[1];
- ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
- ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
- ops[0].flags = 0;
- ops[0].reserved = NULL;
+ grpc_call *call, grpcsharp_batch_context *ctx) {
+ /* TODO: don't use magic number */
+ grpc_op ops[1];
+ ops[0].op = GRPC_OP_RECV_INITIAL_METADATA;
+ ops[0].data.recv_initial_metadata = &(ctx->recv_initial_metadata);
+ ops[0].flags = 0;
+ ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
+ NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -785,6 +785,11 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
NULL);
}
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call,
+ grpc_credentials *creds) {
+ return grpc_call_set_credentials(call, creds);
+}
+
/* Server */
GPR_EXPORT grpc_server *GPR_CALLTYPE
@@ -892,6 +897,47 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
return grpc_server_add_secure_http2_port(server, addr, creds);
}
+GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create(
+ grpc_credentials *creds1,
+ grpc_credentials *creds2) {
+ return grpc_composite_credentials_create(creds1, creds2, NULL);
+}
+
+/* Metadata credentials plugin */
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data, grpc_metadata_array *metadata,
+ grpc_status_code status, const char *error_details) {
+ cb(user_data, metadata->metadata, metadata->count, status, error_details);
+}
+
+typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
+ void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb,
+ void *user_data, gpr_int32 is_destroy);
+
+static void grpcsharp_get_metadata_handler(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data) {
+ grpcsharp_metadata_interceptor_func interceptor =
+ (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
+ interceptor(state, service_url, cb, user_data, 0);
+}
+
+static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
+ grpcsharp_metadata_interceptor_func interceptor =
+ (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
+ interceptor(state, NULL, NULL, NULL, 1);
+}
+
+GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
+ grpcsharp_metadata_interceptor_func metadata_interceptor) {
+ grpc_metadata_credentials_plugin plugin;
+ plugin.get_metadata = grpcsharp_get_metadata_handler;
+ plugin.destroy = grpcsharp_metadata_credentials_destroy_handler;
+ plugin.state = (void*)(gpr_intptr)metadata_interceptor;
+ return grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+}
+
/* Logging */
typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line,
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index a17f45b587..f879e074aa 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -42,7 +42,7 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \
- -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto
+ -I ../.. ../../test/proto/*.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
diff --git a/src/node/.istanbul.yml b/src/node/.istanbul.yml
deleted file mode 100644
index 9ff1379f51..0000000000
--- a/src/node/.istanbul.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-reporting:
- watermarks:
- statements: [80, 95]
- lines: [80, 95]
- functions: [80, 95]
- branches: [80, 95]
diff --git a/src/node/LICENSE b/src/node/LICENSE
deleted file mode 100644
index 0209b570e1..0000000000
--- a/src/node/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2015, Google Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/node/README.md b/src/node/README.md
index 7719d08290..5d89e2228d 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -5,51 +5,19 @@ Beta
## PREREQUISITES
- `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
-- [homebrew][] on Mac OS X. These simplify the installation of the gRPC C core.
## INSTALLATION
-**Linux (Debian):**
-
-Add [Debian jessie-backports][] to your `sources.list` file. Example:
-
-```sh
-echo "deb http://http.debian.net/debian jessie-backports main" | \
-sudo tee -a /etc/apt/sources.list
-```
-
-Install the gRPC Debian package
-
-```sh
-sudo apt-get update
-sudo apt-get install libgrpc-dev
-```
-
Install the gRPC NPM package
```sh
npm install grpc
```
-**Mac OS X**
-
-Install [homebrew][]. Run the following command to install gRPC Node.js.
-```sh
-$ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs
-```
-This will download and run the [gRPC install script][], then install the latest version of gRPC Nodejs npm package.
-
## BUILD FROM SOURCE
1. Clone [the grpc Git Repository](https://github.com/grpc/grpc).
- 2. Follow the instructions in the `INSTALL` file in the root of that repository to install the C core library that this package depends on.
3. Run `npm install`.
-If you install the gRPC C core library in a custom location, then you need to set some environment variables to install this library. The command will look like this:
-
-```sh
-CXXFLAGS=-I<custom location>/include LDFLAGS=-L<custom location>/lib npm install [grpc]
-```
-
## TESTING
To run the test suite, simply run `npm test` in the install location.
@@ -110,7 +78,3 @@ ServerCredentials
```
An object with factory methods for creating credential objects for servers.
-
-[homebrew]:http://brew.sh
-[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
-[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/node/bin/README.md b/src/node/bin/README.md
deleted file mode 100644
index 2f856e428e..0000000000
--- a/src/node/bin/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Command Line Tools
-
-# Service Packager
-
-The command line tool `bin/service_packager`, when called with the following command line:
-
-```bash
-service_packager proto_file -o output_path -n name -v version [-i input_path...]
-```
-
-Populates `output_path` with a node package consisting of a `package.json` populated with `name` and `version`, an `index.js`, a `LICENSE` file copied from gRPC, and a `service.json`, which is compiled from `proto_file` and the given `input_path`s. `require('output_path')` returns an object that is equivalent to
-
-```js
-{ client: require('grpc').load('service.json'),
- auth: require('google-auth-library') }
-```
diff --git a/src/node/bin/service_packager b/src/node/bin/service_packager
deleted file mode 100755
index c7f2460997..0000000000
--- a/src/node/bin/service_packager
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env node
-require(__dirname+'/../cli/service_packager.js').main(process.argv.slice(2)); \ No newline at end of file
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
deleted file mode 100644
index 247719e981..0000000000
--- a/src/node/binding.gyp
+++ /dev/null
@@ -1,100 +0,0 @@
-{
- "variables" : {
- 'config': '<!(echo $CONFIG)'
- },
- "targets" : [
- {
- 'include_dirs': [
- "<!(node -e \"require('nan')\")"
- ],
- 'cflags': [
- '-std=c++0x',
- '-Wall',
- '-pthread',
- '-g',
- '-zdefs',
- '-Werror',
- '-Wno-error=deprecated-declarations'
- ],
- 'ldflags': [
- '-g'
- ],
- "conditions": [
- ['OS != "win"', {
- 'variables': {
- 'pkg_config_grpc': '<!(pkg-config --exists grpc >/dev/null 2>&1 && echo true || echo false)'
- },
- 'conditions': [
- ['config=="gcov"', {
- 'cflags': [
- '-ftest-coverage',
- '-fprofile-arcs',
- '-O0'
- ],
- 'ldflags': [
- '-ftest-coverage',
- '-fprofile-arcs'
- ]
- }
- ],
- ['pkg_config_grpc == "true"', {
- 'link_settings': {
- 'libraries': [
- '<!@(pkg-config --libs-only-l --static grpc)'
- ]
- },
- 'cflags': [
- '<!@(pkg-config --cflags grpc)'
- ],
- 'libraries': [
- '<!@(pkg-config --libs-only-L --static grpc)'
- ],
- 'ldflags': [
- '<!@(pkg-config --libs-only-other --static grpc)'
- ]
- }, {
- 'link_settings': {
- 'libraries': [
- '-lpthread',
- '-lgrpc',
- '-lgpr'
- ],
- },
- 'conditions':[
- ['OS != "mac"', {
- 'link_settings': {
- 'libraries': [
- '-lrt'
- ]
- }
- }]
- ]
- }
- ]
- ]
- }],
- ['OS == "mac"', {
- 'xcode_settings': {
- 'MACOSX_DEPLOYMENT_TARGET': '10.9',
- 'OTHER_CFLAGS': [
- '-std=c++11',
- '-stdlib=libc++'
- ]
- }
- }]
- ],
- "target_name": "grpc",
- "sources": [
- "ext/byte_buffer.cc",
- "ext/call.cc",
- "ext/channel.cc",
- "ext/completion_queue_async_worker.cc",
- "ext/credentials.cc",
- "ext/node_grpc.cc",
- "ext/server.cc",
- "ext/server_credentials.cc",
- "ext/timeval.cc"
- ]
- }
- ]
-}
diff --git a/src/node/cli/service_packager.js b/src/node/cli/service_packager.js
deleted file mode 100644
index c92c450a01..0000000000
--- a/src/node/cli/service_packager.js
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-'use strict';
-
-var fs = require('fs');
-var path = require('path');
-
-var _ = require('lodash');
-var async = require('async');
-var pbjs = require('protobufjs/cli/pbjs');
-var parseArgs = require('minimist');
-var Mustache = require('mustache');
-
-var package_json = require('../package.json');
-
-var template_path = path.resolve(__dirname, 'service_packager');
-
-var package_tpl_path = path.join(template_path, 'package.json.template');
-
-var arg_format = {
- string: ['include', 'out', 'name', 'version'],
- alias: {
- include: 'i',
- out: 'o',
- name: 'n',
- version: 'v'
- }
-};
-
-// TODO(mlumish): autogenerate README.md from proto file
-
-/**
- * Render package.json file from template using provided parameters.
- * @param {Object} params Map of parameter names to values
- * @param {function(Error, string)} callback Callback to pass rendered template
- * text to
- */
-function generatePackage(params, callback) {
- fs.readFile(package_tpl_path, {encoding: 'utf-8'}, function(err, template) {
- if (err) {
- callback(err);
- } else {
- var rendered = Mustache.render(template, params);
- callback(null, rendered);
- }
- });
-}
-
-/**
- * Copy a file
- * @param {string} src_path The filepath to copy from
- * @param {string} dest_path The filepath to copy to
- */
-function copyFile(src_path, dest_path) {
- fs.createReadStream(src_path).pipe(fs.createWriteStream(dest_path));
-}
-
-/**
- * Run the script. Copies the index.js and LICENSE files to the output path,
- * renders the package.json template to the output path, and generates a
- * service.json file from the input proto files using pbjs. The arguments are
- * taken directly from the command line, and handled as follows:
- * -i (--include) : An include path for pbjs (can be dpulicated)
- * -o (--output): The output path
- * -n (--name): The name of the package
- * -v (--version): The package version
- * @param {Array} argv The argument vector
- */
-function main(argv) {
- var args = parseArgs(argv, arg_format);
- var out_path = path.resolve(args.out);
- var include_dirs = [];
- if (args.include) {
- include_dirs = _.map(_.flatten([args.include]), function(p) {
- return path.resolve(p);
- });
- }
- args.grpc_version = package_json.version;
- generatePackage(args, function(err, rendered) {
- if (err) throw err;
- fs.writeFile(path.join(out_path, 'package.json'), rendered, function(err) {
- if (err) throw err;
- });
- });
- copyFile(path.join(template_path, 'index.js'),
- path.join(out_path, 'index.js'));
- copyFile(path.join(__dirname, '..', 'LICENSE'),
- path.join(out_path, 'LICENSE'));
-
- var service_stream = fs.createWriteStream(path.join(out_path,
- 'service.json'));
- var pbjs_args = _.flatten(['node', 'pbjs',
- args._[0],
- '-legacy',
- _.map(include_dirs, function(dir) {
- return "-path=" + dir;
- })]);
- var old_stdout = process.stdout;
- process.__defineGetter__('stdout', function() {
- return service_stream;
- });
- var pbjs_status = pbjs.main(pbjs_args);
- process.__defineGetter__('stdout', function() {
- return old_stdout;
- });
- if (pbjs_status !== pbjs.STATUS_OK) {
- throw new Error('pbjs failed with status code ' + pbjs_status);
- }
-}
-
-exports.main = main;
diff --git a/src/node/cli/service_packager/index.js b/src/node/cli/service_packager/index.js
deleted file mode 100644
index 811e08b89a..0000000000
--- a/src/node/cli/service_packager/index.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-var grpc = require('grpc');
-exports.client = grpc.load(__dirname + '/service.json', 'json');
-exports.auth = require('google-auth-library');
diff --git a/src/node/cli/service_packager/package.json.template b/src/node/cli/service_packager/package.json.template
deleted file mode 100644
index 9f9019172e..0000000000
--- a/src/node/cli/service_packager/package.json.template
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "{{{name}}}",
- "version": "{{{version}}}",
- "author": "Google Inc.",
- "description": "Client library for {{{name}}} built on gRPC",
- "license": "Apache-2.0",
- "dependencies": {
- "grpc": "{{{grpc_version}}}",
- "google-auth-library": "^0.9.2"
- },
- "main": "index.js",
- "files": [
- "LICENSE",
- "index.js",
- "service.json"
- ]
-}
diff --git a/src/node/examples/stock_server.js b/src/node/examples/stock_server.js
deleted file mode 100644
index 12e5479584..0000000000
--- a/src/node/examples/stock_server.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-'use strict';
-
-var _ = require('lodash');
-var grpc = require('..');
-var examples = grpc.load(__dirname + '/stock.proto').examples;
-
-function getLastTradePrice(call, callback) {
- callback(null, {symbol: call.request.symbol, price: 88});
-}
-
-function watchFutureTrades(call) {
- for (var i = 0; i < call.request.num_trades_to_watch; i++) {
- call.write({price: 88.00 + i * 10.00});
- }
- call.end();
-}
-
-function getHighestTradePrice(call, callback) {
- var trades = [];
- call.on('data', function(data) {
- trades.push({symbol: data.symbol, price: _.random(0, 100)});
- });
- call.on('end', function() {
- if(_.isEmpty(trades)) {
- callback(null, {});
- } else {
- callback(null, _.max(trades, function(trade){return trade.price;}));
- }
- });
-}
-
-function getLastTradePriceMultiple(call) {
- call.on('data', function(data) {
- call.write({price: 88});
- });
- call.on('end', function() {
- call.end();
- });
-}
-
-var stockServer = new grpc.Server();
-stockServer.addProtoService(examples.Stock.service, {
- getLastTradePrice: getLastTradePrice,
- getLastTradePriceMultiple: getLastTradePriceMultiple,
- watchFutureTrades: watchFutureTrades,
- getHighestTradePrice: getHighestTradePrice
-});
-
-if (require.main === module) {
- stockServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
- stockServer.start();
-}
-
-module.exports = stockServer;
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index b08a9f96d8..b63e294f9a 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -39,12 +39,14 @@
#include "grpc/support/log.h"
#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
#include "grpc/support/alloc.h"
#include "grpc/support/time.h"
#include "byte_buffer.h"
#include "call.h"
#include "channel.h"
#include "completion_queue_async_worker.h"
+#include "call_credentials.h"
#include "timeval.h"
using std::unique_ptr;
@@ -168,8 +170,9 @@ Local<Value> ParseMetadata(const grpc_metadata_array *metadata_array) {
}
if (EndsWith(elem->key, "-bin")) {
Nan::Set(array, index_map[elem->key],
- Nan::CopyBuffer(elem->value,
- elem->value_length).ToLocalChecked());
+ MakeFastBuffer(
+ Nan::CopyBuffer(elem->value,
+ elem->value_length).ToLocalChecked()));
} else {
Nan::Set(array, index_map[elem->key],
Nan::New(elem->value).ToLocalChecked());
@@ -501,6 +504,7 @@ void Call::Init(Local<Object> exports) {
Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
Nan::SetPrototypeMethod(tpl, "cancelWithStatus", CancelWithStatus);
Nan::SetPrototypeMethod(tpl, "getPeer", GetPeer);
+ Nan::SetPrototypeMethod(tpl, "setCredentials", SetCredentials);
fun_tpl.Reset(tpl);
Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
Nan::Set(exports, Nan::New("Call").ToLocalChecked(), ctr);
@@ -724,5 +728,26 @@ NAN_METHOD(Call::GetPeer) {
info.GetReturnValue().Set(peer_value);
}
+NAN_METHOD(Call::SetCredentials) {
+ Nan::HandleScope scope;
+ if (!HasInstance(info.This())) {
+ return Nan::ThrowTypeError(
+ "setCredentials can only be called on Call objects");
+ }
+ if (!CallCredentials::HasInstance(info[0])) {
+ return Nan::ThrowTypeError(
+ "setCredentials' first argument must be a CallCredentials");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(info.This());
+ CallCredentials *creds_object = ObjectWrap::Unwrap<CallCredentials>(
+ Nan::To<Object>(info[0]).ToLocalChecked());
+ grpc_credentials *creds = creds_object->GetWrappedCredentials();
+ grpc_call_error error = GRPC_CALL_ERROR;
+ if (creds) {
+ error = grpc_call_set_credentials(call->wrapped_call, creds);
+ }
+ info.GetReturnValue().Set(Nan::New<Uint32>(error));
+}
+
} // namespace node
} // namespace grpc
diff --git a/src/node/ext/call.h b/src/node/ext/call.h
index 2f8e1f17aa..dd6c38e4f8 100644
--- a/src/node/ext/call.h
+++ b/src/node/ext/call.h
@@ -73,6 +73,10 @@ struct Resources {
std::vector<unique_ptr<PersistentValue> > handles;
};
+bool CreateMetadataArray(v8::Local<v8::Object> metadata,
+ grpc_metadata_array *array,
+ shared_ptr<Resources> resources);
+
class Op {
public:
virtual v8::Local<v8::Value> GetNodeValue() const = 0;
@@ -122,6 +126,7 @@ class Call : public Nan::ObjectWrap {
static NAN_METHOD(Cancel);
static NAN_METHOD(CancelWithStatus);
static NAN_METHOD(GetPeer);
+ static NAN_METHOD(SetCredentials);
static Nan::Callback *constructor;
// Used for typechecking instances of this javascript class
static Nan::Persistent<v8::FunctionTemplate> fun_tpl;
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
new file mode 100644
index 0000000000..839bb567e4
--- /dev/null
+++ b/src/node/ext/call_credentials.cc
@@ -0,0 +1,259 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
+#include "call_credentials.h"
+#include "call.h"
+
+namespace grpc {
+namespace node {
+
+using Nan::Callback;
+using Nan::EscapableHandleScope;
+using Nan::HandleScope;
+using Nan::Maybe;
+using Nan::MaybeLocal;
+using Nan::ObjectWrap;
+using Nan::Persistent;
+using Nan::Utf8String;
+
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Value;
+
+Nan::Callback *CallCredentials::constructor;
+Persistent<FunctionTemplate> CallCredentials::fun_tpl;
+
+CallCredentials::CallCredentials(grpc_credentials *credentials)
+ : wrapped_credentials(credentials) {}
+
+CallCredentials::~CallCredentials() {
+ grpc_credentials_release(wrapped_credentials);
+}
+
+void CallCredentials::Init(Local<Object> exports) {
+ HandleScope scope;
+ Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
+ tpl->SetClassName(Nan::New("CallCredentials").ToLocalChecked());
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ Nan::SetPrototypeMethod(tpl, "compose", Compose);
+ fun_tpl.Reset(tpl);
+ Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
+ Nan::Set(ctr, Nan::New("createFromPlugin").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<FunctionTemplate>(CreateFromPlugin)).ToLocalChecked());
+ Nan::Set(exports, Nan::New("CallCredentials").ToLocalChecked(), ctr);
+ constructor = new Nan::Callback(ctr);
+}
+
+bool CallCredentials::HasInstance(Local<Value> val) {
+ HandleScope scope;
+ return Nan::New(fun_tpl)->HasInstance(val);
+}
+
+Local<Value> CallCredentials::WrapStruct(grpc_credentials *credentials) {
+ EscapableHandleScope scope;
+ const int argc = 1;
+ if (credentials == NULL) {
+ return scope.Escape(Nan::Null());
+ }
+ Local<Value> argv[argc] = {
+ Nan::New<External>(reinterpret_cast<void *>(credentials))};
+ MaybeLocal<Object> maybe_instance = Nan::NewInstance(
+ constructor->GetFunction(), argc, argv);
+ if (maybe_instance.IsEmpty()) {
+ return scope.Escape(Nan::Null());
+ } else {
+ return scope.Escape(maybe_instance.ToLocalChecked());
+ }
+}
+
+grpc_credentials *CallCredentials::GetWrappedCredentials() {
+ return wrapped_credentials;
+}
+
+NAN_METHOD(CallCredentials::New) {
+ if (info.IsConstructCall()) {
+ if (!info[0]->IsExternal()) {
+ return Nan::ThrowTypeError(
+ "CallCredentials can only be created with the provided functions");
+ }
+ Local<External> ext = info[0].As<External>();
+ grpc_credentials *creds_value =
+ reinterpret_cast<grpc_credentials *>(ext->Value());
+ CallCredentials *credentials = new CallCredentials(creds_value);
+ credentials->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
+ return;
+ } else {
+ const int argc = 1;
+ Local<Value> argv[argc] = {info[0]};
+ MaybeLocal<Object> maybe_instance = constructor->GetFunction()->NewInstance(
+ argc, argv);
+ if (maybe_instance.IsEmpty()) {
+ // There's probably a pending exception
+ return;
+ } else {
+ info.GetReturnValue().Set(maybe_instance.ToLocalChecked());
+ }
+ }
+}
+
+NAN_METHOD(CallCredentials::Compose) {
+ if (!CallCredentials::HasInstance(info.This())) {
+ return Nan::ThrowTypeError(
+ "compose can only be called on CallCredentials objects");
+ }
+ if (!CallCredentials::HasInstance(info[0])) {
+ return Nan::ThrowTypeError(
+ "compose's first argument must be a CallCredentials object");
+ }
+ CallCredentials *self = ObjectWrap::Unwrap<CallCredentials>(info.This());
+ CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>(
+ Nan::To<Object>(info[0]).ToLocalChecked());
+ grpc_credentials *creds = grpc_composite_credentials_create(
+ self->wrapped_credentials, other->wrapped_credentials, NULL);
+ info.GetReturnValue().Set(WrapStruct(creds));
+}
+
+
+
+NAN_METHOD(CallCredentials::CreateFromPlugin) {
+ if (!info[0]->IsFunction()) {
+ return Nan::ThrowTypeError(
+ "createFromPlugin's argument must be a function");
+ }
+ grpc_metadata_credentials_plugin plugin;
+ plugin_state *state = new plugin_state;
+ state->callback = new Nan::Callback(info[0].As<Function>());
+ plugin.get_metadata = plugin_get_metadata;
+ plugin.destroy = plugin_destroy_state;
+ plugin.state = reinterpret_cast<void*>(state);
+ grpc_credentials *creds = grpc_metadata_credentials_create_from_plugin(plugin,
+ NULL);
+ info.GetReturnValue().Set(WrapStruct(creds));
+}
+
+NAN_METHOD(PluginCallback) {
+ // Arguments: status code, error details, metadata
+ if (!info[0]->IsUint32()) {
+ return Nan::ThrowTypeError(
+ "The callback's first argument must be a status code");
+ }
+ if (!info[1]->IsString()) {
+ return Nan::ThrowTypeError(
+ "The callback's second argument must be a string");
+ }
+ if (!info[2]->IsObject()) {
+ return Nan::ThrowTypeError(
+ "The callback's third argument must be an object");
+ }
+ shared_ptr<Resources> resources(new Resources);
+ grpc_status_code code = static_cast<grpc_status_code>(
+ Nan::To<uint32_t>(info[0]).FromJust());
+ char *details = *Utf8String(info[1]);
+ grpc_metadata_array array;
+ if (!CreateMetadataArray(Nan::To<Object>(info[2]).ToLocalChecked(),
+ &array, resources)){
+ return Nan::ThrowError("Failed to parse metadata");
+ }
+ grpc_credentials_plugin_metadata_cb cb =
+ reinterpret_cast<grpc_credentials_plugin_metadata_cb>(
+ Nan::Get(info.Callee(),
+ Nan::New("cb").ToLocalChecked()
+ ).ToLocalChecked().As<External>()->Value());
+ void *user_data =
+ Nan::Get(info.Callee(),
+ Nan::New("user_data").ToLocalChecked()
+ ).ToLocalChecked().As<External>()->Value();
+ cb(user_data, array.metadata, array.count, code, details);
+}
+
+NAUV_WORK_CB(SendPluginCallback) {
+ Nan::HandleScope scope;
+ plugin_callback_data *data = reinterpret_cast<plugin_callback_data*>(
+ async->data);
+ // Attach cb and user_data to plugin_callback so that it can access them later
+ v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
+ Nan::New<v8::FunctionTemplate>(PluginCallback)).ToLocalChecked();
+ Nan::Set(plugin_callback, Nan::New("cb").ToLocalChecked(),
+ Nan::New<v8::External>(reinterpret_cast<void*>(data->cb)));
+ Nan::Set(plugin_callback, Nan::New("user_data").ToLocalChecked(),
+ Nan::New<v8::External>(data->user_data));
+ const int argc = 2;
+ v8::Local<v8::Value> argv[argc] = {
+ Nan::New(data->service_url).ToLocalChecked(),
+ plugin_callback
+ };
+ Nan::Callback *callback = data->state->callback;
+ callback->Call(argc, argv);
+ delete data;
+ uv_unref((uv_handle_t *)async);
+ uv_close((uv_handle_t *)async, (uv_close_cb)free);
+}
+
+void plugin_get_metadata(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data) {
+ uv_async_t *async = static_cast<uv_async_t*>(malloc(sizeof(uv_async_t)));
+ uv_async_init(uv_default_loop(),
+ async,
+ SendPluginCallback);
+ plugin_callback_data *data = new plugin_callback_data;
+ data->state = reinterpret_cast<plugin_state*>(state);
+ data->service_url = service_url;
+ data->cb = cb;
+ data->user_data = user_data;
+ async->data = data;
+ /* libuv says that it will coalesce calls to uv_async_send. If there is ever a
+ * problem with a callback not getting called, that is probably the reason */
+ uv_async_send(async);
+}
+
+void plugin_destroy_state(void *ptr) {
+ plugin_state *state = reinterpret_cast<plugin_state *>(ptr);
+ delete state->callback;
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h
new file mode 100644
index 0000000000..618292d19e
--- /dev/null
+++ b/src/node/ext/call_credentials.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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_NODE_CALL_CREDENTIALS_H_
+#define GRPC_NODE_CALL_CREDENTIALS_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc_security.h"
+
+namespace grpc {
+namespace node {
+
+class CallCredentials : public Nan::ObjectWrap {
+ public:
+ static void Init(v8::Local<v8::Object> exports);
+ static bool HasInstance(v8::Local<v8::Value> val);
+ /* Wrap a grpc_credentials struct in a javascript object */
+ static v8::Local<v8::Value> WrapStruct(grpc_credentials *credentials);
+
+ /* Returns the grpc_credentials struct that this object wraps */
+ grpc_credentials *GetWrappedCredentials();
+
+ private:
+ explicit CallCredentials(grpc_credentials *credentials);
+ ~CallCredentials();
+
+ // Prevent copying
+ CallCredentials(const CallCredentials &);
+ CallCredentials &operator=(const CallCredentials &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(CreateSsl);
+ static NAN_METHOD(CreateFromPlugin);
+
+ static NAN_METHOD(Compose);
+ static Nan::Callback *constructor;
+ // Used for typechecking instances of this javascript class
+ static Nan::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_credentials *wrapped_credentials;
+};
+
+/* Auth metadata plugin functionality */
+
+typedef struct plugin_state {
+ Nan::Callback *callback;
+} plugin_state;
+
+typedef struct plugin_callback_data {
+ plugin_state *state;
+ const char *service_url;
+ grpc_credentials_plugin_metadata_cb cb;
+ void *user_data;
+} plugin_callback_data;
+
+void plugin_get_metadata(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data);
+
+void plugin_destroy_state(void *state);
+
+NAN_METHOD(PluginCallback);
+
+NAUV_WORK_CB(SendPluginCallback);
+
+} // namespace node
+} // namepsace grpc
+
+#endif // GRPC_NODE_CALL_CREDENTIALS_H_
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 6eb1e77688..a328c01713 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -42,7 +42,7 @@
#include "call.h"
#include "channel.h"
#include "completion_queue_async_worker.h"
-#include "credentials.h"
+#include "channel_credentials.h"
#include "timeval.h"
namespace grpc {
@@ -112,11 +112,11 @@ NAN_METHOD(Channel::New) {
// Owned by the Channel object
Utf8String host(info[0]);
grpc_credentials *creds;
- if (!Credentials::HasInstance(info[1])) {
+ if (!ChannelCredentials::HasInstance(info[1])) {
return Nan::ThrowTypeError(
- "Channel's second argument must be a credential");
+ "Channel's second argument must be a ChannelCredentials");
}
- Credentials *creds_object = ObjectWrap::Unwrap<Credentials>(
+ ChannelCredentials *creds_object = ObjectWrap::Unwrap<ChannelCredentials>(
Nan::To<Object>(info[1]).ToLocalChecked());
creds = creds_object->GetWrappedCredentials();
grpc_channel_args *channel_args_ptr;
diff --git a/src/node/ext/credentials.cc b/src/node/ext/channel_credentials.cc
index 4f41c92f6a..3d47ff293d 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/channel_credentials.cc
@@ -36,7 +36,9 @@
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/log.h"
-#include "credentials.h"
+#include "channel_credentials.h"
+#include "call_credentials.h"
+#include "call.h"
namespace grpc {
namespace node {
@@ -60,51 +62,40 @@ using v8::Object;
using v8::ObjectTemplate;
using v8::Value;
-Nan::Callback *Credentials::constructor;
-Persistent<FunctionTemplate> Credentials::fun_tpl;
+Nan::Callback *ChannelCredentials::constructor;
+Persistent<FunctionTemplate> ChannelCredentials::fun_tpl;
-Credentials::Credentials(grpc_credentials *credentials)
+ChannelCredentials::ChannelCredentials(grpc_credentials *credentials)
: wrapped_credentials(credentials) {}
-Credentials::~Credentials() {
+ChannelCredentials::~ChannelCredentials() {
grpc_credentials_release(wrapped_credentials);
}
-void Credentials::Init(Local<Object> exports) {
+void ChannelCredentials::Init(Local<Object> exports) {
HandleScope scope;
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
- tpl->SetClassName(Nan::New("Credentials").ToLocalChecked());
+ tpl->SetClassName(Nan::New("ChannelCredentials").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ Nan::SetPrototypeMethod(tpl, "compose", Compose);
fun_tpl.Reset(tpl);
Local<Function> ctr = Nan::GetFunction(tpl).ToLocalChecked();
- Nan::Set(ctr, Nan::New("createDefault").ToLocalChecked(),
- Nan::GetFunction(
- Nan::New<FunctionTemplate>(CreateDefault)).ToLocalChecked());
Nan::Set(ctr, Nan::New("createSsl").ToLocalChecked(),
Nan::GetFunction(
Nan::New<FunctionTemplate>(CreateSsl)).ToLocalChecked());
- Nan::Set(ctr, Nan::New("createComposite").ToLocalChecked(),
- Nan::GetFunction(
- Nan::New<FunctionTemplate>(CreateComposite)).ToLocalChecked());
- Nan::Set(ctr, Nan::New("createGce").ToLocalChecked(),
- Nan::GetFunction(
- Nan::New<FunctionTemplate>(CreateGce)).ToLocalChecked());
- Nan::Set(ctr, Nan::New("createIam").ToLocalChecked(),
- Nan::GetFunction(
- Nan::New<FunctionTemplate>(CreateIam)).ToLocalChecked());
Nan::Set(ctr, Nan::New("createInsecure").ToLocalChecked(),
Nan::GetFunction(
Nan::New<FunctionTemplate>(CreateInsecure)).ToLocalChecked());
- Nan::Set(exports, Nan::New("Credentials").ToLocalChecked(), ctr);
+ Nan::Set(exports, Nan::New("ChannelCredentials").ToLocalChecked(), ctr);
constructor = new Nan::Callback(ctr);
}
-bool Credentials::HasInstance(Local<Value> val) {
+bool ChannelCredentials::HasInstance(Local<Value> val) {
HandleScope scope;
return Nan::New(fun_tpl)->HasInstance(val);
}
-Local<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
+Local<Value> ChannelCredentials::WrapStruct(grpc_credentials *credentials) {
EscapableHandleScope scope;
const int argc = 1;
Local<Value> argv[argc] = {
@@ -118,20 +109,20 @@ Local<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
}
}
-grpc_credentials *Credentials::GetWrappedCredentials() {
+grpc_credentials *ChannelCredentials::GetWrappedCredentials() {
return wrapped_credentials;
}
-NAN_METHOD(Credentials::New) {
+NAN_METHOD(ChannelCredentials::New) {
if (info.IsConstructCall()) {
if (!info[0]->IsExternal()) {
return Nan::ThrowTypeError(
- "Credentials can only be created with the provided functions");
+ "ChannelCredentials can only be created with the provided functions");
}
Local<External> ext = info[0].As<External>();
grpc_credentials *creds_value =
reinterpret_cast<grpc_credentials *>(ext->Value());
- Credentials *credentials = new Credentials(creds_value);
+ ChannelCredentials *credentials = new ChannelCredentials(creds_value);
credentials->Wrap(info.This());
info.GetReturnValue().Set(info.This());
return;
@@ -149,16 +140,7 @@ NAN_METHOD(Credentials::New) {
}
}
-NAN_METHOD(Credentials::CreateDefault) {
- grpc_credentials *creds = grpc_google_default_credentials_create();
- if (creds == NULL) {
- info.GetReturnValue().SetNull();
- } else {
- info.GetReturnValue().Set(WrapStruct(creds));
- }
-}
-
-NAN_METHOD(Credentials::CreateSsl) {
+NAN_METHOD(ChannelCredentials::CreateSsl) {
char *root_certs = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
if (::node::Buffer::HasInstance(info[0])) {
@@ -188,49 +170,25 @@ NAN_METHOD(Credentials::CreateSsl) {
}
}
-NAN_METHOD(Credentials::CreateComposite) {
- if (!HasInstance(info[0])) {
+NAN_METHOD(ChannelCredentials::Compose) {
+ if (!ChannelCredentials::HasInstance(info.This())) {
return Nan::ThrowTypeError(
- "createComposite's first argument must be a Credentials object");
+ "compose can only be called on ChannelCredentials objects");
}
- if (!HasInstance(info[1])) {
+ if (!CallCredentials::HasInstance(info[0])) {
return Nan::ThrowTypeError(
- "createComposite's second argument must be a Credentials object");
+ "compose's first argument must be a CallCredentials object");
}
- Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(
+ ChannelCredentials *self = ObjectWrap::Unwrap<ChannelCredentials>(
+ info.This());
+ if (self->wrapped_credentials == NULL) {
+ return Nan::ThrowTypeError(
+ "Cannot compose insecure credential");
+ }
+ CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>(
Nan::To<Object>(info[0]).ToLocalChecked());
- Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(
- Nan::To<Object>(info[1]).ToLocalChecked());
grpc_credentials *creds = grpc_composite_credentials_create(
- creds1->wrapped_credentials, creds2->wrapped_credentials, NULL);
- if (creds == NULL) {
- info.GetReturnValue().SetNull();
- } else {
- info.GetReturnValue().Set(WrapStruct(creds));
- }
-}
-
-NAN_METHOD(Credentials::CreateGce) {
- Nan::HandleScope scope;
- grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL);
- if (creds == NULL) {
- info.GetReturnValue().SetNull();
- } else {
- info.GetReturnValue().Set(WrapStruct(creds));
- }
-}
-
-NAN_METHOD(Credentials::CreateIam) {
- if (!info[0]->IsString()) {
- return Nan::ThrowTypeError("createIam's first argument must be a string");
- }
- if (!info[1]->IsString()) {
- return Nan::ThrowTypeError("createIam's second argument must be a string");
- }
- Utf8String auth_token(info[0]);
- Utf8String auth_selector(info[1]);
- grpc_credentials *creds =
- grpc_google_iam_credentials_create(*auth_token, *auth_selector, NULL);
+ self->wrapped_credentials, other->GetWrappedCredentials(), NULL);
if (creds == NULL) {
info.GetReturnValue().SetNull();
} else {
@@ -238,7 +196,7 @@ NAN_METHOD(Credentials::CreateIam) {
}
}
-NAN_METHOD(Credentials::CreateInsecure) {
+NAN_METHOD(ChannelCredentials::CreateInsecure) {
info.GetReturnValue().Set(WrapStruct(NULL));
}
diff --git a/src/node/ext/credentials.h b/src/node/ext/channel_credentials.h
index 1b211175d4..31ea0987bc 100644
--- a/src/node/ext/credentials.h
+++ b/src/node/ext/channel_credentials.h
@@ -31,8 +31,8 @@
*
*/
-#ifndef NET_GRPC_NODE_CREDENTIALS_H_
-#define NET_GRPC_NODE_CREDENTIALS_H_
+#ifndef NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_
+#define NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_
#include <node.h>
#include <nan.h>
@@ -43,7 +43,7 @@ namespace grpc {
namespace node {
/* Wrapper class for grpc_credentials structs */
-class Credentials : public Nan::ObjectWrap {
+class ChannelCredentials : public Nan::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
static bool HasInstance(v8::Local<v8::Value> val);
@@ -54,21 +54,18 @@ class Credentials : public Nan::ObjectWrap {
grpc_credentials *GetWrappedCredentials();
private:
- explicit Credentials(grpc_credentials *credentials);
- ~Credentials();
+ explicit ChannelCredentials(grpc_credentials *credentials);
+ ~ChannelCredentials();
// Prevent copying
- Credentials(const Credentials &);
- Credentials &operator=(const Credentials &);
+ ChannelCredentials(const ChannelCredentials &);
+ ChannelCredentials &operator=(const ChannelCredentials &);
static NAN_METHOD(New);
- static NAN_METHOD(CreateDefault);
static NAN_METHOD(CreateSsl);
- static NAN_METHOD(CreateComposite);
- static NAN_METHOD(CreateGce);
- static NAN_METHOD(CreateFake);
- static NAN_METHOD(CreateIam);
static NAN_METHOD(CreateInsecure);
+
+ static NAN_METHOD(Compose);
static Nan::Callback *constructor;
// Used for typechecking instances of this javascript class
static Nan::Persistent<v8::FunctionTemplate> fun_tpl;
@@ -79,4 +76,4 @@ class Credentials : public Nan::ObjectWrap {
} // namespace node
} // namespace grpc
-#endif // NET_GRPC_NODE_CREDENTIALS_H_
+#endif // NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index caca0fc452..5b5f3c1c5b 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -37,10 +37,11 @@
#include "grpc/grpc.h"
#include "call.h"
+#include "call_credentials.h"
#include "channel.h"
+#include "channel_credentials.h"
#include "server.h"
#include "completion_queue_async_worker.h"
-#include "credentials.h"
#include "server_credentials.h"
using v8::Local;
@@ -240,11 +241,12 @@ void init(Local<Object> exports) {
InitWriteFlags(exports);
grpc::node::Call::Init(exports);
+ grpc::node::CallCredentials::Init(exports);
grpc::node::Channel::Init(exports);
+ grpc::node::ChannelCredentials::Init(exports);
grpc::node::Server::Init(exports);
grpc::node::CompletionQueueAsyncWorker::Init(exports);
- grpc::node::Credentials::Init(exports);
grpc::node::ServerCredentials::Init(exports);
}
-NODE_MODULE(grpc, init)
+NODE_MODULE(grpc_node, init)
diff --git a/src/node/index.js b/src/node/index.js
index 02b73f66ee..591d9dd915 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -43,7 +43,7 @@ var server = require('./src/server.js');
var Metadata = require('./src/metadata.js');
-var grpc = require('bindings')('grpc');
+var grpc = require('bindings')('grpc_node');
/**
* Load a gRPC object from an existing ProtoBuf.Reflect object.
@@ -90,37 +90,10 @@ exports.load = function load(filename, format) {
default:
throw new Error('Unrecognized format "' + format + '"');
}
-
return loadObject(builder.ns);
};
/**
- * Get a function that a client can use to update metadata with authentication
- * information from a Google Auth credential object, which comes from the
- * google-auth-library.
- * @param {Object} credential The credential object to use
- * @return {function(Object, callback)} Metadata updater function
- */
-exports.getGoogleAuthDelegate = function getGoogleAuthDelegate(credential) {
- /**
- * Update a metadata object with authentication information.
- * @param {string} authURI The uri to authenticate to
- * @param {Object} metadata Metadata object
- * @param {function(Error, Object)} callback
- */
- return function updateMetadata(authURI, metadata, callback) {
- credential.getRequestMetadata(authURI, function(err, header) {
- if (err) {
- callback(err);
- return;
- }
- metadata.add('authorization', header.Authorization);
- callback(null, metadata);
- });
- };
-};
-
-/**
* @see module:src/server.Server
*/
exports.Server = server.Server;
@@ -153,7 +126,7 @@ exports.writeFlags = grpc.writeFlags;
/**
* Credentials factories
*/
-exports.Credentials = grpc.Credentials;
+exports.credentials = require('./src/credentials.js');
/**
* ServerCredentials factories
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 215d42121c..cb55083d1a 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -37,17 +37,24 @@ var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var grpc = require('..');
-var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
+var testProto = grpc.load({
+ root: __dirname + '/../../..',
+ file: 'test/proto/test.proto'}).grpc.testing;
var GoogleAuth = require('google-auth-library');
var assert = require('assert');
-var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo';
-var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
-var AUTH_USER = ('155450119199-vefjjaekcc6cmsd5914v6lqufunmh9ue' +
- '@developer.gserviceaccount.com');
-var COMPUTE_ENGINE_USER = ('155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel' +
- '@developer.gserviceaccount.com');
+var SERVICE_ACCOUNT_EMAIL;
+try {
+ SERVICE_ACCOUNT_EMAIL = require(
+ process.env.GOOGLE_APPLICATION_CREDENTIALS).client_email;
+} catch (e) {
+ // This will cause the tests to fail if they need that string
+ SERVICE_ACCOUNT_EMAIL = null;
+}
+
+var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
+var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
/**
* Create a buffer filled with size zeroes
@@ -61,6 +68,27 @@ function zeroBuffer(size) {
}
/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+/**
* Run the empty_unary test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
@@ -271,6 +299,89 @@ function timeoutOnSleepingServer(client, done) {
});
}
+function customMetadata(client, done) {
+ done = multiDone(done, 5);
+ var metadata = new grpc.Metadata();
+ metadata.set(ECHO_INITIAL_KEY, 'test_initial_metadata_value');
+ metadata.set(ECHO_TRAILING_KEY, new Buffer('ababab', 'hex'));
+ var arg = {
+ response_type: 'COMPRESSABLE',
+ response_size: 314159,
+ payload: {
+ body: zeroBuffer(271828)
+ }
+ };
+ var streaming_arg = {
+ payload: {
+ body: zeroBuffer(271828)
+ }
+ };
+ var unary = client.unaryCall(arg, function(err, resp) {
+ assert.ifError(err);
+ done();
+ }, metadata);
+ unary.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get(ECHO_INITIAL_KEY),
+ ['test_initial_metadata_value']);
+ done();
+ });
+ unary.on('status', function(status) {
+ var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY);
+ assert(echo_trailer.length > 0);
+ assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab');
+ done();
+ });
+ var stream = client.fullDuplexCall(metadata);
+ stream.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get(ECHO_INITIAL_KEY),
+ ['test_initial_metadata_value']);
+ done();
+ });
+ stream.on('status', function(status) {
+ var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY);
+ assert(echo_trailer.length > 0);
+ assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab');
+ done();
+ });
+ stream.write(streaming_arg);
+ stream.end();
+}
+
+function statusCodeAndMessage(client, done) {
+ done = multiDone(done, 2);
+ var arg = {
+ response_status: {
+ code: 2,
+ message: 'test status message'
+ }
+ };
+ client.unaryCall(arg, function(err, resp) {
+ assert(err);
+ assert.strictEqual(err.code, 2);
+ assert.strictEqual(err.message, 'test status message');
+ done();
+ });
+ var duplex = client.fullDuplexCall();
+ duplex.on('status', function(status) {
+ assert(status);
+ assert.strictEqual(status.code, 2);
+ assert.strictEqual(status.details, 'test status message');
+ done();
+ });
+ duplex.on('error', function(){});
+ duplex.write(arg);
+ duplex.end();
+}
+
+function unimplementedMethod(client, done) {
+ client.unimplementedCall({}, function(err, resp) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
+ assert(!err.message);
+ done();
+ });
+}
+
/**
* Run one of the authentication tests.
* @param {string} expected_user The expected username in the response
@@ -280,67 +391,110 @@ function timeoutOnSleepingServer(client, done) {
* primarily for use with mocha
*/
function authTest(expected_user, scope, client, done) {
- (new GoogleAuth()).getApplicationDefault(function(err, credential) {
+ var arg = {
+ response_type: 'COMPRESSABLE',
+ response_size: 314159,
+ payload: {
+ body: zeroBuffer(271828)
+ },
+ fill_username: true,
+ fill_oauth_scope: true
+ };
+ client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
- if (credential.createScopedRequired() && scope) {
- credential = credential.createScoped(scope);
+ assert.strictEqual(resp.payload.type, 'COMPRESSABLE');
+ assert.strictEqual(resp.payload.body.length, 314159);
+ assert.strictEqual(resp.username, expected_user);
+ if (scope) {
+ assert(scope.indexOf(resp.oauth_scope) > -1);
+ }
+ if (done) {
+ done();
}
- client.$updateMetadata = grpc.getGoogleAuthDelegate(credential);
+ });
+}
+
+function computeEngineCreds(client, done, extra) {
+ authTest(extra.service_account, null, client, done);
+}
+
+function serviceAccountCreds(client, done, extra) {
+ authTest(SERVICE_ACCOUNT_EMAIL, extra.oauth_scope, client, done);
+}
+
+function jwtTokenCreds(client, done, extra) {
+ authTest(SERVICE_ACCOUNT_EMAIL, null, client, done);
+}
+
+function oauth2Test(client, done, extra) {
+ var arg = {
+ fill_username: true,
+ fill_oauth_scope: true
+ };
+ client.unaryCall(arg, function(err, resp) {
+ assert.ifError(err);
+ assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL);
+ assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1);
+ if (done) {
+ done();
+ }
+ });
+}
+
+function perRpcAuthTest(client, done, extra) {
+ (new GoogleAuth()).getApplicationDefault(function(err, credential) {
+ assert.ifError(err);
var arg = {
- response_type: 'COMPRESSABLE',
- response_size: 314159,
- payload: {
- body: zeroBuffer(271828)
- },
fill_username: true,
fill_oauth_scope: true
};
+ var scope = extra.oauth_scope;
+ if (credential.createScopedRequired() && scope) {
+ credential = credential.createScoped(scope);
+ }
+ var creds = grpc.credentials.createFromGoogleCredential(credential);
client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
- assert.strictEqual(resp.payload.type, 'COMPRESSABLE');
- assert.strictEqual(resp.payload.body.length, 314159);
- assert.strictEqual(resp.username, expected_user);
- if (scope) {
- assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
- }
+ assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL);
+ assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1);
if (done) {
done();
}
- });
+ }, null, {credentials: creds});
});
}
-function oauth2Test(expected_user, scope, per_rpc, client, done) {
+function getApplicationCreds(scope, callback) {
(new GoogleAuth()).getApplicationDefault(function(err, credential) {
- assert.ifError(err);
- var arg = {
- fill_username: true,
- fill_oauth_scope: true
- };
+ if (err) {
+ callback(err);
+ return;
+ }
+ if (credential.createScopedRequired() && scope) {
+ credential = credential.createScoped(scope);
+ }
+ callback(null, grpc.credentials.createFromGoogleCredential(credential));
+ });
+}
+
+function getOauth2Creds(scope, callback) {
+ (new GoogleAuth()).getApplicationDefault(function(err, credential) {
+ if (err) {
+ callback(err);
+ return;
+ }
credential = credential.createScoped(scope);
credential.getAccessToken(function(err, token) {
- assert.ifError(err);
- var updateMetadata = function(authURI, metadata, callback) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var updateMd = function(service_url, callback) {
+ var metadata = new grpc.Metadata();
metadata.add('authorization', 'Bearer ' + token);
callback(null, metadata);
};
- var makeTestCall = function(error, client_metadata) {
- assert.ifError(error);
- client.unaryCall(arg, function(err, resp) {
- assert.ifError(err);
- assert.strictEqual(resp.username, expected_user);
- assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
- if (done) {
- done();
- }
- }, client_metadata);
- };
- if (per_rpc) {
- updateMetadata('', new grpc.Metadata(), makeTestCall);
- } else {
- client.$updateMetadata = updateMetadata;
- makeTestCall(null, new grpc.Metadata());
- }
+ callback(null, grpc.credentials.createFromMetadataGenerator(updateMd));
});
});
}
@@ -349,20 +503,44 @@ function oauth2Test(expected_user, scope, per_rpc, client, done) {
* Map from test case names to test functions
*/
var test_cases = {
- empty_unary: emptyUnary,
- large_unary: largeUnary,
- client_streaming: clientStreaming,
- server_streaming: serverStreaming,
- ping_pong: pingPong,
- empty_stream: emptyStream,
- cancel_after_begin: cancelAfterBegin,
- cancel_after_first_response: cancelAfterFirstResponse,
- timeout_on_sleeping_server: timeoutOnSleepingServer,
- compute_engine_creds: _.partial(authTest, COMPUTE_ENGINE_USER, null),
- service_account_creds: _.partial(authTest, AUTH_USER, AUTH_SCOPE),
- jwt_token_creds: _.partial(authTest, AUTH_USER, null),
- oauth2_auth_token: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, false),
- per_rpc_creds: _.partial(oauth2Test, AUTH_USER, AUTH_SCOPE, true)
+ empty_unary: {run: emptyUnary,
+ Client: testProto.TestService},
+ large_unary: {run: largeUnary,
+ Client: testProto.TestService},
+ client_streaming: {run: clientStreaming,
+ Client: testProto.TestService},
+ server_streaming: {run: serverStreaming,
+ Client: testProto.TestService},
+ ping_pong: {run: pingPong,
+ Client: testProto.TestService},
+ empty_stream: {run: emptyStream,
+ Client: testProto.TestService},
+ cancel_after_begin: {run: cancelAfterBegin,
+ Client: testProto.TestService},
+ cancel_after_first_response: {run: cancelAfterFirstResponse,
+ Client: testProto.TestService},
+ timeout_on_sleeping_server: {run: timeoutOnSleepingServer,
+ Client: testProto.TestService},
+ custom_metadata: {run: customMetadata,
+ Client: testProto.TestService},
+ status_code_and_message: {run: statusCodeAndMessage,
+ Client: testProto.TestService},
+ unimplemented_method: {run: unimplementedMethod,
+ Client: testProto.UnimplementedService},
+ compute_engine_creds: {run: computeEngineCreds,
+ Client: testProto.TestService,
+ getCreds: getApplicationCreds},
+ service_account_creds: {run: serviceAccountCreds,
+ Client: testProto.TestService,
+ getCreds: getApplicationCreds},
+ jwt_token_creds: {run: jwtTokenCreds,
+ Client: testProto.TestService,
+ getCreds: getApplicationCreds},
+ oauth2_auth_token: {run: oauth2Test,
+ Client: testProto.TestService,
+ getCreds: getOauth2Creds},
+ per_rpc_creds: {run: perRpcAuthTest,
+ Client: testProto.TestService}
};
/**
@@ -375,8 +553,9 @@ var test_cases = {
* @param {bool} tls Indicates that a secure channel should be used
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
+ * @param {object=} extra Extra options for some tests
*/
-function runTest(address, host_override, test_case, tls, test_ca, done) {
+function runTest(address, host_override, test_case, tls, test_ca, done, extra) {
// TODO(mlumish): enable TLS functionality
var options = {};
var creds;
@@ -388,30 +567,49 @@ function runTest(address, host_override, test_case, tls, test_ca, done) {
ca_path = process.env.SSL_CERT_FILE;
}
var ca_data = fs.readFileSync(ca_path);
- creds = grpc.Credentials.createSsl(ca_data);
+ creds = grpc.credentials.createSsl(ca_data);
if (host_override) {
options['grpc.ssl_target_name_override'] = host_override;
options['grpc.default_authority'] = host_override;
}
} else {
- creds = grpc.Credentials.createInsecure();
+ creds = grpc.credentials.createInsecure();
}
- var client = new testProto.TestService(address, creds, options);
+ var test = test_cases[test_case];
+
+ var execute = function(err, creds) {
+ assert.ifError(err);
+ var client = new test.Client(address, creds, options);
+ test.run(client, done, extra);
+ };
- test_cases[test_case](client, done);
+ if (test.getCreds) {
+ test.getCreds(extra.oauth_scope, function(err, new_creds) {
+ assert.ifError(err);
+ execute(err, grpc.credentials.combineChannelCredentials(
+ creds, new_creds));
+ });
+ } else {
+ execute(null, creds);
+ }
}
if (require.main === module) {
var parseArgs = require('minimist');
var argv = parseArgs(process.argv, {
string: ['server_host', 'server_host_override', 'server_port', 'test_case',
- 'use_tls', 'use_test_ca']
+ 'use_tls', 'use_test_ca', 'default_service_account', 'oauth_scope',
+ 'service_account_key_file']
});
+ var extra_args = {
+ service_account: argv.default_service_account,
+ oauth_scope: argv.oauth_scope
+ };
runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override,
argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true',
function () {
console.log('OK:', argv.test_case);
- });
+ }, extra_args);
}
/**
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 99155e9958..5321005c86 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -37,7 +37,15 @@ var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var grpc = require('..');
-var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
+var testProto = grpc.load({
+ root: __dirname + '/../../..',
+ file: 'test/proto/test.proto'}).grpc.testing;
+
+var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial';
+var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin';
+
+var incompressible_data = fs.readFileSync(
+ __dirname + '/../../../test/cpp/interop/rnd.dat');
/**
* Create a buffer filled with size zeroes
@@ -51,6 +59,47 @@ function zeroBuffer(size) {
}
/**
+ * Echos a header metadata item as specified in the interop spec.
+ * @param {Call} call The call to echo metadata on
+ */
+function echoHeader(call) {
+ var echo_initial = call.metadata.get(ECHO_INITIAL_KEY);
+ if (echo_initial.length > 0) {
+ var response_metadata = new grpc.Metadata();
+ response_metadata.set(ECHO_INITIAL_KEY, echo_initial[0]);
+ call.sendMetadata(response_metadata);
+ }
+}
+
+/**
+ * Gets the trailer metadata that should be echoed when the call is done,
+ * as specified in the interop spec.
+ * @param {Call} call The call to get metadata from
+ * @return {grpc.Metadata} The metadata to send as a trailer
+ */
+function getEchoTrailer(call) {
+ var echo_trailer = call.metadata.get(ECHO_TRAILING_KEY);
+ var response_trailer = new grpc.Metadata();
+ if (echo_trailer.length > 0) {
+ response_trailer.set(ECHO_TRAILING_KEY, echo_trailer[0]);
+ }
+ return response_trailer;
+}
+
+function getPayload(payload_type, size) {
+ if (payload_type === 'RANDOM') {
+ payload_type = ['COMPRESSABLE',
+ 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
+ }
+ var body;
+ switch (payload_type) {
+ case 'COMPRESSABLE': body = zeroBuffer(size); break;
+ case 'UNCOMPRESSABLE': incompressible_data.slice(size); break;
+ }
+ return {type: payload_type, body: body};
+}
+
+/**
* Respond to an empty parameter with an empty response.
* NOTE: this currently does not work due to issue #137
* @param {Call} call Call to handle
@@ -58,7 +107,8 @@ function zeroBuffer(size) {
* or error
*/
function handleEmpty(call, callback) {
- callback(null, {});
+ echoHeader(call);
+ callback(null, {}, getEchoTrailer(call));
}
/**
@@ -68,14 +118,17 @@ function handleEmpty(call, callback) {
* error
*/
function handleUnary(call, callback) {
+ echoHeader(call);
var req = call.request;
- var zeros = zeroBuffer(req.response_size);
- var payload_type = req.response_type;
- if (payload_type === 'RANDOM') {
- payload_type = ['COMPRESSABLE',
- 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
+ if (req.response_status) {
+ var status = req.response_status;
+ status.metadata = getEchoTrailer(call);
+ callback(status);
+ return;
}
- callback(null, {payload: {type: payload_type, body: zeros}});
+ var payload = getPayload(req.response_type, req.response_size);
+ callback(null, {payload: payload},
+ getEchoTrailer(call));
}
/**
@@ -85,12 +138,14 @@ function handleUnary(call, callback) {
* error
*/
function handleStreamingInput(call, callback) {
+ echoHeader(call);
var aggregate_size = 0;
call.on('data', function(value) {
aggregate_size += value.payload.body.length;
});
call.on('end', function() {
- callback(null, {aggregated_payload_size: aggregate_size});
+ callback(null, {aggregated_payload_size: aggregate_size},
+ getEchoTrailer(call));
});
}
@@ -99,21 +154,18 @@ function handleStreamingInput(call, callback) {
* @param {Call} call Call to handle
*/
function handleStreamingOutput(call) {
+ echoHeader(call);
var req = call.request;
- var payload_type = req.response_type;
- if (payload_type === 'RANDOM') {
- payload_type = ['COMPRESSABLE',
- 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
+ if (req.response_status) {
+ var status = req.response_status;
+ status.metadata = getEchoTrailer(call);
+ call.emit('error', status);
+ return;
}
_.each(req.response_parameters, function(resp_param) {
- call.write({
- payload: {
- body: zeroBuffer(resp_param.size),
- type: payload_type
- }
- });
+ call.write({payload: getPayload(req.response_type, resp_param.size)});
});
- call.end();
+ call.end(getEchoTrailer(call));
}
/**
@@ -122,23 +174,20 @@ function handleStreamingOutput(call) {
* @param {Call} call Call to handle
*/
function handleFullDuplex(call) {
+ echoHeader(call);
call.on('data', function(value) {
- var payload_type = value.response_type;
- if (payload_type === 'RANDOM') {
- payload_type = ['COMPRESSABLE',
- 'UNCOMPRESSABLE'][Math.random() < 0.5 ? 0 : 1];
+ if (value.response_status) {
+ var status = value.response_status;
+ status.metadata = getEchoTrailer(call);
+ call.emit('error', status);
+ return;
}
_.each(value.response_parameters, function(resp_param) {
- call.write({
- payload: {
- body: zeroBuffer(resp_param.size),
- type: payload_type
- }
- });
+ call.write({payload: getPayload(value.response_type, resp_param.size)});
});
});
call.on('end', function() {
- call.end();
+ call.end(getEchoTrailer(call));
});
}
@@ -148,7 +197,7 @@ function handleFullDuplex(call) {
* @param {Call} call Call to handle
*/
function handleHalfDuplex(call) {
- throw new Error('HalfDuplexCall not yet implemented');
+ call.emit('error', Error('HalfDuplexCall not yet implemented'));
}
/**
diff --git a/src/node/interop/messages.proto b/src/node/interop/messages.proto
deleted file mode 100644
index 7df85e3c13..0000000000
--- a/src/node/interop/messages.proto
+++ /dev/null
@@ -1,132 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Message definitions to be used by integration test service definitions.
-
-syntax = "proto3";
-
-package grpc.testing;
-
-// The type of payload that should be returned.
-enum PayloadType {
- // Compressable text format.
- COMPRESSABLE = 0;
-
- // Uncompressable binary format.
- UNCOMPRESSABLE = 1;
-
- // Randomly chosen from all other formats defined in this enum.
- RANDOM = 2;
-}
-
-// A block of data, to simply increase gRPC message size.
-message Payload {
- // The type of data in body.
- PayloadType type = 1;
- // Primary contents of payload.
- bytes body = 2;
-}
-
-// Unary request.
-message SimpleRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, server randomly chooses one from other formats.
- PayloadType response_type = 1;
-
- // Desired payload size in the response from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 response_size = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-
- // Whether SimpleResponse should include username.
- bool fill_username = 4;
-
- // Whether SimpleResponse should include OAuth scope.
- bool fill_oauth_scope = 5;
-}
-
-// Unary response, as configured by the request.
-message SimpleResponse {
- // Payload to increase message size.
- Payload payload = 1;
- // The user the request came from, for verifying authentication was
- // successful when the client expected it.
- string username = 2;
- // OAuth scope.
- string oauth_scope = 3;
-}
-
-// Client-streaming request.
-message StreamingInputCallRequest {
- // Optional input payload sent along with the request.
- Payload payload = 1;
-
- // Not expecting any payload from the response.
-}
-
-// Client-streaming response.
-message StreamingInputCallResponse {
- // Aggregated size of payloads received from the client.
- int32 aggregated_payload_size = 1;
-}
-
-// Configuration for a particular response.
-message ResponseParameters {
- // Desired payload sizes in responses from the server.
- // If response_type is COMPRESSABLE, this denotes the size before compression.
- int32 size = 1;
-
- // Desired interval between consecutive responses in the response stream in
- // microseconds.
- int32 interval_us = 2;
-}
-
-// Server-streaming request.
-message StreamingOutputCallRequest {
- // Desired payload type in the response from the server.
- // If response_type is RANDOM, the payload from each response in the stream
- // might be of different types. This is to simulate a mixed type of payload
- // stream.
- PayloadType response_type = 1;
-
- // Configuration for each expected response message.
- repeated ResponseParameters response_parameters = 2;
-
- // Optional input payload sent along with the request.
- Payload payload = 3;
-}
-
-// Server-streaming response, as configured by the request and parameters.
-message StreamingOutputCallResponse {
- // Payload to increase response size.
- Payload payload = 1;
-}
diff --git a/src/node/interop/test.proto b/src/node/interop/test.proto
deleted file mode 100644
index 24e67497fa..0000000000
--- a/src/node/interop/test.proto
+++ /dev/null
@@ -1,72 +0,0 @@
-
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// An integration test service that covers all the method signature permutations
-// of unary/streaming requests/responses.
-
-syntax = "proto3";
-
-import "empty.proto";
-import "messages.proto";
-
-package grpc.testing;
-
-// A simple service to test the various types of RPCs and experiment with
-// performance with various types of payload.
-service TestService {
- // One empty request followed by one empty response.
- rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
-
- // One request followed by one response.
- rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
-
- // One request followed by a sequence of responses (streamed download).
- // The server returns the payload with client desired type and sizes.
- rpc StreamingOutputCall(StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by one response (streamed upload).
- // The server returns the aggregated size of client payload as the result.
- rpc StreamingInputCall(stream StreamingInputCallRequest)
- returns (StreamingInputCallResponse);
-
- // A sequence of requests with each request served by the server immediately.
- // As one request could lead to multiple responses, this interface
- // demonstrates the idea of full duplexing.
- rpc FullDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-
- // A sequence of requests followed by a sequence of responses.
- // The server buffers all the client requests and then serves them in order. A
- // stream of responses are returned to the client when the server starts with
- // first request.
- rpc HalfDuplexCall(stream StreamingOutputCallRequest)
- returns (stream StreamingOutputCallResponse);
-}
diff --git a/src/node/package.json b/src/node/package.json
deleted file mode 100644
index 0aeca5f659..0000000000
--- a/src/node/package.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "name": "grpc",
- "version": "0.11.1",
- "author": "Google Inc.",
- "description": "gRPC Library for Node",
- "homepage": "http://www.grpc.io/",
- "repository": {
- "type": "git",
- "url": "https://github.com/grpc/grpc.git"
- },
- "bugs": "https://github.com/grpc/grpc/issues",
- "contributors": [
- {
- "name": "Michael Lumish",
- "email": "mlumish@google.com"
- }
- ],
- "directories": {
- "lib": "src",
- "example": "examples"
- },
- "scripts": {
- "lint": "node ./node_modules/jshint/bin/jshint src test examples interop index.js",
- "test": "./node_modules/.bin/mocha && npm run-script lint",
- "gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json",
- "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha"
- },
- "dependencies": {
- "bindings": "^1.2.0",
- "lodash": "^3.9.3",
- "nan": "^2.0.0",
- "protobufjs": "^4.0.0"
- },
- "devDependencies": {
- "async": "^0.9.0",
- "google-auth-library": "^0.9.2",
- "istanbul": "^0.3.21",
- "jsdoc": "^3.3.2",
- "jshint": "^2.5.0",
- "minimist": "^1.1.0",
- "mocha": "~1.21.0",
- "mustache": "^2.0.0",
- "strftime": "^0.8.2"
- },
- "engines": {
- "node": ">=0.10.13"
- },
- "files": [
- "LICENSE",
- "README.md",
- "index.js",
- "binding.gyp",
- "bin",
- "cli",
- "examples",
- "ext",
- "health_check",
- "interop",
- "src",
- "test"
- ],
- "main": "index.js",
- "license": "BSD-3-Clause"
-}
diff --git a/src/node/examples/perf_test.js b/src/node/performance/perf_test.js
index ba8fbf88d2..fe51e4a603 100644
--- a/src/node/examples/perf_test.js
+++ b/src/node/performance/perf_test.js
@@ -42,7 +42,7 @@ function runTest(iterations, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.start();
var client = new testProto.TestService('localhost:' + testServer.port,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
function runIterations(finish) {
var start = process.hrtime();
diff --git a/src/node/examples/qps_test.js b/src/node/performance/qps_test.js
index ec968b8540..491f47364c 100644
--- a/src/node/examples/qps_test.js
+++ b/src/node/performance/qps_test.js
@@ -62,7 +62,7 @@ function runTest(concurrent_calls, seconds, callback) {
var testServer = interop_server.getServer(0, false);
testServer.server.start();
var client = new testProto.TestService('localhost:' + testServer.port,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
var warmup_num = 100;
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 7f510231b3..909376e766 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -40,7 +40,7 @@
var _ = require('lodash');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
var common = require('./common');
@@ -54,7 +54,7 @@ var Readable = stream.Readable;
var Writable = stream.Writable;
var Duplex = stream.Duplex;
var util = require('util');
-var version = require('../package.json').version;
+var version = require('../../../package.json').version;
util.inherits(ClientWritableStream, Writable);
@@ -233,17 +233,23 @@ function getCall(channel, method, options) {
var host;
var parent;
var propagate_flags;
+ var credentials;
if (options) {
deadline = options.deadline;
host = options.host;
parent = _.get(options, 'parent.call');
propagate_flags = options.propagate_flags;
+ credentials = options.credentials;
}
if (deadline === undefined) {
deadline = Infinity;
}
- return new grpc.Call(channel, method, deadline, host,
- parent, propagate_flags);
+ var call = new grpc.Call(channel, method, deadline, host,
+ parent, propagate_flags);
+ if (credentials) {
+ call.setCredentials(credentials);
+ }
+ return call;
}
/**
@@ -282,60 +288,53 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
emitter.getPeer = function getPeer() {
return call.getPeer();
};
- this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
- if (error) {
- call.cancel();
- callback(error);
- return;
- }
- var client_batch = {};
- var message = serialize(argument);
- if (options) {
- message.grpcWriteFlags = options.flags;
- }
- client_batch[grpc.opType.SEND_INITIAL_METADATA] =
- metadata._getCoreRepresentation();
- client_batch[grpc.opType.SEND_MESSAGE] = message;
- client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
- client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
- client_batch[grpc.opType.RECV_MESSAGE] = true;
- client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
- call.startBatch(client_batch, function(err, response) {
- response.status.metadata = Metadata._fromCoreRepresentation(
- response.status.metadata);
- var status = response.status;
- var error;
- var deserialized;
- if (status.code === grpc.status.OK) {
- if (err) {
- // Got a batch error, but OK status. Something went wrong
- callback(err);
- return;
- } else {
- try {
- deserialized = deserialize(response.read);
- } catch (e) {
- /* Change status to indicate bad server response. This will result
- * in passing an error to the callback */
- status = {
- code: grpc.status.INTERNAL,
- details: 'Failed to parse server response'
- };
- }
- }
- }
- if (status.code !== grpc.status.OK) {
- error = new Error(response.status.details);
- error.code = status.code;
- error.metadata = status.metadata;
- callback(error);
+ var client_batch = {};
+ var message = serialize(argument);
+ if (options) {
+ message.grpcWriteFlags = options.flags;
+ }
+ client_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
+ client_batch[grpc.opType.SEND_MESSAGE] = message;
+ client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ var status = response.status;
+ var error;
+ var deserialized;
+ if (status.code === grpc.status.OK) {
+ if (err) {
+ // Got a batch error, but OK status. Something went wrong
+ callback(err);
+ return;
} else {
- callback(null, deserialized);
+ try {
+ deserialized = deserialize(response.read);
+ } catch (e) {
+ /* Change status to indicate bad server response. This will result
+ * in passing an error to the callback */
+ status = {
+ code: grpc.status.INTERNAL,
+ details: 'Failed to parse server response'
+ };
+ }
}
- emitter.emit('status', status);
- emitter.emit('metadata', Metadata._fromCoreRepresentation(
- response.metadata));
- });
+ }
+ if (status.code !== grpc.status.OK) {
+ error = new Error(response.status.details);
+ error.code = status.code;
+ error.metadata = status.metadata;
+ callback(error);
+ } else {
+ callback(null, deserialized);
+ }
+ emitter.emit('status', status);
+ emitter.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
});
return emitter;
}
@@ -371,62 +370,55 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
metadata = metadata.clone();
}
var stream = new ClientWritableStream(call, serialize);
- this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
- if (error) {
- call.cancel();
- callback(error);
+ var metadata_batch = {};
+ metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
+ metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(metadata_batch, function(err, response) {
+ if (err) {
+ // The call has stopped for some reason. A non-OK status will arrive
+ // in the other batch.
return;
}
- var metadata_batch = {};
- metadata_batch[grpc.opType.SEND_INITIAL_METADATA] =
- metadata._getCoreRepresentation();
- metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
- call.startBatch(metadata_batch, function(err, response) {
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
+ });
+ var client_batch = {};
+ client_batch[grpc.opType.RECV_MESSAGE] = true;
+ client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(client_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ var status = response.status;
+ var error;
+ var deserialized;
+ if (status.code === grpc.status.OK) {
if (err) {
- // The call has stopped for some reason. A non-OK status will arrive
- // in the other batch.
+ // Got a batch error, but OK status. Something went wrong
+ callback(err);
return;
- }
- stream.emit('metadata', Metadata._fromCoreRepresentation(
- response.metadata));
- });
- var client_batch = {};
- client_batch[grpc.opType.RECV_MESSAGE] = true;
- client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
- call.startBatch(client_batch, function(err, response) {
- response.status.metadata = Metadata._fromCoreRepresentation(
- response.status.metadata);
- var status = response.status;
- var error;
- var deserialized;
- if (status.code === grpc.status.OK) {
- if (err) {
- // Got a batch error, but OK status. Something went wrong
- callback(err);
- return;
- } else {
- try {
- deserialized = deserialize(response.read);
- } catch (e) {
- /* Change status to indicate bad server response. This will result
- * in passing an error to the callback */
- status = {
- code: grpc.status.INTERNAL,
- details: 'Failed to parse server response'
- };
- }
- }
- }
- if (status.code !== grpc.status.OK) {
- error = new Error(response.status.details);
- error.code = status.code;
- error.metadata = status.metadata;
- callback(error);
} else {
- callback(null, deserialized);
+ try {
+ deserialized = deserialize(response.read);
+ } catch (e) {
+ /* Change status to indicate bad server response. This will result
+ * in passing an error to the callback */
+ status = {
+ code: grpc.status.INTERNAL,
+ details: 'Failed to parse server response'
+ };
+ }
}
- stream.emit('status', status);
- });
+ }
+ if (status.code !== grpc.status.OK) {
+ error = new Error(response.status.details);
+ error.code = status.code;
+ error.metadata = status.metadata;
+ callback(error);
+ } else {
+ callback(null, deserialized);
+ }
+ stream.emit('status', status);
});
return stream;
}
@@ -462,51 +454,44 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
metadata = metadata.clone();
}
var stream = new ClientReadableStream(call, deserialize);
- this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
- if (error) {
- call.cancel();
- stream.emit('error', error);
+ var start_batch = {};
+ var message = serialize(argument);
+ if (options) {
+ message.grpcWriteFlags = options.flags;
+ }
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ start_batch[grpc.opType.SEND_MESSAGE] = message;
+ start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ // The call has stopped for some reason. A non-OK status will arrive
+ // in the other batch.
return;
}
- var start_batch = {};
- var message = serialize(argument);
- if (options) {
- message.grpcWriteFlags = options.flags;
- }
- start_batch[grpc.opType.SEND_INITIAL_METADATA] =
- metadata._getCoreRepresentation();
- start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
- start_batch[grpc.opType.SEND_MESSAGE] = message;
- start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
- call.startBatch(start_batch, function(err, response) {
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ stream.emit('status', response.status);
+ if (response.status.code !== grpc.status.OK) {
+ var error = new Error(response.status.details);
+ error.code = response.status.code;
+ error.metadata = response.status.metadata;
+ stream.emit('error', error);
+ return;
+ } else {
if (err) {
- // The call has stopped for some reason. A non-OK status will arrive
- // in the other batch.
- return;
- }
- stream.emit('metadata', Metadata._fromCoreRepresentation(
- response.metadata));
- });
- var status_batch = {};
- status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
- call.startBatch(status_batch, function(err, response) {
- response.status.metadata = Metadata._fromCoreRepresentation(
- response.status.metadata);
- stream.emit('status', response.status);
- if (response.status.code !== grpc.status.OK) {
- var error = new Error(response.status.details);
- error.code = response.status.code;
- error.metadata = response.status.metadata;
- stream.emit('error', error);
+ // Got a batch error, but OK status. Something went wrong
+ stream.emit('error', err);
return;
- } else {
- if (err) {
- // Got a batch error, but OK status. Something went wrong
- stream.emit('error', err);
- return;
- }
}
- });
+ }
});
return stream;
}
@@ -540,45 +525,38 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
metadata = metadata.clone();
}
var stream = new ClientDuplexStream(call, serialize, deserialize);
- this.$updateMetadata(this.$auth_uri, metadata, function(error, metadata) {
- if (error) {
- call.cancel();
- stream.emit('error', error);
+ var start_batch = {};
+ start_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ metadata._getCoreRepresentation();
+ start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
+ call.startBatch(start_batch, function(err, response) {
+ if (err) {
+ // The call has stopped for some reason. A non-OK status will arrive
+ // in the other batch.
return;
}
- var start_batch = {};
- start_batch[grpc.opType.SEND_INITIAL_METADATA] =
- metadata._getCoreRepresentation();
- start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
- call.startBatch(start_batch, function(err, response) {
+ stream.emit('metadata', Metadata._fromCoreRepresentation(
+ response.metadata));
+ });
+ var status_batch = {};
+ status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
+ call.startBatch(status_batch, function(err, response) {
+ response.status.metadata = Metadata._fromCoreRepresentation(
+ response.status.metadata);
+ stream.emit('status', response.status);
+ if (response.status.code !== grpc.status.OK) {
+ var error = new Error(response.status.details);
+ error.code = response.status.code;
+ error.metadata = response.status.metadata;
+ stream.emit('error', error);
+ return;
+ } else {
if (err) {
- // The call has stopped for some reason. A non-OK status will arrive
- // in the other batch.
+ // Got a batch error, but OK status. Something went wrong
+ stream.emit('error', err);
return;
}
- stream.emit('metadata', Metadata._fromCoreRepresentation(
- response.metadata));
- });
- var status_batch = {};
- status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
- call.startBatch(status_batch, function(err, response) {
- response.status.metadata = Metadata._fromCoreRepresentation(
- response.status.metadata);
- stream.emit('status', response.status);
- if (response.status.code !== grpc.status.OK) {
- var error = new Error(response.status.details);
- error.code = response.status.code;
- error.metadata = response.status.metadata;
- stream.emit('error', error);
- return;
- } else {
- if (err) {
- // Got a batch error, but OK status. Something went wrong
- stream.emit('error', err);
- return;
- }
- }
- });
+ }
});
return stream;
}
@@ -618,15 +596,8 @@ exports.makeClientConstructor = function(methods, serviceName) {
* @param {grpc.Credentials} credentials Credentials to use to connect
* to the server
* @param {Object} options Options to pass to the underlying channel
- * @param {function(string, Object, function)=} updateMetadata function to
- * update the metadata for each request
*/
- function Client(address, credentials, options, updateMetadata) {
- if (!updateMetadata) {
- updateMetadata = function(uri, metadata, callback) {
- callback(null, metadata);
- };
- }
+ function Client(address, credentials, options) {
if (!options) {
options = {};
}
@@ -634,11 +605,6 @@ exports.makeClientConstructor = function(methods, serviceName) {
/* Private fields use $ as a prefix instead of _ because it is an invalid
* prefix of a method name */
this.$channel = new grpc.Channel(address, credentials, options);
- // Remove the optional DNS scheme, trailing port, and trailing backslash
- address = address.replace(/^(dns:\/{3})?([^:\/]+)(:\d+)?\/?$/, '$2');
- this.$server_address = address;
- this.$auth_uri = 'https://' + this.$server_address + '/' + serviceName;
- this.$updateMetadata = updateMetadata;
}
_.each(methods, function(attrs, name) {
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
new file mode 100644
index 0000000000..ddc094f896
--- /dev/null
+++ b/src/node/src/credentials.js
@@ -0,0 +1,163 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Credentials module
+ *
+ * This module contains factory methods for two different credential types:
+ * CallCredentials and ChannelCredentials. ChannelCredentials are things like
+ * SSL credentials that can be used to secure a connection, and are used to
+ * construct a Client object. CallCredentials genrally modify metadata, so they
+ * can be attached to an individual method call.
+ *
+ * CallCredentials can be composed with other CallCredentials to create
+ * CallCredentials. ChannelCredentials can be composed with CallCredentials
+ * to create ChannelCredentials. No combined credential can have more than
+ * one ChannelCredentials.
+ *
+ * For example, to create a client secured with SSL that uses Google
+ * default application credentials to authenticate:
+ *
+ * var channel_creds = credentials.createSsl(root_certs);
+ * (new GoogleAuth()).getApplicationDefault(function(err, credential) {
+ * var call_creds = credentials.createFromGoogleCredential(credential);
+ * var combined_creds = credentials.combineChannelCredentials(
+ * channel_creds, call_creds);
+ * var client = new Client(address, combined_creds);
+ * });
+ *
+ * @module
+ */
+
+'use strict';
+
+var grpc = require('bindings')('grpc_node.node');
+
+var CallCredentials = grpc.CallCredentials;
+
+var ChannelCredentials = grpc.ChannelCredentials;
+
+var Metadata = require('./metadata.js');
+
+/**
+ * Create an SSL Credentials object. If using a client-side certificate, both
+ * the second and third arguments must be passed.
+ * @param {Buffer} root_certs The root certificate data
+ * @param {Buffer=} private_key The client certificate private key, if
+ * applicable
+ * @param {Buffer=} cert_chain The client certificate cert chain, if applicable
+ * @return {ChannelCredentials} The SSL Credentials object
+ */
+exports.createSsl = ChannelCredentials.createSsl;
+
+/**
+ * Create a gRPC credentials object from a metadata generation function. This
+ * function gets the service URL and a callback as parameters. The error
+ * passed to the callback can optionally have a 'code' value attached to it,
+ * which corresponds to a status code that this library uses.
+ * @param {function(String, function(Error, Metadata))} metadata_generator The
+ * function that generates metadata
+ * @return {CallCredentials} The credentials object
+ */
+exports.createFromMetadataGenerator = function(metadata_generator) {
+ return CallCredentials.createFromPlugin(function(service_url, callback) {
+ metadata_generator(service_url, function(error, metadata) {
+ var code = grpc.status.OK;
+ var message = '';
+ if (error) {
+ message = error.message;
+ if (error.hasOwnProperty('code')) {
+ code = error.code;
+ }
+ }
+ callback(code, message, metadata._getCoreRepresentation());
+ });
+ });
+};
+
+/**
+ * Create a gRPC credential from a Google credential object.
+ * @param {Object} google_credential The Google credential object to use
+ * @return {CallCredentials} The resulting credentials object
+ */
+exports.createFromGoogleCredential = function(google_credential) {
+ return exports.createFromMetadataGenerator(function(service_url, callback) {
+ google_credential.getRequestMetadata(service_url, function(err, header) {
+ if (err) {
+ callback(err);
+ return;
+ }
+ var metadata = new Metadata();
+ metadata.add('authorization', header.Authorization);
+ callback(null, metadata);
+ });
+ });
+};
+
+/**
+ * Combine a ChannelCredentials with any number of CallCredentials into a single
+ * ChannelCredentials object.
+ * @param {ChannelCredentials} channel_credential The ChannelCredentials to
+ * start with
+ * @param {...CallCredentials} credentials The CallCredentials to compose
+ * @return ChannelCredentials A credentials object that combines all of the
+ * input credentials
+ */
+exports.combineChannelCredentials = function(channel_credential) {
+ var current = channel_credential;
+ for (var i = 1; i < arguments.length; i++) {
+ current = current.compose(arguments[i]);
+ }
+ return current;
+};
+
+/**
+ * Combine any number of CallCredentials into a single CallCredentials object
+ * @param {...CallCredentials} credentials the CallCredentials to compose
+ * @return CallCredentials A credentials object that combines all of the input
+ * credentials
+ */
+exports.combineCallCredentials = function() {
+ var current = arguments[0];
+ for (var i = 1; i < arguments.length; i++) {
+ current = current.compose(arguments[i]);
+ }
+ return current;
+};
+
+/**
+ * Create an insecure credentials object. This is used to create a channel that
+ * does not use SSL. This cannot be composed with anything.
+ * @return {ChannelCredentials} The insecure credentials object
+ */
+exports.createInsecure = ChannelCredentials.createInsecure;
diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js
index c1da70b197..5c24e46c9b 100644
--- a/src/node/src/metadata.js
+++ b/src/node/src/metadata.js
@@ -59,6 +59,7 @@ function normalizeKey(key) {
function validate(key, value) {
if (_.endsWith(key, '-bin')) {
if (!(value instanceof Buffer)) {
+ console.log(value.constructor.toString());
throw new Error('keys that end with \'-bin\' must have Buffer values');
}
} else {
@@ -173,7 +174,9 @@ Metadata.prototype._getCoreRepresentation = function() {
Metadata._fromCoreRepresentation = function(metadata) {
var newMetadata = new Metadata();
if (metadata) {
- newMetadata._internal_repr = _.cloneDeep(metadata);
+ _.forOwn(metadata, function(value, key) {
+ newMetadata._internal_repr[key] = _.clone(value);
+ });
}
return newMetadata;
};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 70b4a9d80e..a974d593c9 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -40,7 +40,7 @@
var _ = require('lodash');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
var common = require('./common');
@@ -629,7 +629,7 @@ function Server(options) {
(new Metadata())._getCoreRepresentation();
batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
code: grpc.status.UNIMPLEMENTED,
- details: 'This method is not available on this server.',
+ details: '',
metadata: {}
};
batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
diff --git a/src/node/test/async_test.js b/src/node/test/async_test.js
index e81de62bc9..6d71ea24f5 100644
--- a/src/node/test/async_test.js
+++ b/src/node/test/async_test.js
@@ -36,7 +36,7 @@
var assert = require('assert');
var grpc = require('..');
-var math = grpc.load(__dirname + '/../examples/math.proto').math;
+var math = grpc.load(__dirname + '/math/math.proto').math;
/**
@@ -47,7 +47,7 @@ var math_client;
/**
* Server to test against
*/
-var getServer = require('../examples/math_server.js');
+var getServer = require('./math/math_server.js');
var server = getServer();
@@ -57,7 +57,7 @@ describe('Async functionality', function() {
grpc.ServerCredentials.createInsecure());
server.start();
math_client = new math.Math('localhost:' + port_num,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
done();
});
after(function() {
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index e7f071bcd5..c316fe7f10 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -34,7 +34,7 @@
'use strict';
var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
/**
* Helper function to return an absolute deadline given a relative timeout in
@@ -48,7 +48,7 @@ function getDeadline(timeout_secs) {
return deadline;
}
-var insecureCreds = grpc.Credentials.createInsecure();
+var insecureCreds = grpc.ChannelCredentials.createInsecure();
describe('call', function() {
var channel;
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
index d81df2a36d..05269f7b6e 100644
--- a/src/node/test/channel_test.js
+++ b/src/node/test/channel_test.js
@@ -34,7 +34,7 @@
'use strict';
var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
/**
* This is used for testing functions with multiple asynchronous calls that
@@ -56,7 +56,7 @@ function multiDone(done, count) {
}
};
}
-var insecureCreds = grpc.Credentials.createInsecure();
+var insecureCreds = grpc.ChannelCredentials.createInsecure();
describe('channel', function() {
describe('constructor', function() {
@@ -155,6 +155,7 @@ describe('channel', function() {
deadline.setSeconds(deadline.getSeconds() + 1);
channel.watchConnectivityState(old_state, deadline, function(err, value) {
assert(err);
+ console.log('Callback from watchConnectivityState');
done();
});
});
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
index fa06ad4e4d..b17cd339cb 100644
--- a/src/node/test/constant_test.js
+++ b/src/node/test/constant_test.js
@@ -34,7 +34,7 @@
'use strict';
var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
/**
* List of all status names
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
new file mode 100644
index 0000000000..7fc311a888
--- /dev/null
+++ b/src/node/test/credentials_test.js
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+
+var grpc = require('..');
+
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+describe('client credentials', function() {
+ var Client;
+ var server;
+ var port;
+ var client_ssl_creds;
+ var client_options = {};
+ before(function() {
+ var proto = grpc.load(__dirname + '/test_service.proto');
+ server = new grpc.Server();
+ server.addProtoService(proto.TestService.service, {
+ unary: function(call, cb) {
+ call.sendMetadata(call.metadata);
+ cb(null, {});
+ },
+ clientStream: function(stream, cb){
+ stream.on('data', function(data) {});
+ stream.on('end', function() {
+ stream.sendMetadata(stream.metadata);
+ cb(null, {});
+ });
+ },
+ serverStream: function(stream) {
+ stream.sendMetadata(stream.metadata);
+ stream.end();
+ },
+ bidiStream: function(stream) {
+ stream.on('data', function(data) {});
+ stream.on('end', function() {
+ stream.sendMetadata(stream.metadata);
+ stream.end();
+ });
+ }
+ });
+ var key_path = path.join(__dirname, './data/server1.key');
+ var pem_path = path.join(__dirname, './data/server1.pem');
+ var key_data = fs.readFileSync(key_path);
+ var pem_data = fs.readFileSync(pem_path);
+ var creds = grpc.ServerCredentials.createSsl(null,
+ [{private_key: key_data,
+ cert_chain: pem_data}]);
+ //creds = grpc.ServerCredentials.createInsecure();
+ port = server.bind('localhost:0', creds);
+ server.start();
+
+ Client = proto.TestService;
+ var ca_path = path.join(__dirname, '../test/data/ca.pem');
+ var ca_data = fs.readFileSync(ca_path);
+ client_ssl_creds = grpc.credentials.createSsl(ca_data);
+ var host_override = 'foo.test.google.fr';
+ client_options['grpc.ssl_target_name_override'] = host_override;
+ client_options['grpc.default_authority'] = host_override;
+ });
+ after(function() {
+ server.forceShutdown();
+ });
+ it('Should accept SSL creds for a client', function(done) {
+ var client = new Client('localhost:' + port, client_ssl_creds,
+ client_options);
+ client.unary({}, function(err, data) {
+ assert.ifError(err);
+ done();
+ });
+ });
+ it('Should update metadata with SSL creds', function(done) {
+ var metadataUpdater = function(service_url, callback) {
+ var metadata = new grpc.Metadata();
+ metadata.set('plugin_key', 'plugin_value');
+ callback(null, metadata);
+ };
+ var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
+ var combined_creds = grpc.credentials.combineChannelCredentials(
+ client_ssl_creds, creds);
+ var client = new Client('localhost:' + port, combined_creds,
+ client_options);
+ var call = client.unary({}, function(err, data) {
+ assert.ifError(err);
+ });
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ });
+ it('Should update metadata for two simultaneous calls', function(done) {
+ done = multiDone(done, 2);
+ var metadataUpdater = function(service_url, callback) {
+ var metadata = new grpc.Metadata();
+ metadata.set('plugin_key', 'plugin_value');
+ callback(null, metadata);
+ };
+ var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
+ var combined_creds = grpc.credentials.combineChannelCredentials(
+ client_ssl_creds, creds);
+ var client = new Client('localhost:' + port, combined_creds,
+ client_options);
+ var call = client.unary({}, function(err, data) {
+ assert.ifError(err);
+ });
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ var call2 = client.unary({}, function(err, data) {
+ assert.ifError(err);
+ });
+ call2.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ });
+ describe('Per-rpc creds', function() {
+ var client;
+ var updater_creds;
+ before(function() {
+ client = new Client('localhost:' + port, client_ssl_creds,
+ client_options);
+ var metadataUpdater = function(service_url, callback) {
+ var metadata = new grpc.Metadata();
+ metadata.set('plugin_key', 'plugin_value');
+ callback(null, metadata);
+ };
+ updater_creds = grpc.credentials.createFromMetadataGenerator(
+ metadataUpdater);
+ });
+ it('Should update metadata on a unary call', function(done) {
+ var call = client.unary({}, function(err, data) {
+ assert.ifError(err);
+ }, null, {credentials: updater_creds});
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ });
+ it('should update metadata on a client streaming call', function(done) {
+ var call = client.clientStream(function(err, data) {
+ assert.ifError(err);
+ }, null, {credentials: updater_creds});
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ call.end();
+ });
+ it('should update metadata on a server streaming call', function(done) {
+ var call = client.serverStream({}, null, {credentials: updater_creds});
+ call.on('data', function() {});
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ });
+ it('should update metadata on a bidi streaming call', function(done) {
+ var call = client.bidiStream(null, {credentials: updater_creds});
+ call.on('data', function() {});
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ done();
+ });
+ call.end();
+ });
+ it('should be able to use multiple plugin credentials', function(done) {
+ var altMetadataUpdater = function(service_url, callback) {
+ var metadata = new grpc.Metadata();
+ metadata.set('other_plugin_key', 'other_plugin_value');
+ callback(null, metadata);
+ };
+ var alt_updater_creds = grpc.credentials.createFromMetadataGenerator(
+ altMetadataUpdater);
+ var combined_updater = grpc.credentials.combineCallCredentials(
+ updater_creds, alt_updater_creds);
+ var call = client.unary({}, function(err, data) {
+ assert.ifError(err);
+ }, null, {credentials: combined_updater});
+ call.on('metadata', function(metadata) {
+ assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
+ assert.deepEqual(metadata.get('other_plugin_key'),
+ ['other_plugin_value']);
+ done();
+ });
+ });
+ });
+});
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index 4b8da3bfb1..0f6c5941c4 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -34,7 +34,7 @@
'use strict';
var assert = require('assert');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
/**
* This is used for testing functions with multiple asynchronous calls that
@@ -57,7 +57,7 @@ function multiDone(done, count) {
};
}
-var insecureCreds = grpc.Credentials.createInsecure();
+var insecureCreds = grpc.ChannelCredentials.createInsecure();
describe('end-to-end', function() {
var server;
diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js
index 9267bff7eb..a4dc24cf46 100644
--- a/src/node/test/health_test.js
+++ b/src/node/test/health_test.js
@@ -54,7 +54,7 @@ describe('Health Checking', function() {
grpc.ServerCredentials.createInsecure());
healthServer.start();
healthClient = new health.Client('localhost:' + port_num,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
});
after(function() {
healthServer.forceShutdown();
diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js
index 2ca07c1d50..f8c0b14137 100644
--- a/src/node/test/interop_sanity_test.js
+++ b/src/node/test/interop_sanity_test.js
@@ -71,7 +71,7 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'server_streaming', true, true,
done);
});
- it('should pass ping_pong', function(done) {
+ it.only('should pass ping_pong', function(done) {
interop_client.runTest(port, name_override, 'ping_pong', true, true, done);
});
it('should pass empty_stream', function(done) {
@@ -90,4 +90,16 @@ describe('Interop tests', function() {
interop_client.runTest(port, name_override, 'timeout_on_sleeping_server',
true, true, done);
});
+ it('should pass custom_metadata', function(done) {
+ interop_client.runTest(port, name_override, 'custom_metadata',
+ true, true, done);
+ });
+ it('should pass status_code_and_message', function(done) {
+ interop_client.runTest(port, name_override, 'status_code_and_message',
+ true, true, done);
+ });
+ it('should pass unimplemented_method', function(done) {
+ interop_client.runTest(port, name_override, 'unimplemented_method',
+ true, true, done);
+ });
});
diff --git a/src/node/examples/math.proto b/src/node/test/math/math.proto
index 311e148c02..311e148c02 100644
--- a/src/node/examples/math.proto
+++ b/src/node/test/math/math.proto
diff --git a/src/node/examples/math_server.js b/src/node/test/math/math_server.js
index a4b237aeeb..9d06596f3d 100644
--- a/src/node/examples/math_server.js
+++ b/src/node/test/math/math_server.js
@@ -33,7 +33,7 @@
'use strict';
-var grpc = require('..');
+var grpc = require('../..');
var math = grpc.load(__dirname + '/math.proto').math;
/**
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index 6a6607ec74..6361d97857 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -36,7 +36,7 @@
var assert = require('assert');
var grpc = require('..');
-var math = grpc.load(__dirname + '/../examples/math.proto').math;
+var math = grpc.load(__dirname + '/math/math.proto').math;
/**
* Client to use to make requests to a running server.
@@ -46,7 +46,7 @@ var math_client;
/**
* Server to test against
*/
-var getServer = require('../examples/math_server.js');
+var getServer = require('./math/math_server.js');
var server = getServer();
@@ -56,7 +56,7 @@ describe('Math client', function() {
grpc.ServerCredentials.createInsecure());
server.start();
math_client = new math.Math('localhost:' + port_num,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
done();
});
after(function() {
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
index 1e69d52e58..999a183b3c 100644
--- a/src/node/test/server_test.js
+++ b/src/node/test/server_test.js
@@ -36,7 +36,7 @@
var assert = require('assert');
var fs = require('fs');
var path = require('path');
-var grpc = require('bindings')('grpc.node');
+var grpc = require('bindings')('grpc_node');
describe('server', function() {
describe('constructor', function() {
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index d917c7a171..395ea887ec 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -41,7 +41,7 @@ var ProtoBuf = require('protobufjs');
var grpc = require('..');
-var math_proto = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
+var math_proto = ProtoBuf.loadProtoFile(__dirname + '/math/math.proto');
var mathService = math_proto.lookup('math.Math');
@@ -163,7 +163,7 @@ describe('waitForClientReady', function() {
Client = surface_client.makeProtobufClientConstructor(mathService);
});
beforeEach(function() {
- client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
});
after(function() {
server.forceShutdown();
@@ -217,7 +217,7 @@ describe('Echo service', function() {
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(echo_service);
- client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
after(function() {
@@ -263,7 +263,7 @@ describe('Generic client and server', function() {
server.start();
var Client = grpc.makeGenericClientConstructor(string_service_attrs);
client = new Client('localhost:' + port,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
});
after(function() {
server.forceShutdown();
@@ -311,7 +311,7 @@ describe('Echo metadata', function() {
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(test_service);
- client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
metadata = new grpc.Metadata();
metadata.set('key', 'value');
@@ -356,7 +356,7 @@ describe('Echo metadata', function() {
call.end();
});
it('shows the correct user-agent string', function(done) {
- var version = require('../package.json').version;
+ var version = require('../../../package.json').version;
var call = client.unary({}, function(err, data) { assert.ifError(err); },
metadata);
call.on('metadata', function(metadata) {
@@ -437,7 +437,7 @@ describe('Other conditions', function() {
});
port = server.bind('localhost:0', server_insecure_creds);
Client = surface_client.makeProtobufClientConstructor(test_service);
- client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
after(function() {
@@ -484,7 +484,7 @@ describe('Other conditions', function() {
var Client = surface_client.makeClientConstructor(test_service_attrs,
'TestService');
misbehavingClient = new Client('localhost:' + port,
- grpc.Credentials.createInsecure());
+ grpc.credentials.createInsecure());
});
it('should respond correctly to a unary call', function(done) {
misbehavingClient.unary(badArg, function(err, data) {
@@ -690,165 +690,187 @@ describe('Other conditions', function() {
});
});
});
- describe('Call propagation', function() {
- var proxy;
- var proxy_impl;
- beforeEach(function() {
- proxy = new grpc.Server();
- proxy_impl = {
- unary: function(call) {},
- clientStream: function(stream) {},
- serverStream: function(stream) {},
- bidiStream: function(stream) {}
- };
+});
+describe('Call propagation', function() {
+ var proxy;
+ var proxy_impl;
+
+ var test_service;
+ var Client;
+ var client;
+ var server;
+ before(function() {
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+ test_service = test_proto.lookup('TestService');
+ server = new grpc.Server();
+ server.addProtoService(test_service, {
+ unary: function(call) {},
+ clientStream: function(stream) {},
+ serverStream: function(stream) {},
+ bidiStream: function(stream) {}
});
- afterEach(function() {
- console.log('Shutting down server');
- proxy.forceShutdown();
- });
- describe('Cancellation', function() {
- it('With a unary call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.unary = function(parent, callback) {
- client.unary(parent.request, function(err, value) {
- try {
- assert(err);
- assert.strictEqual(err.code, grpc.status.CANCELLED);
- } finally {
- callback(err, value);
- done();
- }
- }, null, {parent: parent});
- call.cancel();
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var call = proxy_client.unary({}, function(err, value) {
- done();
- });
- });
- it('With a client stream call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.clientStream = function(parent, callback) {
- client.clientStream(function(err, value) {
- try {
- assert(err);
- assert.strictEqual(err.code, grpc.status.CANCELLED);
- } finally {
- callback(err, value);
- done();
- }
- }, null, {parent: parent});
- call.cancel();
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var call = proxy_client.clientStream(function(err, value) {
- done();
- });
- });
- it('With a server stream call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.serverStream = function(parent) {
- var child = client.serverStream(parent.request, null,
- {parent: parent});
- child.on('error', function(err) {
+ var port = server.bind('localhost:0', server_insecure_creds);
+ Client = surface_client.makeProtobufClientConstructor(test_service);
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
+ server.start();
+ });
+ after(function() {
+ server.forceShutdown();
+ });
+ beforeEach(function() {
+ proxy = new grpc.Server();
+ proxy_impl = {
+ unary: function(call) {},
+ clientStream: function(stream) {},
+ serverStream: function(stream) {},
+ bidiStream: function(stream) {}
+ };
+ });
+ afterEach(function() {
+ proxy.forceShutdown();
+ });
+ describe('Cancellation', function() {
+ it('With a unary call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.unary = function(parent, callback) {
+ client.unary(parent.request, function(err, value) {
+ try {
assert(err);
assert.strictEqual(err.code, grpc.status.CANCELLED);
+ } finally {
+ callback(err, value);
done();
- });
- call.cancel();
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var call = proxy_client.serverStream({});
- call.on('error', function(err) {
- done();
- });
+ }
+ }, null, {parent: parent});
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var call = proxy_client.unary({}, function(err, value) {
+ done();
});
- it('With a bidi stream call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.bidiStream = function(parent) {
- var child = client.bidiStream(null, {parent: parent});
- child.on('error', function(err) {
+ });
+ it('With a client stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.clientStream = function(parent, callback) {
+ client.clientStream(function(err, value) {
+ try {
assert(err);
assert.strictEqual(err.code, grpc.status.CANCELLED);
+ } finally {
+ callback(err, value);
done();
- });
- call.cancel();
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var call = proxy_client.bidiStream();
- call.on('error', function(err) {
+ }
+ }, null, {parent: parent});
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var call = proxy_client.clientStream(function(err, value) {
+ done();
+ });
+ });
+ it('With a server stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.serverStream = function(parent) {
+ var child = client.serverStream(parent.request, null,
+ {parent: parent});
+ child.on('error', function(err) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
done();
});
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var call = proxy_client.serverStream({});
+ call.on('error', function(err) {
+ done();
});
});
- describe('Deadline', function() {
- /* jshint bitwise:false */
- var deadline_flags = (grpc.propagate.DEFAULTS &
- ~grpc.propagate.CANCELLATION);
- it('With a client stream call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.clientStream = function(parent, callback) {
- client.clientStream(function(err, value) {
- try {
- assert(err);
- assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
- err.code === grpc.status.INTERNAL);
- } finally {
- callback(err, value);
- done();
- }
- }, null, {parent: parent, propagate_flags: deadline_flags});
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + 1);
- proxy_client.clientStream(function(err, value) {
+ it('With a bidi stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.bidiStream = function(parent) {
+ var child = client.bidiStream(null, {parent: parent});
+ child.on('error', function(err) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
done();
- }, null, {deadline: deadline});
- });
- it('With a bidi stream call', function(done) {
- done = multiDone(done, 2);
- proxy_impl.bidiStream = function(parent) {
- var child = client.bidiStream(
- null, {parent: parent, propagate_flags: deadline_flags});
- child.on('error', function(err) {
+ });
+ call.cancel();
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var call = proxy_client.bidiStream();
+ call.on('error', function(err) {
+ done();
+ });
+ });
+ });
+ describe('Deadline', function() {
+ /* jshint bitwise:false */
+ var deadline_flags = (grpc.propagate.DEFAULTS &
+ ~grpc.propagate.CANCELLATION);
+ it('With a client stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.clientStream = function(parent, callback) {
+ client.clientStream(function(err, value) {
+ try {
assert(err);
assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
err.code === grpc.status.INTERNAL);
+ } finally {
+ callback(err, value);
done();
- });
- };
- proxy.addProtoService(test_service, proxy_impl);
- var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
- proxy.start();
- var proxy_client = new Client('localhost:' + proxy_port,
- grpc.Credentials.createInsecure());
- var deadline = new Date();
- deadline.setSeconds(deadline.getSeconds() + 1);
- var call = proxy_client.bidiStream(null, {deadline: deadline});
- call.on('error', function(err) {
+ }
+ }, null, {parent: parent, propagate_flags: deadline_flags});
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ proxy_client.clientStream(function(err, value) {
+ done();
+ }, null, {deadline: deadline});
+ });
+ it('With a bidi stream call', function(done) {
+ done = multiDone(done, 2);
+ proxy_impl.bidiStream = function(parent) {
+ var child = client.bidiStream(
+ null, {parent: parent, propagate_flags: deadline_flags});
+ child.on('error', function(err) {
+ assert(err);
+ assert(err.code === grpc.status.DEADLINE_EXCEEDED ||
+ err.code === grpc.status.INTERNAL);
done();
});
+ };
+ proxy.addProtoService(test_service, proxy_impl);
+ var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
+ proxy.start();
+ var proxy_client = new Client('localhost:' + proxy_port,
+ grpc.credentials.createInsecure());
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 1);
+ var call = proxy_client.bidiStream(null, {deadline: deadline});
+ call.on('error', function(err) {
+ done();
});
});
});
@@ -866,7 +888,7 @@ describe('Cancelling surface client', function() {
});
var port = server.bind('localhost:0', server_insecure_creds);
var Client = surface_client.makeProtobufClientConstructor(mathService);
- client = new Client('localhost:' + port, grpc.Credentials.createInsecure());
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
server.start();
});
after(function() {
diff --git a/src/objective-c/README.md b/src/objective-c/README.md
index 6c27657def..a861a9f6f9 100644
--- a/src/objective-c/README.md
+++ b/src/objective-c/README.md
@@ -17,7 +17,7 @@ services.
<a name="install"></a>
## Install protoc with the gRPC plugin
-On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][].
+On Mac OS X, install [homebrew][].
Run the following command to install _protoc_ and the gRPC _protoc_ plugin:
```sh
@@ -153,7 +153,7 @@ _protoc_, in which case no system modification nor renaming is necessary.
<a name="no-cocoapods"></a>
### Integrate the generated gRPC library without using Cocoapods
-You need to compile the generated `.pbpbjc.*` files (the enums and messages) without ARC support,
+You need to compile the generated `.pbobjc.*` files (the enums and messages) without ARC support,
and the generated `.pbrpc.*` files (the services) with ARC support. The generated code depends on
v0.5+ of the Objective-C gRPC runtime library and v3.0.0-alpha-3+ of the Objective-C Protobuf
runtime library.
@@ -168,7 +168,6 @@ Objective-C Protobuf runtime library.
[Protocol Buffers]:https://developers.google.com/protocol-buffers/
[homebrew]:http://brew.sh
-[linuxbrew]:https://github.com/Homebrew/linuxbrew
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[example Podfile]:https://github.com/grpc/grpc/blob/master/src/objective-c/examples/Sample/Podfile
[sample app]: https://github.com/grpc/grpc/tree/master/src/objective-c/examples/Sample
diff --git a/src/objective-c/RxLibrary/GRXWriter.m b/src/objective-c/RxLibrary/GRXWriter.m
index 019fcbd785..fee33f5556 100644
--- a/src/objective-c/RxLibrary/GRXWriter.m
+++ b/src/objective-c/RxLibrary/GRXWriter.m
@@ -35,4 +35,14 @@
@implementation GRXWriter
+- (void)startWithWriteable:(id<GRXWriteable>)writeable {
+ NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd));
+ [self doesNotRecognizeSelector:_cmd];
+}
+
+- (void)finishWithError:(NSError *)errorOrNil {
+ NSAssert(NO, @"Missing base implementation for %@", NSStringFromSelector(_cmd));
+ [self doesNotRecognizeSelector:_cmd];
+}
+
@end
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index f41902f041..921cfc6ae6 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,10 +10,10 @@
<email>grpc-packages@google.com</email>
<active>yes</active>
</lead>
- <date>2015-09-24</date>
- <time>09:51:04</time>
+ <date>2015-10-07</date>
+ <time>13:40:54</time>
<version>
- <release>0.6.0</release>
+ <release>0.6.1</release>
<api>0.6.0</api>
</version>
<stability>
@@ -22,12 +22,7 @@
</stability>
<license>BSD</license>
<notes>
-- support per message compression disable
-- expose per-call host override option
-- expose connectivity API
-- expose channel target and call peer
-- add user-agent
-- update to wrap gRPC C core library beta version 0.11.0
+- fixed undefined constant fatal error when run with apache/nginx #2275
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@@ -44,7 +39,7 @@
<file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
<file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
<file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
- <file baseinstalldir="/" md5sum="6a550516a1423def0786851c76f87c85" name="php_grpc.c" role="src" />
+ <file baseinstalldir="/" md5sum="b77f1f3941aaf7a21090b493e9f26037" name="php_grpc.c" role="src" />
<file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
<file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
<file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
@@ -118,5 +113,20 @@ Update to wrap gRPC C Core version 0.10.0
- update to wrap gRPC C core library beta version 0.11.0
</notes>
</release>
+ <release>
+ <version>
+ <release>0.6.1</release>
+ <api>0.6.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2015-10-07</date>
+ <license>BSD</license>
+ <notes>
+- fixed undefined constant fatal error when run with apache/nginx #2275
+ </notes>
+ </release>
</changelog>
</package>
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 0f730ea756..fcd94a6306 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -109,91 +109,125 @@ PHP_MINIT_FUNCTION(grpc) {
*/
/* Register call error constants */
grpc_init();
- REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK,
+ CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER",
- GRPC_CALL_ERROR_NOT_ON_SERVER, CONST_CS);
+ GRPC_CALL_ERROR_NOT_ON_SERVER,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT",
- GRPC_CALL_ERROR_NOT_ON_CLIENT, CONST_CS);
+ GRPC_CALL_ERROR_NOT_ON_CLIENT,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED",
- GRPC_CALL_ERROR_ALREADY_INVOKED, CONST_CS);
+ GRPC_CALL_ERROR_ALREADY_INVOKED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED",
- GRPC_CALL_ERROR_NOT_INVOKED, CONST_CS);
+ GRPC_CALL_ERROR_NOT_INVOKED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED",
- GRPC_CALL_ERROR_ALREADY_FINISHED, CONST_CS);
+ GRPC_CALL_ERROR_ALREADY_FINISHED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS",
- GRPC_CALL_ERROR_TOO_MANY_OPERATIONS, CONST_CS);
+ GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
- GRPC_CALL_ERROR_INVALID_FLAGS, CONST_CS);
+ GRPC_CALL_ERROR_INVALID_FLAGS,
+ CONST_CS | CONST_PERSISTENT);
/* Register flag constants */
REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
/* Register status constants */
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", GRPC_STATUS_UNKNOWN, CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", GRPC_STATUS_UNKNOWN,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
- GRPC_STATUS_INVALID_ARGUMENT, CONST_CS);
+ GRPC_STATUS_INVALID_ARGUMENT,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
- GRPC_STATUS_DEADLINE_EXCEEDED, CONST_CS);
+ GRPC_STATUS_DEADLINE_EXCEEDED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND", GRPC_STATUS_NOT_FOUND,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS",
- GRPC_STATUS_ALREADY_EXISTS, CONST_CS);
+ GRPC_STATUS_ALREADY_EXISTS,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED",
- GRPC_STATUS_PERMISSION_DENIED, CONST_CS);
+ GRPC_STATUS_PERMISSION_DENIED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED",
- GRPC_STATUS_UNAUTHENTICATED, CONST_CS);
+ GRPC_STATUS_UNAUTHENTICATED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED",
- GRPC_STATUS_RESOURCE_EXHAUSTED, CONST_CS);
+ GRPC_STATUS_RESOURCE_EXHAUSTED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION",
- GRPC_STATUS_FAILED_PRECONDITION, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE,
- CONST_CS);
+ GRPC_STATUS_FAILED_PRECONDITION,
+ CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED,
+ CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE",
+ GRPC_STATUS_OUT_OF_RANGE,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
- GRPC_STATUS_UNIMPLEMENTED, CONST_CS);
+ GRPC_STATUS_UNIMPLEMENTED,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL", GRPC_STATUS_INTERNAL,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE", GRPC_STATUS_UNAVAILABLE,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
- CONST_CS);
+ CONST_CS | CONST_PERSISTENT);
/* Register op type constants */
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_INITIAL_METADATA",
- GRPC_OP_SEND_INITIAL_METADATA, CONST_CS);
+ GRPC_OP_SEND_INITIAL_METADATA,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_MESSAGE",
- GRPC_OP_SEND_MESSAGE, CONST_CS);
+ GRPC_OP_SEND_MESSAGE,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_CLOSE_FROM_CLIENT",
- GRPC_OP_SEND_CLOSE_FROM_CLIENT, CONST_CS);
+ GRPC_OP_SEND_CLOSE_FROM_CLIENT,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_SEND_STATUS_FROM_SERVER",
- GRPC_OP_SEND_STATUS_FROM_SERVER, CONST_CS);
+ GRPC_OP_SEND_STATUS_FROM_SERVER,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_INITIAL_METADATA",
- GRPC_OP_RECV_INITIAL_METADATA, CONST_CS);
+ GRPC_OP_RECV_INITIAL_METADATA,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_MESSAGE",
- GRPC_OP_RECV_MESSAGE, CONST_CS);
+ GRPC_OP_RECV_MESSAGE,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_STATUS_ON_CLIENT",
- GRPC_OP_RECV_STATUS_ON_CLIENT, CONST_CS);
+ GRPC_OP_RECV_STATUS_ON_CLIENT,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\OP_RECV_CLOSE_ON_SERVER",
- GRPC_OP_RECV_CLOSE_ON_SERVER, CONST_CS);
+ GRPC_OP_RECV_CLOSE_ON_SERVER,
+ CONST_CS | CONST_PERSISTENT);
/* Register connectivity state constants */
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_IDLE",
- GRPC_CHANNEL_IDLE, CONST_CS);
+ GRPC_CHANNEL_IDLE,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_CONNECTING",
- GRPC_CHANNEL_CONNECTING, CONST_CS);
+ GRPC_CHANNEL_CONNECTING,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_READY",
- GRPC_CHANNEL_READY, CONST_CS);
+ GRPC_CHANNEL_READY,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_TRANSIENT_FAILURE",
- GRPC_CHANNEL_TRANSIENT_FAILURE, CONST_CS);
+ GRPC_CHANNEL_TRANSIENT_FAILURE,
+ CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("Grpc\\CHANNEL_FATAL_FAILURE",
- GRPC_CHANNEL_FATAL_FAILURE, CONST_CS);
+ GRPC_CHANNEL_FATAL_FAILURE,
+ CONST_CS | CONST_PERSISTENT);
grpc_init_call(TSRMLS_C);
grpc_init_channel(TSRMLS_C);
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index 381b114399..0a3e1f78bf 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -114,7 +114,7 @@ class BaseStub {
return true;
}
if ($new_state == \Grpc\CHANNEL_FATAL_FAILURE) {
- throw new Exception('Failed to connect to server');
+ throw new \Exception('Failed to connect to server');
}
return false;
}
@@ -153,6 +153,25 @@ class BaseStub {
return array($metadata_copy, $timeout);
}
+ /**
+ * validate and normalize the metadata array
+ * @param $metadata The metadata map
+ * @return $metadata Validated and key-normalized metadata map
+ * @throw InvalidArgumentException if key contains invalid characters
+ */
+ private function _validate_and_normalize_metadata($metadata) {
+ $metadata_copy = array();
+ foreach ($metadata as $key => $value) {
+ if (!preg_match('/^[A-Za-z\d_-]+$/', $key)) {
+ throw new \InvalidArgumentException(
+ 'Metadata keys must be nonempty strings containing only '.
+ 'alphanumeric characters, hyphens and underscores');
+ }
+ $metadata_copy[strtolower($key)] = $value;
+ }
+ return $metadata_copy;
+ }
+
/* This class is intended to be subclassed by generated code, so all functions
begin with "_" to avoid name collisions. */
@@ -178,6 +197,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
+ $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($argument, $actual_metadata, $options);
return $call;
}
@@ -204,6 +224,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
+ $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($actual_metadata);
return $call;
}
@@ -231,6 +252,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
+ $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($argument, $actual_metadata, $options);
return $call;
}
@@ -254,6 +276,7 @@ class BaseStub {
$actual_metadata,
$jwt_aud_uri);
}
+ $actual_metadata = $this->_validate_and_normalize_metadata($actual_metadata);
$call->start($actual_metadata);
return $call;
}
diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
index 9cee188666..5cdba1e5a0 100644
--- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
+++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php
@@ -51,6 +51,14 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase {
$this->assertTrue(is_string(self::$client->getTarget()));
}
+ /**
+ * @expectedException InvalidArgumentException
+ */
+ public function testInvalidMetadata() {
+ $div_arg = new math\DivArgs();
+ $call = self::$client->Div($div_arg, array(' ' => 'abc123'));
+ }
+
public function testWriteFlags() {
$div_arg = new math\DivArgs();
$div_arg->setDividend(7);
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index d55d5629b7..0590264ef8 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -251,6 +251,23 @@ function pingPong($stub) {
}
/**
+ * Run the empty_stream test.
+ * Passes when run against the Node server as of 2015-10-09
+ * @param $stub Stub object that has service methods.
+ */
+function emptyStream($stub) {
+ // for the current PHP implementation, $call->read() will wait
+ // forever for a server response if the server is not sending any.
+ // so this test is imeplemented as a timeout to indicate the absence
+ // of receiving any response from the server
+ $call = $stub->FullDuplexCall(array('timeout' => 100000));
+ $call->writesDone();
+ hardAssert($call->read() === null, 'Server returned too many responses');
+ hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
+ 'Call did not complete successfully');
+}
+
+/**
* Run the cancel_after_begin test.
* Passes when run against the Node server as of 2015-08-28
* @param $stub Stub object that has service methods.
@@ -370,6 +387,9 @@ switch ($args['test_case']) {
case 'ping_pong':
pingPong($stub);
break;
+ case 'empty_stream':
+ emptyStream($stub);
+ break;
case 'cancel_after_begin':
cancelAfterBegin($stub);
break;
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 8c92384529..b8e33ad295 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -176,8 +176,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
- kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
+ md = update_metadata(kw, method)
return c.request_response(req, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@@ -244,8 +243,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
- kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
+ md = update_metadata(kw, method)
return c.client_streamer(requests, **md) unless return_op
# return the operation view of the active_call; define #execute as a
@@ -322,8 +320,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
- kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
+ md = update_metadata(kw, method)
return c.server_streamer(req, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@@ -439,8 +436,7 @@ module GRPC
deadline: deadline,
timeout: timeout,
parent: parent)
- kw_with_jwt_uri = self.class.update_with_jwt_aud_uri(kw, @host, method)
- md = @update_metadata.nil? ? kw : @update_metadata.call(kw_with_jwt_uri)
+ md = update_metadata(kw, method)
return c.bidi_streamer(requests, **md, &blk) unless return_op
# return the operation view of the active_call; define #execute
@@ -454,6 +450,16 @@ module GRPC
private
+ def update_metadata(kw, method)
+ return kw if @update_metadata.nil?
+ just_jwt_uri = self.class.update_with_jwt_aud_uri({}, @host, method)
+ updated = @update_metadata.call(just_jwt_uri)
+
+ # keys should be lowercase
+ updated = Hash[updated.each_pair.map { |k, v| [k.downcase, v] }]
+ kw.merge(updated)
+ end
+
# Creates a new active stub
#
# @param method [string] the method being called.
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index a05433df75..c5173aee1d 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -159,6 +159,20 @@ describe 'ClientStub' do
th.join
end
+ it 'should downcase the keys provided by the metadata updater' do
+ server_port = create_test_server
+ host = "localhost:#{server_port}"
+ th = run_request_response(@sent_msg, @resp, @pass,
+ k1: 'downcased-key-v1', k2: 'v2')
+ update_md = proc do |md|
+ md[:K1] = 'downcased-key-v1'
+ md
+ end
+ stub = GRPC::ClientStub.new(host, @cq, update_metadata: update_md)
+ expect(get_response(stub)).to eq(@resp)
+ th.join
+ end
+
it 'should send a request when configured using an override channel' do
server_port = create_test_server
alt_host = "localhost:#{server_port}"