From 518e3fe700015759cedea57f2e4febf300d57ba7 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 21 Jul 2015 15:49:42 -0700 Subject: [PATCH 01/47] Fixes for streaming compression. --- src/core/channel/compress_filter.c | 2 ++ src/core/transport/chttp2/frame_data.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c index 14cb3da62da..9b9e82caba9 100644 --- a/src/core/channel/compress_filter.c +++ b/src/core/channel/compress_filter.c @@ -174,6 +174,8 @@ static void process_send_ops(grpc_call_element *elem, size_t i; int did_compress = 0; + /* In streaming calls, we need to reset the previously accumulated slices */ + gpr_slice_buffer_reset_and_unref(&calld->slices); for (i = 0; i < send_ops->nops; ++i) { grpc_stream_op *sop = &send_ops->ops[i]; switch (sop->type) { diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c index 7a4c355f230..40bf2ebd790 100644 --- a/src/core/transport/chttp2/frame_data.c +++ b/src/core/transport/chttp2/frame_data.c @@ -92,7 +92,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse( p->frame_type = *cur; switch (p->frame_type) { case 0: - /* noop */ + p->is_frame_compressed = 0; /* GPR_FALSE */ break; case 1: p->is_frame_compressed = 1; /* GPR_TRUE */ From 8b25f2aaebc261004a08fb05151795f0c332b066 Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 21 Jul 2015 23:54:36 -0700 Subject: [PATCH 02/47] move fake_transport_security_credentials to private API --- Makefile | 2 - build.json | 2 - include/grpc/grpc_security.h | 8 --- src/core/security/credentials.h | 8 +++ src/node/ext/credentials.cc | 7 --- src/php/ext/grpc/credentials.c | 10 ---- .../_adapter/_c/types/client_credentials.c | 17 ------ .../src/grpc/_cython/_cygrpc/credentials.pyx | 11 ---- src/python/src/grpc/_cython/_cygrpc/grpc.pxd | 2 - test/cpp/end2end/end2end_test.cc | 60 +++++++++++-------- test/cpp/util/fake_credentials.cc | 58 ------------------ test/cpp/util/fake_credentials.h | 51 ---------------- tools/run_tests/sources_and_headers.json | 3 - 13 files changed, 44 insertions(+), 195 deletions(-) delete mode 100644 test/cpp/util/fake_credentials.cc delete mode 100644 test/cpp/util/fake_credentials.h diff --git a/Makefile b/Makefile index 2ae0cd052df..b5fc9348063 100644 --- a/Makefile +++ b/Makefile @@ -4117,7 +4117,6 @@ LIBGRPC++_TEST_UTIL_SRC = \ $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \ test/cpp/util/cli_call.cc \ test/cpp/util/create_test_channel.cc \ - test/cpp/util/fake_credentials.cc \ test/cpp/util/subprocess.cc \ @@ -4164,7 +4163,6 @@ endif endif $(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/test/cpp/util/fake_credentials.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc diff --git a/build.json b/build.json index 2755703e1cf..e61dc67a68a 100644 --- a/build.json +++ b/build.json @@ -609,7 +609,6 @@ "headers": [ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.h", - "test/cpp/util/fake_credentials.h", "test/cpp/util/subprocess.h" ], "src": [ @@ -618,7 +617,6 @@ "test/cpp/util/echo_duplicate.proto", "test/cpp/util/cli_call.cc", "test/cpp/util/create_test_channel.cc", - "test/cpp/util/fake_credentials.cc", "test/cpp/util/subprocess.cc" ], "deps": [ diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 37d66c04ae5..18d9d2f899d 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -140,9 +140,6 @@ grpc_credentials *grpc_access_token_credentials_create( grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, const char *authority_selector); -/* Creates a fake transport security credentials object for testing. */ -grpc_credentials *grpc_fake_transport_security_credentials_create(void); - /* --- Secure channel creation. --- */ /* The caller of the secure_channel_create functions may override the target @@ -182,10 +179,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs); -/* Creates a fake server transport security credentials object for testing. */ -grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( - void); - /* --- Server-side secure ports. --- */ /* Add a HTTP2 over an encrypted link over tcp listener. @@ -206,7 +199,6 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call, /* TODO(jboeuf): Define some well-known property names. */ #define GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME "transport_security_type" -#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" #define GRPC_SSL_TRANSPORT_SECURITY_TYPE "ssl" #define GRPC_X509_CN_PROPERTY_NAME "x509_common_name" diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index d988901cf74..f5635122af2 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -52,6 +52,8 @@ typedef enum { GRPC_CREDENTIALS_ERROR } grpc_credentials_status; +#define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake" + #define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" #define GRPC_CREDENTIALS_TYPE_JWT "Jwt" @@ -112,6 +114,12 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); /* --- grpc_credentials. --- */ +/* Creates a fake transport security credentials object for testing. */ +grpc_credentials *grpc_fake_transport_security_credentials_create(void); +/* Creates a fake server transport security credentials object for testing. */ +grpc_server_credentials *grpc_fake_transport_security_server_credentials_create( + void); + /* It is the caller's responsibility to gpr_free the result if not NULL. */ char *grpc_get_well_known_google_credentials_file_path(void); diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc index 34872017ea1..d6cff0631d3 100644 --- a/src/node/ext/credentials.cc +++ b/src/node/ext/credentials.cc @@ -79,8 +79,6 @@ void Credentials::Init(Handle exports) { NanNew(CreateComposite)->GetFunction()); ctr->Set(NanNew("createGce"), NanNew(CreateGce)->GetFunction()); - ctr->Set(NanNew("createFake"), - NanNew(CreateFake)->GetFunction()); ctr->Set(NanNew("createIam"), NanNew(CreateIam)->GetFunction()); constructor = new NanCallback(ctr); @@ -180,11 +178,6 @@ NAN_METHOD(Credentials::CreateGce) { NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create())); } -NAN_METHOD(Credentials::CreateFake) { - NanScope(); - NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create())); -} - NAN_METHOD(Credentials::CreateIam) { NanScope(); if (!args[0]->IsString()) { diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c index a262b9981f5..3e781d4747a 100644 --- a/src/php/ext/grpc/credentials.c +++ b/src/php/ext/grpc/credentials.c @@ -175,15 +175,6 @@ PHP_METHOD(Credentials, createGce) { RETURN_DESTROY_ZVAL(creds_object); } -/** - * Create fake credentials. Only to be used for testing. - * @return Credentials The new fake credentials object - */ -PHP_METHOD(Credentials, createFake) { - grpc_credentials *creds = grpc_fake_transport_security_credentials_create(); - zval *creds_object = grpc_php_wrap_credentials(creds); - RETURN_DESTROY_ZVAL(creds_object); -} static zend_function_entry credentials_methods[] = { PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) @@ -191,7 +182,6 @@ static zend_function_entry credentials_methods[] = { PHP_ME(Credentials, createComposite, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(Credentials, createFake, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END}; void grpc_init_credentials(TSRMLS_D) { diff --git a/src/python/src/grpc/_adapter/_c/types/client_credentials.c b/src/python/src/grpc/_adapter/_c/types/client_credentials.c index 6a4561c0606..6e1a3e6f303 100644 --- a/src/python/src/grpc/_adapter/_c/types/client_credentials.c +++ b/src/python/src/grpc/_adapter/_c/types/client_credentials.c @@ -54,9 +54,6 @@ PyMethodDef pygrpc_ClientCredentials_methods[] = { METH_CLASS|METH_KEYWORDS, ""}, {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token, METH_CLASS|METH_KEYWORDS, ""}, - {"fake_transport_security", - (PyCFunction)pygrpc_ClientCredentials_fake_transport_security, - METH_CLASS|METH_NOARGS, ""}, {"iam", (PyCFunction)pygrpc_ClientCredentials_iam, METH_CLASS|METH_KEYWORDS, ""}, {NULL} @@ -249,20 +246,6 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token( return self; } -ClientCredentials *pygrpc_ClientCredentials_fake_transport_security( - PyTypeObject *type, PyObject *ignored) { - ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_fake_transport_security_credentials_create(); - if (!self->c_creds) { - Py_DECREF(self); - PyErr_SetString(PyExc_RuntimeError, - "couldn't create fake credentials; " - "something is horribly wrong with the universe"); - return NULL; - } - return self; -} - ClientCredentials *pygrpc_ClientCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx index c14d8844ddd..14e7ce84c01 100644 --- a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx +++ b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx @@ -152,12 +152,6 @@ def client_credentials_refresh_token(json_refresh_token): credentials.references.append(json_refresh_token) return credentials -def client_credentials_fake_transport_security(): - cdef ClientCredentials credentials = ClientCredentials() - credentials.c_credentials = ( - grpc.grpc_fake_transport_security_credentials_create()) - return credentials - def client_credentials_iam(authorization_token, authority_selector): if isinstance(authorization_token, bytes): pass @@ -210,8 +204,3 @@ def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs): ) return credentials -def server_credentials_fake_transport_security(): - cdef ServerCredentials credentials = ServerCredentials() - credentials.c_credentials = ( - grpc.grpc_fake_transport_security_server_credentials_create()) - return credentials diff --git a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd index 7db8fbe31c1..7f361362502 100644 --- a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd @@ -317,7 +317,6 @@ cdef extern from "grpc/grpc_security.h": gpr_timespec token_lifetime) grpc_credentials *grpc_refresh_token_credentials_create( const char *json_refresh_token) - grpc_credentials *grpc_fake_transport_security_credentials_create() grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, const char *authority_selector) void grpc_credentials_release(grpc_credentials *creds) @@ -334,7 +333,6 @@ cdef extern from "grpc/grpc_security.h": const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs); - grpc_server_credentials *grpc_fake_transport_security_server_credentials_create() void grpc_server_credentials_release(grpc_server_credentials *creds) int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 8b4424c7353..fc6b54305c6 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -35,11 +35,11 @@ #include #include "src/core/security/credentials.h" +#include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/util/echo_duplicate.grpc.pb.h" #include "test/cpp/util/echo.grpc.pb.h" -#include "test/cpp/util/fake_credentials.h" #include #include #include @@ -83,13 +83,12 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request, } } -template -void CheckAuthContext(T* context) { +void CheckServerAuthContext(const ServerContext* context) { std::shared_ptr auth_ctx = context->auth_context(); - std::vector fake = + std::vector ssl = auth_ctx->FindPropertyValues("transport_security_type"); - EXPECT_EQ(1u, fake.size()); - EXPECT_EQ("fake", fake[0]); + EXPECT_EQ(1u, ssl.size()); + EXPECT_EQ("ssl", ssl[0]); EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty()); EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty()); } @@ -142,7 +141,7 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { } } if (request->has_param() && request->param().check_auth_context()) { - CheckAuthContext(context); + CheckServerAuthContext(context); } return Status::OK; } @@ -235,10 +234,15 @@ class End2endTest : public ::testing::Test { server_address_ << "localhost:" << port; // Setup server ServerBuilder builder; + SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, + test_server1_cert}; + SslServerCredentialsOptions ssl_opts; + ssl_opts.pem_root_certs = ""; + ssl_opts.pem_key_cert_pairs.push_back(pkcp); builder.AddListeningPort(server_address_.str(), - FakeTransportSecurityServerCredentials()); + SslServerCredentials(ssl_opts)); builder.RegisterService(&service_); - builder.RegisterService("special", &special_service_); + builder.RegisterService("foo.test.youtube.com", &special_service_); builder.SetMaxMessageSize( kMaxMessageSize_); // For testing max message size. builder.RegisterService(&dup_pkg_service_); @@ -249,12 +253,15 @@ class End2endTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), FakeTransportSecurityCredentials(), - ChannelArguments()); - stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); + SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; + ChannelArguments args; + args.SetSslTargetNameOverride("foo.test.google.fr"); + channel_ = CreateChannel(server_address_.str(), SslCredentials(ssl_opts), + args); + stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } + std::shared_ptr channel_; std::unique_ptr stub_; std::unique_ptr server_; std::ostringstream server_address_; @@ -288,11 +295,11 @@ TEST_F(End2endTest, SimpleRpcWithHost) { request.set_message("Hello"); ClientContext context; - context.set_authority("special"); + context.set_authority("foo.test.youtube.com"); Status s = stub_->Echo(&context, request, &response); EXPECT_EQ(response.message(), request.message()); EXPECT_TRUE(response.has_param()); - EXPECT_EQ(response.param().host(), "special"); + EXPECT_EQ("special", response.param().host()); EXPECT_TRUE(s.ok()); } @@ -481,24 +488,19 @@ TEST_F(End2endTest, BidiStream) { // Talk to the two services with the same name but different package names. // The two stubs are created on the same channel. TEST_F(End2endTest, DiffPackageServices) { - std::shared_ptr channel = - CreateChannel(server_address_.str(), FakeTransportSecurityCredentials(), - ChannelArguments()); - + ResetStub(); EchoRequest request; EchoResponse response; request.set_message("Hello"); - std::unique_ptr stub( - grpc::cpp::test::util::TestService::NewStub(channel)); ClientContext context; - Status s = stub->Echo(&context, request, &response); + Status s = stub_->Echo(&context, request, &response); EXPECT_EQ(response.message(), request.message()); EXPECT_TRUE(s.ok()); std::unique_ptr dup_pkg_stub( - grpc::cpp::test::util::duplicate::TestService::NewStub(channel)); + grpc::cpp::test::util::duplicate::TestService::NewStub(channel_)); ClientContext context2; s = dup_pkg_stub->Echo(&context2, request, &response); EXPECT_EQ("no package", response.message()); @@ -782,7 +784,17 @@ TEST_F(End2endTest, ClientAuthContext) { EXPECT_EQ(response.message(), request.message()); EXPECT_TRUE(s.ok()); - CheckAuthContext(&context); + std::shared_ptr auth_ctx = context.auth_context(); + std::vector ssl = + auth_ctx->FindPropertyValues("transport_security_type"); + EXPECT_EQ(1u, ssl.size()); + EXPECT_EQ("ssl", ssl[0]); + EXPECT_EQ("x509_subject_alternative_name", + auth_ctx->GetPeerIdentityPropertyName()); + EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size()); + EXPECT_EQ("*.test.google.fr", auth_ctx->GetPeerIdentity()[0]); + EXPECT_EQ("waterzooi.test.google.be", auth_ctx->GetPeerIdentity()[1]); + EXPECT_EQ("*.test.youtube.com", auth_ctx->GetPeerIdentity()[2]); } } // namespace testing diff --git a/test/cpp/util/fake_credentials.cc b/test/cpp/util/fake_credentials.cc deleted file mode 100644 index f5b83b8159f..00000000000 --- a/test/cpp/util/fake_credentials.cc +++ /dev/null @@ -1,58 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include "src/cpp/client/channel.h" -#include "src/cpp/client/secure_credentials.h" -#include "src/cpp/server/secure_server_credentials.h" - -namespace grpc { -namespace testing { - -std::shared_ptr FakeTransportSecurityCredentials() { - grpc_credentials* c_creds = grpc_fake_transport_security_credentials_create(); - return std::shared_ptr(new SecureCredentials(c_creds)); -} - -std::shared_ptr FakeTransportSecurityServerCredentials() { - grpc_server_credentials* c_creds = - grpc_fake_transport_security_server_credentials_create(); - return std::shared_ptr( - new SecureServerCredentials(c_creds)); -} - -} // namespace testing -} // namespace grpc diff --git a/test/cpp/util/fake_credentials.h b/test/cpp/util/fake_credentials.h deleted file mode 100644 index e1ba7bb9e4a..00000000000 --- a/test/cpp/util/fake_credentials.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H -#define GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H - -#include - -namespace grpc { -class Credentials; -class ServerCredentials; - -namespace testing { - -std::shared_ptr FakeTransportSecurityCredentials(); -std::shared_ptr FakeTransportSecurityServerCredentials(); - -} // namespace testing -} // namespace grpc - -#endif // GRPC_TEST_CPP_UTIL_FAKE_CREDENTIALS_H diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index abddaab6994..15f66396620 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -10783,7 +10783,6 @@ "test/cpp/util/echo.pb.h", "test/cpp/util/echo_duplicate.grpc.pb.h", "test/cpp/util/echo_duplicate.pb.h", - "test/cpp/util/fake_credentials.h", "test/cpp/util/messages.grpc.pb.h", "test/cpp/util/messages.pb.h", "test/cpp/util/subprocess.h" @@ -10795,8 +10794,6 @@ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.cc", "test/cpp/util/create_test_channel.h", - "test/cpp/util/fake_credentials.cc", - "test/cpp/util/fake_credentials.h", "test/cpp/util/subprocess.cc", "test/cpp/util/subprocess.h" ] From 52e4de1ea1b2c9b07d53b557bef943d507f5d9c9 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 22 Jul 2015 10:33:18 -0700 Subject: [PATCH 03/47] Fix node test. Remove all the server fake credentials references --- src/node/ext/server_credentials.cc | 8 -------- src/node/ext/server_credentials.h | 1 - src/node/test/server_test.js | 10 ++++++++-- src/php/ext/grpc/credentials.c | 1 - src/php/ext/grpc/server_credentials.c | 13 ------------- src/python/src/grpc/_adapter/_c/types.h | 4 ---- .../grpc/_adapter/_c/types/server_credentials.c | 10 ---------- src/python/src/grpc/_adapter/_c_test.py | 12 ------------ src/python/src/grpc/_cython/adapter_low.py | 8 -------- src/python/src/grpc/_cython/cygrpc.pyx | 4 ---- src/python/src/grpc/_cython/cygrpc_test.py | 14 -------------- 11 files changed, 8 insertions(+), 77 deletions(-) diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc index d2b63cdc4ec..66aaa3300fc 100644 --- a/src/node/ext/server_credentials.cc +++ b/src/node/ext/server_credentials.cc @@ -73,8 +73,6 @@ void ServerCredentials::Init(Handle exports) { Handle ctr = tpl->GetFunction(); ctr->Set(NanNew("createSsl"), NanNew(CreateSsl)->GetFunction()); - ctr->Set(NanNew("createFake"), - NanNew(CreateFake)->GetFunction()); constructor = new NanCallback(ctr); exports->Set(NanNew("ServerCredentials"), ctr); } @@ -144,11 +142,5 @@ NAN_METHOD(ServerCredentials::CreateSsl) { grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1))); } -NAN_METHOD(ServerCredentials::CreateFake) { - NanScope(); - NanReturnValue( - WrapStruct(grpc_fake_transport_security_server_credentials_create())); -} - } // namespace node } // namespace grpc diff --git a/src/node/ext/server_credentials.h b/src/node/ext/server_credentials.h index aaa7ef297a4..80747504a14 100644 --- a/src/node/ext/server_credentials.h +++ b/src/node/ext/server_credentials.h @@ -63,7 +63,6 @@ class ServerCredentials : public ::node::ObjectWrap { static NAN_METHOD(New); static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateFake); static NanCallback *constructor; // Used for typechecking instances of this javascript class static v8::Persistent fun_tpl; diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js index 7cb34fa0cb5..9c7bb465aa3 100644 --- a/src/node/test/server_test.js +++ b/src/node/test/server_test.js @@ -34,6 +34,8 @@ 'use strict'; var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); var grpc = require('bindings')('grpc.node'); describe('server', function() { @@ -67,9 +69,13 @@ describe('server', function() { before(function() { server = new grpc.Server(); }); - it('should bind to an unused port with fake credentials', function() { + it('should bind to an unused port with ssl credentials', function() { var port; - var creds = grpc.ServerCredentials.createFake(); + var key_path = path.join(__dirname, '../test/data/server1.key'); + var pem_path = path.join(__dirname, '../test/data/server1.pem'); + var key_data = fs.readFileSync(key_path); + var pem_data = fs.readFileSync(pem_path); + var creds = grpc.ServerCredentials.createSsl(null, key_data, pem_data); assert.doesNotThrow(function() { port = server.addSecureHttp2Port('0.0.0.0:0', creds); }); diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c index 3e781d4747a..01cb94e3aa1 100644 --- a/src/php/ext/grpc/credentials.c +++ b/src/php/ext/grpc/credentials.c @@ -175,7 +175,6 @@ PHP_METHOD(Credentials, createGce) { RETURN_DESTROY_ZVAL(creds_object); } - static zend_function_entry credentials_methods[] = { PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c index c4c1fabb1a5..4c4a598cb0c 100644 --- a/src/php/ext/grpc/server_credentials.c +++ b/src/php/ext/grpc/server_credentials.c @@ -121,21 +121,8 @@ PHP_METHOD(ServerCredentials, createSsl) { RETURN_DESTROY_ZVAL(creds_object); } -/** - * Create fake credentials. Only to be used for testing. - * @return ServerCredentials The new fake credentials object - */ -PHP_METHOD(ServerCredentials, createFake) { - grpc_server_credentials *creds = - grpc_fake_transport_security_server_credentials_create(); - zval *creds_object = grpc_php_wrap_server_credentials(creds); - RETURN_DESTROY_ZVAL(creds_object); -} - static zend_function_entry server_credentials_methods[] = { PHP_ME(ServerCredentials, createSsl, NULL, - ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) - PHP_ME(ServerCredentials, createFake, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END}; void grpc_init_server_credentials(TSRMLS_D) { diff --git a/src/python/src/grpc/_adapter/_c/types.h b/src/python/src/grpc/_adapter/_c/types.h index 3449f0643f7..4e0da4a28a9 100644 --- a/src/python/src/grpc/_adapter/_c/types.h +++ b/src/python/src/grpc/_adapter/_c/types.h @@ -63,8 +63,6 @@ ClientCredentials *pygrpc_ClientCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs); ClientCredentials *pygrpc_ClientCredentials_refresh_token( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ClientCredentials *pygrpc_ClientCredentials_fake_transport_security( - PyTypeObject *type, PyObject *ignored); ClientCredentials *pygrpc_ClientCredentials_iam( PyTypeObject *type, PyObject *args, PyObject *kwargs); extern PyTypeObject pygrpc_ClientCredentials_type; @@ -81,8 +79,6 @@ typedef struct ServerCredentials { void pygrpc_ServerCredentials_dealloc(ServerCredentials *self); ServerCredentials *pygrpc_ServerCredentials_ssl( PyTypeObject *type, PyObject *args, PyObject *kwargs); -ServerCredentials *pygrpc_ServerCredentials_fake_transport_security( - PyTypeObject *type, PyObject *ignored); extern PyTypeObject pygrpc_ServerCredentials_type; diff --git a/src/python/src/grpc/_adapter/_c/types/server_credentials.c b/src/python/src/grpc/_adapter/_c/types/server_credentials.c index 2e02c8fe816..f22edbf1872 100644 --- a/src/python/src/grpc/_adapter/_c/types/server_credentials.c +++ b/src/python/src/grpc/_adapter/_c/types/server_credentials.c @@ -43,9 +43,6 @@ PyMethodDef pygrpc_ServerCredentials_methods[] = { {"ssl", (PyCFunction)pygrpc_ServerCredentials_ssl, METH_CLASS|METH_KEYWORDS, ""}, - {"fake_transport_security", - (PyCFunction)pygrpc_ServerCredentials_fake_transport_security, - METH_CLASS|METH_NOARGS, ""}, {NULL} }; const char pygrpc_ServerCredentials_doc[] = ""; @@ -137,10 +134,3 @@ ServerCredentials *pygrpc_ServerCredentials_ssl( return self; } -ServerCredentials *pygrpc_ServerCredentials_fake_transport_security( - PyTypeObject *type, PyObject *ignored) { - ServerCredentials *self = (ServerCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_fake_transport_security_server_credentials_create(); - return self; -} - diff --git a/src/python/src/grpc/_adapter/_c_test.py b/src/python/src/grpc/_adapter/_c_test.py index 133b124072c..fe020e2a9cf 100644 --- a/src/python/src/grpc/_adapter/_c_test.py +++ b/src/python/src/grpc/_adapter/_c_test.py @@ -36,14 +36,6 @@ from grpc._adapter import _types class CTypeSmokeTest(unittest.TestCase): - def testClientCredentialsUpDown(self): - credentials = _c.ClientCredentials.fake_transport_security() - del credentials - - def testServerCredentialsUpDown(self): - credentials = _c.ServerCredentials.fake_transport_security() - del credentials - def testCompletionQueueUpDown(self): completion_queue = _c.CompletionQueue() del completion_queue @@ -58,10 +50,6 @@ class CTypeSmokeTest(unittest.TestCase): channel = _c.Channel('[::]:0', []) del channel - def testSecureChannelUpDown(self): - channel = _c.Channel('[::]:0', [], _c.ClientCredentials.fake_transport_security()) - del channel - if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/python/src/grpc/_cython/adapter_low.py b/src/python/src/grpc/_cython/adapter_low.py index 7546dd15992..2bb468eece8 100644 --- a/src/python/src/grpc/_cython/adapter_low.py +++ b/src/python/src/grpc/_cython/adapter_low.py @@ -71,10 +71,6 @@ class ClientCredentials(object): def refresh_token(): raise NotImplementedError() - @staticmethod - def fake_transport_security(): - raise NotImplementedError() - @staticmethod def iam(): raise NotImplementedError() @@ -88,10 +84,6 @@ class ServerCredentials(object): def ssl(): raise NotImplementedError() - @staticmethod - def fake_transport_security(): - raise NotImplementedError() - class CompletionQueue(type_interfaces.CompletionQueue): def __init__(self): diff --git a/src/python/src/grpc/_cython/cygrpc.pyx b/src/python/src/grpc/_cython/cygrpc.pyx index dcb06f345c7..f4d9661580b 100644 --- a/src/python/src/grpc/_cython/cygrpc.pyx +++ b/src/python/src/grpc/_cython/cygrpc.pyx @@ -82,12 +82,8 @@ client_credentials_compute_engine = ( credentials.client_credentials_compute_engine) client_credentials_jwt = credentials.client_credentials_jwt client_credentials_refresh_token = credentials.client_credentials_refresh_token -client_credentials_fake_transport_security = ( - credentials.client_credentials_fake_transport_security) client_credentials_iam = credentials.client_credentials_iam server_credentials_ssl = credentials.server_credentials_ssl -server_credentials_fake_transport_security = ( - credentials.server_credentials_fake_transport_security) CompletionQueue = completion_queue.CompletionQueue Channel = channel.Channel diff --git a/src/python/src/grpc/_cython/cygrpc_test.py b/src/python/src/grpc/_cython/cygrpc_test.py index 838e1e22548..22d210b16b5 100644 --- a/src/python/src/grpc/_cython/cygrpc_test.py +++ b/src/python/src/grpc/_cython/cygrpc_test.py @@ -76,14 +76,6 @@ class TypeSmokeTest(unittest.TestCase): timespec = cygrpc.Timespec(now) self.assertAlmostEqual(now, float(timespec), places=8) - def testClientCredentialsUpDown(self): - credentials = cygrpc.client_credentials_fake_transport_security() - del credentials - - def testServerCredentialsUpDown(self): - credentials = cygrpc.server_credentials_fake_transport_security() - del credentials - def testCompletionQueueUpDown(self): completion_queue = cygrpc.CompletionQueue() del completion_queue @@ -96,12 +88,6 @@ class TypeSmokeTest(unittest.TestCase): channel = cygrpc.Channel('[::]:0', cygrpc.ChannelArgs([])) del channel - def testSecureChannelUpDown(self): - channel = cygrpc.Channel( - '[::]:0', cygrpc.ChannelArgs([]), - cygrpc.client_credentials_fake_transport_security()) - del channel - @unittest.skip('TODO(atash): undo skip after #2229 is merged') def testServerStartNoExplicitShutdown(self): server = cygrpc.Server() From fe4c3f4f1436e2fc2297d5544859ce14e03659bf Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Wed, 22 Jul 2015 16:20:13 -0700 Subject: [PATCH 04/47] Renaming jwt_credentials to service_account_jwt_access_credentials. --- include/grpc++/credentials.h | 6 ++--- include/grpc/grpc_security.h | 4 ++-- src/core/security/credentials.c | 23 +++++++++++-------- src/core/security/credentials.h | 5 ++-- .../security/google_default_credentials.c | 5 ++-- src/cpp/client/secure_credentials.cc | 8 +++---- .../_adapter/_c/types/client_credentials.c | 3 ++- .../src/grpc/_cython/_cygrpc/credentials.pyx | 3 ++- src/python/src/grpc/_cython/_cygrpc/grpc.pxd | 2 +- test/core/security/credentials_test.c | 14 ++++++----- test/cpp/interop/client_helper.cc | 3 ++- 11 files changed, 43 insertions(+), 33 deletions(-) diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h index 0eaaefcbcae..a4f1e731185 100644 --- a/include/grpc++/credentials.h +++ b/include/grpc++/credentials.h @@ -106,13 +106,13 @@ std::shared_ptr ServiceAccountCredentials( const grpc::string& json_key, const grpc::string& scope, long token_lifetime_seconds); -// Builds JWT credentials. +// Builds Service Account JWT Access credentials. // json_key is the JSON key string containing the client's private key. // token_lifetime_seconds is the lifetime in seconds of each Json Web Token // (JWT) created with this credentials. It should not exceed // grpc_max_auth_token_lifetime or will be cropped to this value. -std::shared_ptr JWTCredentials(const grpc::string& json_key, - long token_lifetime_seconds); +std::shared_ptr ServiceAccountJWTAccessCredentials( + const grpc::string& json_key, long token_lifetime_seconds); // Builds refresh token credentials. // json_refresh_token is the JSON string containing the refresh token along diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 37d66c04ae5..4dd058063dc 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -119,8 +119,8 @@ grpc_credentials *grpc_service_account_credentials_create( - token_lifetime is the lifetime of each Json Web Token (JWT) created with this credentials. It should not exceed grpc_max_auth_token_lifetime or will be cropped to this value. */ -grpc_credentials *grpc_jwt_credentials_create(const char *json_key, - gpr_timespec token_lifetime); +grpc_credentials *grpc_service_account_jwt_access_credentials_create( + const char *json_key, gpr_timespec token_lifetime); /* Creates an Oauth2 Refresh Token credentials object. May return NULL if the input is invalid. diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index fb59fa4b0e5..38612cf308e 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -315,7 +315,7 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( /* -- Jwt credentials -- */ -static void jwt_reset_cache(grpc_jwt_credentials *c) { +static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) { if (c->cached.jwt_md != NULL) { grpc_credentials_md_store_unref(c->cached.jwt_md); c->cached.jwt_md = NULL; @@ -328,7 +328,8 @@ static void jwt_reset_cache(grpc_jwt_credentials *c) { } static void jwt_destroy(grpc_credentials *creds) { - grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; + grpc_service_account_jwt_access_credentials *c = + (grpc_service_account_jwt_access_credentials *)creds; grpc_auth_json_key_destruct(&c->key); jwt_reset_cache(c); gpr_mu_destroy(&c->cache_mu); @@ -346,7 +347,8 @@ static void jwt_get_request_metadata(grpc_credentials *creds, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { - grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; + grpc_service_account_jwt_access_credentials *c = + (grpc_service_account_jwt_access_credentials *)creds; gpr_timespec refresh_threshold = gpr_time_from_seconds( GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN); @@ -399,15 +401,16 @@ static grpc_credentials_vtable jwt_vtable = { jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, jwt_get_request_metadata, NULL}; -grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key( +grpc_credentials * +grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime) { - grpc_jwt_credentials *c; + grpc_service_account_jwt_access_credentials *c; if (!grpc_auth_json_key_is_valid(&key)) { gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); return NULL; } - c = gpr_malloc(sizeof(grpc_jwt_credentials)); - memset(c, 0, sizeof(grpc_jwt_credentials)); + c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials)); + memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_JWT; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &jwt_vtable; @@ -418,9 +421,9 @@ grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key( return &c->base; } -grpc_credentials *grpc_jwt_credentials_create(const char *json_key, - gpr_timespec token_lifetime) { - return grpc_jwt_credentials_create_from_auth_json_key( +grpc_credentials *grpc_service_account_jwt_access_credentials_create( + const char *json_key, gpr_timespec token_lifetime) { + return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key_create_from_string(json_key), token_lifetime); } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index d988901cf74..7f4141967d4 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -188,7 +188,8 @@ grpc_credentials *grpc_fake_oauth2_credentials_create( /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ -grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key( +grpc_credentials * +grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key key, gpr_timespec token_lifetime); /* Private constructor for refresh token credentials from an already parsed @@ -240,7 +241,7 @@ typedef struct { grpc_auth_json_key key; gpr_timespec jwt_lifetime; -} grpc_jwt_credentials; +} grpc_service_account_jwt_access_credentials; /* -- Oauth2TokenFetcher credentials -- diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index 833484310f2..de1929fe763 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -140,8 +140,9 @@ static grpc_credentials *create_default_creds_from_path(char *creds_path) { /* First, try an auth json key. */ key = grpc_auth_json_key_create_from_json(json); if (grpc_auth_json_key_is_valid(&key)) { - result = grpc_jwt_credentials_create_from_auth_json_key( - key, grpc_max_auth_token_lifetime); + result = + grpc_service_account_jwt_access_credentials_create_from_auth_json_key( + key, grpc_max_auth_token_lifetime); goto end; } diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 01c7f14f1a0..abf0cb387e3 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -99,8 +99,8 @@ std::shared_ptr ServiceAccountCredentials( } // Builds JWT credentials. -std::shared_ptr JWTCredentials(const grpc::string& json_key, - long token_lifetime_seconds) { +std::shared_ptr ServiceAccountJWTAccessCredentials( + const grpc::string& json_key, long token_lifetime_seconds) { if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create JWTCredentials with non-positive lifetime"); @@ -108,8 +108,8 @@ std::shared_ptr JWTCredentials(const grpc::string& json_key, } gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN); - return WrapCredentials( - grpc_jwt_credentials_create(json_key.c_str(), lifetime)); + return WrapCredentials(grpc_service_account_jwt_access_credentials_create( + json_key.c_str(), lifetime)); } // Builds refresh token credentials. diff --git a/src/python/src/grpc/_adapter/_c/types/client_credentials.c b/src/python/src/grpc/_adapter/_c/types/client_credentials.c index 6a4561c0606..9ea2b39cad7 100644 --- a/src/python/src/grpc/_adapter/_c/types/client_credentials.c +++ b/src/python/src/grpc/_adapter/_c/types/client_credentials.c @@ -208,6 +208,7 @@ ClientCredentials *pygrpc_ClientCredentials_service_account( return self; } +/* TODO: Rename this credentials to something like service_account_jwt_access */ ClientCredentials *pygrpc_ClientCredentials_jwt( PyTypeObject *type, PyObject *args, PyObject *kwargs) { ClientCredentials *self; @@ -219,7 +220,7 @@ ClientCredentials *pygrpc_ClientCredentials_jwt( return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_jwt_credentials_create( + self->c_creds = grpc_service_account_jwt_access_credentials_create( json_key, pygrpc_cast_double_to_gpr_timespec(lifetime)); if (!self->c_creds) { Py_DECREF(self); diff --git a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx index c14d8844ddd..7bb3f798b21 100644 --- a/src/python/src/grpc/_cython/_cygrpc/credentials.pyx +++ b/src/python/src/grpc/_cython/_cygrpc/credentials.pyx @@ -126,6 +126,7 @@ def client_credentials_service_account( credentials.references.extend([json_key, scope]) return credentials +#TODO rename to something like client_credentials_service_account_jwt_access. def client_credentials_jwt(json_key, records.Timespec token_lifetime not None): if isinstance(json_key, bytes): pass @@ -134,7 +135,7 @@ def client_credentials_jwt(json_key, records.Timespec token_lifetime not None): else: raise TypeError("expected json_key to be str or bytes") cdef ClientCredentials credentials = ClientCredentials() - credentials.c_credentials = grpc.grpc_jwt_credentials_create( + credentials.c_credentials = grpc.grpc_service_account_jwt_access_credentials_create( json_key, token_lifetime.c_time) credentials.references.append(json_key) return credentials diff --git a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd index 7db8fbe31c1..a76ddfc9e1f 100644 --- a/src/python/src/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/src/grpc/_cython/_cygrpc/grpc.pxd @@ -313,7 +313,7 @@ cdef extern from "grpc/grpc_security.h": grpc_credentials *grpc_compute_engine_credentials_create() grpc_credentials *grpc_service_account_credentials_create( const char *json_key, const char *scope, gpr_timespec token_lifetime) - grpc_credentials *grpc_jwt_credentials_create(const char *json_key, + grpc_credentials *grpc_service_account_jwt_access_credentials_create(const char *json_key, gpr_timespec token_lifetime) grpc_credentials *grpc_refresh_token_credentials_create( const char *json_refresh_token) diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index d3fea9680a3..dd6e0d7bb3c 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -826,8 +826,9 @@ static void on_jwt_creds_get_metadata_failure(void *user_data, static void test_jwt_creds_success(void) { char *json_key_string = test_json_key_str(); - grpc_credentials *jwt_creds = grpc_jwt_credentials_create( - json_key_string, grpc_max_auth_token_lifetime); + grpc_credentials *jwt_creds = + grpc_service_account_jwt_access_credentials_create( + json_key_string, grpc_max_auth_token_lifetime); GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); @@ -858,8 +859,9 @@ static void test_jwt_creds_success(void) { static void test_jwt_creds_signing_failure(void) { char *json_key_string = test_json_key_str(); - grpc_credentials *jwt_creds = grpc_jwt_credentials_create( - json_key_string, grpc_max_auth_token_lifetime); + grpc_credentials *jwt_creds = + grpc_service_account_jwt_access_credentials_create( + json_key_string, grpc_max_auth_token_lifetime); GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); @@ -900,7 +902,7 @@ static grpc_credentials *composite_inner_creds(grpc_credentials *creds, } static void test_google_default_creds_auth_key(void) { - grpc_jwt_credentials *jwt; + grpc_service_account_jwt_access_credentials *jwt; grpc_credentials *creds; char *json_key = test_json_key_str(); grpc_flush_cached_google_default_credentials(); @@ -909,7 +911,7 @@ static void test_google_default_creds_auth_key(void) { gpr_free(json_key); creds = grpc_google_default_credentials_create(); GPR_ASSERT(creds != NULL); - jwt = (grpc_jwt_credentials *)composite_inner_creds( + jwt = (grpc_service_account_jwt_access_credentials *)composite_inner_creds( creds, GRPC_CREDENTIALS_TYPE_JWT); GPR_ASSERT( strcmp(jwt->key.client_id, diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc index 48b1b2e864f..73d82f7b888 100644 --- a/test/cpp/interop/client_helper.cc +++ b/test/cpp/interop/client_helper.cc @@ -123,7 +123,8 @@ std::shared_ptr CreateChannelForTestCase( GPR_ASSERT(FLAGS_enable_ssl); grpc::string json_key = GetServiceAccountJsonKey(); std::chrono::seconds token_lifetime = std::chrono::hours(1); - creds = JWTCredentials(json_key, token_lifetime.count()); + creds = + ServiceAccountJWTAccessCredentials(json_key, token_lifetime.count()); return CreateTestChannel(host_port, FLAGS_server_host_override, FLAGS_enable_ssl, FLAGS_use_prod_roots, creds); } else if (test_case == "oauth2_auth_token") { From 39ae034403ee043ca0c67b1f5aac0ed44a529fad Mon Sep 17 00:00:00 2001 From: Jeff Peoples Date: Wed, 22 Jul 2015 16:40:52 -0700 Subject: [PATCH 05/47] Update README.md --- src/node/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/README.md b/src/node/README.md index 78781dab147..7d3d8c7fa10 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -85,7 +85,7 @@ An object with factory methods for creating credential objects for clients. ServerCredentials ``` -An object with factory methods fro creating credential objects for servers. +An object with factory methods for creating credential objects for servers. [homebrew]:http://brew.sh [linuxbrew]:https://github.com/Homebrew/linuxbrew#installation From 9835a136280e8debc8d61008b2c78bea45b2ff5b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Wed, 22 Jul 2015 17:37:39 -0700 Subject: [PATCH 06/47] Handle a race where a new call comes in post-shutdown a little better --- src/core/surface/server.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 439452aea27..ce8b2af9c45 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -400,6 +400,15 @@ static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem, call_data *calld = elem->call_data; int request_id; + if (gpr_atm_acq_load(&server->shutdown_flag)) { + gpr_mu_lock(&calld->mu_state); + calld->state = ZOMBIED; + gpr_mu_unlock(&calld->mu_state); + grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem); + grpc_iomgr_add_callback(&calld->kill_zombie_closure); + return; + } + request_id = gpr_stack_lockfree_pop(request_matcher->requests); if (request_id == -1) { gpr_mu_lock(&server->mu_call); From 6f30decf79da066bb199163a820a31fb057c0157 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 22 Jul 2015 23:11:56 -0700 Subject: [PATCH 07/47] Flow control fix --- src/core/transport/chttp2/writing.c | 3 ++- test/cpp/end2end/end2end_test.cc | 20 ++++++++++++++++++++ test/cpp/util/messages.proto | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index d8ec117aa5d..041c4efd1f5 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -66,7 +66,8 @@ int grpc_chttp2_unlocking_check_writes( /* for each grpc_chttp2_stream that's become writable, frame it's data (according to available window sizes) and add to the output buffer */ - while (grpc_chttp2_list_pop_writable_stream(transport_global, + while (transport_global->outgoing_window > 0 && + grpc_chttp2_list_pop_writable_stream(transport_global, transport_writing, &stream_global, &stream_writing)) { stream_writing->id = stream_global->id; diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 20e4c4ed55b..c433b789482 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -144,6 +144,11 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { if (request->has_param() && request->param().check_auth_context()) { CheckAuthContext(context); } + if (request->has_param() && + request->param().response_message_length() > 0) { + response->set_message( + grpc::string(request->param().response_message_length(), '\0')); + } return Status::OK; } @@ -786,6 +791,21 @@ TEST_F(End2endTest, ClientAuthContext) { CheckAuthContext(&context); } +// Make the response larger than the flow control window. +TEST_F(End2endTest, HugeResponse) { + ResetStub(); + EchoRequest request; + EchoResponse response; + request.set_message("huge response"); + const int kResponseSize = 1024 * (1024 + 10); + request.mutable_param()->set_response_message_length(kResponseSize); + + ClientContext context; + Status s = stub_->Echo(&context, request, &response); + EXPECT_EQ(kResponseSize, response.message().size()); + EXPECT_TRUE(s.ok()); +} + } // namespace testing } // namespace grpc diff --git a/test/cpp/util/messages.proto b/test/cpp/util/messages.proto index 3708972b905..2fad8b42a21 100644 --- a/test/cpp/util/messages.proto +++ b/test/cpp/util/messages.proto @@ -38,6 +38,7 @@ message RequestParams { optional int32 server_cancel_after_us = 3; optional bool echo_metadata = 4; optional bool check_auth_context = 5; + optional int32 response_message_length = 6; } message EchoRequest { From 94329d09656f3eeb8eee40b72b96ec9cd3578559 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Jul 2015 09:52:11 -0700 Subject: [PATCH 08/47] Make the server report monotonic times for deadlines For very high performance systems, we're going to want to be able to simply push the value reported from the server down onto clients. If we report realtime now, then all wrapped languages are going to assume it, meaning that such a change will be impossible later. --- src/core/surface/call.c | 3 ++- src/core/surface/server.c | 6 ++++-- src/core/transport/chttp2/parsing.c | 2 +- src/cpp/util/time.cc | 3 ++- src/node/ext/timeval.cc | 1 + src/python/src/grpc/_adapter/_c/utility.c | 1 + src/ruby/ext/grpc/rb_grpc.c | 6 ++++-- src/ruby/ext/grpc/rb_server.c | 13 ++++++------- 8 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/core/surface/call.c b/src/core/surface/call.c index e08273e451c..1f73f9cf717 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -1368,7 +1368,8 @@ static void recv_metadata(grpc_call *call, grpc_metadata_batch *md) { l->md = 0; } } - if (gpr_time_cmp(md->deadline, gpr_inf_future(GPR_CLOCK_REALTIME)) != 0) { + if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) != + 0) { set_deadline_alarm(call, md->deadline); } if (!is_trailing) { diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 439452aea27..a0d4ab3b0a1 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -530,6 +530,7 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) { static void server_on_recv(void *ptr, int success) { grpc_call_element *elem = ptr; call_data *calld = elem->call_data; + gpr_timespec op_deadline; if (success && !calld->got_initial_metadata) { size_t i; @@ -539,8 +540,9 @@ static void server_on_recv(void *ptr, int success) { grpc_stream_op *op = &ops[i]; if (op->type != GRPC_OP_METADATA) continue; grpc_metadata_batch_filter(&op->data.metadata, server_filter, elem); - if (0 != gpr_time_cmp(op->data.metadata.deadline, - gpr_inf_future(GPR_CLOCK_REALTIME))) { + op_deadline = op->data.metadata.deadline; + if (0 != + gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) { calld->deadline = op->data.metadata.deadline; } calld->got_initial_metadata = 1; diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c index 904b9afce7e..50a2f752f62 100644 --- a/src/core/transport/chttp2/parsing.c +++ b/src/core/transport/chttp2/parsing.c @@ -607,7 +607,7 @@ static void on_header(void *tp, grpc_mdelem *md) { } grpc_chttp2_incoming_metadata_buffer_set_deadline( &stream_parsing->incoming_metadata, - gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout)); + gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout)); GRPC_MDELEM_UNREF(md); } else { grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata, diff --git a/src/cpp/util/time.cc b/src/cpp/util/time.cc index a814cad452e..799c597e0b9 100644 --- a/src/cpp/util/time.cc +++ b/src/cpp/util/time.cc @@ -79,9 +79,10 @@ void TimepointHR2Timespec(const high_resolution_clock::time_point& from, } system_clock::time_point Timespec2Timepoint(gpr_timespec t) { - if (gpr_time_cmp(t, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) { + if (gpr_time_cmp(t, gpr_inf_future(t.clock_type)) == 0) { return system_clock::time_point::max(); } + t = gpr_convert_clock_type(t, GPR_CLOCK_REALTIME); system_clock::time_point tp; tp += duration_cast(seconds(t.tv_sec)); tp += diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc index 60de4d816dd..bf68513c487 100644 --- a/src/node/ext/timeval.cc +++ b/src/node/ext/timeval.cc @@ -52,6 +52,7 @@ gpr_timespec MillisecondsToTimespec(double millis) { } double TimespecToMilliseconds(gpr_timespec timespec) { + timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); if (gpr_time_cmp(timespec, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) { return std::numeric_limits::infinity(); } else if (gpr_time_cmp(timespec, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) { diff --git a/src/python/src/grpc/_adapter/_c/utility.c b/src/python/src/grpc/_adapter/_c/utility.c index d9f911a41a9..51f3c9be01b 100644 --- a/src/python/src/grpc/_adapter/_c/utility.c +++ b/src/python/src/grpc/_adapter/_c/utility.c @@ -374,6 +374,7 @@ PyObject *pygrpc_consume_ops(grpc_op *op, size_t nops) { } double pygrpc_cast_gpr_timespec_to_double(gpr_timespec timespec) { + timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); return timespec.tv_sec + 1e-9*timespec.tv_nsec; } diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 829f8255979..65d9c9a237b 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -209,10 +209,12 @@ static ID id_to_s; /* Converts a wrapped time constant to a standard time. */ static VALUE grpc_rb_time_val_to_time(VALUE self) { gpr_timespec *time_const = NULL; + gpr_timespec real_time; TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type, time_const); - return rb_funcall(rb_cTime, id_at, 2, INT2NUM(time_const->tv_sec), - INT2NUM(time_const->tv_nsec)); + real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME); + return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec), + INT2NUM(real_time.tv_nsec)); } /* Invokes inspect on the ctime version of the time val. */ diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index e3a0a5ad805..375a651d247 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -213,6 +213,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, grpc_call_error err; request_call_stack st; VALUE result; + gpr_timespec deadline; TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "destroyed!"); @@ -245,15 +246,13 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, } /* build the NewServerRpc struct result */ + deadline = gpr_convert_clock_type(st.details.deadline, GPR_CLOCK_REALTIME); result = rb_struct_new( - grpc_rb_sNewServerRpc, - rb_str_new2(st.details.method), + grpc_rb_sNewServerRpc, rb_str_new2(st.details.method), rb_str_new2(st.details.host), - rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec), - INT2NUM(st.details.deadline.tv_nsec)), - grpc_rb_md_ary_to_h(&st.md_ary), - grpc_rb_wrap_call(call), - NULL); + rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec), + INT2NUM(deadline.tv_nsec)), + grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call), NULL); grpc_request_call_stack_cleanup(&st); return result; } From a627d8939d4ea116a5b4f8ce8df0105db421edc3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 23 Jul 2015 10:40:19 -0700 Subject: [PATCH 09/47] Changed object keys to valid identifier names --- src/node/ext/call.cc | 8 +-- src/node/ext/server.cc | 2 +- src/node/src/server.js | 2 +- src/node/test/call_test.js | 4 +- src/node/test/end_to_end_test.js | 110 +++++++++++++++---------------- 5 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 15c9b2d97d6..9a01816958c 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -192,7 +192,7 @@ class SendMetadataOp : public Op { } protected: std::string GetTypeString() const { - return "send metadata"; + return "send_metadata"; } }; @@ -216,7 +216,7 @@ class SendMessageOp : public Op { } protected: std::string GetTypeString() const { - return "send message"; + return "send_message"; } }; @@ -232,7 +232,7 @@ class SendClientCloseOp : public Op { } protected: std::string GetTypeString() const { - return "client close"; + return "client_close"; } }; @@ -276,7 +276,7 @@ class SendServerStatusOp : public Op { } protected: std::string GetTypeString() const { - return "send status"; + return "send_status"; } }; diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc index 34cde9ffab0..8554fce7772 100644 --- a/src/node/ext/server.cc +++ b/src/node/ext/server.cc @@ -108,7 +108,7 @@ class NewCallOp : public Op { protected: std::string GetTypeString() const { - return "new call"; + return "new_call"; } }; diff --git a/src/node/src/server.js b/src/node/src/server.js index 0a3a0031bdf..68647741b16 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -544,7 +544,7 @@ function Server(options) { if (err) { return; } - var details = event['new call']; + var details = event.new_call; var call = details.call; var method = details.method; var metadata = details.metadata; diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 98158ffff35..ff41b26b1ab 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -132,7 +132,7 @@ describe('call', function() { 'key2': ['value2']}; call.startBatch(batch, function(err, resp) { assert.ifError(err); - assert.deepEqual(resp, {'send metadata': true}); + assert.deepEqual(resp, {'send_metadata': true}); done(); }); }); @@ -147,7 +147,7 @@ describe('call', function() { }; call.startBatch(batch, function(err, resp) { assert.ifError(err); - assert.deepEqual(resp, {'send metadata': true}); + assert.deepEqual(resp, {'send_metadata': true}); done(); }); }); diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js index 667852f3826..5d3baf823da 100644 --- a/src/node/test/end_to_end_test.js +++ b/src/node/test/end_to_end_test.js @@ -85,37 +85,37 @@ describe('end-to-end', function() { call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { - 'send metadata': true, - 'client close': true, - 'metadata': {}, - 'status': { - 'code': grpc.status.OK, - 'details': status_text, - 'metadata': {} + send_metadata: true, + client_close: true, + metadata: {}, + status: { + code: grpc.status.OK, + details: status_text, + metadata: {} } }); done(); }); server.requestCall(function(err, call_details) { - var new_call = call_details['new call']; + var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - 'metadata': {}, - 'code': grpc.status.OK, - 'details': status_text + metadata: {}, + code: grpc.status.OK, + details: status_text }; server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { - 'send metadata': true, - 'send status': true, - 'cancelled': false + send_metadata: true, + send_status: true, + cancelled: false }); done(); }); @@ -131,7 +131,7 @@ describe('end-to-end', function() { Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = { - 'client_key': ['client_value'] + client_key: ['client_value'] }; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; @@ -139,18 +139,18 @@ describe('end-to-end', function() { call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response,{ - 'send metadata': true, - 'client close': true, + send_metadata: true, + client_close: true, metadata: {server_key: ['server_value']}, - status: {'code': grpc.status.OK, - 'details': status_text, - 'metadata': {}} + status: {code: grpc.status.OK, + details: status_text, + metadata: {}} }); done(); }); server.requestCall(function(err, call_details) { - var new_call = call_details['new call']; + var new_call = call_details.new_call; assert.notEqual(new_call, null); assert.strictEqual(new_call.metadata.client_key[0], 'client_value'); @@ -158,20 +158,20 @@ describe('end-to-end', function() { assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = { - 'server_key': ['server_value'] + server_key: ['server_value'] }; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - 'metadata': {}, - 'code': grpc.status.OK, - 'details': status_text + metadata: {}, + code: grpc.status.OK, + details: status_text }; server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { - 'send metadata': true, - 'send status': true, - 'cancelled': false + send_metadata: true, + send_status: true, + cancelled: false }); done(); }); @@ -196,19 +196,19 @@ describe('end-to-end', function() { client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); - assert(response['send metadata']); - assert(response['client close']); + assert(response.send_metadata); + assert(response.client_close); assert.deepEqual(response.metadata, {}); - assert(response['send message']); + assert(response.send_message); assert.strictEqual(response.read.toString(), reply_text); - assert.deepEqual(response.status, {'code': grpc.status.OK, - 'details': status_text, - 'metadata': {}}); + assert.deepEqual(response.status, {code: grpc.status.OK, + details: status_text, + metadata: {}}); done(); }); server.requestCall(function(err, call_details) { - var new_call = call_details['new call']; + var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); @@ -217,18 +217,18 @@ describe('end-to-end', function() { server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); - assert(response['send metadata']); + assert(response.send_metadata); assert.strictEqual(response.read.toString(), req_text); var response_batch = {}; response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text); response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - 'metadata': {}, - 'code': grpc.status.OK, - 'details': status_text + metadata: {}, + code: grpc.status.OK, + details: status_text }; response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; server_call.startBatch(response_batch, function(err, response) { - assert(response['send status']); + assert(response.send_status); assert(!response.cancelled); done(); }); @@ -251,9 +251,9 @@ describe('end-to-end', function() { call.startBatch(client_batch, function(err, response) { assert.ifError(err); assert.deepEqual(response, { - 'send metadata': true, - 'send message': true, - 'metadata': {} + send_metadata: true, + send_message: true, + metadata: {} }); var req2_batch = {}; req2_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[1]); @@ -262,12 +262,12 @@ describe('end-to-end', function() { call.startBatch(req2_batch, function(err, resp) { assert.ifError(err); assert.deepEqual(resp, { - 'send message': true, - 'client close': true, - 'status': { - 'code': grpc.status.OK, - 'details': status_text, - 'metadata': {} + send_message: true, + client_close: true, + status: { + code: grpc.status.OK, + details: status_text, + metadata: {} } }); done(); @@ -275,7 +275,7 @@ describe('end-to-end', function() { }); server.requestCall(function(err, call_details) { - var new_call = call_details['new call']; + var new_call = call_details.new_call; assert.notEqual(new_call, null); var server_call = new_call.call; assert.notEqual(server_call, null); @@ -284,7 +284,7 @@ describe('end-to-end', function() { server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); - assert(response['send metadata']); + assert(response.send_metadata); assert.strictEqual(response.read.toString(), requests[0]); var snd_batch = {}; snd_batch[grpc.opType.RECV_MESSAGE] = true; @@ -294,13 +294,13 @@ describe('end-to-end', function() { var end_batch = {}; end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - 'metadata': {}, - 'code': grpc.status.OK, - 'details': status_text + metadata: {}, + code: grpc.status.OK, + details: status_text }; server_call.startBatch(end_batch, function(err, response) { assert.ifError(err); - assert(response['send status']); + assert(response.send_status); assert(!response.cancelled); done(); }); From 994c2620e3540de869aee52b2ad0678006ef8a6b Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Jul 2015 14:00:58 -0700 Subject: [PATCH 10/47] Fix flow control - sending of window updates is now integrated with the primary write path, making this far more robust - iomgr starts up after shutdown correctly again --- src/core/channel/client_channel.c | 2 +- src/core/iomgr/iomgr.c | 1 + src/core/iomgr/tcp_posix.c | 4 +- src/core/transport/chttp2/internal.h | 21 ++---- src/core/transport/chttp2/parsing.c | 3 +- src/core/transport/chttp2/stream_lists.c | 68 +++++++++-------- src/core/transport/chttp2/writing.c | 93 ++++++++++++++---------- src/core/transport/chttp2_transport.c | 10 +-- 8 files changed, 108 insertions(+), 94 deletions(-) diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c index 108a6dfdf10..ec6ca428896 100644 --- a/src/core/channel/client_channel.c +++ b/src/core/channel/client_channel.c @@ -460,7 +460,7 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { while (wakeup_closures) { grpc_iomgr_closure *next = wakeup_closures->next; - grpc_iomgr_add_callback(wakeup_closures); + wakeup_closures->cb(wakeup_closures->cb_arg, 1); wakeup_closures = next; } diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c index a18c176b305..aa4bc6e20df 100644 --- a/src/core/iomgr/iomgr.c +++ b/src/core/iomgr/iomgr.c @@ -88,6 +88,7 @@ void grpc_kick_poller(void) { void grpc_iomgr_init(void) { gpr_thd_id id; + g_shutdown = 0; gpr_mu_init(&g_mu); gpr_cv_init(&g_rcv); grpc_alarm_list_init(gpr_now(GPR_CLOCK_MONOTONIC)); diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c index 1e8432d463a..63a8a2720e6 100644 --- a/src/core/iomgr/tcp_posix.c +++ b/src/core/iomgr/tcp_posix.c @@ -319,7 +319,7 @@ static void call_read_cb(grpc_tcp *tcp, gpr_slice *slices, size_t nslices, gpr_log(GPR_DEBUG, "read: status=%d", status); for (i = 0; i < nslices; i++) { char *dump = gpr_dump_slice(slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); - gpr_log(GPR_DEBUG, "READ: %s", dump); + gpr_log(GPR_DEBUG, "READ %p: %s", tcp, dump); gpr_free(dump); } } @@ -448,7 +448,7 @@ static void grpc_tcp_notify_on_read(grpc_endpoint *ep, grpc_endpoint_read_cb cb, grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_closure); } else { tcp->handle_read_closure.cb_arg = tcp; - grpc_iomgr_add_callback(&tcp->handle_read_closure); + grpc_iomgr_add_delayed_callback(&tcp->handle_read_closure, 1); } } diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h index e7901da510e..f0eeb6de505 100644 --- a/src/core/transport/chttp2/internal.h +++ b/src/core/transport/chttp2/internal.h @@ -60,7 +60,6 @@ typedef enum { GRPC_CHTTP2_LIST_WRITABLE, GRPC_CHTTP2_LIST_WRITING, GRPC_CHTTP2_LIST_WRITTEN, - GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE, GRPC_CHTTP2_LIST_PARSING_SEEN, GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING, GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING, @@ -383,6 +382,8 @@ typedef struct { gpr_uint8 published_cancelled; /** is this stream in the stream map? (boolean) */ gpr_uint8 in_stream_map; + /** is this stream actively being written? */ + gpr_uint8 writing_now; /** stream state already published to the upper layer */ grpc_stream_state published_state; @@ -475,11 +476,17 @@ void grpc_chttp2_publish_reads(grpc_chttp2_transport_global *global, void grpc_chttp2_list_add_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_stream_global *stream_global); +void grpc_chttp2_list_add_first_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); int grpc_chttp2_list_pop_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing); +void grpc_chttp2_list_remove_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global); void grpc_chttp2_list_add_incoming_window_updated( grpc_chttp2_transport_global *transport_global, @@ -511,18 +518,6 @@ int grpc_chttp2_list_pop_written_stream( grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_writing **stream_writing); -void grpc_chttp2_list_add_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); -int grpc_chttp2_list_pop_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing); -void grpc_chttp2_list_remove_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global); - void grpc_chttp2_list_add_parsing_seen_stream( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing); diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c index 904b9afce7e..9105746567b 100644 --- a/src/core/transport/chttp2/parsing.c +++ b/src/core/transport/chttp2/parsing.c @@ -182,8 +182,7 @@ void grpc_chttp2_publish_reads( stream_global->max_recv_bytes -= stream_parsing->incoming_window_delta; stream_parsing->incoming_window_delta = 0; - grpc_chttp2_list_add_writable_window_update_stream(transport_global, - stream_global); + grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } /* update outgoing flow control window */ diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c index 590f6abfbc3..9e68c1e146f 100644 --- a/src/core/transport/chttp2/stream_lists.c +++ b/src/core/transport/chttp2/stream_lists.c @@ -108,6 +108,23 @@ static void stream_list_maybe_remove(grpc_chttp2_transport *t, } } +static void stream_list_add_head(grpc_chttp2_transport *t, + grpc_chttp2_stream *s, + grpc_chttp2_stream_list_id id) { + grpc_chttp2_stream *old_head; + GPR_ASSERT(!s->included[id]); + old_head = t->lists[id].head; + s->links[id].next = old_head; + s->links[id].prev = NULL; + if (old_head) { + old_head->links[id].prev = s; + } else { + t->lists[id].tail = s; + } + t->lists[id].head = s; + s->included[id] = 1; +} + static void stream_list_add_tail(grpc_chttp2_transport *t, grpc_chttp2_stream *s, grpc_chttp2_stream_list_id id) { @@ -119,7 +136,6 @@ static void stream_list_add_tail(grpc_chttp2_transport *t, if (old_tail) { old_tail->links[id].next = s; } else { - s->links[id].prev = NULL; t->lists[id].head = s; } t->lists[id].tail = s; @@ -144,6 +160,18 @@ void grpc_chttp2_list_add_writable_stream( STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE); } +void grpc_chttp2_list_add_first_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + GPR_ASSERT(stream_global->id != 0); + gpr_log(GPR_DEBUG, "add:%d:%d:%d:%d", stream_global->id, + stream_global->write_state, stream_global->in_stream_map, + stream_global->read_closed); + stream_list_add_head(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_WRITABLE); +} + int grpc_chttp2_list_pop_writable_stream( grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_writing *transport_writing, @@ -157,6 +185,14 @@ int grpc_chttp2_list_pop_writable_stream( return r; } +void grpc_chttp2_list_remove_writable_stream( + grpc_chttp2_transport_global *transport_global, + grpc_chttp2_stream_global *stream_global) { + stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), + STREAM_FROM_GLOBAL(stream_global), + GRPC_CHTTP2_LIST_WRITABLE); +} + void grpc_chttp2_list_add_writing_stream( grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_stream_writing *stream_writing) { @@ -202,36 +238,6 @@ int grpc_chttp2_list_pop_written_stream( return r; } -void grpc_chttp2_list_add_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - GPR_ASSERT(stream_global->id != 0); - stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE); -} - -int grpc_chttp2_list_pop_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_transport_writing *transport_writing, - grpc_chttp2_stream_global **stream_global, - grpc_chttp2_stream_writing **stream_writing) { - grpc_chttp2_stream *stream; - int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, - GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE); - *stream_global = &stream->global; - *stream_writing = &stream->writing; - return r; -} - -void grpc_chttp2_list_remove_writable_window_update_stream( - grpc_chttp2_transport_global *transport_global, - grpc_chttp2_stream_global *stream_global) { - stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), - STREAM_FROM_GLOBAL(stream_global), - GRPC_CHTTP2_LIST_WRITABLE_WINDOW_UPDATE); -} - void grpc_chttp2_list_add_parsing_seen_stream( grpc_chttp2_transport_parsing *transport_parsing, grpc_chttp2_stream_parsing *stream_parsing) { diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index 041c4efd1f5..54d38f2841b 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -44,6 +44,7 @@ int grpc_chttp2_unlocking_check_writes( grpc_chttp2_transport_writing *transport_writing) { grpc_chttp2_stream_global *stream_global; grpc_chttp2_stream_writing *stream_writing; + grpc_chttp2_stream_global *first_reinserted_stream = NULL; gpr_uint32 window_delta; /* simple writes are queued to qbuf, and flushed here */ @@ -64,51 +65,53 @@ int grpc_chttp2_unlocking_check_writes( } /* for each grpc_chttp2_stream that's become writable, frame it's data - (according to - available window sizes) and add to the output buffer */ - while (transport_global->outgoing_window > 0 && - grpc_chttp2_list_pop_writable_stream(transport_global, - transport_writing, &stream_global, - &stream_writing)) { + (according to available window sizes) and add to the output buffer */ + while (grpc_chttp2_list_pop_writable_stream( + transport_global, transport_writing, &stream_global, &stream_writing)) { + if (stream_global == first_reinserted_stream) { + /* prevent infinite loop */ + grpc_chttp2_list_add_first_writable_stream(transport_global, + stream_global); + break; + } + stream_writing->id = stream_global->id; - window_delta = grpc_chttp2_preencode( - stream_global->outgoing_sopb->ops, &stream_global->outgoing_sopb->nops, - GPR_MIN(transport_global->outgoing_window, - stream_global->outgoing_window), - &stream_writing->sopb); - GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( - "write", transport_global, outgoing_window, -(gpr_int64)window_delta); - GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, - outgoing_window, -(gpr_int64)window_delta); - transport_global->outgoing_window -= window_delta; - stream_global->outgoing_window -= window_delta; - - if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE && - stream_global->outgoing_sopb->nops == 0) { - if (!transport_global->is_client && !stream_global->read_closed) { - stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM; - } else { - stream_writing->send_closed = GRPC_SEND_CLOSED; + stream_writing->send_closed = GRPC_DONT_SEND_CLOSED; + + if (stream_global->outgoing_sopb) { + window_delta = + grpc_chttp2_preencode(stream_global->outgoing_sopb->ops, + &stream_global->outgoing_sopb->nops, + GPR_MIN(transport_global->outgoing_window, + stream_global->outgoing_window), + &stream_writing->sopb); + GRPC_CHTTP2_FLOWCTL_TRACE_TRANSPORT( + "write", transport_global, outgoing_window, -(gpr_int64)window_delta); + GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, + outgoing_window, + -(gpr_int64)window_delta); + transport_global->outgoing_window -= window_delta; + stream_global->outgoing_window -= window_delta; + + if (stream_global->write_state == GRPC_WRITE_STATE_QUEUED_CLOSE && + stream_global->outgoing_sopb->nops == 0) { + if (!transport_global->is_client && !stream_global->read_closed) { + stream_writing->send_closed = GRPC_SEND_CLOSED_WITH_RST_STREAM; + } else { + stream_writing->send_closed = GRPC_SEND_CLOSED; + } } - } - if (stream_writing->sopb.nops > 0 || - stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { - grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); - } - if (stream_global->outgoing_window > 0 && - stream_global->outgoing_sopb->nops != 0) { - grpc_chttp2_list_add_writable_stream(transport_global, stream_global); + if (stream_global->outgoing_window > 0 && + stream_global->outgoing_sopb->nops != 0) { + grpc_chttp2_list_add_writable_stream(transport_global, stream_global); + if (first_reinserted_stream == NULL && + transport_global->outgoing_window == 0) { + first_reinserted_stream = stream_global; + } + } } - } - /* for each grpc_chttp2_stream that wants to update its window, add that - * window here */ - while (grpc_chttp2_list_pop_writable_window_update_stream(transport_global, - transport_writing, - &stream_global, - &stream_writing)) { - stream_writing->id = stream_global->id; if (!stream_global->read_closed && stream_global->unannounced_incoming_window > 0) { stream_writing->announce_window = stream_global->unannounced_incoming_window; GRPC_CHTTP2_FLOWCTL_TRACE_STREAM("write", transport_global, stream_global, @@ -119,6 +122,11 @@ int grpc_chttp2_unlocking_check_writes( stream_global->unannounced_incoming_window = 0; grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); + stream_global->writing_now = 1; + grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); + } else if (stream_writing->sopb.nops > 0 || + stream_writing->send_closed != GRPC_DONT_SEND_CLOSED) { + stream_global->writing_now = 1; grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing); } } @@ -206,6 +214,8 @@ void grpc_chttp2_cleanup_writing( while (grpc_chttp2_list_pop_written_stream( transport_global, transport_writing, &stream_global, &stream_writing)) { + GPR_ASSERT(stream_global->writing_now); + stream_global->writing_now = 0; if (stream_global->outgoing_sopb != NULL && stream_global->outgoing_sopb->nops == 0) { stream_global->outgoing_sopb = NULL; @@ -219,6 +229,9 @@ void grpc_chttp2_cleanup_writing( } grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); + } else if (stream_global->read_closed) { + grpc_chttp2_list_add_read_write_state_changed(transport_global, + stream_global); } } transport_writing->outbuf.count = 0; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index eb435a2ee8f..05402525465 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -395,7 +395,6 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { } grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global); - grpc_chttp2_list_remove_writable_window_update_stream(&t->global, &s->global); gpr_mu_unlock(&t->mu); @@ -576,8 +575,6 @@ static void maybe_start_some_streams( grpc_chttp2_list_add_incoming_window_updated(transport_global, stream_global); grpc_chttp2_list_add_writable_stream(transport_global, stream_global); - grpc_chttp2_list_add_writable_window_update_stream(transport_global, - stream_global); } /* cancel out streams that will never be started */ @@ -643,8 +640,7 @@ static void perform_stream_op_locked( if (stream_global->id != 0) { grpc_chttp2_list_add_read_write_state_changed(transport_global, stream_global); - grpc_chttp2_list_add_writable_window_update_stream(transport_global, - stream_global); + grpc_chttp2_list_add_writable_stream(transport_global, stream_global); } } @@ -752,6 +748,7 @@ static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) { if (!s) { s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); } + grpc_chttp2_list_remove_writable_stream(&t->global, &s->global); GPR_ASSERT(s); s->global.in_stream_map = 0; if (t->parsing.incoming_stream == &s->parsing) { @@ -833,6 +830,9 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) { if (!stream_global->publish_sopb) { continue; } + if (stream_global->writing_now) { + continue; + } /* FIXME(ctiller): we include in_stream_map in our computation of whether the stream is write-closed. This is completely bogus, but has the effect of delaying stream-closed until the stream From b28456b1e46085bd35b6389b03e6d4de8866bdaf Mon Sep 17 00:00:00 2001 From: vjpai Date: Thu, 23 Jul 2015 14:17:10 -0700 Subject: [PATCH 11/47] Add dynamic thread pool and initial port of test --- BUILD | 4 + Makefile | 49 ++++++- build.json | 17 +++ include/grpc++/dynamic_thread_pool.h | 81 +++++++++++ src/cpp/server/dynamic_thread_pool.cc | 130 ++++++++++++++++++ test/cpp/server/dynamic_thread_pool_test.cc | 77 +++++++++++ tools/doxygen/Doxyfile.c++ | 1 + tools/doxygen/Doxyfile.c++.internal | 2 + tools/run_tests/sources_and_headers.json | 21 +++ tools/run_tests/tests.json | 9 ++ vsprojects/grpc++/grpc++.vcxproj | 3 + vsprojects/grpc++/grpc++.vcxproj.filters | 6 + .../grpc++_unsecure/grpc++_unsecure.vcxproj | 3 + .../grpc++_unsecure.vcxproj.filters | 6 + 14 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 include/grpc++/dynamic_thread_pool.h create mode 100644 src/cpp/server/dynamic_thread_pool.cc create mode 100644 test/cpp/server/dynamic_thread_pool_test.cc diff --git a/BUILD b/BUILD index e116d4584bb..dee119cbfe9 100644 --- a/BUILD +++ b/BUILD @@ -661,6 +661,7 @@ cc_library( "src/cpp/proto/proto_utils.cc", "src/cpp/server/async_generic_service.cc", "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/fixed_size_thread_pool.cc", "src/cpp/server/insecure_server_credentials.cc", "src/cpp/server/server.cc", @@ -686,6 +687,7 @@ cc_library( "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -746,6 +748,7 @@ cc_library( "src/cpp/proto/proto_utils.cc", "src/cpp/server/async_generic_service.cc", "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/fixed_size_thread_pool.cc", "src/cpp/server/insecure_server_credentials.cc", "src/cpp/server/server.cc", @@ -771,6 +774,7 @@ cc_library( "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", diff --git a/Makefile b/Makefile index 2ae0cd052df..315740d3eb6 100644 --- a/Makefile +++ b/Makefile @@ -851,6 +851,7 @@ credentials_test: $(BINDIR)/$(CONFIG)/credentials_test cxx_byte_buffer_test: $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test cxx_slice_test: $(BINDIR)/$(CONFIG)/cxx_slice_test cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test +dynamic_thread_pool_test: $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test end2end_test: $(BINDIR)/$(CONFIG)/end2end_test fixed_size_thread_pool_test: $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test @@ -1532,7 +1533,7 @@ buildtests: buildtests_c buildtests_cxx buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_compression_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_compressed_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test -buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test +buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/auth_property_iterator_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/fixed_size_thread_pool_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_stress_test test: test_c test_cxx @@ -2803,6 +2804,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/cxx_slice_test || ( echo test cxx_slice_test failed ; exit 1 ) $(E) "[RUN] Testing cxx_time_test" $(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 ) + $(E) "[RUN] Testing dynamic_thread_pool_test" + $(Q) $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test || ( echo test dynamic_thread_pool_test failed ; exit 1 ) $(E) "[RUN] Testing end2end_test" $(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 ) $(E) "[RUN] Testing fixed_size_thread_pool_test" @@ -3941,6 +3944,7 @@ LIBGRPC++_SRC = \ src/cpp/proto/proto_utils.cc \ src/cpp/server/async_generic_service.cc \ src/cpp/server/create_default_thread_pool.cc \ + src/cpp/server/dynamic_thread_pool.cc \ src/cpp/server/fixed_size_thread_pool.cc \ src/cpp/server/insecure_server_credentials.cc \ src/cpp/server/server.cc \ @@ -3966,6 +3970,7 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/config_protobuf.h \ include/grpc++/create_channel.h \ include/grpc++/credentials.h \ + include/grpc++/dynamic_thread_pool.h \ include/grpc++/fixed_size_thread_pool.h \ include/grpc++/generic_stub.h \ include/grpc++/impl/call.h \ @@ -4184,6 +4189,7 @@ LIBGRPC++_UNSECURE_SRC = \ src/cpp/proto/proto_utils.cc \ src/cpp/server/async_generic_service.cc \ src/cpp/server/create_default_thread_pool.cc \ + src/cpp/server/dynamic_thread_pool.cc \ src/cpp/server/fixed_size_thread_pool.cc \ src/cpp/server/insecure_server_credentials.cc \ src/cpp/server/server.cc \ @@ -4209,6 +4215,7 @@ PUBLIC_HEADERS_CXX += \ include/grpc++/config_protobuf.h \ include/grpc++/create_channel.h \ include/grpc++/credentials.h \ + include/grpc++/dynamic_thread_pool.h \ include/grpc++/fixed_size_thread_pool.h \ include/grpc++/generic_stub.h \ include/grpc++/impl/call.h \ @@ -8447,6 +8454,46 @@ endif endif +DYNAMIC_THREAD_POOL_TEST_SRC = \ + test/cpp/server/dynamic_thread_pool_test.cc \ + +DYNAMIC_THREAD_POOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DYNAMIC_THREAD_POOL_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: openssl_dep_error + +else + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. + +$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/dynamic_thread_pool_test: $(PROTOBUF_DEP) $(DYNAMIC_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(DYNAMIC_THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/dynamic_thread_pool_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/server/dynamic_thread_pool_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a +deps_dynamic_thread_pool_test: $(DYNAMIC_THREAD_POOL_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(DYNAMIC_THREAD_POOL_TEST_OBJS:.o=.dep) +endif +endif + + END2END_TEST_SRC = \ test/cpp/end2end/end2end_test.cc \ diff --git a/build.json b/build.json index 2755703e1cf..a7cc013f2e2 100644 --- a/build.json +++ b/build.json @@ -41,6 +41,7 @@ "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -88,6 +89,7 @@ "src/cpp/proto/proto_utils.cc", "src/cpp/server/async_generic_service.cc", "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/fixed_size_thread_pool.cc", "src/cpp/server/insecure_server_credentials.cc", "src/cpp/server/server.cc", @@ -2044,6 +2046,21 @@ "gpr" ] }, + { + "name": "dynamic_thread_pool_test", + "build": "test", + "language": "c++", + "src": [ + "test/cpp/server/dynamic_thread_pool_test.cc" + ], + "deps": [ + "grpc_test_util", + "grpc++", + "grpc", + "gpr_test_util", + "gpr" + ] + }, { "name": "end2end_test", "build": "test", diff --git a/include/grpc++/dynamic_thread_pool.h b/include/grpc++/dynamic_thread_pool.h new file mode 100644 index 00000000000..7519a47726c --- /dev/null +++ b/include/grpc++/dynamic_thread_pool.h @@ -0,0 +1,81 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPCXX_DYNAMIC_THREAD_POOL_H +#define GRPCXX_DYNAMIC_THREAD_POOL_H + +#include + +#include +#include +#include + +#include +#include + +namespace grpc { + +class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface { + public: + explicit DynamicThreadPool(int reserve_threads); + ~DynamicThreadPool(); + + void Add(const std::function& callback) GRPC_OVERRIDE; + + private: + class DynamicThread { + public: + DynamicThread(DynamicThreadPool *pool); + ~DynamicThread(); + private: + DynamicThreadPool *pool_; + std::unique_ptr thd_; + void ThreadFunc(); + }; + grpc::mutex mu_; + grpc::condition_variable cv_; + bool shutdown_; + std::queue> callbacks_; + int reserve_threads_; + int nthreads_; + int threads_waiting_; + std::list live_threads_; + std::list dead_threads_; + + void ThreadFunc(); + static void ReapThreads(std::list* tlist); +}; + +} // namespace grpc + +#endif // GRPCXX_DYNAMIC_THREAD_POOL_H diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc new file mode 100644 index 00000000000..bc0d16f1704 --- /dev/null +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -0,0 +1,130 @@ +/* + * + * 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 +#include +#include + +namespace grpc { +DynamicThreadPool::DynamicThread::DynamicThread(DynamicThreadPool *pool): + pool_(pool), + thd_(new grpc::thread(&DynamicThreadPool::DynamicThread::ThreadFunc, this)) { +} +DynamicThreadPool::DynamicThread::~DynamicThread() { + thd_->join(); + thd_.reset(); +} + +void DynamicThreadPool::DynamicThread::ThreadFunc() { + pool_->ThreadFunc(); + // Now that we have killed ourselves, we should reduce the thread count + grpc::unique_lock lock(pool_->mu_); + pool_->nthreads_--; + // Move ourselves from live list to dead list + for (auto t = pool_->live_threads_.begin(); t != pool_->live_threads_.end(); + t++) { + if ((*t) == this) { + t = pool_->live_threads_.erase(t); + pool_->dead_threads_.push_back(this); + } + } +} + +void DynamicThreadPool::ThreadFunc() { + for (;;) { + // Wait until work is available or we are shutting down. + grpc::unique_lock lock(mu_); + if (!shutdown_ && callbacks_.empty()) { + // If there are too many threads waiting, then quit this thread + if (threads_waiting_ == reserve_threads_) { + break; + } + threads_waiting_++; + cv_.wait(lock); + threads_waiting_--; + } + // Drain callbacks before considering shutdown to ensure all work + // gets completed. + if (!callbacks_.empty()) { + auto cb = callbacks_.front(); + callbacks_.pop(); + lock.unlock(); + cb(); + } else if (shutdown_) { + break; + } + } +} + +DynamicThreadPool::DynamicThreadPool(int reserve_threads) : + shutdown_(false), reserve_threads_(reserve_threads), threads_waiting_(0) { + for (int i = 0; i < reserve_threads_; i++) { + grpc::lock_guard lock(mu_); + nthreads_++; + live_threads_.push_back(new DynamicThread(this)); + } +} + +void DynamicThreadPool::ReapThreads(std::list* tlist) { + for (auto t = tlist->begin(); t != tlist->end(); t++) { + delete *t; + t = tlist->erase(t); + } +} + +DynamicThreadPool::~DynamicThreadPool() { + { + grpc::lock_guard lock(mu_); + shutdown_ = true; + cv_.notify_all(); + } + ReapThreads(&live_threads_); + ReapThreads(&dead_threads_); +} + +void DynamicThreadPool::Add(const std::function& callback) { + grpc::lock_guard lock(mu_); + if (threads_waiting_ == 0) { + // Kick off a new thread + nthreads_++; + live_threads_.push_back(new DynamicThread(this)); + } + callbacks_.push(callback); + cv_.notify_one(); + // Also use this chance to harvest dead threads + if (!dead_threads_.empty()) { + ReapThreads(&dead_threads_); + } +} + +} // namespace grpc diff --git a/test/cpp/server/dynamic_thread_pool_test.cc b/test/cpp/server/dynamic_thread_pool_test.cc new file mode 100644 index 00000000000..615b5470770 --- /dev/null +++ b/test/cpp/server/dynamic_thread_pool_test.cc @@ -0,0 +1,77 @@ +/* + * + * 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 +#include +#include + +#include +#include + +namespace grpc { + +class DynamicThreadPoolTest : public ::testing::Test { + public: + DynamicThreadPoolTest() : thread_pool_(4) {} + + protected: + DynamicThreadPool thread_pool_; +}; + +void Callback(std::mutex* mu, std::condition_variable* cv, bool* done) { + std::unique_lock lock(*mu); + *done = true; + cv->notify_all(); +} + +TEST_F(DynamicThreadPoolTest, Add) { + std::mutex mu; + std::condition_variable cv; + bool done = false; + std::function callback = std::bind(Callback, &mu, &cv, &done); + thread_pool_.Add(callback); + + // Wait for the callback to finish. + std::unique_lock lock(mu); + while (!done) { + cv.wait(lock); + } +} + +} // namespace grpc + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 4bdd8babde5..785779beb5d 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -773,6 +773,7 @@ include/grpc++/config.h \ include/grpc++/config_protobuf.h \ include/grpc++/create_channel.h \ include/grpc++/credentials.h \ +include/grpc++/dynamic_thread_pool.h \ include/grpc++/fixed_size_thread_pool.h \ include/grpc++/generic_stub.h \ include/grpc++/impl/call.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1c73ca62947..5cf6168388e 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -773,6 +773,7 @@ include/grpc++/config.h \ include/grpc++/config_protobuf.h \ include/grpc++/create_channel.h \ include/grpc++/credentials.h \ +include/grpc++/dynamic_thread_pool.h \ include/grpc++/fixed_size_thread_pool.h \ include/grpc++/generic_stub.h \ include/grpc++/impl/call.h \ @@ -825,6 +826,7 @@ src/cpp/common/rpc_method.cc \ src/cpp/proto/proto_utils.cc \ src/cpp/server/async_generic_service.cc \ src/cpp/server/create_default_thread_pool.cc \ +src/cpp/server/dynamic_thread_pool.cc \ src/cpp/server/fixed_size_thread_pool.cc \ src/cpp/server/insecure_server_credentials.cc \ src/cpp/server/server.cc \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index abddaab6994..021602928ab 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -1181,6 +1181,21 @@ "test/cpp/util/time_test.cc" ] }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc++", + "grpc_test_util" + ], + "headers": [], + "language": "c++", + "name": "dynamic_thread_pool_test", + "src": [ + "test/cpp/server/dynamic_thread_pool_test.cc" + ] + }, { "deps": [ "gpr", @@ -10646,6 +10661,7 @@ "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -10695,6 +10711,7 @@ "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -10745,6 +10762,7 @@ "src/cpp/proto/proto_utils.cc", "src/cpp/server/async_generic_service.cc", "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/fixed_size_thread_pool.cc", "src/cpp/server/insecure_server_credentials.cc", "src/cpp/server/secure_server_credentials.cc", @@ -10820,6 +10838,7 @@ "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -10866,6 +10885,7 @@ "include/grpc++/config_protobuf.h", "include/grpc++/create_channel.h", "include/grpc++/credentials.h", + "include/grpc++/dynamic_thread_pool.h", "include/grpc++/fixed_size_thread_pool.h", "include/grpc++/generic_stub.h", "include/grpc++/impl/call.h", @@ -10910,6 +10930,7 @@ "src/cpp/proto/proto_utils.cc", "src/cpp/server/async_generic_service.cc", "src/cpp/server/create_default_thread_pool.cc", + "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/fixed_size_thread_pool.cc", "src/cpp/server/insecure_server_credentials.cc", "src/cpp/server/server.cc", diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json index 98ef004c4bb..b8a074534f9 100644 --- a/tools/run_tests/tests.json +++ b/tools/run_tests/tests.json @@ -675,6 +675,15 @@ "posix" ] }, + { + "flaky": false, + "language": "c++", + "name": "dynamic_thread_pool_test", + "platforms": [ + "windows", + "posix" + ] + }, { "flaky": false, "language": "c++", diff --git a/vsprojects/grpc++/grpc++.vcxproj b/vsprojects/grpc++/grpc++.vcxproj index 2d13bf046b5..51b91c64340 100644 --- a/vsprojects/grpc++/grpc++.vcxproj +++ b/vsprojects/grpc++/grpc++.vcxproj @@ -159,6 +159,7 @@ + @@ -235,6 +236,8 @@ + + diff --git a/vsprojects/grpc++/grpc++.vcxproj.filters b/vsprojects/grpc++/grpc++.vcxproj.filters index c5d8db57aec..85b743a8fb4 100644 --- a/vsprojects/grpc++/grpc++.vcxproj.filters +++ b/vsprojects/grpc++/grpc++.vcxproj.filters @@ -61,6 +61,9 @@ src\cpp\server + + src\cpp\server + src\cpp\server @@ -132,6 +135,9 @@ include\grpc++ + + include\grpc++ + include\grpc++ diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj index f03715b353d..6886bbc2a01 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj @@ -159,6 +159,7 @@ + @@ -222,6 +223,8 @@ + + diff --git a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters index 8f7f3bcd5e9..7f109a25578 100644 --- a/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters +++ b/vsprojects/grpc++_unsecure/grpc++_unsecure.vcxproj.filters @@ -46,6 +46,9 @@ src\cpp\server + + src\cpp\server + src\cpp\server @@ -117,6 +120,9 @@ include\grpc++ + + include\grpc++ + include\grpc++ From b76f3ada1177f8ae4ce749a6305b55c3552fb92a Mon Sep 17 00:00:00 2001 From: vjpai Date: Thu, 23 Jul 2015 14:41:23 -0700 Subject: [PATCH 12/47] Fix bug on shutdown case --- include/grpc++/dynamic_thread_pool.h | 1 + src/cpp/server/dynamic_thread_pool.cc | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/grpc++/dynamic_thread_pool.h b/include/grpc++/dynamic_thread_pool.h index 7519a47726c..e01063ced23 100644 --- a/include/grpc++/dynamic_thread_pool.h +++ b/include/grpc++/dynamic_thread_pool.h @@ -64,6 +64,7 @@ class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface { }; grpc::mutex mu_; grpc::condition_variable cv_; + grpc::condition_variable shutdown_cv_; bool shutdown_; std::queue> callbacks_; int reserve_threads_; diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc index bc0d16f1704..c42563103c6 100644 --- a/src/cpp/server/dynamic_thread_pool.cc +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -58,6 +58,9 @@ void DynamicThreadPool::DynamicThread::ThreadFunc() { pool_->dead_threads_.push_back(this); } } + if ((pool_->shutdown_) && (pool_->nthreads_ == 0)) { + pool_->shutdown_cv_.notify_one(); + } } void DynamicThreadPool::ThreadFunc() { @@ -103,12 +106,12 @@ void DynamicThreadPool::ReapThreads(std::list* tlist) { } DynamicThreadPool::~DynamicThreadPool() { - { - grpc::lock_guard lock(mu_); - shutdown_ = true; - cv_.notify_all(); + grpc::unique_lock lock(mu_); + shutdown_ = true; + cv_.notify_all(); + while (nthreads_ != 0) { + shutdown_cv_.wait(lock); } - ReapThreads(&live_threads_); ReapThreads(&dead_threads_); } From 05cc0c4ba0efe3b838eacf364ea4a6413a8b5afe Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Jul 2015 16:01:27 -0700 Subject: [PATCH 13/47] Integration fix --- src/core/transport/chttp2/writing.c | 8 +++----- src/core/transport/chttp2_transport.c | 6 +++++- src/core/transport/transport_op_string.c | 10 +++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c index 54d38f2841b..d39b0c42f7f 100644 --- a/src/core/transport/chttp2/writing.c +++ b/src/core/transport/chttp2/writing.c @@ -77,6 +77,7 @@ int grpc_chttp2_unlocking_check_writes( stream_writing->id = stream_global->id; stream_writing->send_closed = GRPC_DONT_SEND_CLOSED; + GPR_ASSERT(!stream_global->writing_now); if (stream_global->outgoing_sopb) { window_delta = @@ -227,12 +228,9 @@ void grpc_chttp2_cleanup_writing( if (!transport_global->is_client) { stream_global->read_closed = 1; } - grpc_chttp2_list_add_read_write_state_changed(transport_global, - stream_global); - } else if (stream_global->read_closed) { - grpc_chttp2_list_add_read_write_state_changed(transport_global, - stream_global); } + grpc_chttp2_list_add_read_write_state_changed(transport_global, + stream_global); } transport_writing->outbuf.count = 0; transport_writing->outbuf.length = 0; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index 05402525465..bca6090b6b6 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -399,7 +399,11 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { gpr_mu_unlock(&t->mu); for (i = 0; i < STREAM_LIST_COUNT; i++) { - GPR_ASSERT(!s->included[i]); + if (s->included[i]) { + gpr_log(GPR_ERROR, "%s stream %d still included in list %d", + t->global.is_client ? "client" : "server", s->global.id, i); + abort(); + } } GPR_ASSERT(s->global.outgoing_sopb == NULL); diff --git a/src/core/transport/transport_op_string.c b/src/core/transport/transport_op_string.c index 10d796fc158..f62c340e97f 100644 --- a/src/core/transport/transport_op_string.c +++ b/src/core/transport/transport_op_string.c @@ -116,10 +116,9 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { if (op->send_ops) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; - gpr_strvec_add(&b, gpr_strdup("SEND")); - if (op->is_last_send) { - gpr_strvec_add(&b, gpr_strdup("_LAST")); - } + gpr_asprintf(&tmp, "SEND%s:%p", op->is_last_send ? "_LAST" : "", + op->on_done_send); + gpr_strvec_add(&b, tmp); gpr_strvec_add(&b, gpr_strdup("[")); gpr_strvec_add(&b, grpc_sopb_string(op->send_ops)); gpr_strvec_add(&b, gpr_strdup("]")); @@ -128,7 +127,8 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op) { if (op->recv_ops) { if (!first) gpr_strvec_add(&b, gpr_strdup(" ")); first = 0; - gpr_asprintf(&tmp, "RECV:max_recv_bytes=%d", op->max_recv_bytes); + gpr_asprintf(&tmp, "RECV:%p:max_recv_bytes=%d", op->on_done_recv, + op->max_recv_bytes); gpr_strvec_add(&b, tmp); } From 1f3e6c1ebed11e1477be01c57f3be4ab1d0af00b Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 23 Jul 2015 16:18:21 -0700 Subject: [PATCH 14/47] Start switching everything to dynamic pool --- src/cpp/server/create_default_thread_pool.cc | 4 ++-- test/cpp/end2end/end2end_test.cc | 4 ++-- test/cpp/end2end/mock_test.cc | 4 ++-- test/cpp/end2end/thread_stress_test.cc | 4 ++-- test/cpp/qps/server_async.cc | 1 - test/cpp/qps/server_sync.cc | 13 ++++++++++--- test/cpp/util/cli_call_test.cc | 4 ++-- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/cpp/server/create_default_thread_pool.cc b/src/cpp/server/create_default_thread_pool.cc index cc182f59f4e..81c84474d83 100644 --- a/src/cpp/server/create_default_thread_pool.cc +++ b/src/cpp/server/create_default_thread_pool.cc @@ -32,7 +32,7 @@ */ #include -#include +#include #ifndef GRPC_CUSTOM_DEFAULT_THREAD_POOL @@ -41,7 +41,7 @@ namespace grpc { ThreadPoolInterface* CreateDefaultThreadPool() { int cores = gpr_cpu_num_cores(); if (!cores) cores = 4; - return new FixedSizeThreadPool(cores); + return new DynamicThreadPool(cores); } } // namespace grpc diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index a865a0e359e..d6b3e255d7c 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include @@ -263,7 +263,7 @@ class End2endTest : public ::testing::Test { TestServiceImpl service_; TestServiceImpl special_service_; TestServiceImplDupPkg dup_pkg_service_; - FixedSizeThreadPool thread_pool_; + DynamicThreadPool thread_pool_; }; static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub, diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index 74b40d54d82..32130e24e94 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -260,7 +260,7 @@ class MockTest : public ::testing::Test { std::unique_ptr server_; std::ostringstream server_address_; TestServiceImpl service_; - FixedSizeThreadPool thread_pool_; + DynamicThreadPool thread_pool_; }; // Do one real rpc and one mocked one diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc index e47139641b4..ff9c945c7c3 100644 --- a/test/cpp/end2end/thread_stress_test.cc +++ b/test/cpp/end2end/thread_stress_test.cc @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -208,7 +208,7 @@ class End2endTest : public ::testing::Test { const int kMaxMessageSize_; TestServiceImpl service_; TestServiceImplDupPkg dup_pkg_service_; - FixedSizeThreadPool thread_pool_; + DynamicThreadPool thread_pool_; }; static void SendRpc(grpc::cpp::test::util::TestService::Stub* stub, diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 846f8f31b0d..33b6fa55c38 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc index d90ff2212bc..4c3c9cb497f 100644 --- a/test/cpp/qps/server_sync.cc +++ b/test/cpp/qps/server_sync.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,13 @@ class TestServiceImpl GRPC_FINAL : public TestService::Service { class SynchronousServer GRPC_FINAL : public grpc::testing::Server { public: SynchronousServer(const ServerConfig& config, int port) - : thread_pool_(config.threads()), impl_(MakeImpl(port)) {} + : thread_pool_(), impl_(MakeImpl(port)) { + if (config.threads() > 0) { + thread_pool_.reset(new FixedSizeThreadPool(config.threads())); + } else { + thread_pool_.reset(new DynamicThreadPool(-config.threads())); + } + } private: std::unique_ptr MakeImpl(int port) { @@ -105,13 +112,13 @@ class SynchronousServer GRPC_FINAL : public grpc::testing::Server { builder.RegisterService(&service_); - builder.SetThreadPool(&thread_pool_); + builder.SetThreadPool(thread_pool_.get()); return builder.BuildAndStart(); } TestServiceImpl service_; - FixedSizeThreadPool thread_pool_; + std::unique_ptr thread_pool_; std::unique_ptr impl_; }; diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 00bb821ae67..848a3aee577 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -102,7 +102,7 @@ class CliCallTest : public ::testing::Test { std::unique_ptr server_; std::ostringstream server_address_; TestServiceImpl service_; - FixedSizeThreadPool thread_pool_; + DynamicThreadPool thread_pool_; }; // Send a rpc with a normal stub and then a CliCall. Verify they match. From e3086f812e9a55ab665f4fbf49ac27861d2b6aea Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Thu, 23 Jul 2015 16:25:00 -0700 Subject: [PATCH 15/47] Integration fix --- src/core/transport/chttp2_transport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index bca6090b6b6..5f49b2ddd60 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -395,6 +395,7 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) { } grpc_chttp2_list_remove_incoming_window_updated(&t->global, &s->global); + grpc_chttp2_list_remove_writable_stream(&t->global, &s->global); gpr_mu_unlock(&t->mu); From 67ab91052d74f908988ec0abb830d6f012188217 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Thu, 23 Jul 2015 16:32:25 -0700 Subject: [PATCH 16/47] Start off with zero reserve threads to make sure that that case works --- test/cpp/server/dynamic_thread_pool_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/server/dynamic_thread_pool_test.cc b/test/cpp/server/dynamic_thread_pool_test.cc index 615b5470770..63b603b8f7b 100644 --- a/test/cpp/server/dynamic_thread_pool_test.cc +++ b/test/cpp/server/dynamic_thread_pool_test.cc @@ -42,7 +42,7 @@ namespace grpc { class DynamicThreadPoolTest : public ::testing::Test { public: - DynamicThreadPoolTest() : thread_pool_(4) {} + DynamicThreadPoolTest() : thread_pool_(0) {} protected: DynamicThreadPool thread_pool_; From 02b80549e9f6283b29bd4bb4b0b87682c24ba5e3 Mon Sep 17 00:00:00 2001 From: vjpai Date: Thu, 23 Jul 2015 17:44:45 -0700 Subject: [PATCH 17/47] Bug fixes --- include/grpc++/dynamic_thread_pool.h | 1 - src/cpp/server/dynamic_thread_pool.cc | 27 +++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/include/grpc++/dynamic_thread_pool.h b/include/grpc++/dynamic_thread_pool.h index e01063ced23..bc4e2d4d749 100644 --- a/include/grpc++/dynamic_thread_pool.h +++ b/include/grpc++/dynamic_thread_pool.h @@ -70,7 +70,6 @@ class DynamicThreadPool GRPC_FINAL : public ThreadPoolInterface { int reserve_threads_; int nthreads_; int threads_waiting_; - std::list live_threads_; std::list dead_threads_; void ThreadFunc(); diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc index c42563103c6..7e9b01143aa 100644 --- a/src/cpp/server/dynamic_thread_pool.cc +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -50,14 +50,9 @@ void DynamicThreadPool::DynamicThread::ThreadFunc() { // Now that we have killed ourselves, we should reduce the thread count grpc::unique_lock lock(pool_->mu_); pool_->nthreads_--; - // Move ourselves from live list to dead list - for (auto t = pool_->live_threads_.begin(); t != pool_->live_threads_.end(); - t++) { - if ((*t) == this) { - t = pool_->live_threads_.erase(t); - pool_->dead_threads_.push_back(this); - } - } + // Move ourselves to dead list + pool_->dead_threads_.push_back(this); + if ((pool_->shutdown_) && (pool_->nthreads_ == 0)) { pool_->shutdown_cv_.notify_one(); } @@ -69,7 +64,7 @@ void DynamicThreadPool::ThreadFunc() { grpc::unique_lock lock(mu_); if (!shutdown_ && callbacks_.empty()) { // If there are too many threads waiting, then quit this thread - if (threads_waiting_ == reserve_threads_) { + if (threads_waiting_ >= reserve_threads_) { break; } threads_waiting_++; @@ -90,11 +85,12 @@ void DynamicThreadPool::ThreadFunc() { } DynamicThreadPool::DynamicThreadPool(int reserve_threads) : - shutdown_(false), reserve_threads_(reserve_threads), threads_waiting_(0) { + shutdown_(false), reserve_threads_(reserve_threads), nthreads_(0), + threads_waiting_(0) { for (int i = 0; i < reserve_threads_; i++) { grpc::lock_guard lock(mu_); nthreads_++; - live_threads_.push_back(new DynamicThread(this)); + new DynamicThread(this); } } @@ -117,13 +113,16 @@ DynamicThreadPool::~DynamicThreadPool() { void DynamicThreadPool::Add(const std::function& callback) { grpc::lock_guard lock(mu_); + // Add works to the callbacks list + callbacks_.push(callback); + // Increase pool size or notify as needed if (threads_waiting_ == 0) { // Kick off a new thread nthreads_++; - live_threads_.push_back(new DynamicThread(this)); + new DynamicThread(this); + } else { + cv_.notify_one(); } - callbacks_.push(callback); - cv_.notify_one(); // Also use this chance to harvest dead threads if (!dead_threads_.empty()) { ReapThreads(&dead_threads_); From f6410f54bc5426217f09a57dc9deaea2acf3d1d5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 22 Jul 2015 16:21:57 -0700 Subject: [PATCH 18/47] robust conversion from Timespec to DateTime and tests --- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 2 +- .../Grpc.Core.Tests/Internal/TimespecTest.cs | 158 ++++++++++++++++++ src/csharp/Grpc.Core.Tests/TimespecTest.cs | 101 ----------- src/csharp/Grpc.Core/Internal/Timespec.cs | 128 ++++++++++---- src/csharp/ext/grpc_csharp_ext.c | 12 +- 5 files changed, 264 insertions(+), 137 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs delete mode 100644 src/csharp/Grpc.Core.Tests/TimespecTest.cs diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 927954c448a..7070802d0f4 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -44,13 +44,13 @@ - + diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs new file mode 100644 index 00000000000..69b94bb3933 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -0,0 +1,158 @@ +#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 Grpc.Core.Internal; +using NUnit.Framework; + +namespace Grpc.Core.Internal.Tests +{ + public class TimespecTest + { + [Test] + public void Now() + { + var timespec = Timespec.Now; + } + + [Test] + public void InfFuture() + { + var timespec = Timespec.InfFuture; + } + + [Test] + public void InfPast() + { + var timespec = Timespec.InfPast; + } + + [Test] + public void TimespecSizeIsNativeSize() + { + Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec))); + } + + [Test] + public void ToDateTime() + { + Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), + new Timespec(IntPtr.Zero, 0).ToDateTime()); + + Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50), + new Timespec(new IntPtr(10), 5000).ToDateTime()); + + Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc), + new Timespec(new IntPtr(1437452508), 0).ToDateTime()); + + // before epoch + Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10), + new Timespec(new IntPtr(-5), 1000).ToDateTime()); + } + + [Test] + public void ToDateTime_RoundUp() + { + Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1), + new Timespec(IntPtr.Zero, 99).ToDateTime()); + } + + [Test] + public void ToDateTime_WrongInputs() + { + Assert.Throws(typeof(InvalidOperationException), + () => new Timespec(new IntPtr(0), -2).ToDateTime()); + Assert.Throws(typeof(InvalidOperationException), + () => new Timespec(new IntPtr(0), 1000 * 1000 * 1000).ToDateTime()); + Assert.Throws(typeof(InvalidOperationException), + () => new Timespec(new IntPtr(0), 0, GPRClockType.Monotonic).ToDateTime()); + } + + [Test] + public void ToDateTime_ReturnsUtc() + { + Assert.AreEqual(DateTimeKind.Utc, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind); + Assert.AreNotEqual(DateTimeKind.Unspecified, new Timespec(new IntPtr(1437452508), 0).ToDateTime().Kind); + } + + [Test] + public void ToDateTime_Infinity() + { + Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime()); + Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime()); + } + + [Test] + public void ToDateTime_OverflowGivesMaxOrMinVal() + { + // we can only get overflow in ticks arithmetic on 64-bit + if (IntPtr.Size == 8) + { + var timespec = new Timespec(new IntPtr(long.MaxValue - 100), 0); + Assert.AreNotEqual(Timespec.InfFuture, timespec); + Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime()); + + Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(long.MinValue + 100), 0).ToDateTime()); + } + else + { + Console.WriteLine("Test cannot be run on this platform, skipping the test."); + } + } + + [Test] + public void ToDateTime_OutOfRangeGivesMaxOrMinVal() + { + // we can only get out of range on 64-bit, on 32 bit the max + // timestamp is ~ Jan 19 2038, which is far within range of DateTime + // same case for min value. + if (IntPtr.Size == 8) + { + // DateTime range goes up to year 9999, 20000 years from now should + // be out of range. + long seconds = 20000L * 365L * 24L * 3600L; + + var timespec = new Timespec(new IntPtr(seconds), 0); + Assert.AreNotEqual(Timespec.InfFuture, timespec); + Assert.AreEqual(DateTime.MaxValue, timespec.ToDateTime()); + + Assert.AreEqual(DateTime.MinValue, new Timespec(new IntPtr(-seconds), 0).ToDateTime()); + } + else + { + Console.WriteLine("Test cannot be run on this platform, skipping the test"); + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/TimespecTest.cs deleted file mode 100644 index a34b407a016..00000000000 --- a/src/csharp/Grpc.Core.Tests/TimespecTest.cs +++ /dev/null @@ -1,101 +0,0 @@ -#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 Grpc.Core.Internal; -using NUnit.Framework; - -namespace Grpc.Core.Internal.Tests -{ - public class TimespecTest - { - [Test] - public void Now() - { - var timespec = Timespec.Now; - } - - [Test] - public void InfFuture() - { - var timespec = Timespec.InfFuture; - } - - [Test] - public void TimespecSizeIsNativeSize() - { - Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec))); - } - - [Test] - public void ToDateTime() - { - Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), - new Timespec(IntPtr.Zero, 0).ToDateTime()); - - Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50), - new Timespec(new IntPtr(10), 5000).ToDateTime()); - - Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc), - new Timespec(new IntPtr(1437452508), 0).ToDateTime()); - } - - [Test] - public void Add() - { - var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 }; - var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10)); - Assert.AreEqual(result.tv_sec, new IntPtr(12355)); - Assert.AreEqual(result.tv_nsec, 123456789); - } - - [Test] - public void Add_Nanos() - { - var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 123456789 }; - var result = t.Add(TimeSpan.FromTicks(10)); - Assert.AreEqual(result.tv_sec, new IntPtr(12345)); - Assert.AreEqual(result.tv_nsec, 123456789 + 1000); - } - - [Test] - public void Add_NanosOverflow() - { - var t = new Timespec { tv_sec = new IntPtr(12345), tv_nsec = 999999999 }; - var result = t.Add(TimeSpan.FromTicks(TimeSpan.TicksPerSecond * 10 + 10)); - Assert.AreEqual(result.tv_sec, new IntPtr(12356)); - Assert.AreEqual(result.tv_nsec, 999); - } - } -} diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index da2819f14df..32a9c93f770 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -32,6 +32,8 @@ using System; using System.Runtime.InteropServices; using System.Threading; +using Grpc.Core.Utils; + namespace Grpc.Core.Internal { /// @@ -40,32 +42,40 @@ namespace Grpc.Core.Internal [StructLayout(LayoutKind.Sequential)] internal struct Timespec { - const int NanosPerSecond = 1000 * 1000 * 1000; - const int NanosPerTick = 100; + const long NanosPerSecond = 1000 * 1000 * 1000; + const long NanosPerTick = 100; + const long TicksPerSecond = NanosPerSecond / NanosPerTick; static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); [DllImport("grpc_csharp_ext.dll")] - static extern Timespec gprsharp_now(); + static extern Timespec gprsharp_now(GPRClockType clockType); + + [DllImport("grpc_csharp_ext.dll")] + static extern Timespec gprsharp_inf_future(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] - static extern Timespec gprsharp_inf_future(); + static extern Timespec gprsharp_inf_past(GPRClockType clockType); [DllImport("grpc_csharp_ext.dll")] static extern int gprsharp_sizeof_timespec(); - public Timespec(IntPtr tv_sec, int tv_nsec) + public Timespec(IntPtr tv_sec, int tv_nsec) : this(tv_sec, tv_nsec, GPRClockType.Realtime) + { + } + + public Timespec(IntPtr tv_sec, int tv_nsec, GPRClockType clock_type) { this.tv_sec = tv_sec; this.tv_nsec = tv_nsec; - this.clock_type = GPRClockType.Realtime; + this.clock_type = clock_type; } // NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8 // so IntPtr seems to have the right size to work on both. - public System.IntPtr tv_sec; - public int tv_nsec; - public GPRClockType clock_type; + private System.IntPtr tv_sec; + private int tv_nsec; + private GPRClockType clock_type; /// /// Timespec a long time in the future. @@ -74,54 +84,108 @@ namespace Grpc.Core.Internal { get { - return gprsharp_inf_future(); + return gprsharp_inf_future(GPRClockType.Realtime); } } - public static Timespec Now + /// + /// Timespec a long time in the past. + /// + public static Timespec InfPast { get { - return gprsharp_now(); + return gprsharp_inf_past(GPRClockType.Realtime); } } - - public DateTime ToDateTime() + + /// + /// Return Timespec representing the current time. + /// + public static Timespec Now { - return UnixEpoch.AddTicks(tv_sec.ToInt64() * (NanosPerSecond / NanosPerTick) + tv_nsec / NanosPerTick); + get + { + return gprsharp_now(GPRClockType.Realtime); + } } - internal static int NativeSize + /// + /// Seconds since unix epoch. + /// + public IntPtr TimevalSeconds { get { - return gprsharp_sizeof_timespec(); + return tv_sec; } } /// - /// Creates a GPR deadline from current instant and given timeout. + /// The nanoseconds part of timeval. /// - /// The from timeout. - public static Timespec DeadlineFromTimeout(TimeSpan timeout) + public int TimevalNanos { - if (timeout == Timeout.InfiniteTimeSpan) + get { - return Timespec.InfFuture; + return tv_nsec; } - return Timespec.Now.Add(timeout); } + + /// + /// Converts Timespec to DateTime. + /// Timespec needs to be of type GPRClockType.Realtime and needs to represent a legal value. + /// DateTime has lower resolution (100ns), so rounding can occurs. + /// Value are always rounded up to the nearest DateTime value in the future. + /// + /// For Timespec.InfFuture or if timespec is after the largest representable DateTime, DateTime.MaxValue is returned. + /// For Timespec.InfPast or if timespec is before the lowest representable DateTime, DateTime.MinValue is returned. + /// + /// Unless DateTime.MaxValue or DateTime.MinValue is returned, the resulting DateTime is always in UTC + /// (DateTimeKind.Utc) + /// + public DateTime ToDateTime() + { + Preconditions.CheckState(tv_nsec >= 0 && tv_nsec < NanosPerSecond); + Preconditions.CheckState(clock_type == GPRClockType.Realtime); + + // fast path for InfFuture + if (this.Equals(InfFuture)) + { + return DateTime.MaxValue; + } + + // fast path for InfPast + if (this.Equals(InfPast)) + { + return DateTime.MinValue; + } - public Timespec Add(TimeSpan timeSpan) + try + { + // convert nanos to ticks, round up to the nearest tick + long ticksFromNanos = tv_nsec / NanosPerTick + ((tv_nsec % NanosPerTick != 0) ? 1 : 0); + long ticksTotal = checked(tv_sec.ToInt64() * TicksPerSecond + ticksFromNanos); + return UnixEpoch.AddTicks(ticksTotal); + } + catch (OverflowException) + { + // ticks out of long range + return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue; + } + catch (ArgumentOutOfRangeException) + { + // resulting date time would be larger than MaxValue + return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue; + } + } + + internal static int NativeSize { - long nanos = (long)tv_nsec + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * NanosPerTick; - long overflow_sec = (nanos > NanosPerSecond) ? 1 : 0; - - Timespec result; - result.tv_nsec = (int)(nanos % NanosPerSecond); - result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec); - result.clock_type = GPRClockType.Realtime; - return result; + get + { + return gprsharp_sizeof_timespec(); + } } } } diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 682521446f4..1cc44ebda7e 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -433,10 +433,16 @@ grpcsharp_channel_args_destroy(grpc_channel_args *args) { /* Timespec */ -GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(GPR_CLOCK_REALTIME); } +GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(gpr_clock_type clock_type) { + return gpr_now(clock_type); +} + +GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(gpr_clock_type clock_type) { + return gpr_inf_future(clock_type); +} -GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(void) { - return gpr_inf_future(GPR_CLOCK_REALTIME); +GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_past(gpr_clock_type clock_type) { + return gpr_inf_past(clock_type); } GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) { From 4113ba5420852aeadb8c5698b0af20fcf3da1bd0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 22 Jul 2015 18:37:35 -0700 Subject: [PATCH 19/47] implemented FromDateTime --- .../Grpc.Core.Tests/Internal/TimespecTest.cs | 15 +++++++- src/csharp/Grpc.Core/Internal/Timespec.cs | 35 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs index 69b94bb3933..8469a9e3da4 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -41,9 +41,22 @@ namespace Grpc.Core.Internal.Tests public class TimespecTest { [Test] - public void Now() + public void Now_IsInUtc() + { + Assert.AreEqual(DateTimeKind.Utc, Timespec.Now.ToDateTime().Kind); + } + + [Test] + public void Now_AgreesWithUtcNow() { var timespec = Timespec.Now; + var utcNow = DateTime.UtcNow; + + TimeSpan difference = utcNow - timespec.ToDateTime(); + + // This test is inherently a race - but the two timestamps + // should really be way less that a minute apart. + Assert.IsTrue(difference.TotalSeconds < 60); } [Test] diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index 32a9c93f770..887eae5dd75 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -179,6 +179,41 @@ namespace Grpc.Core.Internal return tv_sec.ToInt64() > 0 ? DateTime.MaxValue : DateTime.MinValue; } } + + public static Timespec FromDateTime(DateTime dateTime) + { + if (dateTime == DateTime.MaxValue) + { + return Timespec.InfFuture; + } + + if (dateTime == DateTime.MinValue) + { + return Timespec.InfPast; + } + + Preconditions.CheckArgument(dateTime.Kind == DateTimeKind.Utc, "dateTime"); + + try + { + TimeSpan timeSpan = dateTime - UnixEpoch; + long ticks = timeSpan.Ticks; + + IntPtr seconds = new IntPtr(ticks / TicksPerSecond); // possible OverflowException + // (x % m + m) % m is workaround for modulo semantics with negative numbers. + int nanos = (int)(((ticks % TicksPerSecond + TicksPerSecond) % TicksPerSecond) * NanosPerTick); + + return new Timespec(seconds, nanos); + } + catch (OverflowException) + { + return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; + } + catch (ArgumentOutOfRangeException) + { + return dateTime > UnixEpoch ? Timespec.InfFuture : Timespec.InfPast; + } + } internal static int NativeSize { From 50b836539c69c17b917224416fa2889c44e53cde Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 13:37:46 -0700 Subject: [PATCH 20/47] Timespec.FromDateTime implementation and tests --- .../Grpc.Core.Tests/Internal/TimespecTest.cs | 65 ++++++++++++++----- src/csharp/Grpc.Core/Internal/Timespec.cs | 23 +++++-- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs index 8469a9e3da4..e38d48d464c 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -92,18 +92,16 @@ namespace Grpc.Core.Internal.Tests // before epoch Assert.AreEqual(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10), new Timespec(new IntPtr(-5), 1000).ToDateTime()); - } - [Test] - public void ToDateTime_RoundUp() - { + // infinity + Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime()); + Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime()); + + // nanos are rounded to ticks are rounded up Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks(1), new Timespec(IntPtr.Zero, 99).ToDateTime()); - } - [Test] - public void ToDateTime_WrongInputs() - { + // Illegal inputs Assert.Throws(typeof(InvalidOperationException), () => new Timespec(new IntPtr(0), -2).ToDateTime()); Assert.Throws(typeof(InvalidOperationException), @@ -120,14 +118,7 @@ namespace Grpc.Core.Internal.Tests } [Test] - public void ToDateTime_Infinity() - { - Assert.AreEqual(DateTime.MaxValue, Timespec.InfFuture.ToDateTime()); - Assert.AreEqual(DateTime.MinValue, Timespec.InfPast.ToDateTime()); - } - - [Test] - public void ToDateTime_OverflowGivesMaxOrMinVal() + public void ToDateTime_Overflow() { // we can only get overflow in ticks arithmetic on 64-bit if (IntPtr.Size == 8) @@ -145,7 +136,7 @@ namespace Grpc.Core.Internal.Tests } [Test] - public void ToDateTime_OutOfRangeGivesMaxOrMinVal() + public void ToDateTime_OutOfDateTimeRange() { // we can only get out of range on 64-bit, on 32 bit the max // timestamp is ~ Jan 19 2038, which is far within range of DateTime @@ -167,5 +158,45 @@ namespace Grpc.Core.Internal.Tests Console.WriteLine("Test cannot be run on this platform, skipping the test"); } } + + [Test] + public void FromDateTime() + { + Assert.AreEqual(new Timespec(IntPtr.Zero, 0), + Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))); + + Assert.AreEqual(new Timespec(new IntPtr(10), 5000), + Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50))); + + Assert.AreEqual(new Timespec(new IntPtr(1437452508), 0), + Timespec.FromDateTime(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc))); + + // before epoch + Assert.AreEqual(new Timespec(new IntPtr(-5), 1000), + Timespec.FromDateTime(new DateTime(1969, 12, 31, 23, 59, 55, DateTimeKind.Utc).AddTicks(10))); + + // infinity + Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(DateTime.MaxValue)); + Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(DateTime.MinValue)); + + // illegal inputs + Assert.Throws(typeof(ArgumentException), + () => Timespec.FromDateTime(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Unspecified))); + } + + [Test] + public void FromDateTime_OutOfTimespecRange() + { + // we can only get overflow in Timespec on 32-bit + if (IntPtr.Size == 4) + { + Assert.AreEqual(Timespec.InfFuture, new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.AreEqual(Timespec.InfPast, new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + } + else + { + Console.WriteLine("Test cannot be run on this platform, skipping the test."); + } + } } } diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index 887eae5dd75..0e58e2048df 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -180,6 +180,14 @@ namespace Grpc.Core.Internal } } + /// + /// Creates DateTime to Timespec. + /// DateTime has to be in UTC (DateTimeKind.Utc) unless it's DateTime.MaxValue or DateTime.MinValue. + /// For DateTime.MaxValue of date time after the largest representable Timespec, Timespec.InfFuture is returned. + /// For DateTime.MinValue of date time before the lowest representable Timespec, Timespec.InfPast is returned. + /// + /// The date time. + /// Date time. public static Timespec FromDateTime(DateTime dateTime) { if (dateTime == DateTime.MaxValue) @@ -199,11 +207,16 @@ namespace Grpc.Core.Internal TimeSpan timeSpan = dateTime - UnixEpoch; long ticks = timeSpan.Ticks; - IntPtr seconds = new IntPtr(ticks / TicksPerSecond); // possible OverflowException - // (x % m + m) % m is workaround for modulo semantics with negative numbers. - int nanos = (int)(((ticks % TicksPerSecond + TicksPerSecond) % TicksPerSecond) * NanosPerTick); - - return new Timespec(seconds, nanos); + long seconds = ticks / TicksPerSecond; + int nanos = (int)((ticks % TicksPerSecond) * NanosPerTick); + if (nanos < 0) + { + // correct the result based on C# modulo semantics for negative dividend + seconds--; + nanos += (int)NanosPerSecond; + } + // new IntPtr possibly throws OverflowException + return new Timespec(new IntPtr(seconds), nanos); } catch (OverflowException) { From 74529562e3227517f952d5b8d527f0e7b616db1c Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 14:04:51 -0700 Subject: [PATCH 21/47] added deadline to generated stubs --- src/compiler/csharp_generator.cc | 12 ++--- src/csharp/Grpc.Examples/MathGrpc.cs | 30 ++++++------ src/csharp/Grpc.HealthCheck/HealthGrpc.cs | 12 ++--- .../Grpc.IntegrationTesting/TestGrpc.cs | 48 +++++++++---------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc index 64371047e00..586d6a79948 100644 --- a/src/compiler/csharp_generator.cc +++ b/src/compiler/csharp_generator.cc @@ -269,7 +269,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) { if (method_type == METHODTYPE_NO_STREAMING) { // unary calls have an extra synchronous stub method out->Print( - "$response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n", + "$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n", "methodname", method->name(), "request", GetClassName(method->input_type()), "response", GetClassName(method->output_type())); @@ -280,7 +280,7 @@ void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) { method_name += "Async"; // prevent name clash with synchronous method. } out->Print( - "$returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken));\n", + "$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n", "methodname", method_name, "request_maybe", GetMethodRequestParamMaybe(method), "returntype", GetMethodReturnTypeClient(method)); @@ -332,13 +332,13 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) { if (method_type == METHODTYPE_NO_STREAMING) { // unary calls have an extra synchronous stub method out->Print( - "public $response$ $methodname$($request$ request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n", + "public $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n", "methodname", method->name(), "request", GetClassName(method->input_type()), "response", GetClassName(method->output_type())); out->Print("{\n"); out->Indent(); - out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n", + out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n", "servicenamefield", GetServiceNameFieldName(), "methodfield", GetMethodFieldName(method)); out->Print("return Calls.BlockingUnaryCall(call, request, cancellationToken);\n"); @@ -351,13 +351,13 @@ void GenerateClientStub(Printer* out, const ServiceDescriptor *service) { method_name += "Async"; // prevent name clash with synchronous method. } out->Print( - "public $returntype$ $methodname$($request_maybe$Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken))\n", + "public $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n", "methodname", method_name, "request_maybe", GetMethodRequestParamMaybe(method), "returntype", GetMethodReturnTypeClient(method)); out->Print("{\n"); out->Indent(); - out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers);\n", + out->Print("var call = CreateCall($servicenamefield$, $methodfield$, headers, deadline);\n", "servicenamefield", GetServiceNameFieldName(), "methodfield", GetMethodFieldName(method)); switch (GetMethodType(method)) { diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index ef787cf1d87..67827e7b4f6 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -44,11 +44,11 @@ namespace math { // client interface public interface IMathClient { - global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); + global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); } // server-side interface @@ -66,29 +66,29 @@ namespace math { public MathClient(Channel channel) : base(channel) { } - public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Div, headers); + var call = CreateCall(__ServiceName, __Method_Div, headers, deadline); return Calls.BlockingUnaryCall(call, request, cancellationToken); } - public AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Div, headers); + var call = CreateCall(__ServiceName, __Method_Div, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } - public AsyncDuplexStreamingCall DivMany(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_DivMany, headers); + var call = CreateCall(__ServiceName, __Method_DivMany, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } - public AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Fib, headers); + var call = CreateCall(__ServiceName, __Method_Fib, headers, deadline); return Calls.AsyncServerStreamingCall(call, request, cancellationToken); } - public AsyncClientStreamingCall Sum(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Sum, headers); + var call = CreateCall(__ServiceName, __Method_Sum, headers, deadline); return Calls.AsyncClientStreamingCall(call, cancellationToken); } } diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index 217127eca73..892cdb3f042 100644 --- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -24,8 +24,8 @@ namespace Grpc.Health.V1Alpha { // client interface public interface IHealthClient { - global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); } // server-side interface @@ -40,14 +40,14 @@ namespace Grpc.Health.V1Alpha { public HealthClient(Channel channel) : base(channel) { } - public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Check, headers); + var call = CreateCall(__ServiceName, __Method_Check, headers, deadline); return Calls.BlockingUnaryCall(call, request, cancellationToken); } - public AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_Check, headers); + var call = CreateCall(__ServiceName, __Method_Check, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } } diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index de2fa074411..ddcd0c29585 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -59,14 +59,14 @@ namespace grpc.testing { // client interface public interface ITestServiceClient { - global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)); + global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); } // server-side interface @@ -86,44 +86,44 @@ namespace grpc.testing { public TestServiceClient(Channel channel) : base(channel) { } - public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_EmptyCall, headers); + var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline); return Calls.BlockingUnaryCall(call, request, cancellationToken); } - public AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_EmptyCall, headers); + var call = CreateCall(__ServiceName, __Method_EmptyCall, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } - public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_UnaryCall, headers); + var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline); return Calls.BlockingUnaryCall(call, request, cancellationToken); } - public AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_UnaryCall, headers); + var call = CreateCall(__ServiceName, __Method_UnaryCall, headers, deadline); return Calls.AsyncUnaryCall(call, request, cancellationToken); } - public AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers); + var call = CreateCall(__ServiceName, __Method_StreamingOutputCall, headers, deadline); return Calls.AsyncServerStreamingCall(call, request, cancellationToken); } - public AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers); + var call = CreateCall(__ServiceName, __Method_StreamingInputCall, headers, deadline); return Calls.AsyncClientStreamingCall(call, cancellationToken); } - public AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers); + var call = CreateCall(__ServiceName, __Method_FullDuplexCall, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } - public AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { - var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers); + var call = CreateCall(__ServiceName, __Method_HalfDuplexCall, headers, deadline); return Calls.AsyncDuplexStreamingCall(call, cancellationToken); } } From 0846b68eb7bc6f6f63770880a2d48e787274ef67 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 17:02:12 -0700 Subject: [PATCH 22/47] add Timeout support and tests --- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 192 ++++++++++++++++++ src/csharp/Grpc.Core/Call.cs | 15 ++ src/csharp/Grpc.Core/Calls.cs | 18 +- src/csharp/Grpc.Core/ClientBase.cs | 6 +- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 16 +- .../Grpc.Core/Internal/AsyncCallServer.cs | 20 ++ .../Grpc.Core/Internal/CallSafeHandle.cs | 10 - .../Grpc.Core/Internal/ChannelSafeHandle.cs | 10 + .../Grpc.Core/Internal/ServerCallHandler.cs | 12 +- 10 files changed, 264 insertions(+), 36 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/TimeoutsTest.cs diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 7070802d0f4..9364779df9e 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -51,6 +51,7 @@ + diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs new file mode 100644 index 00000000000..7c844c7953d --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -0,0 +1,192 @@ +#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.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + /// + /// Tests for Deadline support. + /// + public class TimeoutsTest + { + const string Host = "localhost"; + const string ServiceName = "/tests.Test"; + + static readonly Method TestMethod = new Method( + MethodType.Unary, + "/tests.Test/Test", + Marshallers.StringMarshaller, + Marshallers.StringMarshaller); + + static readonly ServerServiceDefinition ServiceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) + .AddMethod(TestMethod, TestMethodHandler) + .Build(); + + // provides a way how to retrieve an out-of-band result value from server handler + static TaskCompletionSource stringFromServerHandlerTcs; + + Server server; + Channel channel; + + [SetUp] + public void Init() + { + server = new Server(); + server.AddServiceDefinition(ServiceDefinition); + int port = server.AddListeningPort(Host, Server.PickUnusedPort); + server.Start(); + channel = new Channel(Host, port); + + stringFromServerHandlerTcs = new TaskCompletionSource(); + } + + [TearDown] + public void Cleanup() + { + channel.Dispose(); + server.ShutdownAsync().Wait(); + } + + [TestFixtureTearDown] + public void CleanupClass() + { + GrpcEnvironment.Shutdown(); + } + + [Test] + public void InfiniteDeadline() + { + // no deadline specified, check server sees infinite deadline + var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty); + Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None)); + + // DateTime.MaxValue deadline specified, check server sees infinite deadline + var internalCall2 = new Call(ServiceName, TestMethod, channel, Metadata.Empty, DateTime.MaxValue); + Assert.AreEqual("DATETIME_MAXVALUE", Calls.BlockingUnaryCall(internalCall2, "RETURN_DEADLINE", CancellationToken.None)); + } + + [Test] + public void DeadlineTransferredToServer() + { + var remainingTimeClient = TimeSpan.FromDays(7); + var deadline = DateTime.UtcNow + remainingTimeClient; + Thread.Sleep(1000); + var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + + var serverDeadlineTicksString = Calls.BlockingUnaryCall(internalCall, "RETURN_DEADLINE", CancellationToken.None); + var serverDeadline = new DateTime(long.Parse(serverDeadlineTicksString), DateTimeKind.Utc); + + // A fairly relaxed check that the deadline set by client and deadline seen by server + // are in agreement. C core takes care of the work with transferring deadline over the wire, + // so we don't need an exact check here. + Assert.IsTrue(Math.Abs((deadline - serverDeadline).TotalMilliseconds) < 5000); + } + + [Test] + public void DeadlineExceededStatusOnTimeout() + { + // no deadline specified, check server sees infinite deadline + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(1)); + var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + + try + { + Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); + } + } + + [Test] + public void ServerReceivesCancellationOnTimeout() + { + // no deadline specified, check server sees infinite deadline + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(1)); + var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + + try + { + Calls.BlockingUnaryCall(internalCall, "CHECK_CANCELLATION_RECEIVED", CancellationToken.None); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); + } + Assert.AreEqual("CANCELLED", stringFromServerHandlerTcs.Task.Result); + } + + private static async Task TestMethodHandler(string request, ServerCallContext context) + { + if (request == "TIMEOUT") + { + await Task.Delay(60000); + return ""; + } + + if (request == "RETURN_DEADLINE") + { + if (context.Deadline == DateTime.MaxValue) + { + return "DATETIME_MAXVALUE"; + } + + return context.Deadline.Ticks.ToString(); + } + + if (request == "CHECK_CANCELLATION_RECEIVED") + { + // wait until cancellation token is fired. + var tcs = new TaskCompletionSource(); + context.CancellationToken.Register(() => { tcs.SetResult(null); }); + await tcs.Task; + stringFromServerHandlerTcs.SetResult("CANCELLED"); + return ""; + } + + return ""; + } + } +} diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs index 37b452f020d..94c5e260822 100644 --- a/src/csharp/Grpc.Core/Call.cs +++ b/src/csharp/Grpc.Core/Call.cs @@ -47,14 +47,21 @@ namespace Grpc.Core readonly Marshaller responseMarshaller; readonly Channel channel; readonly Metadata headers; + readonly DateTime deadline; public Call(string serviceName, Method method, Channel channel, Metadata headers) + : this(serviceName, method, channel, headers, DateTime.MaxValue) + { + } + + public Call(string serviceName, Method method, Channel channel, Metadata headers, DateTime deadline) { this.name = method.GetFullName(serviceName); this.requestMarshaller = method.RequestMarshaller; this.responseMarshaller = method.ResponseMarshaller; this.channel = Preconditions.CheckNotNull(channel); this.headers = Preconditions.CheckNotNull(headers); + this.deadline = deadline; } public Channel Channel @@ -87,6 +94,14 @@ namespace Grpc.Core } } + public DateTime Deadline + { + get + { + return this.deadline; + } + } + public Marshaller RequestMarshaller { get diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index 359fe537416..054fc274917 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -50,7 +50,7 @@ namespace Grpc.Core var asyncCall = new AsyncCall(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); // TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts. RegisterCancellationCallback(asyncCall, token); - return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers); + return asyncCall.UnaryCall(call.Channel, call.Name, req, call.Headers, call.Deadline); } public static AsyncUnaryCall AsyncUnaryCall(Call call, TRequest req, CancellationToken token) @@ -58,8 +58,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name); - var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers); + asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); + var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers, call.Deadline); RegisterCancellationCallback(asyncCall, token); return new AsyncUnaryCall(asyncResult, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); } @@ -69,8 +69,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name); - asyncCall.StartServerStreamingCall(req, call.Headers); + asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); + asyncCall.StartServerStreamingCall(req, call.Headers, call.Deadline); RegisterCancellationCallback(asyncCall, token); var responseStream = new ClientResponseStream(asyncCall); return new AsyncServerStreamingCall(responseStream, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); @@ -81,8 +81,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name); - var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers); + asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); + var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers, call.Deadline); RegisterCancellationCallback(asyncCall, token); var requestStream = new ClientRequestStream(asyncCall); return new AsyncClientStreamingCall(requestStream, resultTask, asyncCall.GetStatus, asyncCall.GetTrailers, asyncCall.Cancel); @@ -93,8 +93,8 @@ namespace Grpc.Core where TResponse : class { var asyncCall = new AsyncCall(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); - asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name); - asyncCall.StartDuplexStreamingCall(call.Headers); + asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name, Timespec.FromDateTime(call.Deadline)); + asyncCall.StartDuplexStreamingCall(call.Headers, call.Deadline); RegisterCancellationCallback(asyncCall, token); var requestStream = new ClientRequestStream(asyncCall); var responseStream = new ClientResponseStream(asyncCall); diff --git a/src/csharp/Grpc.Core/ClientBase.cs b/src/csharp/Grpc.Core/ClientBase.cs index a099f96aeab..fd3473128a9 100644 --- a/src/csharp/Grpc.Core/ClientBase.cs +++ b/src/csharp/Grpc.Core/ClientBase.cs @@ -76,7 +76,7 @@ namespace Grpc.Core /// /// Creates a new call to given method. /// - protected Call CreateCall(string serviceName, Method method, Metadata metadata) + protected Call CreateCall(string serviceName, Method method, Metadata metadata, DateTime? deadline) where TRequest : class where TResponse : class { @@ -87,8 +87,8 @@ namespace Grpc.Core interceptor(metadata); metadata.Freeze(); } - metadata = metadata ?? Metadata.Empty; - return new Call(serviceName, method, channel, metadata); + return new Call(serviceName, method, channel, + metadata ?? Metadata.Empty, deadline ?? DateTime.MaxValue); } } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index f983dbb759c..51022ac34fc 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -61,10 +61,10 @@ namespace Grpc.Core.Internal { } - public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName) + public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName, Timespec deadline) { this.channel = channel; - var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture); + var call = channel.Handle.CreateCall(channel.CompletionRegistry, cq, methodName, channel.Target, deadline); channel.Environment.DebugStats.ActiveClientCalls.Increment(); InitializeInternal(call); } @@ -76,7 +76,7 @@ namespace Grpc.Core.Internal /// /// Blocking unary request - unary response call. /// - public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers) + public TResponse UnaryCall(Channel channel, string methodName, TRequest msg, Metadata headers, DateTime deadline) { using (CompletionQueueSafeHandle cq = CompletionQueueSafeHandle.Create()) { @@ -86,7 +86,7 @@ namespace Grpc.Core.Internal lock (myLock) { - Initialize(channel, cq, methodName); + Initialize(channel, cq, methodName, Timespec.FromDateTime(deadline)); started = true; halfcloseRequested = true; readingDone = true; @@ -126,7 +126,7 @@ namespace Grpc.Core.Internal /// /// Starts a unary request - unary response call. /// - public Task UnaryCallAsync(TRequest msg, Metadata headers) + public Task UnaryCallAsync(TRequest msg, Metadata headers, DateTime deadline) { lock (myLock) { @@ -151,7 +151,7 @@ namespace Grpc.Core.Internal /// Starts a streamed request - unary response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// - public Task ClientStreamingCallAsync(Metadata headers) + public Task ClientStreamingCallAsync(Metadata headers, DateTime deadline) { lock (myLock) { @@ -173,7 +173,7 @@ namespace Grpc.Core.Internal /// /// Starts a unary request - streamed response call. /// - public void StartServerStreamingCall(TRequest msg, Metadata headers) + public void StartServerStreamingCall(TRequest msg, Metadata headers, DateTime deadline) { lock (myLock) { @@ -196,7 +196,7 @@ namespace Grpc.Core.Internal /// Starts a streaming request - streaming response call. /// Use StartSendMessage and StartSendCloseFromClient to stream requests. /// - public void StartDuplexStreamingCall(Metadata headers) + public void StartDuplexStreamingCall(Metadata headers, DateTime deadline) { lock (myLock) { diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index f809f4a84ca..702f1ce9e7e 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -48,6 +48,7 @@ namespace Grpc.Core.Internal internal class AsyncCallServer : AsyncCallBase { readonly TaskCompletionSource finishedServersideTcs = new TaskCompletionSource(); + readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); readonly GrpcEnvironment environment; public AsyncCallServer(Func serializer, Func deserializer, GrpcEnvironment environment) : base(serializer, deserializer) @@ -118,6 +119,18 @@ namespace Grpc.Core.Internal } } + /// + /// Gets cancellation token that gets cancelled once close completion + /// is received and the cancelled flag is set. + /// + public CancellationToken CancellationToken + { + get + { + return cancellationTokenSource.Token; + } + } + protected override void OnReleaseResources() { environment.DebugStats.ActiveServerCalls.Decrement(); @@ -138,6 +151,8 @@ namespace Grpc.Core.Internal { // Once we cancel, we don't have to care that much // about reads and writes. + + // TODO(jtattermusch): is this still necessary? Cancel(); } @@ -145,6 +160,11 @@ namespace Grpc.Core.Internal } // TODO(jtattermusch): handle error + if (cancelled) + { + cancellationTokenSource.Cancel(); + } + finishedServersideTcs.SetResult(null); } } diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 19dbb83f243..04e35a5efdf 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -45,9 +45,6 @@ namespace Grpc.Core.Internal const uint GRPC_WRITE_BUFFER_HINT = 1; CompletionRegistry completionRegistry; - [DllImport("grpc_csharp_ext.dll")] - static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); - [DllImport("grpc_csharp_ext.dll")] static extern GRPCCallError grpcsharp_call_cancel(CallSafeHandle call); @@ -98,13 +95,6 @@ namespace Grpc.Core.Internal { } - public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) - { - var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline); - result.SetCompletionRegistry(registry); - return result; - } - public void SetCompletionRegistry(CompletionRegistry completionRegistry) { this.completionRegistry = completionRegistry; diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index f046f4c6d0d..53c506c872e 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -46,6 +46,9 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); + [DllImport("grpc_csharp_ext.dll")] + static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline); + [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_channel_destroy(IntPtr channel); @@ -63,6 +66,13 @@ namespace Grpc.Core.Internal return grpcsharp_secure_channel_create(credentials, target, channelArgs); } + public CallSafeHandle CreateCall(CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline) + { + var result = grpcsharp_channel_create_call(this, cq, method, host, deadline); + result.SetCompletionRegistry(registry); + return result; + } + protected override bool ReleaseHandle() { grpcsharp_channel_destroy(handle); diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 3680b1e791b..9bbcb172669 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -72,7 +72,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -126,7 +126,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -180,7 +180,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); try { var result = await handler(requestStream, context); @@ -238,7 +238,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc); + var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); try { await handler(requestStream, responseStream, context); @@ -295,11 +295,11 @@ namespace Grpc.Core.Internal return new Status(StatusCode.Unknown, "Exception was thrown by handler."); } - public static ServerCallContext NewContext(ServerRpcNew newRpc) + public static ServerCallContext NewContext(ServerRpcNew newRpc, CancellationToken cancellationToken) { return new ServerCallContext( newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(), - newRpc.RequestMetadata, CancellationToken.None); + newRpc.RequestMetadata, cancellationToken); } } } From f7cfc8a7b8652bbf81e336f3e62a7cd0da8be2f0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 17:26:35 -0700 Subject: [PATCH 23/47] implemented cancellation support for MathService.Fib --- .../MathClientServerTests.cs | 33 +++++++++++++++++++ src/csharp/Grpc.Examples/MathServiceImpl.cs | 9 +++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 7a957c5b6ff..6edc07912b6 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -132,6 +132,39 @@ namespace math.Tests }).Wait(); } + [Test] + public void FibWithCancel() + { + Task.Run(async () => + { + var cts = new CancellationTokenSource(); + + using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), + cancellationToken: cts.Token)) + { + List responses = new List(); + + try + { + while (await call.ResponseStream.MoveNext()) + { + if (responses.Count == 0) + { + cts.CancelAfter(500); // make sure we cancel soon + } + responses.Add(call.ResponseStream.Current.Num_); + } + Assert.Fail(); + } + catch (RpcException e) + { + Assert.IsTrue(responses.Count > 0); + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); + } + } + }).Wait(); + } + // TODO: test Fib with limit=0 and cancellation [Test] public void Sum() diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index 3dd0f53a0d1..dd26b1d3501 100644 --- a/src/csharp/Grpc.Examples/MathServiceImpl.cs +++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs @@ -54,8 +54,13 @@ namespace math { if (request.Limit <= 0) { - // TODO(jtattermusch): support cancellation - throw new NotImplementedException("Not implemented yet"); + // keep streaming the sequence until cancelled. + IEnumerator fibEnumerator = FibInternal(long.MaxValue).GetEnumerator(); + while (!context.CancellationToken.IsCancellationRequested && fibEnumerator.MoveNext()) + { + await responseStream.WriteAsync(fibEnumerator.Current); + await Task.Delay(100); + } } if (request.Limit > 0) From 4106259c79fecafa91e3bed35de008ebdc3a4857 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 17:30:24 -0700 Subject: [PATCH 24/47] add MathService.Fib test with deadline --- .../MathClientServerTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 6edc07912b6..dd56016a394 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -165,6 +165,27 @@ namespace math.Tests }).Wait(); } + [Test] + public void FibWithDeadline() + { + Task.Run(async () => + { + using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), + deadline: DateTime.UtcNow.AddMilliseconds(500))) + { + try + { + await call.ResponseStream.ToList(); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); + } + } + }).Wait(); + } + // TODO: test Fib with limit=0 and cancellation [Test] public void Sum() From 7a3ac62d9cdd1392b06a4bb94c57a4828ec0b32e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 18:40:48 -0700 Subject: [PATCH 25/47] explicitly convert deadline for server handlers to realtime --- src/csharp/Grpc.Core/Internal/ServerCallHandler.cs | 4 +++- src/csharp/Grpc.Core/Internal/Timespec.cs | 11 +++++++++++ src/csharp/ext/grpc_csharp_ext.c | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 9bbcb172669..93e1c0b2946 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -297,8 +297,10 @@ namespace Grpc.Core.Internal public static ServerCallContext NewContext(ServerRpcNew newRpc, CancellationToken cancellationToken) { + DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); + return new ServerCallContext( - newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(), + newRpc.Method, newRpc.Host, realtimeDeadline, newRpc.RequestMetadata, cancellationToken); } } diff --git a/src/csharp/Grpc.Core/Internal/Timespec.cs b/src/csharp/Grpc.Core/Internal/Timespec.cs index 0e58e2048df..e83d21f4a4a 100644 --- a/src/csharp/Grpc.Core/Internal/Timespec.cs +++ b/src/csharp/Grpc.Core/Internal/Timespec.cs @@ -57,6 +57,9 @@ namespace Grpc.Core.Internal [DllImport("grpc_csharp_ext.dll")] static extern Timespec gprsharp_inf_past(GPRClockType clockType); + [DllImport("grpc_csharp_ext.dll")] + static extern Timespec gprsharp_convert_clock_type(Timespec t, GPRClockType targetClock); + [DllImport("grpc_csharp_ext.dll")] static extern int gprsharp_sizeof_timespec(); @@ -131,6 +134,14 @@ namespace Grpc.Core.Internal return tv_nsec; } } + + /// + /// Converts the timespec to desired clock type. + /// + public Timespec ToClockType(GPRClockType targetClock) + { + return gprsharp_convert_clock_type(this, targetClock); + } /// /// Converts Timespec to DateTime. diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 1cc44ebda7e..7e30a84a629 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -445,6 +445,10 @@ GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_past(gpr_clock_type clock_type return gpr_inf_past(clock_type); } +GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock) { + return gpr_convert_clock_type(t, target_clock); +} + GPR_EXPORT gpr_int32 GPR_CALLTYPE gprsharp_sizeof_timespec(void) { return sizeof(gpr_timespec); } From 24b3b7e3d4d0c65cbd729bd29c462765d5a74e34 Mon Sep 17 00:00:00 2001 From: vjpai Date: Thu, 23 Jul 2015 18:51:03 -0700 Subject: [PATCH 26/47] Fix thread list iterator --- src/cpp/server/dynamic_thread_pool.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cpp/server/dynamic_thread_pool.cc b/src/cpp/server/dynamic_thread_pool.cc index 7e9b01143aa..f58d0420dfb 100644 --- a/src/cpp/server/dynamic_thread_pool.cc +++ b/src/cpp/server/dynamic_thread_pool.cc @@ -95,9 +95,8 @@ DynamicThreadPool::DynamicThreadPool(int reserve_threads) : } void DynamicThreadPool::ReapThreads(std::list* tlist) { - for (auto t = tlist->begin(); t != tlist->end(); t++) { - delete *t; - t = tlist->erase(t); + for (auto t = tlist->begin(); t != tlist->end(); t = tlist->erase(t)) { + delete *t; } } From 6835b92c8b2f5ea7bb692e6fb52983a045a54bf9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 18:51:38 -0700 Subject: [PATCH 27/47] fix test on windows --- src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs index e38d48d464c..874df02baa0 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/TimespecTest.cs @@ -190,8 +190,8 @@ namespace Grpc.Core.Internal.Tests // we can only get overflow in Timespec on 32-bit if (IntPtr.Size == 4) { - Assert.AreEqual(Timespec.InfFuture, new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc)); - Assert.AreEqual(Timespec.InfPast, new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.AreEqual(Timespec.InfFuture, Timespec.FromDateTime(new DateTime(2040, 1, 1, 0, 0, 0, DateTimeKind.Utc))); + Assert.AreEqual(Timespec.InfPast, Timespec.FromDateTime(new DateTime(1800, 1, 1, 0, 0, 0, DateTimeKind.Utc))); } else { From 49313cec38d42d9614132aa78a665cdc9193949b Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 19:17:30 -0700 Subject: [PATCH 28/47] tiny fixes --- src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index 7c844c7953d..c350391acdd 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -121,11 +121,27 @@ namespace Grpc.Core.Tests Assert.IsTrue(Math.Abs((deadline - serverDeadline).TotalMilliseconds) < 5000); } + [Test] + public void DeadlineInThePast() + { + var deadline = DateTime.MinValue; + var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); + + try + { + Calls.BlockingUnaryCall(internalCall, "TIMEOUT", CancellationToken.None); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); + } + } + [Test] public void DeadlineExceededStatusOnTimeout() { - // no deadline specified, check server sees infinite deadline - var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(1)); + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); try @@ -142,8 +158,7 @@ namespace Grpc.Core.Tests [Test] public void ServerReceivesCancellationOnTimeout() { - // no deadline specified, check server sees infinite deadline - var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(1)); + var deadline = DateTime.UtcNow.Add(TimeSpan.FromSeconds(5)); var internalCall = new Call(ServiceName, TestMethod, channel, Metadata.Empty, deadline); try From 7cbac4cf95bf685157f9e18608ec877c415d2696 Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 23 Jul 2015 23:00:52 -0700 Subject: [PATCH 29/47] Fix gpr_inf_future call --- include/grpc++/impl/sync_no_cxx11.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h index dda939bf715..fda668957eb 100644 --- a/include/grpc++/impl/sync_no_cxx11.h +++ b/include/grpc++/impl/sync_no_cxx11.h @@ -87,7 +87,7 @@ class condition_variable { ~condition_variable() { gpr_cv_destroy(&cv_); } void wait(lock_guard &mu) { mu.locked = false; - gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future); + gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME); mu.locked = true; } void notify_one() { gpr_cv_signal(&cv_); } From a75098d0afb6c8492cc8cdbef014b4de92f8b4c2 Mon Sep 17 00:00:00 2001 From: Stanley Cheung Date: Fri, 24 Jul 2015 09:03:39 -0700 Subject: [PATCH 30/47] add user-agent for php --- composer.json | 1 + src/php/composer.json | 2 +- src/php/lib/Grpc/BaseStub.php | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 875ec55d8a0..1d78a2ce210 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,7 @@ "name": "grpc/grpc", "type": "library", "description": "gRPC library for PHP", + "version": "0.5.1", "keywords": ["rpc"], "homepage": "http://grpc.io", "license": "BSD-3-Clause", diff --git a/src/php/composer.json b/src/php/composer.json index b0115bdadd2..2d0fe0c87a2 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -1,7 +1,7 @@ { "name": "grpc/grpc", "description": "gRPC library for PHP", - "version": "0.5.0", + "version": "0.5.1", "homepage": "http://grpc.io", "license": "BSD-3-Clause", "repositories": [ diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php index 48c00977eb8..8c438e4bf92 100755 --- a/src/php/lib/Grpc/BaseStub.php +++ b/src/php/lib/Grpc/BaseStub.php @@ -60,7 +60,10 @@ class BaseStub { } unset($opts['update_metadata']); } - + $package_config = json_decode( + file_get_contents(dirname(__FILE__) . '/../../composer.json'), true); + $opts['grpc.primary_user_agent'] = + 'grpc-php/' . $package_config['version']; $this->channel = new Channel($hostname, $opts); } From ea12b97243f95d1830a9f70c3c176b82ef37cb04 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 24 Jul 2015 10:43:27 -0700 Subject: [PATCH 31/47] Exposed channel target and call peer in Node wrapper --- src/node/ext/call.cc | 14 ++++++++++++ src/node/ext/call.h | 1 + src/node/ext/channel.cc | 11 ++++++++++ src/node/ext/channel.h | 1 + src/node/src/client.js | 16 ++++++++++++++ src/node/src/server.js | 16 ++++++++++++++ src/node/test/call_test.js | 6 ++++++ src/node/test/channel_test.js | 6 ++++++ src/node/test/surface_test.js | 40 +++++++++++++++++++++++++++++++++++ 9 files changed, 111 insertions(+) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 15c9b2d97d6..b647735ead7 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -453,6 +453,8 @@ void Call::Init(Handle exports) { NanNew(StartBatch)->GetFunction()); NanSetPrototypeTemplate(tpl, "cancel", NanNew(Cancel)->GetFunction()); + NanSetPrototypeTemplate(tpl, "getPeer", + NanNew(GetPeer)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle ctr = tpl->GetFunction(); ctr->Set(NanNew("WRITE_BUFFER_HINT"), @@ -608,5 +610,17 @@ NAN_METHOD(Call::Cancel) { NanReturnUndefined(); } +NAN_METHOD(Call::GetPeer) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("getPeer can only be called on Call objects"); + } + Call *call = ObjectWrap::Unwrap(args.This()); + char *peer = grpc_call_get_peer(call->wrapped_call); + Handle peer_value = NanNew(peer); + gpr_free(peer); + NanReturnValue(peer_value); +} + } // namespace node } // namespace grpc diff --git a/src/node/ext/call.h b/src/node/ext/call.h index 43142c7091f..6acda76197f 100644 --- a/src/node/ext/call.h +++ b/src/node/ext/call.h @@ -120,6 +120,7 @@ class Call : public ::node::ObjectWrap { static NAN_METHOD(New); static NAN_METHOD(StartBatch); static NAN_METHOD(Cancel); + static NAN_METHOD(GetPeer); static NanCallback *constructor; // Used for typechecking instances of this javascript class static v8::Persistent fun_tpl; diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index d37bf763ddc..0b7333e4502 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -76,6 +76,8 @@ void Channel::Init(Handle exports) { tpl->InstanceTemplate()->SetInternalFieldCount(1); NanSetPrototypeTemplate(tpl, "close", NanNew(Close)->GetFunction()); + NanSetPrototypeTemplate(tpl, "getTarget", + NanNew(GetTarget)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle ctr = tpl->GetFunction(); constructor = new NanCallback(ctr); @@ -185,5 +187,14 @@ NAN_METHOD(Channel::Close) { NanReturnUndefined(); } +NAN_METHOD(Channel::GetTarget) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("getTarget can only be called on Channel objects"); + } + Channel *channel = ObjectWrap::Unwrap(args.This()); + NanReturnValue(NanNew(grpc_channel_get_target(channel->wrapped_channel))); +} + } // namespace node } // namespace grpc diff --git a/src/node/ext/channel.h b/src/node/ext/channel.h index b3aa0f700fa..6725ebb03f0 100644 --- a/src/node/ext/channel.h +++ b/src/node/ext/channel.h @@ -66,6 +66,7 @@ class Channel : public ::node::ObjectWrap { static NAN_METHOD(New); static NAN_METHOD(Close); + static NAN_METHOD(GetTarget); static NanCallback *constructor; static v8::Persistent fun_tpl; diff --git a/src/node/src/client.js b/src/node/src/client.js index da6327b4320..d89c656c07e 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -187,6 +187,19 @@ ClientReadableStream.prototype.cancel = cancel; ClientWritableStream.prototype.cancel = cancel; ClientDuplexStream.prototype.cancel = cancel; +/** + * Get the endpoint this call/stream is connected to. + * @return {string} The URI of the endpoint + */ +function getPeer() { + /* jshint validthis: true */ + return this.call.getPeer(); +} + +ClientReadableStream.prototype.getPeer = getPeer; +ClientWritableStream.prototype.getPeer = getPeer; +ClientDuplexStream.prototype.getPeer = getPeer; + /** * Get a function that can make unary requests to the specified method. * @param {string} method The name of the method to request @@ -223,6 +236,9 @@ function makeUnaryRequestFunction(method, serialize, deserialize) { emitter.cancel = function cancel() { call.cancel(); }; + emitter.getPeer = function getPeer() { + return call.getPeer(); + }; this.updateMetadata(this.auth_uri, metadata, function(error, metadata) { if (error) { call.cancel(); diff --git a/src/node/src/server.js b/src/node/src/server.js index 0a3a0031bdf..cb86b95f381 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -373,6 +373,19 @@ ServerDuplexStream.prototype._read = _read; ServerDuplexStream.prototype._write = _write; ServerDuplexStream.prototype.sendMetadata = sendMetadata; +/** + * Get the endpoint this call/stream is connected to. + * @return {string} The URI of the endpoint + */ +function getPeer() { + /* jshint validthis: true */ + return this.call.getPeer(); +} + +ServerReadableStream.prototype.getPeer = getPeer; +ServerWritableStream.prototype.getPeer = getPeer; +ServerDuplexStream.prototype.getPeer = getPeer; + /** * Fully handle a unary call * @param {grpc.Call} call The call to handle @@ -389,6 +402,9 @@ function handleUnary(call, handler, metadata) { call.startBatch(batch, function() {}); } }; + emitter.getPeer = function() { + return call.getPeer(); + }; emitter.on('error', function(error) { handleError(call, error); }); diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 98158ffff35..0079144ae6d 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -184,4 +184,10 @@ describe('call', function() { }); }); }); + describe('getPeer', function() { + it('should return a string', function() { + var call = new grpc.Call(channel, 'method', getDeadline(1)); + assert.strictEqual(typeof call.getPeer(), 'string'); + }); + }); }); diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js index 33200c99ee2..3e61d3bbc62 100644 --- a/src/node/test/channel_test.js +++ b/src/node/test/channel_test.js @@ -87,4 +87,10 @@ describe('channel', function() { }); }); }); + describe('getTarget', function() { + it('should return a string', function() { + var channel = new grpc.Channel('localhost', {}); + assert.strictEqual(typeof channel.getTarget(), 'string'); + }); + }); }); diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 3cb68f8cd83..9005cbd505a 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -344,6 +344,9 @@ describe('Other conditions', function() { after(function() { server.shutdown(); }); + it('channel.getTarget should be available', function() { + assert.strictEqual(typeof client.channel.getTarget(), 'string'); + }); describe('Server recieving bad input', function() { var misbehavingClient; var badArg = new Buffer([0xFF]); @@ -549,6 +552,43 @@ describe('Other conditions', function() { }); }); }); + describe('call.getPeer should return the peer', function() { + it('for a unary call', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + done(); + }); + assert.strictEqual(typeof call.getPeer(), 'string'); + }); + it('for a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + done(); + }); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.write({error: false}); + call.end(); + }); + it('for a server stream call', function(done) { + var call = client.serverStream({error: false}); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); + it('for a bidi stream call', function(done) { + var call = client.bidiStream(); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.write({error: false}); + call.end(); + call.on('data', function(){}); + call.on('status', function(status) { + done(); + }); + }); + }); }); describe('Cancelling surface client', function() { var client; From 3f7809d89cc677893a51da26cbf0b371167a46c4 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 13:20:40 -0700 Subject: [PATCH 32/47] fix getpeername code on windows --- src/core/iomgr/tcp_server_windows.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index 8f634fcd7a3..a175398825d 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -250,6 +250,7 @@ static void on_accept(void *arg, int from_iocp) { DWORD transfered_bytes; DWORD flags; BOOL wsa_success; + int err; /* The general mechanism for shutting down is to queue abortion calls. While this is necessary in the read/write case, it's useless for the accept @@ -281,8 +282,21 @@ static void on_accept(void *arg, int from_iocp) { } } else { if (!sp->shutting_down) { - getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len); - peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name); + peer_name_string = NULL; + err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&sp->socket->socket, sizeof(sp->socket->socket)); + if (err) { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); + gpr_free(utf8_message); + } + err = getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len); + if (!err) { + peer_name_string = grpc_sockaddr_to_uri((struct sockaddr*)&peer_name); + } else { + char *utf8_message = gpr_format_message(WSAGetLastError()); + gpr_log(GPR_ERROR, "getpeername error: %s", utf8_message); + gpr_free(utf8_message); + } gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), peer_name_string); gpr_free(fd_name); From d298a9528ace23650b9b51cadb85312ec68e0ec2 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 13:45:56 -0700 Subject: [PATCH 33/47] fix whitespaces and line length --- src/core/iomgr/tcp_server_windows.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c index a175398825d..cc680507ffc 100644 --- a/src/core/iomgr/tcp_server_windows.c +++ b/src/core/iomgr/tcp_server_windows.c @@ -283,10 +283,12 @@ static void on_accept(void *arg, int from_iocp) { } else { if (!sp->shutting_down) { peer_name_string = NULL; - err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&sp->socket->socket, sizeof(sp->socket->socket)); + err = setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + (char *)&sp->socket->socket, + sizeof(sp->socket->socket)); if (err) { char *utf8_message = gpr_format_message(WSAGetLastError()); - gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); + gpr_log(GPR_ERROR, "setsockopt error: %s", utf8_message); gpr_free(utf8_message); } err = getpeername(sock, (struct sockaddr*)&peer_name, &peer_name_len); @@ -298,7 +300,8 @@ static void on_accept(void *arg, int from_iocp) { gpr_free(utf8_message); } gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string); - ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), peer_name_string); + ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name), + peer_name_string); gpr_free(fd_name); gpr_free(peer_name_string); } From 51d22752d6a967fe7ea7de96c3c4a0cd2b8eeca7 Mon Sep 17 00:00:00 2001 From: vjpai Date: Fri, 24 Jul 2015 14:11:04 -0700 Subject: [PATCH 34/47] Switch an int to size_t or else it fails on Mac --- test/cpp/end2end/end2end_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index c433b789482..e722a776698 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -797,7 +797,7 @@ TEST_F(End2endTest, HugeResponse) { EchoRequest request; EchoResponse response; request.set_message("huge response"); - const int kResponseSize = 1024 * (1024 + 10); + const size_t kResponseSize = 1024 * (1024 + 10); request.mutable_param()->set_response_message_length(kResponseSize); ClientContext context; From 062c329cf8afaa8479031c6d91124e1dc936feba Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 20:28:42 -0700 Subject: [PATCH 35/47] expose peer info in serverside call handlers --- .../Grpc.Core.Tests/ClientServerTest.cs | 15 ++++- src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + .../Grpc.Core/Internal/AsyncCallServer.cs | 8 +++ .../Grpc.Core/Internal/CStringSafeHandle.cs | 60 +++++++++++++++++++ .../Grpc.Core/Internal/CallSafeHandle.cs | 11 ++++ .../Grpc.Core/Internal/ServerCallHandler.cs | 12 ++-- src/csharp/Grpc.Core/ServerCallContext.cs | 13 +++- src/csharp/ext/grpc_csharp_ext.c | 8 +++ 8 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 8ba2c8a9a2b..2536c003459 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -45,7 +45,7 @@ namespace Grpc.Core.Tests { public class ClientServerTest { - const string Host = "localhost"; + const string Host = "127.0.0.1"; const string ServiceName = "/tests.Test"; static readonly Method EchoMethod = new Method( @@ -277,6 +277,14 @@ namespace Grpc.Core.Tests Assert.IsTrue(userAgent.StartsWith("grpc-csharp/")); } + [Test] + public void PeerInfoPresent() + { + var internalCall = new Call(ServiceName, EchoMethod, channel, Metadata.Empty); + string peer = Calls.BlockingUnaryCall(internalCall, "RETURN-PEER", CancellationToken.None); + Assert.IsTrue(peer.Contains(Host)); + } + private static async Task EchoHandler(string request, ServerCallContext context) { foreach (Metadata.Entry metadataEntry in context.RequestHeaders) @@ -292,6 +300,11 @@ namespace Grpc.Core.Tests return context.RequestHeaders.Where(entry => entry.Key == "user-agent").Single().Value; } + if (request == "RETURN-PEER") + { + return context.Peer; + } + if (request == "THROW") { throw new Exception("This was thrown on purpose by a test"); diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index fd68b91851e..d756254b022 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -103,6 +103,7 @@ + diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 702f1ce9e7e..513902ee364 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -131,6 +131,14 @@ namespace Grpc.Core.Internal } } + public string Peer + { + get + { + return call.GetPeer(); + } + } + protected override void OnReleaseResources() { environment.DebugStats.ActiveServerCalls.Decrement(); diff --git a/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs new file mode 100644 index 00000000000..92fbe8cf0f1 --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/CStringSafeHandle.cs @@ -0,0 +1,60 @@ +#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.Tasks; + +namespace Grpc.Core.Internal +{ + /// + /// Owned char* object. + /// + internal class CStringSafeHandle : SafeHandleZeroIsInvalid + { + [DllImport("grpc_csharp_ext.dll")] + static extern void gprsharp_free(IntPtr ptr); + + private CStringSafeHandle() + { + } + + public string GetValue() + { + return Marshal.PtrToStringAnsi(handle); + } + + protected override bool ReleaseHandle() + { + gprsharp_free(handle); + return true; + } + } +} diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 04e35a5efdf..714749b171f 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -88,6 +88,9 @@ namespace Grpc.Core.Internal static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call, BatchContextSafeHandle ctx); + [DllImport("grpc_csharp_ext.dll")] + static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call); + [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_call_destroy(IntPtr call); @@ -180,6 +183,14 @@ namespace Grpc.Core.Internal grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail).CheckOk(); } + public string GetPeer() + { + using (var cstring = grpcsharp_call_get_peer(this)) + { + return cstring.GetValue(); + } + } + protected override bool ReleaseHandle() { grpcsharp_call_destroy(handle); diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 93e1c0b2946..84ea346ebc0 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -72,7 +72,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -126,7 +126,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { Preconditions.CheckArgument(await requestStream.MoveNext()); @@ -180,7 +180,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { var result = await handler(requestStream, context); @@ -238,7 +238,7 @@ namespace Grpc.Core.Internal var responseStream = new ServerResponseStream(asyncCall); Status status; - var context = HandlerUtils.NewContext(newRpc, asyncCall.CancellationToken); + var context = HandlerUtils.NewContext(newRpc, asyncCall.Peer, asyncCall.CancellationToken); try { await handler(requestStream, responseStream, context); @@ -295,12 +295,12 @@ namespace Grpc.Core.Internal return new Status(StatusCode.Unknown, "Exception was thrown by handler."); } - public static ServerCallContext NewContext(ServerRpcNew newRpc, CancellationToken cancellationToken) + public static ServerCallContext NewContext(ServerRpcNew newRpc, string peer, CancellationToken cancellationToken) { DateTime realtimeDeadline = newRpc.Deadline.ToClockType(GPRClockType.Realtime).ToDateTime(); return new ServerCallContext( - newRpc.Method, newRpc.Host, realtimeDeadline, + newRpc.Method, newRpc.Host, peer, realtimeDeadline, newRpc.RequestMetadata, cancellationToken); } } diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs index 17a2eefd078..0c48adaea52 100644 --- a/src/csharp/Grpc.Core/ServerCallContext.cs +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -47,6 +47,7 @@ namespace Grpc.Core private readonly string method; private readonly string host; + private readonly string peer; private readonly DateTime deadline; private readonly Metadata requestHeaders; private readonly CancellationToken cancellationToken; @@ -54,10 +55,11 @@ namespace Grpc.Core private Status status = Status.DefaultSuccess; - public ServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken) + public ServerCallContext(string method, string host, string peer, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken) { this.method = method; this.host = host; + this.peer = peer; this.deadline = deadline; this.requestHeaders = requestHeaders; this.cancellationToken = cancellationToken; @@ -81,6 +83,15 @@ namespace Grpc.Core } } + /// Address of the remote endpoint in URI format. + public string Peer + { + get + { + return this.peer; + } + } + /// Deadline for this RPC. public DateTime Deadline { diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 7e30a84a629..756493358fc 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -465,6 +465,14 @@ grpcsharp_call_cancel_with_status(grpc_call *call, grpc_status_code status, return grpc_call_cancel_with_status(call, status, description); } +GPR_EXPORT char *GPR_CALLTYPE grpcsharp_call_get_peer(grpc_call *call) { + return grpc_call_get_peer(call); +} + +GPR_EXPORT void GPR_CALLTYPE gprsharp_free(void *p) { + gpr_free(p); +} + GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) { grpc_call_destroy(call); } From 88a9b329369d6d5effa5df6763edf66c4c134d5f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 21:43:44 -0700 Subject: [PATCH 36/47] added option to authenticate client using root cert chain --- src/csharp/Grpc.Core/Credentials.cs | 48 +++++++++-- src/csharp/Grpc.Core/Grpc.Core.csproj | 1 + .../Internal/CredentialsSafeHandle.cs | 11 ++- .../Internal/ServerCredentialsSafeHandle.cs | 4 +- src/csharp/Grpc.Core/KeyCertificatePair.cs | 84 +++++++++++++++++++ src/csharp/Grpc.Core/ServerCredentials.cs | 67 ++++++++------- 6 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 src/csharp/Grpc.Core/KeyCertificatePair.cs diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs index e64c1e3dc1d..d2dbaaf52f1 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/Credentials.cs @@ -53,27 +53,63 @@ namespace Grpc.Core /// public class SslCredentials : Credentials { - string pemRootCerts; + readonly string rootCertificates; + readonly KeyCertificatePair keyCertificatePair; - public SslCredentials(string pemRootCerts) + /// + /// Creates client-side SSL credentials loaded from + /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable. + /// If that fails, gets the roots certificates from a well known place on disk. + /// + public SslCredentials() : this(null, null) { - this.pemRootCerts = pemRootCerts; + } + + /// + /// Creates client-side SSL credentials from + /// a string containing PEM encoded root certificates. + /// + public SslCredentials(string rootCertificates) : this(rootCertificates, null) + { + } + + /// + /// Creates client-side SSL credentials. + /// + /// string containing PEM encoded server root certificates. + /// a key certificate pair. + public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) + { + this.rootCertificates = rootCertificates; + this.keyCertificatePair = keyCertificatePair; } /// /// PEM encoding of the server root certificates. /// - public string RootCerts + public string RootCertificates + { + get + { + return this.rootCertificates; + } + } + + /// + /// Client side key and certificate pair. + /// If null, client will not use key and certificate pair. + /// + public KeyCertificatePair KeyCertificatePair { get { - return this.pemRootCerts; + return this.keyCertificatePair; } } internal override CredentialsSafeHandle ToNativeCredentials() { - return CredentialsSafeHandle.CreateSslCredentials(pemRootCerts); + return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); } } } diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index d756254b022..2705c95a261 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -104,6 +104,7 @@ + diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs index f361199068e..52d4dfbbac9 100644 --- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs @@ -50,9 +50,16 @@ namespace Grpc.Core.Internal { } - public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts) + public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) { - return grpcsharp_ssl_credentials_create(pemRootCerts, null, null); + if (keyCertPair != null) + { + return grpcsharp_ssl_credentials_create(pemRootCerts, keyCertPair.CertificateChain, keyCertPair.PrivateKey); + } + else + { + return grpcsharp_ssl_credentials_create(pemRootCerts, null, null); + } } protected override bool ReleaseHandle() diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs index 961180741a9..59238a452cf 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs @@ -51,10 +51,10 @@ namespace Grpc.Core.Internal { } - public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray) + public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray) { Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length); - return grpcsharp_ssl_server_credentials_create(null, + return grpcsharp_ssl_server_credentials_create(pemRootCerts, keyCertPairCertChainArray, keyCertPairPrivateKeyArray, new UIntPtr((ulong)keyCertPairCertChainArray.Length)); } diff --git a/src/csharp/Grpc.Core/KeyCertificatePair.cs b/src/csharp/Grpc.Core/KeyCertificatePair.cs new file mode 100644 index 00000000000..7cea18618ef --- /dev/null +++ b/src/csharp/Grpc.Core/KeyCertificatePair.cs @@ -0,0 +1,84 @@ +#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.Collections.Immutable; + +using Grpc.Core.Internal; +using Grpc.Core.Utils; + +namespace Grpc.Core +{ + /// + /// Key certificate pair (in PEM encoding). + /// + public sealed class KeyCertificatePair + { + readonly string certificateChain; + readonly string privateKey; + + /// + /// Creates a new certificate chain - private key pair. + /// + /// PEM encoded certificate chain. + /// PEM encoded private key. + public KeyCertificatePair(string certificateChain, string privateKey) + { + this.certificateChain = Preconditions.CheckNotNull(certificateChain); + this.privateKey = Preconditions.CheckNotNull(privateKey); + } + + /// + /// PEM encoded certificate chain. + /// + public string CertificateChain + { + get + { + return certificateChain; + } + } + + /// + /// PEM encoded private key. + /// + public string PrivateKey + { + get + { + return privateKey; + } + } + } +} diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index ab7d0b49143..334211e9f90 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -35,6 +35,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using Grpc.Core.Internal; +using Grpc.Core.Utils; namespace Grpc.Core { @@ -51,59 +52,69 @@ namespace Grpc.Core } /// - /// Key certificate pair (in PEM encoding). + /// Server-side SSL credentials. /// - public class KeyCertificatePair + public class SslServerCredentials : ServerCredentials { - readonly string certChain; - readonly string privateKey; + readonly IList keyCertificatePairs; + readonly string rootCertificates; - public KeyCertificatePair(string certChain, string privateKey) + /// + /// Creates server-side SSL credentials. + /// + /// PEM encoded client root certificates used to authenticate client. + /// Key-certificates to use. + public SslServerCredentials(IEnumerable keyCertificatePairs, string rootCertificates) { - this.certChain = certChain; - this.privateKey = privateKey; + this.rootCertificates = rootCertificates; + this.keyCertificatePairs = new List(keyCertificatePairs).AsReadOnly(); + Preconditions.CheckArgument(this.keyCertificatePairs.Count == 0, + "At least one KeyCertificatePair needs to be provided"); } - public string CertChain + /// + /// Creates server-side SSL credentials. + /// This constructor should be use if you do not wish to autheticate client + /// using client root certificates. + /// + /// Key-certificates to use. + public SslServerCredentials(IEnumerable keyCertificatePairs) : this(keyCertificatePairs, null) { - get - { - return certChain; - } } - public string PrivateKey + /// + /// Key-certificate pairs. + /// + public IList KeyCertificatePairs { get { - return privateKey; + return this.keyCertificatePairs; } } - } - /// - /// Server-side SSL credentials. - /// - public class SslServerCredentials : ServerCredentials - { - ImmutableList keyCertPairs; - - public SslServerCredentials(ImmutableList keyCertPairs) + /// + /// PEM encoded client root certificates. + /// + public string RootCertificates { - this.keyCertPairs = keyCertPairs; + get + { + return this.rootCertificates; + } } internal override ServerCredentialsSafeHandle ToNativeCredentials() { - int count = keyCertPairs.Count; + int count = keyCertificatePairs.Count; string[] certChains = new string[count]; string[] keys = new string[count]; for (int i = 0; i < count; i++) { - certChains[i] = keyCertPairs[i].CertChain; - keys[i] = keyCertPairs[i].PrivateKey; + certChains[i] = keyCertificatePairs[i].CertificateChain; + keys[i] = keyCertificatePairs[i].PrivateKey; } - return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys); + return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys); } } } From eea5955b56f8ddbbfd8b42a50c4f7db72add3a84 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 22:05:32 -0700 Subject: [PATCH 37/47] added test for client SSL authentication --- src/csharp/Grpc.Core/ServerCredentials.cs | 4 +- .../Grpc.IntegrationTesting.csproj | 59 +++++------ .../SslCredentialsTest.cs | 98 +++++++++++++++++++ .../TestCredentials.cs | 2 +- 4 files changed, 125 insertions(+), 38 deletions(-) create mode 100644 src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index 334211e9f90..1b40ce8f6af 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -66,10 +66,10 @@ namespace Grpc.Core /// Key-certificates to use. public SslServerCredentials(IEnumerable keyCertificatePairs, string rootCertificates) { - this.rootCertificates = rootCertificates; this.keyCertificatePairs = new List(keyCertificatePairs).AsReadOnly(); - Preconditions.CheckArgument(this.keyCertificatePairs.Count == 0, + Preconditions.CheckArgument(this.keyCertificatePairs.Count > 0, "At least one KeyCertificatePair needs to be provided"); + this.rootCertificates = rootCertificates; } /// diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index d3c69ab9eb9..934899f0839 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -3,8 +3,6 @@ Debug x86 - 8.0.30703 - 2.0 {C61154BA-DD4A-4838-8420-0162A28925E0} Library Grpc.IntegrationTesting @@ -32,59 +30,49 @@ x86 - - False + + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + + + ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll - - False + ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll - - False + ..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll - - False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll - - False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll - - False + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - - False + ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll - - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - - ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll - - - False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - - ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll - - - - - False + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll - - False + ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll - @@ -99,6 +87,7 @@ + diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs new file mode 100644 index 00000000000..b2397d4e236 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -0,0 +1,98 @@ +#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.Threading; +using System.Threading.Tasks; +using grpc.testing; +using Grpc.Core; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.IntegrationTesting +{ + /// + /// Test SSL credentials where server authenticates client + /// and client authenticates the server. + /// + public class SslCredentialsTest + { + string host = "localhost"; + Server server; + Channel channel; + TestService.ITestServiceClient client; + + [TestFixtureSetUp] + public void Init() + { + var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath); + var keyCertPair = new KeyCertificatePair( + File.ReadAllText(TestCredentials.ServerCertChainPath), + File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); + + var serverCredentials = new SslServerCredentials(new [] { keyCertPair }, rootCert); + var clientCredentials = new SslCredentials(rootCert, keyCertPair); + + server = new Server(); + server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); + int port = server.AddListeningPort(host, Server.PickUnusedPort, serverCredentials); + server.Start(); + + var options = new List + { + new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) + }; + + channel = new Channel(host, port, clientCredentials, options); + client = TestService.NewClient(channel); + } + + [TestFixtureTearDown] + public void Cleanup() + { + channel.Dispose(); + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } + + [Test] + public void AuthenticatedClientAndServer() + { + var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build()); + Assert.AreEqual(10, response.Payload.Body.Length); + } + + } +} diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs index 401c50b1aea..54d8587713c 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs @@ -78,7 +78,7 @@ namespace Grpc.IntegrationTesting var keyCertPair = new KeyCertificatePair( File.ReadAllText(ServerCertChainPath), File.ReadAllText(ServerPrivateKeyPath)); - return new SslServerCredentials(ImmutableList.Create(keyCertPair)); + return new SslServerCredentials(new[] { keyCertPair }); } } } From dce9f6e4c2c0ff118fc1b4412cd118833f091720 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 22:20:21 -0700 Subject: [PATCH 38/47] fix x86 target to be AnyCPU --- .../Grpc.Examples.MathClient.csproj | 10 +- .../Grpc.Examples.MathServer.csproj | 10 +- .../Grpc.IntegrationTesting.Client.csproj | 10 +- .../Grpc.IntegrationTesting.Server.csproj | 10 +- .../Grpc.IntegrationTesting.csproj | 10 +- src/csharp/Grpc.sln | 100 +++++++++--------- 6 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj index 5d5401593d0..85996a570cd 100644 --- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj +++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj @@ -2,7 +2,7 @@ Debug - x86 + AnyCPU 10.0.0 2.0 {61ECB8EE-0C96-4F8E-B187-8E4D227417C0} @@ -11,7 +11,7 @@ MathClient v4.5 - + true full false @@ -20,16 +20,16 @@ prompt 4 true - x86 + AnyCPU - + full true bin\Release prompt 4 true - x86 + AnyCPU diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj index 677d87da205..6c8856cc921 100644 --- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj +++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj @@ -2,7 +2,7 @@ Debug - x86 + AnyCPU 10.0.0 2.0 {BF62FE08-373A-43D6-9D73-41CAA38B7011} @@ -11,7 +11,7 @@ MathServer v4.5 - + true full false @@ -20,16 +20,16 @@ prompt 4 true - x86 + AnyCPU - + full true bin\Release prompt 4 true - x86 + AnyCPU diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj index dc1d0a44c04..37d53d61e0d 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj @@ -2,7 +2,7 @@ Debug - x86 + AnyCPU {3D166931-BA2D-416E-95A3-D36E8F6E90B9} Exe Grpc.IntegrationTesting.Client @@ -10,7 +10,7 @@ Grpc.IntegrationTesting.Client.Program v4.5 - + true full false @@ -19,16 +19,16 @@ prompt 4 true - x86 + AnyCPU - + full true bin\Release prompt 4 true - x86 + AnyCPU diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj index f03c8f3ce3e..0f3b9eb5101 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj @@ -2,7 +2,7 @@ Debug - x86 + AnyCPU {A654F3B8-E859-4E6A-B30D-227527DBEF0D} Exe Grpc.IntegrationTesting.Server @@ -10,7 +10,7 @@ Grpc.IntegrationTesting.Server.Program v4.5 - + true full false @@ -19,16 +19,16 @@ prompt 4 true - x86 + AnyCPU - + full true bin\Release prompt 4 true - x86 + AnyCPU diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 934899f0839..f34d034d88a 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -2,14 +2,14 @@ Debug - x86 + AnyCPU {C61154BA-DD4A-4838-8420-0162A28925E0} Library Grpc.IntegrationTesting Grpc.IntegrationTesting v4.5 - + true full false @@ -18,16 +18,16 @@ prompt 4 true - x86 + AnyCPU - + full true bin\Release prompt 4 true - x86 + AnyCPU diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index 705e4fb1c21..0cd8aaef6d2 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -34,58 +34,58 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "G EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU - {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU - {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU - {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU - {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86 - {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86 - {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86 - {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86 - {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86 - {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86 - {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86 - {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86 - {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU - {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU - {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU - {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU - {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU - {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU - {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU - {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU - {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86 - {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86 - {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86 - {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86 - {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU - {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU - {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU - {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU - {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU - {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU - {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU - {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86 - {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86 - {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86 - {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86 - {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86 - {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86 - {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86 - {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86 - {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU - {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU - {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU - {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU - {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU - {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU - {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU - {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU + {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU + {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU + {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU + {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU + {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU + {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU + {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU + {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU + {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU + {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU + {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution EndGlobalSection From a6b82884689ddbbae2c63763dfc1992a616dd72d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 23 Jul 2015 22:48:28 -0700 Subject: [PATCH 39/47] upgrade Grpc.Auth to latest version of Google.Apis.Auth and remove unneeded code --- src/csharp/Grpc.Auth/GoogleCredential.cs | 21 ++------ src/csharp/Grpc.Auth/Grpc.Auth.csproj | 40 +++++++++------ src/csharp/Grpc.Auth/Grpc.Auth.nuspec | 3 +- src/csharp/Grpc.Auth/app.config | 2 +- src/csharp/Grpc.Auth/packages.config | 12 ++--- .../Grpc.IntegrationTesting.Client/app.config | 2 +- .../Grpc.IntegrationTesting.Server/app.config | 2 +- .../Grpc.IntegrationTesting.csproj | 51 +++++++++++-------- src/csharp/Grpc.IntegrationTesting/app.config | 2 +- .../Grpc.IntegrationTesting/packages.config | 12 ++--- 10 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs index 7edf19ed67a..9936cf583ca 100644 --- a/src/csharp/Grpc.Auth/GoogleCredential.cs +++ b/src/csharp/Grpc.Auth/GoogleCredential.cs @@ -89,17 +89,15 @@ namespace Grpc.Auth return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer())); } - JObject o1 = JObject.Parse(File.ReadAllText(credsPath)); - string clientEmail = o1.GetValue(ClientEmailFieldName).Value(); - string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value(); - var privateKey = ParsePrivateKeyFromString(privateKeyString); + JObject jsonCredentialParameters = JObject.Parse(File.ReadAllText(credsPath)); + string clientEmail = jsonCredentialParameters.GetValue(ClientEmailFieldName).Value(); + string privateKeyString = jsonCredentialParameters.GetValue(PrivateKeyFieldName).Value(); var serviceCredential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(clientEmail) { Scopes = scopes, - Key = privateKey - }); + }.FromPrivateKey(privateKeyString)); return new GoogleCredential(serviceCredential); } @@ -123,16 +121,5 @@ namespace Grpc.Auth return credential; } } - - private RSACryptoServiceProvider ParsePrivateKeyFromString(string base64PrivateKey) - { - // TODO(jtattermusch): temporary code to create RSACryptoServiceProvider. - base64PrivateKey = base64PrivateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("\n", "").Replace("-----END PRIVATE KEY-----", ""); - RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(base64PrivateKey)); - RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(key); - RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); - rsa.ImportParameters(rsaParameters); - return rsa; - } } } diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index fdec2e7bd7f..afb8204c07e 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -11,6 +11,7 @@ Grpc.Auth v4.5 bin\$(Configuration)\Grpc.Auth.Xml + 9b408026 true @@ -34,14 +35,17 @@ ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll - - ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll + + False + ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll - - ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll + + False + ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll - - ..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + False + ..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll @@ -52,18 +56,20 @@ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - + False - ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll - - ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll + + False + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll - - ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll + + False + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll @@ -87,9 +93,11 @@ - - - - + + + + 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}. + + \ No newline at end of file diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec index 1262bdbdab8..eeaa49aa92a 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec +++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec @@ -15,8 +15,7 @@ Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 Auth OAuth2 - - + diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config index 966b777192f..0a82bb4f16c 100644 --- a/src/csharp/Grpc.Auth/app.config +++ b/src/csharp/Grpc.Auth/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config index 7d348872ba7..29be953bf3e 100644 --- a/src/csharp/Grpc.Auth/packages.config +++ b/src/csharp/Grpc.Auth/packages.config @@ -1,11 +1,11 @@  - - - + + + - - - + + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config index 966b777192f..0a82bb4f16c 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config index 966b777192f..0a82bb4f16c 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/app.config +++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index f34d034d88a..c8302476e02 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -8,6 +8,7 @@ Grpc.IntegrationTesting Grpc.IntegrationTesting v4.5 + 041c163e true @@ -30,6 +31,22 @@ AnyCPU + + False + ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll + + + False + ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.PlatformServices.dll + + + False + ..\packages\Google.Apis.Core.1.9.2\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll @@ -42,16 +59,15 @@ - - - ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll + + False + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll - - ..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll - - - ..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + False + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll @@ -61,18 +77,9 @@ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll - - ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll - ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - - ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll - - - ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll - @@ -122,9 +129,11 @@ - - - - + + + + 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}. + + \ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config index 966b777192f..0a82bb4f16c 100644 --- a/src/csharp/Grpc.IntegrationTesting/app.config +++ b/src/csharp/Grpc.IntegrationTesting/app.config @@ -4,7 +4,7 @@ - + diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index c74ac75d79a..29107e5d369 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -1,14 +1,14 @@  - - + + - + - - - + + + \ No newline at end of file From f9c2d9760570d321794dd89b34ed67f4606084c5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 01:30:20 -0700 Subject: [PATCH 40/47] fix reference to bouncyCastles assembly --- .../Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj | 3 +++ src/csharp/Grpc.IntegrationTesting/packages.config | 1 + 2 files changed, 4 insertions(+) diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index c8302476e02..db2e304d373 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -31,6 +31,9 @@ AnyCPU + + ..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll + False ..\packages\Google.Apis.Auth.1.9.2\lib\net40\Google.Apis.Auth.dll diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index 29107e5d369..746133a7a5c 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -1,5 +1,6 @@  + From 0526161385677fdd8a27dd21611c3e9721d9fc90 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 00:28:16 -0700 Subject: [PATCH 41/47] introduce gRPC logger --- src/csharp/Grpc.Core/Grpc.Core.csproj | 7 +- src/csharp/Grpc.Core/GrpcEnvironment.cs | 33 +++++- src/csharp/Grpc.Core/Internal/AsyncCall.cs | 5 +- .../Grpc.Core/Internal/AsyncCallBase.cs | 13 ++- .../Grpc.Core/Internal/CompletionRegistry.cs | 5 +- .../Grpc.Core/Internal/GrpcThreadPool.cs | 10 +- .../{GrpcLog.cs => NativeLogRedirector.cs} | 37 +++++-- .../Grpc.Core/Internal/ServerCallHandler.cs | 17 ++- src/csharp/Grpc.Core/Logging/ConsoleLogger.cs | 103 ++++++++++++++++++ src/csharp/Grpc.Core/Logging/ILogger.cs | 57 ++++++++++ src/csharp/Grpc.Core/Server.cs | 5 +- src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs | 10 +- .../SslCredentialsTest.cs | 3 +- 13 files changed, 265 insertions(+), 40 deletions(-) rename src/csharp/Grpc.Core/Internal/{GrpcLog.cs => NativeLogRedirector.cs} (74%) create mode 100644 src/csharp/Grpc.Core/Logging/ConsoleLogger.cs create mode 100644 src/csharp/Grpc.Core/Logging/ILogger.cs diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 2705c95a261..0d879e9b1e0 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -47,7 +47,6 @@ - @@ -105,6 +104,9 @@ + + + @@ -135,4 +137,7 @@ + + + \ No newline at end of file diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs index 47d1651aab8..034a66be3c5 100644 --- a/src/csharp/Grpc.Core/GrpcEnvironment.cs +++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs @@ -35,6 +35,7 @@ using System; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core @@ -55,6 +56,8 @@ namespace Grpc.Core static object staticLock = new object(); static GrpcEnvironment instance; + static ILogger logger = new ConsoleLogger(); + readonly GrpcThreadPool threadPool; readonly CompletionRegistry completionRegistry; readonly DebugStats debugStats = new DebugStats(); @@ -92,18 +95,39 @@ namespace Grpc.Core } } + /// + /// Gets application-wide logger used by gRPC. + /// + /// The logger. + public static ILogger Logger + { + get + { + return logger; + } + } + + /// + /// Sets the application-wide logger that should be used by gRPC. + /// + public static void SetLogger(ILogger customLogger) + { + Preconditions.CheckNotNull(customLogger); + logger = customLogger; + } + /// /// Creates gRPC environment. /// private GrpcEnvironment() { - GrpcLog.RedirectNativeLogs(Console.Error); + NativeLogRedirector.Redirect(); grpcsharp_init(); completionRegistry = new CompletionRegistry(this); threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE); threadPool.Start(); // TODO: use proper logging here - Console.WriteLine("GRPC initialized."); + Logger.Info("gRPC initialized."); } /// @@ -154,8 +178,7 @@ namespace Grpc.Core debugStats.CheckOK(); - // TODO: use proper logging here - Console.WriteLine("GRPC shutdown."); + Logger.Info("gRPC shutdown."); } /// @@ -171,7 +194,7 @@ namespace Grpc.Core } catch (Exception e) { - Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e); + Logger.Error(e, "Error occured while shutting down GrpcEnvironment."); } }); } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 51022ac34fc..bfcb9366a12 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -38,6 +38,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -47,6 +48,8 @@ namespace Grpc.Core.Internal /// internal class AsyncCall : AsyncCallBase { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + Channel channel; // Completion of a pending unary response if not null. @@ -106,7 +109,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured while invoking completion delegate: " + e); + Logger.Error(e, "Exception occured while invoking completion delegate."); } } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 64713c8c52c..38f2a5baebd 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -38,6 +38,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -48,6 +49,8 @@ namespace Grpc.Core.Internal /// internal abstract class AsyncCallBase { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + readonly Func serializer; readonly Func deserializer; @@ -233,9 +236,9 @@ namespace Grpc.Core.Internal payload = serializer(msg); return true; } - catch (Exception) + catch (Exception e) { - Console.WriteLine("Exception occured while trying to serialize message"); + Logger.Error(e, "Exception occured while trying to serialize message"); payload = null; return false; } @@ -248,9 +251,9 @@ namespace Grpc.Core.Internal msg = deserializer(payload); return true; } - catch (Exception) + catch (Exception e) { - Console.WriteLine("Exception occured while trying to deserialize message"); + Logger.Error(e, "Exception occured while trying to deserialize message."); msg = default(TRead); return false; } @@ -264,7 +267,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured while invoking completion delegate: " + e); + Logger.Error(e, "Exception occured while invoking completion delegate."); } } diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs index f6d8aa0600f..2796c959a38 100644 --- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs +++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs @@ -35,6 +35,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.InteropServices; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -45,6 +46,8 @@ namespace Grpc.Core.Internal internal class CompletionRegistry { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + readonly GrpcEnvironment environment; readonly ConcurrentDictionary dict = new ConcurrentDictionary(); @@ -81,7 +84,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured while invoking completion delegate: " + e); + Logger.Error(e, "Exception occured while invoking completion delegate."); } finally { diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs index b77e8930447..cb4c7c821e7 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs +++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs @@ -36,7 +36,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using Grpc.Core.Internal; +using Grpc.Core.Logging; namespace Grpc.Core.Internal { @@ -45,6 +45,8 @@ namespace Grpc.Core.Internal /// internal class GrpcThreadPool { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + readonly GrpcEnvironment environment; readonly object myLock = new object(); readonly List threads = new List(); @@ -82,7 +84,7 @@ namespace Grpc.Core.Internal { cq.Shutdown(); - Console.WriteLine("Waiting for GRPC threads to finish."); + Logger.Info("Waiting for GRPC threads to finish."); foreach (var thread in threads) { thread.Join(); @@ -129,12 +131,12 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured while invoking completion delegate: " + e); + Logger.Error(e, "Exception occured while invoking completion delegate"); } } } while (ev.type != GRPCCompletionType.Shutdown); - Console.WriteLine("Completion queue has shutdown successfully, thread " + Thread.CurrentThread.Name + " exiting."); + Logger.Info("Completion queue has shutdown successfully, thread {0} exiting.", Thread.CurrentThread.Name); } } } diff --git a/src/csharp/Grpc.Core/Internal/GrpcLog.cs b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs similarity index 74% rename from src/csharp/Grpc.Core/Internal/GrpcLog.cs rename to src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs index 2f3c8ad71c1..b8a55c5fe85 100644 --- a/src/csharp/Grpc.Core/Internal/GrpcLog.cs +++ b/src/csharp/Grpc.Core/Internal/NativeLogRedirector.cs @@ -44,30 +44,26 @@ namespace Grpc.Core.Internal /// /// Logs from gRPC C core library can get lost if your application is not a console app. - /// This class allows redirection of logs to arbitrary destination. + /// This class allows redirection of logs to gRPC logger. /// - internal static class GrpcLog + internal static class NativeLogRedirector { static object staticLock = new object(); static GprLogDelegate writeCallback; - static TextWriter dest; [DllImport("grpc_csharp_ext.dll")] static extern void grpcsharp_redirect_log(GprLogDelegate callback); /// - /// Sets text writer as destination for logs from native gRPC C core library. - /// Only first invocation has effect. + /// Redirects logs from native gRPC C core library to a general logger. /// - /// - public static void RedirectNativeLogs(TextWriter textWriter) + public static void Redirect() { lock (staticLock) { if (writeCallback == null) { writeCallback = new GprLogDelegate(HandleWrite); - dest = textWriter; grpcsharp_redirect_log(writeCallback); } } @@ -77,13 +73,30 @@ namespace Grpc.Core.Internal { try { - // TODO: DateTime format used here is different than in C core. - dest.WriteLine(string.Format("{0}{1} {2} {3}:{4}: {5}", - Marshal.PtrToStringAnsi(severityStringPtr), DateTime.Now, + var logger = GrpcEnvironment.Logger; + string severityString = Marshal.PtrToStringAnsi(severityStringPtr); + string message = string.Format("{0} {1}:{2}: {3}", threadId, Marshal.PtrToStringAnsi(fileStringPtr), line, - Marshal.PtrToStringAnsi(msgPtr))); + Marshal.PtrToStringAnsi(msgPtr)); + + switch (severityString) + { + case "D": + logger.Debug(message); + break; + case "I": + logger.Info(message); + break; + case "E": + logger.Error(message); + break; + default: + // severity not recognized, default to error. + logger.Error(message); + break; + } } catch (Exception e) { diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 84ea346ebc0..19f0e3c57f6 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -37,6 +37,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core.Internal @@ -50,6 +51,8 @@ namespace Grpc.Core.Internal where TRequest : class where TResponse : class { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + readonly Method method; readonly UnaryServerMethod handler; @@ -85,7 +88,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured in handler: " + e); + Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try @@ -104,6 +107,8 @@ namespace Grpc.Core.Internal where TRequest : class where TResponse : class { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + readonly Method method; readonly ServerStreamingServerMethod handler; @@ -138,7 +143,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured in handler: " + e); + Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } @@ -158,6 +163,8 @@ namespace Grpc.Core.Internal where TRequest : class where TResponse : class { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + readonly Method method; readonly ClientStreamingServerMethod handler; @@ -196,7 +203,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured in handler: " + e); + Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } @@ -216,6 +223,8 @@ namespace Grpc.Core.Internal where TRequest : class where TResponse : class { + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + readonly Method method; readonly DuplexStreamingServerMethod handler; @@ -246,7 +255,7 @@ namespace Grpc.Core.Internal } catch (Exception e) { - Console.WriteLine("Exception occured in handler: " + e); + Logger.Error(e, "Exception occured in handler."); status = HandlerUtils.StatusFromException(e); } try diff --git a/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs new file mode 100644 index 00000000000..c67765c78d5 --- /dev/null +++ b/src/csharp/Grpc.Core/Logging/ConsoleLogger.cs @@ -0,0 +1,103 @@ +#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; + +namespace Grpc.Core.Logging +{ + /// Logger that logs to System.Console. + public class ConsoleLogger : ILogger + { + readonly Type forType; + readonly string forTypeString; + + public ConsoleLogger() : this(null) + { + } + + private ConsoleLogger(Type forType) + { + this.forType = forType; + this.forTypeString = forType != null ? forType.FullName + " " : ""; + } + + public ILogger ForType() + { + if (typeof(T) == forType) + { + return this; + } + return new ConsoleLogger(typeof(T)); + } + + public void Debug(string message, params object[] formatArgs) + { + Log("D", message, formatArgs); + } + + public void Info(string message, params object[] formatArgs) + { + Log("I", message, formatArgs); + } + + public void Warning(string message, params object[] formatArgs) + { + Log("W", message, formatArgs); + } + + public void Warning(Exception exception, string message, params object[] formatArgs) + { + Log("W", message + " " + exception, formatArgs); + } + + public void Error(string message, params object[] formatArgs) + { + Log("E", message, formatArgs); + } + + public void Error(Exception exception, string message, params object[] formatArgs) + { + Log("E", message + " " + exception, formatArgs); + } + + private void Log(string severityString, string message, object[] formatArgs) + { + Console.Error.WriteLine("{0}{1} {2}{3}", + severityString, + DateTime.Now, + forTypeString, + string.Format(message, formatArgs)); + } + } +} diff --git a/src/csharp/Grpc.Core/Logging/ILogger.cs b/src/csharp/Grpc.Core/Logging/ILogger.cs new file mode 100644 index 00000000000..0d58f133e3a --- /dev/null +++ b/src/csharp/Grpc.Core/Logging/ILogger.cs @@ -0,0 +1,57 @@ +#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; + +namespace Grpc.Core.Logging +{ + /// For logging messages. + public interface ILogger + { + /// Returns a logger associated with the specified type. + ILogger ForType(); + + void Debug(string message, params object[] formatArgs); + + void Info(string message, params object[] formatArgs); + + void Warning(string message, params object[] formatArgs); + + void Warning(Exception exception, string message, params object[] formatArgs); + + void Error(string message, params object[] formatArgs); + + void Error(Exception exception, string message, params object[] formatArgs); + } +} diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index fd30735359f..d80e3d624fb 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -38,6 +38,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Logging; using Grpc.Core.Utils; namespace Grpc.Core @@ -52,6 +53,8 @@ namespace Grpc.Core /// public const int PickUnusedPort = 0; + static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); + readonly GrpcEnvironment environment; readonly List options; readonly ServerSafeHandle handle; @@ -233,7 +236,7 @@ namespace Grpc.Core } catch (Exception e) { - Console.WriteLine("Exception while handling RPC: " + e); + Logger.Warning(e, "Exception while handling RPC."); } } diff --git a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs index 4180d989385..82653c3a1f5 100644 --- a/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs +++ b/src/csharp/Grpc.Core/Utils/BenchmarkUtil.cs @@ -46,13 +46,15 @@ namespace Grpc.Core.Utils /// public static void RunBenchmark(int warmupIterations, int benchmarkIterations, Action action) { - Console.WriteLine("Warmup iterations: " + warmupIterations); + var logger = GrpcEnvironment.Logger; + + logger.Info("Warmup iterations: {0}", warmupIterations); for (int i = 0; i < warmupIterations; i++) { action(); } - Console.WriteLine("Benchmark iterations: " + benchmarkIterations); + logger.Info("Benchmark iterations: {0}", benchmarkIterations); var stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < benchmarkIterations; i++) @@ -60,8 +62,8 @@ namespace Grpc.Core.Utils action(); } stopwatch.Stop(); - Console.WriteLine("Elapsed time: " + stopwatch.ElapsedMilliseconds + "ms"); - Console.WriteLine("Ops per second: " + (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds)); + logger.Info("Elapsed time: {0}ms", stopwatch.ElapsedMilliseconds); + logger.Info("Ops per second: {0}", (int)((double)benchmarkIterations * 1000 / stopwatch.ElapsedMilliseconds)); } } } diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index b2397d4e236..2d841a9c119 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -62,7 +62,7 @@ namespace Grpc.IntegrationTesting File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); - var serverCredentials = new SslServerCredentials(new [] { keyCertPair }, rootCert); + var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert); var clientCredentials = new SslCredentials(rootCert, keyCertPair); server = new Server(); @@ -93,6 +93,5 @@ namespace Grpc.IntegrationTesting var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build()); Assert.AreEqual(10, response.Payload.Body.Length); } - } } From a96ac058f47bb155af0e835a679d9b47a57271f9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 14:49:30 -0700 Subject: [PATCH 42/47] make insecure channel and server explicit --- .../Grpc.Core.Tests/ClientServerTest.cs | 4 +- src/csharp/Grpc.Core.Tests/ServerTest.cs | 2 +- src/csharp/Grpc.Core.Tests/TimeoutsTest.cs | 4 +- src/csharp/Grpc.Core/Channel.cs | 18 +++--- src/csharp/Grpc.Core/Credentials.cs | 27 ++++++++- .../Grpc.Core/Internal/ChannelSafeHandle.cs | 6 +- .../Internal/CredentialsSafeHandle.cs | 7 +++ .../Grpc.Core/Internal/ServerSafeHandle.cs | 8 +-- src/csharp/Grpc.Core/Server.cs | 55 +++++++------------ src/csharp/Grpc.Core/ServerCredentials.cs | 22 ++++++++ .../Grpc.Examples.MathClient/MathClient.cs | 2 +- .../Grpc.Examples.MathServer/MathServer.cs | 2 +- .../MathClientServerTests.cs | 4 +- .../HealthClientServerTest.cs | 4 +- .../InteropClientServerTest.cs | 2 +- .../Grpc.IntegrationTesting/InteropServer.cs | 4 +- .../SslCredentialsTest.cs | 2 +- src/csharp/ext/grpc_csharp_ext.c | 4 +- 18 files changed, 105 insertions(+), 72 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 2536c003459..643af4daf9a 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -79,9 +79,9 @@ namespace Grpc.Core.Tests { server = new Server(); server.AddServiceDefinition(ServiceDefinition); - int port = server.AddListeningPort(Host, Server.PickUnusedPort); + int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); server.Start(); - channel = new Channel(Host, port); + channel = new Channel(Host, port, Credentials.Insecure); } [TearDown] diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs index 1119aa370e5..ba9efae8713 100644 --- a/src/csharp/Grpc.Core.Tests/ServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs @@ -45,7 +45,7 @@ namespace Grpc.Core.Tests public void StartAndShutdownServer() { Server server = new Server(); - server.AddListeningPort("localhost", Server.PickUnusedPort); + server.AddPort("localhost", Server.PickUnusedPort, ServerCredentials.Insecure); server.Start(); server.ShutdownAsync().Wait(); GrpcEnvironment.Shutdown(); diff --git a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs index c350391acdd..010ffd898a0 100644 --- a/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs +++ b/src/csharp/Grpc.Core.Tests/TimeoutsTest.cs @@ -72,9 +72,9 @@ namespace Grpc.Core.Tests { server = new Server(); server.AddServiceDefinition(ServiceDefinition); - int port = server.AddListeningPort(Host, Server.PickUnusedPort); + int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); server.Start(); - channel = new Channel(Host, port); + channel = new Channel(Host, port, Credentials.Insecure); stringFromServerHandlerTcs = new TaskCompletionSource(); } diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index e5c6abd2cb4..18e6f2fda57 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -56,26 +56,24 @@ namespace Grpc.Core /// Port will default to 80 for an unsecure channel and to 443 a secure channel. /// /// The DNS name of IP address of the host. - /// Optional credentials to create a secure channel. + /// Credentials to secure the channel. /// Channel options. - public Channel(string host, Credentials credentials = null, IEnumerable options = null) + public Channel(string host, Credentials credentials, IEnumerable options = null) { this.environment = GrpcEnvironment.GetInstance(); this.options = options != null ? new List(options) : new List(); EnsureUserAgentChannelOption(this.options); + using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials()) using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options)) { - if (credentials != null) + if (nativeCredentials != null) { - using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials()) - { - this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs); - } + this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, host, nativeChannelArgs); } else { - this.handle = ChannelSafeHandle.Create(host, nativeChannelArgs); + this.handle = ChannelSafeHandle.CreateInsecure(host, nativeChannelArgs); } } this.target = GetOverridenTarget(host, this.options); @@ -86,9 +84,9 @@ namespace Grpc.Core /// /// DNS name or IP address /// the port - /// Optional credentials to create a secure channel. + /// Credentials to secure the channel. /// Channel options. - public Channel(string host, int port, Credentials credentials = null, IEnumerable options = null) : + public Channel(string host, int port, Credentials credentials, IEnumerable 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/Credentials.cs index d2dbaaf52f1..4fcac0c4c00 100644 --- a/src/csharp/Grpc.Core/Credentials.cs +++ b/src/csharp/Grpc.Core/Credentials.cs @@ -41,17 +41,40 @@ namespace Grpc.Core /// public abstract class Credentials { + static readonly Credentials InsecureInstance = new InsecureCredentialsImpl(); + + /// + /// Returns instance of credential that provides no security and + /// will result in creating an unsecure channel with no encryption whatsoever. + /// + public static Credentials Insecure + { + get + { + return InsecureInstance; + } + } + /// - /// Creates native object for the credentials. + /// Creates native object for the credentials. May return null if insecure channel + /// should be created. /// /// The native credentials. internal abstract CredentialsSafeHandle ToNativeCredentials(); + + private sealed class InsecureCredentialsImpl : Credentials + { + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } } /// /// Client-side SSL credentials. /// - public class SslCredentials : Credentials + public sealed class SslCredentials : Credentials { readonly string rootCertificates; readonly KeyCertificatePair keyCertificatePair; diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs index 53c506c872e..20815efbd35 100644 --- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs @@ -41,7 +41,7 @@ namespace Grpc.Core.Internal internal class ChannelSafeHandle : SafeHandleZeroIsInvalid { [DllImport("grpc_csharp_ext.dll")] - static extern ChannelSafeHandle grpcsharp_channel_create(string target, ChannelArgsSafeHandle channelArgs); + static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs); [DllImport("grpc_csharp_ext.dll")] static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs); @@ -56,9 +56,9 @@ namespace Grpc.Core.Internal { } - public static ChannelSafeHandle Create(string target, ChannelArgsSafeHandle channelArgs) + public static ChannelSafeHandle CreateInsecure(string target, ChannelArgsSafeHandle channelArgs) { - return grpcsharp_channel_create(target, channelArgs); + return grpcsharp_insecure_channel_create(target, channelArgs); } public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs) diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs index 52d4dfbbac9..8b4fa85e5db 100644 --- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs @@ -50,6 +50,13 @@ namespace Grpc.Core.Internal { } + public static CredentialsSafeHandle CreateNullCredentials() + { + var creds = new CredentialsSafeHandle(); + creds.SetHandle(IntPtr.Zero); + return creds; + } + public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair) { if (keyCertPair != null) diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs index 9e1170e6ddb..f9b44b1acfb 100644 --- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs @@ -48,7 +48,7 @@ namespace Grpc.Core.Internal static extern ServerSafeHandle grpcsharp_server_create(CompletionQueueSafeHandle cq, ChannelArgsSafeHandle args); [DllImport("grpc_csharp_ext.dll")] - static extern int grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr); + static extern int grpcsharp_server_add_insecure_http2_port(ServerSafeHandle server, string addr); [DllImport("grpc_csharp_ext.dll")] static extern int grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds); @@ -77,12 +77,12 @@ namespace Grpc.Core.Internal return grpcsharp_server_create(cq, args); } - public int AddListeningPort(string addr) + public int AddInsecurePort(string addr) { - return grpcsharp_server_add_http2_port(this, addr); + return grpcsharp_server_add_insecure_http2_port(this, addr); } - public int AddListeningPort(string addr, ServerCredentialsSafeHandle credentials) + public int AddSecurePort(string addr, ServerCredentialsSafeHandle credentials) { return grpcsharp_server_add_secure_http2_port(this, addr, credentials); } diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index d80e3d624fb..3217547cc47 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -98,28 +98,31 @@ namespace Grpc.Core } /// - /// Add a non-secure port on which server should listen. + /// Add a port on which server should listen. /// Only call this before Start(). /// /// The port on which server will be listening. /// the host /// the port. If zero, an unused port is chosen automatically. - public int AddListeningPort(string host, int port) + public int AddPort(string host, int port, ServerCredentials credentials) { - return AddListeningPortInternal(host, port, null); - } - - /// - /// Add a non-secure port on which server should listen. - /// Only call this before Start(). - /// - /// The port on which server will be listening. - /// the host - /// the port. If zero, an unused port is chosen automatically. - public int AddListeningPort(string host, int port, ServerCredentials credentials) - { - Preconditions.CheckNotNull(credentials); - return AddListeningPortInternal(host, port, credentials); + lock (myLock) + { + Preconditions.CheckNotNull(credentials); + Preconditions.CheckState(!startRequested); + var address = string.Format("{0}:{1}", host, port); + using (var nativeCredentials = credentials.ToNativeCredentials()) + { + if (nativeCredentials != null) + { + return handle.AddSecurePort(address, nativeCredentials); + } + else + { + return handle.AddInsecurePort(address); + } + } + } } /// @@ -186,26 +189,6 @@ namespace Grpc.Core handle.Dispose(); } - private int AddListeningPortInternal(string host, int port, ServerCredentials credentials) - { - lock (myLock) - { - Preconditions.CheckState(!startRequested); - var address = string.Format("{0}:{1}", host, port); - if (credentials != null) - { - using (var nativeCredentials = credentials.ToNativeCredentials()) - { - return handle.AddListeningPort(address, nativeCredentials); - } - } - else - { - return handle.AddListeningPort(address); - } - } - } - /// /// Allows one new RPC call to be received by server. /// diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs index 1b40ce8f6af..32ed4b78a1f 100644 --- a/src/csharp/Grpc.Core/ServerCredentials.cs +++ b/src/csharp/Grpc.Core/ServerCredentials.cs @@ -44,11 +44,33 @@ namespace Grpc.Core /// public abstract class ServerCredentials { + static readonly ServerCredentials InsecureInstance = new InsecureServerCredentialsImpl(); + + /// + /// Returns instance of credential that provides no security and + /// will result in creating an unsecure server port with no encryption whatsoever. + /// + public static ServerCredentials Insecure + { + get + { + return InsecureInstance; + } + } + /// /// Creates native object for the credentials. /// /// The native credentials. internal abstract ServerCredentialsSafeHandle ToNativeCredentials(); + + private sealed class InsecureServerCredentialsImpl : ServerCredentials + { + internal override ServerCredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } } /// diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index cfe2a069160..f9839d99f1d 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) { - using (Channel channel = new Channel("127.0.0.1", 23456)) + using (Channel channel = new Channel("127.0.0.1", 23456, Credentials.Insecure)) { Math.IMathClient client = new Math.MathClient(channel); MathExamples.DivExample(client); diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index f4409851127..468eefbe3e1 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -44,7 +44,7 @@ namespace math Server server = new Server(); server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host, 23456); + int port = server.AddPort(host, 23456, ServerCredentials.Insecure); server.Start(); Console.WriteLine("MathServer listening on port " + port); diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index dd56016a394..ecd9d514fd9 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -56,9 +56,9 @@ namespace math.Tests { server = new Server(); server.AddServiceDefinition(Math.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host, Server.PickUnusedPort); + int port = server.AddPort(host, Server.PickUnusedPort, ServerCredentials.Insecure); server.Start(); - channel = new Channel(host, port); + channel = new Channel(host, port, Credentials.Insecure); client = Math.NewClient(channel); // TODO(jtattermusch): get rid of the custom header here once we have dedicated tests diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index bc14a0a62f2..9d89698a8f0 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -59,9 +59,9 @@ namespace Grpc.HealthCheck.Tests server = new Server(); server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl)); - int port = server.AddListeningPort(Host, Server.PickUnusedPort); + int port = server.AddPort(Host, Server.PickUnusedPort, ServerCredentials.Insecure); server.Start(); - channel = new Channel(Host, port); + channel = new Channel(Host, port, Credentials.Insecure); client = Grpc.Health.V1Alpha.Health.NewClient(channel); } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index f306289cfb5..7e913b3b8b8 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -57,7 +57,7 @@ namespace Grpc.IntegrationTesting { server = new Server(); server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); - int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials()); + int port = server.AddPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials()); server.Start(); var options = new List diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 9475e66c408..bf6947e09dc 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -95,11 +95,11 @@ namespace Grpc.IntegrationTesting int port = options.port.Value; if (options.useTls) { - server.AddListeningPort(host, port, TestCredentials.CreateTestServerCredentials()); + server.AddPort(host, port, TestCredentials.CreateTestServerCredentials()); } else { - server.AddListeningPort(host, options.port.Value); + server.AddPort(host, options.port.Value, ServerCredentials.Insecure); } Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port)); server.Start(); diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index 2d841a9c119..1baf40eea2e 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -67,7 +67,7 @@ namespace Grpc.IntegrationTesting server = new Server(); server.AddServiceDefinition(TestService.BindService(new TestServiceImpl())); - int port = server.AddListeningPort(host, Server.PickUnusedPort, serverCredentials); + int port = server.AddPort(host, Server.PickUnusedPort, serverCredentials); server.Start(); var options = new List diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 756493358fc..1c5891bbffe 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -367,7 +367,7 @@ grpcsharp_completion_queue_pluck(grpc_completion_queue *cq, void *tag) { /* Channel */ GPR_EXPORT grpc_channel *GPR_CALLTYPE -grpcsharp_channel_create(const char *target, const grpc_channel_args *args) { +grpcsharp_insecure_channel_create(const char *target, const grpc_channel_args *args) { return grpc_channel_create(target, args); } @@ -717,7 +717,7 @@ grpcsharp_server_create(grpc_completion_queue *cq, } GPR_EXPORT gpr_int32 GPR_CALLTYPE -grpcsharp_server_add_http2_port(grpc_server *server, const char *addr) { +grpcsharp_server_add_insecure_http2_port(grpc_server *server, const char *addr) { return grpc_server_add_http2_port(server, addr); } From d2a9b6da13d84e9e9cb75b56e0adc365a35b0ee0 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Sat, 25 Jul 2015 00:56:33 +0000 Subject: [PATCH 43/47] Isolate nullptr to grpc namespace when we must define it ourselves Change the one non-namespace use of nullptr to NULL (used as an argument to a C function anyway) --- include/grpc++/config.h | 2 ++ test/cpp/qps/timer.cc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/grpc++/config.h b/include/grpc++/config.h index 1362c0a1fa8..889dc39eb7b 100644 --- a/include/grpc++/config.h +++ b/include/grpc++/config.h @@ -79,6 +79,7 @@ #ifdef GRPC_CXX0X_NO_NULLPTR #include +namespace grpc { const class { public: template @@ -98,6 +99,7 @@ const class { private: void operator&() const = delete; } nullptr = {}; +} #endif #ifndef GRPC_CUSTOM_STRING diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc index 07289f699bf..c1ba23decd9 100644 --- a/test/cpp/qps/timer.cc +++ b/test/cpp/qps/timer.cc @@ -52,7 +52,7 @@ static double time_double(struct timeval* tv) { Timer::Result Timer::Sample() { struct rusage usage; struct timeval tv; - gettimeofday(&tv, nullptr); + gettimeofday(&tv, NULL); getrusage(RUSAGE_SELF, &usage); Result r; From 6832792c20d0f3bc9ca9c74d34d891f9d58da46e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 21:08:16 -0700 Subject: [PATCH 44/47] add NUnitTestAdapter for VS --- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 16 ++++++++++++++++ src/csharp/Grpc.Core.Tests/packages.config | 1 + 2 files changed, 17 insertions(+) diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 9364779df9e..7582d1359f4 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -28,9 +28,25 @@ false + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll + False + + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.interfaces.dll + False + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll + + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.util.dll + False + + + ..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll + False + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config index 28af8d78c6c..62077f41bee 100644 --- a/src/csharp/Grpc.Core.Tests/packages.config +++ b/src/csharp/Grpc.Core.Tests/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file From 9b048e529e9db136e48867f98d5e325d4faffd06 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 21:20:24 -0700 Subject: [PATCH 45/47] introducing async tests --- .../Grpc.Core.Tests/ClientServerTest.cs | 69 ++++----- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 4 +- .../MathClientServerTests.cs | 138 ++++++++---------- 3 files changed, 93 insertions(+), 118 deletions(-) diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index 643af4daf9a..e286ea519f9 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -158,59 +158,50 @@ namespace Grpc.Core.Tests } [Test] - public void AsyncUnaryCall_ServerHandlerThrows() + public async Task AsyncUnaryCall_ServerHandlerThrows() { - Task.Run(async () => + var internalCall = new Call(ServiceName, EchoMethod, channel, Metadata.Empty); + try { - var internalCall = new Call(ServiceName, EchoMethod, channel, Metadata.Empty); - try - { - await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); - } - }).Wait(); + await Calls.AsyncUnaryCall(internalCall, "THROW", CancellationToken.None); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Unknown, e.Status.StatusCode); + } } [Test] - public void ClientStreamingCall() + public async Task ClientStreamingCall() { - Task.Run(async () => - { - var internalCall = new Call(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); - var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None); + var internalCall = new Call(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); + var call = Calls.AsyncClientStreamingCall(internalCall, CancellationToken.None); - await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); - Assert.AreEqual("ABC", await call.ResponseAsync); - }).Wait(); + await call.RequestStream.WriteAll(new string[] { "A", "B", "C" }); + Assert.AreEqual("ABC", await call.ResponseAsync); } [Test] - public void ClientStreamingCall_CancelAfterBegin() + public async Task ClientStreamingCall_CancelAfterBegin() { - Task.Run(async () => - { - var internalCall = new Call(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); + var internalCall = new Call(ServiceName, ConcatAndEchoMethod, channel, Metadata.Empty); - var cts = new CancellationTokenSource(); - var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token); + var cts = new CancellationTokenSource(); + var call = Calls.AsyncClientStreamingCall(internalCall, cts.Token); - // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. - await Task.Delay(1000); - cts.Cancel(); + // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. + await Task.Delay(1000); + cts.Cancel(); - try - { - await call.ResponseAsync; - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } - }).Wait(); + try + { + await call.ResponseAsync; + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); + } } [Test] diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 7582d1359f4..618951cb8ae 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -77,7 +77,9 @@ - + + Designer + diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index ecd9d514fd9..26f332c1cf7 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -108,123 +108,105 @@ namespace math.Tests } [Test] - public void DivAsync() + public async Task DivAsync() { - Task.Run(async () => - { - DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); - Assert.AreEqual(3, response.Quotient); - Assert.AreEqual(1, response.Remainder); - }).Wait(); + DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); + Assert.AreEqual(3, response.Quotient); + Assert.AreEqual(1, response.Remainder); } [Test] - public void Fib() + public async Task Fib() { - Task.Run(async () => + using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) { - using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) - { - var responses = await call.ResponseStream.ToList(); - CollectionAssert.AreEqual(new List { 1, 1, 2, 3, 5, 8 }, - responses.ConvertAll((n) => n.Num_)); - } - }).Wait(); + var responses = await call.ResponseStream.ToList(); + CollectionAssert.AreEqual(new List { 1, 1, 2, 3, 5, 8 }, + responses.ConvertAll((n) => n.Num_)); + } } [Test] - public void FibWithCancel() + public async Task FibWithCancel() { - Task.Run(async () => + var cts = new CancellationTokenSource(); + + using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), + cancellationToken: cts.Token)) { - var cts = new CancellationTokenSource(); + List responses = new List(); - using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), - cancellationToken: cts.Token)) + try { - List responses = new List(); - - try + while (await call.ResponseStream.MoveNext()) { - while (await call.ResponseStream.MoveNext()) + if (responses.Count == 0) { - if (responses.Count == 0) - { - cts.CancelAfter(500); // make sure we cancel soon - } - responses.Add(call.ResponseStream.Current.Num_); + cts.CancelAfter(500); // make sure we cancel soon } - Assert.Fail(); - } - catch (RpcException e) - { - Assert.IsTrue(responses.Count > 0); - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); + responses.Add(call.ResponseStream.Current.Num_); } + Assert.Fail(); + } + catch (RpcException e) + { + Assert.IsTrue(responses.Count > 0); + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); } - }).Wait(); + } } [Test] - public void FibWithDeadline() + public async Task FibWithDeadline() { - Task.Run(async () => + using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), + deadline: DateTime.UtcNow.AddMilliseconds(500))) { - using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), - deadline: DateTime.UtcNow.AddMilliseconds(500))) + try { - try - { - await call.ResponseStream.ToList(); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); - } + await call.ResponseStream.ToList(); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.DeadlineExceeded, e.Status.StatusCode); } - }).Wait(); + } } // TODO: test Fib with limit=0 and cancellation [Test] - public void Sum() + public async Task Sum() { - Task.Run(async () => + using (var call = client.Sum()) { - using (var call = client.Sum()) - { - var numbers = new List { 10, 20, 30 }.ConvertAll( - n => Num.CreateBuilder().SetNum_(n).Build()); + var numbers = new List { 10, 20, 30 }.ConvertAll( + n => Num.CreateBuilder().SetNum_(n).Build()); - await call.RequestStream.WriteAll(numbers); - var result = await call.ResponseAsync; - Assert.AreEqual(60, result.Num_); - } - }).Wait(); + await call.RequestStream.WriteAll(numbers); + var result = await call.ResponseAsync; + Assert.AreEqual(60, result.Num_); + } } [Test] - public void DivMany() + public async Task DivMany() { - Task.Run(async () => + var divArgsList = new List { - var divArgsList = new List - { - new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), - new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), - new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() - }; + new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), + new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), + new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() + }; - using (var call = client.DivMany()) - { - await call.RequestStream.WriteAll(divArgsList); - var result = await call.ResponseStream.ToList(); + using (var call = client.DivMany()) + { + await call.RequestStream.WriteAll(divArgsList); + var result = await call.ResponseStream.ToList(); - CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); - CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); - } - }).Wait(); + CollectionAssert.AreEqual(new long[] { 3, 4, 3 }, result.ConvertAll((divReply) => divReply.Quotient)); + CollectionAssert.AreEqual(new long[] { 1, 16, 1 }, result.ConvertAll((divReply) => divReply.Remainder)); + } } } } From b98e1dd7c4f1038b61992e20efe2173c289b08f9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 21:30:14 -0700 Subject: [PATCH 46/47] make some interop tests run as async methods --- .../Grpc.IntegrationTesting/InteropClient.cs | 254 ++++++++---------- .../InteropClientServerTest.cs | 24 +- 2 files changed, 130 insertions(+), 148 deletions(-) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index ce255f94237..4f8a5a5da73 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -130,12 +130,12 @@ namespace Grpc.IntegrationTesting client.HeaderInterceptor = OAuth2InterceptorFactory.Create(credential); } - RunTestCase(options.testCase, client); + RunTestCaseAsync(options.testCase, client).Wait(); } GrpcEnvironment.Shutdown(); } - private void RunTestCase(string testCase, TestService.TestServiceClient client) + private async Task RunTestCaseAsync(string testCase, TestService.TestServiceClient client) { switch (testCase) { @@ -146,16 +146,16 @@ namespace Grpc.IntegrationTesting RunLargeUnary(client); break; case "client_streaming": - RunClientStreaming(client); + await RunClientStreamingAsync(client); break; case "server_streaming": - RunServerStreaming(client); + await RunServerStreamingAsync(client); break; case "ping_pong": - RunPingPong(client); + await RunPingPongAsync(client); break; case "empty_stream": - RunEmptyStream(client); + await RunEmptyStreamAsync(client); break; case "service_account_creds": RunServiceAccountCreds(client); @@ -170,10 +170,10 @@ namespace Grpc.IntegrationTesting RunPerRpcCreds(client); break; case "cancel_after_begin": - RunCancelAfterBegin(client); + await RunCancelAfterBeginAsync(client); break; case "cancel_after_first_response": - RunCancelAfterFirstResponse(client); + await RunCancelAfterFirstResponseAsync(client); break; case "benchmark_empty_unary": RunBenchmarkEmptyUnary(client); @@ -207,118 +207,106 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunClientStreaming(TestService.ITestServiceClient client) + public static async Task RunClientStreamingAsync(TestService.ITestServiceClient client) { - Task.Run(async () => - { - Console.WriteLine("running client_streaming"); + Console.WriteLine("running client_streaming"); - var bodySizes = new List { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build()); + var bodySizes = new List { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build()); - using (var call = client.StreamingInputCall()) - { - await call.RequestStream.WriteAll(bodySizes); + using (var call = client.StreamingInputCall()) + { + await call.RequestStream.WriteAll(bodySizes); - var response = await call.ResponseAsync; - Assert.AreEqual(74922, response.AggregatedPayloadSize); - } - Console.WriteLine("Passed!"); - }).Wait(); + var response = await call.ResponseAsync; + Assert.AreEqual(74922, response.AggregatedPayloadSize); + } + Console.WriteLine("Passed!"); } - public static void RunServerStreaming(TestService.ITestServiceClient client) + public static async Task RunServerStreamingAsync(TestService.ITestServiceClient client) { - Task.Run(async () => - { - Console.WriteLine("running server_streaming"); + Console.WriteLine("running server_streaming"); - var bodySizes = new List { 31415, 9, 2653, 58979 }; + var bodySizes = new List { 31415, 9, 2653, 58979 }; - var request = StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddRangeResponseParameters(bodySizes.ConvertAll( - (size) => ResponseParameters.CreateBuilder().SetSize(size).Build())) - .Build(); + var request = StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddRangeResponseParameters(bodySizes.ConvertAll( + (size) => ResponseParameters.CreateBuilder().SetSize(size).Build())) + .Build(); - using (var call = client.StreamingOutputCall(request)) + using (var call = client.StreamingOutputCall(request)) + { + var responseList = await call.ResponseStream.ToList(); + foreach (var res in responseList) { - var responseList = await call.ResponseStream.ToList(); - foreach (var res in responseList) - { - Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); - } - CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length)); + Assert.AreEqual(PayloadType.COMPRESSABLE, res.Payload.Type); } - Console.WriteLine("Passed!"); - }).Wait(); + CollectionAssert.AreEqual(bodySizes, responseList.ConvertAll((item) => item.Payload.Body.Length)); + } + Console.WriteLine("Passed!"); } - public static void RunPingPong(TestService.ITestServiceClient client) + public static async Task RunPingPongAsync(TestService.ITestServiceClient client) { - Task.Run(async () => - { - Console.WriteLine("running ping_pong"); + Console.WriteLine("running ping_pong"); - using (var call = client.FullDuplexCall()) - { - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) - .SetPayload(CreateZerosPayload(27182)).Build()); + using (var call = client.FullDuplexCall()) + { + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) + .SetPayload(CreateZerosPayload(27182)).Build()); - Assert.IsTrue(await call.ResponseStream.MoveNext()); - Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); - Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); + Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9)) - .SetPayload(CreateZerosPayload(8)).Build()); + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9)) + .SetPayload(CreateZerosPayload(8)).Build()); - Assert.IsTrue(await call.ResponseStream.MoveNext()); - Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); - Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); + Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653)) - .SetPayload(CreateZerosPayload(1828)).Build()); + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653)) + .SetPayload(CreateZerosPayload(1828)).Build()); - Assert.IsTrue(await call.ResponseStream.MoveNext()); - Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); - Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); + Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979)) - .SetPayload(CreateZerosPayload(45904)).Build()); + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979)) + .SetPayload(CreateZerosPayload(45904)).Build()); - Assert.IsTrue(await call.ResponseStream.MoveNext()); - Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); - Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); + Assert.AreEqual(58979, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.CompleteAsync(); + await call.RequestStream.CompleteAsync(); - Assert.IsFalse(await call.ResponseStream.MoveNext()); - } - Console.WriteLine("Passed!"); - }).Wait(); + Assert.IsFalse(await call.ResponseStream.MoveNext()); + } + Console.WriteLine("Passed!"); } - public static void RunEmptyStream(TestService.ITestServiceClient client) + public static async Task RunEmptyStreamAsync(TestService.ITestServiceClient client) { - Task.Run(async () => + Console.WriteLine("running empty_stream"); + using (var call = client.FullDuplexCall()) { - Console.WriteLine("running empty_stream"); - using (var call = client.FullDuplexCall()) - { - await call.RequestStream.CompleteAsync(); + await call.RequestStream.CompleteAsync(); - var responseList = await call.ResponseStream.ToList(); - Assert.AreEqual(0, responseList.Count); - } - Console.WriteLine("Passed!"); - }).Wait(); + var responseList = await call.ResponseStream.ToList(); + Assert.AreEqual(0, responseList.Count); + } + Console.WriteLine("Passed!"); } public static void RunServiceAccountCreds(TestService.ITestServiceClient client) @@ -406,65 +394,59 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunCancelAfterBegin(TestService.ITestServiceClient client) + public static async Task RunCancelAfterBeginAsync(TestService.ITestServiceClient client) { - Task.Run(async () => + Console.WriteLine("running cancel_after_begin"); + + var cts = new CancellationTokenSource(); + using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) { - Console.WriteLine("running cancel_after_begin"); + // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. + await Task.Delay(1000); + cts.Cancel(); - var cts = new CancellationTokenSource(); - using (var call = client.StreamingInputCall(cancellationToken: cts.Token)) + try { - // TODO(jtattermusch): we need this to ensure call has been initiated once we cancel it. - await Task.Delay(1000); - cts.Cancel(); - - try - { - var response = await call.ResponseAsync; - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } + var response = await call.ResponseAsync; + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); } - Console.WriteLine("Passed!"); - }).Wait(); + } + Console.WriteLine("Passed!"); } - public static void RunCancelAfterFirstResponse(TestService.ITestServiceClient client) + public static async Task RunCancelAfterFirstResponseAsync(TestService.ITestServiceClient client) { - Task.Run(async () => - { - Console.WriteLine("running cancel_after_first_response"); + Console.WriteLine("running cancel_after_first_response"); - var cts = new CancellationTokenSource(); - using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) - { - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) - .SetPayload(CreateZerosPayload(27182)).Build()); + var cts = new CancellationTokenSource(); + using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) + { + await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() + .SetResponseType(PayloadType.COMPRESSABLE) + .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) + .SetPayload(CreateZerosPayload(27182)).Build()); - Assert.IsTrue(await call.ResponseStream.MoveNext()); - Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); - Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); + Assert.IsTrue(await call.ResponseStream.MoveNext()); + Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); + Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); - cts.Cancel(); + cts.Cancel(); - try - { - await call.ResponseStream.MoveNext(); - Assert.Fail(); - } - catch (RpcException e) - { - Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); - } + try + { + await call.ResponseStream.MoveNext(); + Assert.Fail(); + } + catch (RpcException e) + { + Assert.AreEqual(StatusCode.Cancelled, e.Status.StatusCode); } - Console.WriteLine("Passed!"); - }).Wait(); + } + Console.WriteLine("Passed!"); } // This is not an official interop test, but it's useful. diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index 7e913b3b8b8..2756ce97aa3 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -89,39 +89,39 @@ namespace Grpc.IntegrationTesting } [Test] - public void ClientStreaming() + public async Task ClientStreaming() { - InteropClient.RunClientStreaming(client); + await InteropClient.RunClientStreamingAsync(client); } [Test] - public void ServerStreaming() + public async Task ServerStreaming() { - InteropClient.RunServerStreaming(client); + await InteropClient.RunServerStreamingAsync(client); } [Test] - public void PingPong() + public async Task PingPong() { - InteropClient.RunPingPong(client); + await InteropClient.RunPingPongAsync(client); } [Test] - public void EmptyStream() + public async Task EmptyStream() { - InteropClient.RunEmptyStream(client); + await InteropClient.RunEmptyStreamAsync(client); } [Test] - public void CancelAfterBegin() + public async Task CancelAfterBegin() { - InteropClient.RunCancelAfterBegin(client); + await InteropClient.RunCancelAfterBeginAsync(client); } [Test] - public void CancelAfterFirstResponse() + public async Task CancelAfterFirstResponse() { - InteropClient.RunCancelAfterFirstResponse(client); + await InteropClient.RunCancelAfterFirstResponseAsync(client); } } } From 9a5c4f516fedd13d2ccbf75745ec89d7b6d620df Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 24 Jul 2015 23:22:59 -0700 Subject: [PATCH 47/47] make sure async test wont be silently skipped with old NUnit --- .../Grpc.Core.Tests/Grpc.Core.Tests.csproj | 1 + .../Grpc.Core.Tests/NUnitVersionTest.cs | 79 +++++++++++++++++++ tools/run_tests/run_csharp.sh | 5 +- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 618951cb8ae..1c4cca8b698 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -68,6 +68,7 @@ + diff --git a/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs new file mode 100644 index 00000000000..600df1a18dd --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/NUnitVersionTest.cs @@ -0,0 +1,79 @@ +#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 Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + /// + /// Tests if the version of nunit-console used is sufficient to run async tests. + /// + public class NUnitVersionTest + { + private int testRunCount = 0; + + [TestFixtureTearDown] + public void Cleanup() + { + if (testRunCount != 2) + { + Console.Error.WriteLine("You are using and old version of NUnit that doesn't support async tests and skips them instead. " + + "This test has failed to indicate that."); + Console.Error.Flush(); + Environment.Exit(1); + } + } + + [Test] + public void NUnitVersionTest1() + { + testRunCount++; + } + + // Old version of NUnit will skip this test + [Test] + public async Task NUnitVersionTest2() + { + testRunCount ++; + await Task.Delay(10); + } + + + } +} diff --git a/tools/run_tests/run_csharp.sh b/tools/run_tests/run_csharp.sh index 752e83ef705..c0fedca1935 100755 --- a/tools/run_tests/run_csharp.sh +++ b/tools/run_tests/run_csharp.sh @@ -32,6 +32,8 @@ set -ex CONFIG=${CONFIG:-opt} +NUNIT_CONSOLE="mono packages/NUnit.Runners.2.6.4/tools/nunit-console.exe" + if [ "$CONFIG" = "dbg" ] then MSBUILD_CONFIG="Debug" @@ -46,6 +48,7 @@ root=`pwd` cd src/csharp export LD_LIBRARY_PATH=$root/libs/$CONFIG -nunit-console -labels "$1/bin/$MSBUILD_CONFIG/$1.dll" + +$NUNIT_CONSOLE -labels "$1/bin/$MSBUILD_CONFIG/$1.dll"